"A tool that can read any text field has to draw one line in permanent ink: never the password."
The Field You Must Not Touch
Flint's whole job is reading and writing text fields, which makes one category of field radically off-limits: the secure field — a password box, a PIN entry, anything the app has marked as sensitive. Reading a password for 'context' would be a catastrophe; writing into a secure control blindly is nearly as bad. So Flint treats secure fields as a place it simply does not go. This isn't a soft preference; it's the one boundary in the app drawn in permanent ink.
Detect at Capture
The enforcement lives at the earliest possible moment: capture. When Flint snapshots the focused element, it also reads the element's role and subrole. macOS marks secure text fields with a secure subrole, so a single check at capture time tells Flint 'this is a password field.' If it is, Flint stops right there — it does not read the selection, does not build any context, does not proceed. Catching it at capture means a secure field never even becomes a candidate for a transformation.
capture focused element
read role + subrole
subrole == secure text field ?
yes -> STOP. no read, no context, no insert. off-limits.
no -> continue with the normal flow
What About Opaque Fields?
The opaque targets from Track 3 complicate this honestly. A Chromium or Electron app that hides its focused element also hides whether that element is secure — Flint can't see the field type. Its rule there is conservative in a different way: the window-level fallback pastes at the existing keyboard focus without ever reading the destination's contents. So even where Flint can't confirm a field is safe, it never reads it; the absolute half of the rule — never read a secret — holds even when the classification is invisible.
Enforce your hardest boundary at the earliest point in the flow. The most important 'never' in a system should be checked before anything else happens, not deep in the logic where a code path might skip it. Flint checks for a secure field at capture — the first step — so no later branch can accidentally read or target it. The earlier a critical guard sits, the fewer ways there are to get around it, and the boundary that must never break should have the fewest gates in front of it.
Never read is absolute; refuse to write is where the role is known. The two halves of the rule have different reach. 'Never read a secure field' holds unconditionally — including opaque targets, where Flint simply never inspects destination content. 'Refuse to write' applies wherever the control declares itself secure; for opaque windows that don't disclose the field type, Flint's window-level paste writes at focus without reading, which keeps the read-boundary intact even when the write-classification is unavailable.
Exercise
Explain why the secure-field check belongs at capture rather than just before insertion, using a concrete flow where a late check could be skipped. Then handle the harder case: an opaque Electron app whose focused element type is invisible to Accessibility — which half of 'never read the secret' still holds absolutely, and how does Flint honor it without being able to classify the field?
Hint
At capture, the check gates the entire flow, so no later branch (a fallback path, an early return) can read or target a secure field; a check only 'just before insertion' could be bypassed by any path that reads context earlier. For the opaque case, the 'never read' half holds absolutely: Flint's window-level fallback pastes at the existing focus without ever reading the destination's contents, so it can't classify the field but also never inspects it — the read-boundary survives the missing classification.