A rotation job holds read rights over every stored value because each write reads the current value first — how do you remove that read right?
answer
- the widest read right is a robot
- merge, skip, compare, validate all read
- ask about the value, not for it
- conditional write sends the expected version
- migration reads once, on a temporary identity
basics
~20 sRemove the reasons the write reads. Store each credential as its own whole value so a write replaces rather than merges, compare versions instead of contents, check existence through metadata, and let the consumer confirm by use — then the job needs write and version metadata only.
solid answer
~50 sThe read right did not come from a decision; it came from the write path's shape. A job that merges one field into a structured value must fetch the whole record, one that skips values already set must look, and one that avoids clobbering a concurrent change compares contents. Because the job runs for every team, that read is estate-wide — usually the widest grant in the estate, held by a robot nobody reviews. Each shape has a replacement that needs metadata rather than contents: give each credential its own name so a write replaces it whole; send the **expected version** with the write and let the store reject a mismatch; test existence, not value; and confirm by the consumer authenticating. What survives is genuinely rare, and it belongs on a temporary identity, not a standing one.
code
pseudocode · 14 lines# Why the job ended up holding read over every stored value
rotate(name):
current = store.read(name) # the only line that needs a read right
updated = replaceField(current, password, generate(name.format))
store.write(name, updated) # merging is what forced the read
# Blind write: the password is its own value, so a write replaces it whole
rotate(name):
expected = store.versionOf(name) # metadata about the value, not its contents
ok = store.writeNewValue(name, generate(policyFor(name)), ifVersion = expected)
if not ok:
# another writer moved first; no comparison of contents anywhere
retry(name)
# correctness is confirmed by the consumer authenticating, never by reading backgo deeper
Recall that a job which changes a stored value does not automatically need to see it, and that a permission held by an automated job counts exactly as much as one held by a person.
Explain the four write-path shapes that force a read — merging a field, skipping when set, comparing before writing, validating after — and the metadata each one can use instead.
Show the diagnosis: find the widest read grant in the estate, trace it to the write path that created it, and change the path rather than trimming the grant around a design that still reads.
Own the consequence for naming and tooling: whether credentials get their own names estate-wide, and how a standing automation identity is reviewed against the one-off it was modelled on.
## The widest read right in the estate usually belongs to a robot When a team audits who can read the payments team's database password, they look at people. The answer is often a rotation job, and its grant is far wider than any person's, because the job runs for every team and therefore holds read over every name. Nobody granted that deliberately. It arrived as a consequence of how the write was written. This matters exactly as much as a human holding the same right. A standing identity that can read every value is a standing identity worth stealing, it runs unattended, and its reads look routine in the record because they are. ## Four shapes that turn a write into a read 1. **Merge a field.** The stored value is a structured record — a host, a port, a user name and a password together — and the job changes one field. To write the record back intact, it must first fetch the record, password included. 2. **Skip if already set.** The job avoids overwriting a value someone configured by hand, so it reads first and writes only when the value is empty or matches a placeholder. 3. **Compare before writing.** To avoid a needless write, or to refuse to clobber a change made since the run started, the job reads the current contents and compares. 4. **Validate after writing.** The job reads the value back to confirm that what it sent is what landed. Every one of them is defensible in isolation, and together they explain nearly every estate-wide read grant that exists. ## Replacing each one | Shape | What it actually wanted | Replacement | Right it needs | |---|---|---|---| | Merge a field | to preserve the rest of the record | keep the credential as its own value, so a write replaces it whole | write | | Skip if already set | to know whether a value exists | ask whether the name exists, not what it holds | existence or metadata | | Compare before writing | to detect a concurrent change | send the expected version with the write and let the store reject a mismatch | version metadata, write | | Validate after writing | to know the rotation took effect | let the consumer authenticate with the value and report | none | The common thread: each replacement asks the store about the value rather than for it. A version number, an existence flag, a last-modified stamp and a content fingerprint are all metadata, and a grant over metadata is not a grant over contents — provided the fingerprint is not itself short enough to brute-force back into the value, which for a generated password it is not. The format problem has the same answer. A job that must generate a value of the right shape takes the shape from a record **about** the credential — length, character classes, which account it belongs to — not by inspecting the value it is replacing. ## What you give up - **Idempotence gets cheaper but coarser.** Without reading, the job cannot tell "already the value I would have written" from "a different value"; it writes a new version either way. For a rotated credential that is correct behaviour, since the point is a new value. - **Splitting a structured record into separate names is real work**, and it moves a decision into how values are named — which is a subject of its own. - **Conflict handling becomes explicit.** A rejected conditional write has to be handled: re-read the version, regenerate, retry, and give up loudly rather than silently overwriting. ## When a read really is required Some jobs genuinely need contents: moving values from one store to another, or re-encrypting an estate under new protection. Those are real, and they are also **one-off**. The distinction is standing against temporary: a migration gets an identity that exists for the migration, is scoped to what it moves, is recorded, and is removed at the end. How such a grant is requested, approved and expired is a separate subject; what belongs here is the rule that a permanent robot should not carry a right that a one-off job needed. The interview-grade version of the whole answer is short: the read right is not a permission problem, it is a design problem in the write path. Narrowing the grant while the write path still reads just moves the same right to a smaller name. Change what the write does, and the grant narrows by itself — and then it stays narrow, because the job would break if someone widened the shape again.
- The job must not clobber a change made by someone else mid-run. How does it detect that without reading?By version rather than by contents. It notes the version the name is on, sends that version with the write, and the store refuses the write if the name has moved on. The job then re-reads the version — not the value — regenerates and retries, or fails loudly. Detecting a concurrent change never required knowing what the other writer put there.
- Why is granting that read right for a shorter window not a fix?Because the write path still reads, so the right still has to exist, and while it exists it covers every value the job touches. A short window narrows when the estate is exposed, not to what; and the grant is renewed on every run, which is continuous in practice. Removing the read from the write path removes the right permanently.
- A migration genuinely has to read every value to copy it. How is that different?It is temporary and attributable. A migration identity exists for the migration, is scoped to what it moves, has every read recorded, and is removed when the move completes — after which the values it touched are usually replaced anyway. The defect is a permanent robot carrying a right that only a one-off job ever needed.
saying these in an interview costs you the question
- Says the store requires the old value before it will accept a write
- Treats a read right that only a robot uses as harmless
- Shortens the grant's lifetime instead of removing the read
- Assumes comparing contents is the only way to detect a concurrent change
- Keeps merging fields into one record and calls the read unavoidable