Passante A Passante publication

En Passante

In Passing
Field Kit

Five lists disagreed about what was installed

A static manifest records intent, not state, so enumerate dynamic resources by probing the live system and let files supply only the metadata the probe cannot.

What happened

On 2026-09-08 a coding assistant built a resource picker from a YAML manifest instead of the live system, listing software the user did not have and omitting what they did, and a follow-up inventory found five separate lists that disagreed, with one shared roster proposed to resolve four reported issues.

2026-09-08 a local dev app · YAML and JSON manifests measured: five disagreeing lists, four reported issues
4 prompts, in order
  1. Find the authoritative list before coding A picker, dropdown or status panel shows resources the machine does not have, or omits ones it does.
  2. Inventory every copy of the list Two components disagree about supported resources, or a one-line fix in one file did not change the symptom.
  3. Write a checker that probes reality The lists have been unified once and you need the fix to survive the next contributor.
  4. Generate the second format, never maintain it A guide, plan or status page exists in two formats and they have started to disagree.

1Find the authoritative list before coding

Run it when
A picker, dropdown or status panel shows resources the machine does not have, or omits ones it does.
It asks you for
The exact wrong output, every candidate source of the list, and how each source is produced.
You get back
A ranked list of sources with one named primary authority, and the reason the others are secondary.
It refuses if
No live probe exists for the resource type, so authority cannot be established by evidence.
copy this into a model
<stance>
You have chased this the expensive way. A resource list rendered cleanly, parsed without error, and was wrong in both directions at once: entries for software that was never installed, nothing for software that was. The file was not corrupt. It was simply a record of what someone intended at the time they wrote it. The wrong answer that will feel persuasive here is the file that parses, because a clean parse looks like confirmation. It is not. Treat every static list as a claim that needs checking against the machine.
</stance>

<inputs>
Ask for these and wait. Do not reason from assumptions about a missing item.
1. The incorrect output as rendered, verbatim, including wrong entries and missing ones.
2. Every file this list could come from, such as config files or committed JSON.
3. Any list text supplied in the request itself, quoted exactly.
4. For each source, who writes it and when it was last written.
5. The command or API call that reports what is actually present right now.
</inputs>

<method>

1. Run or ask for the live enumeration from input 5. Record its exact output. This is your reference set.
2. For each candidate source, extract the list it implies and diff it against the reference set. Report per-source counts of entries present only in the file and only in the live probe.
3. Rank by authority, not convenience. A live probe outranks text supplied in the request. That text outranks a committed file. A committed file outranks a file generated by an unrelated tool.
4. Name the primary authority in one sentence. State which fields it cannot supply, such as display names or capability flags. Those fields, and only those, may come from a file.
5. If no live probe exists, stop. Say the question cannot be settled yet. State what command or endpoint would settle it.

</method>

<deliver>

- Reference set: the live output, quoted
- Source table: each candidate, its implied list, its two diff counts
- Primary authority: one named source and why
- Metadata exception: fields that must still come from a file
- Unresolved: anything the evidence does not settle

</deliver>

<refuse>
Do not declare a source authoritative because it is well formatted, checked into the repository, or easiest to read. Do not infer the live state from the file you are testing. Do not fill a gap in the probe output with a plausible default. If input 1 or input 5 is missing, say so and stop rather than proceeding on a guess.
</refuse>

2Inventory every copy of the list

Run it when
Two components disagree about supported resources, or a one-line fix in one file did not change the symptom.
It asks you for
Repository search permission, the resource names in dispute, and the list of components that render or validate them.
You get back
Every location the list is defined, a disagreement matrix, and a migration plan to one roster.
It refuses if
The search is incomplete or a consumer's source is unavailable, making the count unverifiable.
copy this into a model
<stance>
You have seen a synchronisation bug get fixed four times in four files and come back on the fifth. In the case these notes record, an inventory turned up five separate lists of the same resource that disagreed with each other, and a single shared roster resolved four distinct reported issues at once. The persuasive wrong move is to patch the file nearest the symptom and call it done. Duplication is the defect. Each copy is a future contradiction with a date on it.
</stance>

<inputs>
Request these and wait for each.
1. The resource names currently in dispute, as the user sees them.
2. Permission to search the whole tree, and the directories to skip.
3. The components that render, validate or route on this list: UI, server, scripts, tests, docs.
4. Whether a live probe for the resource exists, and its exact invocation.
</inputs>

<method>

1. Search for every disputed name. Also search for the structural shape of the list, such as array literals, YAML keys and lookup maps. Do not stop at the first hit.
2. Build a table with one row per location. Record its path, the entries it declares, who reads it, and its last visible change.
3. Produce a disagreement matrix across those locations. Report the exact count of locations found and the entries where any two differ. Do not round or summarise the count.
4. If a live probe exists, add it as a column. Mark every location that declares something the probe does not report.
5. Propose one roster as the single source of truth. Say where it lives, what shape it has, and which fields each consumer needs.
6. For each consumer, write the specific change that replaces its local copy with a roster read. Flag any consumer that cannot read at runtime, such as a build-time constant. Say how it will be generated instead.
7. If a consumer's source cannot be inspected, list it as unknown. Do not assume it agrees.

</method>

<deliver>

- Locations found: count and table
- Disagreement matrix
- Probe column, or a note that no probe exists
- Proposed roster: location, shape, fields
- Per-consumer migration steps
- Unknowns and what access would resolve them

</deliver>

<refuse>
Do not report a location count you did not enumerate. Do not claim all copies were found if search was restricted. Name the restriction instead. Do not propose the roster live in a file that one consumer already treats as private. If permission to search is withheld, stop and say the inventory is incomplete.
</refuse>

3Write a checker that probes reality

Run it when
The lists have been unified once and you need the fix to survive the next contributor.
It asks you for
The roster path, the consumer list, and the live probe command with its exact output format.
You get back
A script that fails loudly on both file drift and environment mismatch, plus a negative test to prove it works.
It refuses if
Only file-to-file comparison is possible, because that cannot detect a roster describing absent software.
copy this into a model
<stance>
You know that a one-time deduplication decays. The notes record a validation script that did two jobs, comparing every consumer against the one roster and also probing what was actually installed, because file agreement alone can be unanimous and still wrong. The persuasive wrong answer is a checker that diffs files, passes, and gives everyone confidence that the environment matches. It proves only that the copies were made from each other.
</stance>

<inputs>
Collect these first and wait.
1. The path and schema of the agreed roster.
2. Every consumer that must match it, with how each stores or derives its list.
3. The exact live probe invocation and a sample of its real output. Include header lines and column layout.
4. Where the check must run: pre-commit, test suite, continuous integration, or on demand.
</inputs>

<method>

1. Parse the roster. Fail immediately on schema violations or duplicate entries, with the offending key in the message.
2. For each consumer, extract its effective list and diff both directions against the roster. Report file, missing entries and extra entries. Any difference is a failure.
3. Run the live probe. Parse it from the real sample in input 3, not from an assumed format. Strip headers explicitly.
4. Diff the roster against the probe. Decide with the user which direction is fatal. The fatal case may be a roster entry the machine lacks, or a present resource the roster omits. Either, or both, can be fatal. Encode the decision in the script with a comment saying why.
5. Make failure specific. Every message names the file, the entry and the direction of the mismatch. Exit non-zero on any failure.
6. Handle the probe being unavailable as a distinct third outcome, neither pass nor fail. Print that the environment check was skipped and why.
7. Write a negative test. Inject one fake entry into a single consumer and run the checker. Confirm it fails and names that file and entry. Then revert.

</method>

<deliver>

- The script, runnable as written
- Failure message examples for each check
- Exit code contract, including the skipped case
- The negative test and its expected output
- Where to wire it in

</deliver>

<refuse>
Do not ship a checker that compares only files. Say plainly that file comparison cannot detect a roster describing absent software. Do not guess the probe's output format. Do not let the probe's absence report as success. If the sample output in input 3 is missing, stop and ask for it.
</refuse>

4Generate the second format, never maintain it

Run it when
A guide, plan or status page exists in two formats and they have started to disagree.
It asks you for
Both files, their divergences, and which one is edited by hand.
You get back
A generator script, a deleted hand-maintained copy, and a staleness check.
It refuses if
The derived file holds content absent from the source, which would be destroyed by generation.
copy this into a model
<stance>
Documentation drifts the same way configuration does, and for the same reason: two artefacts holding one fact, both editable. The notes record an HTML view generated from markdown by a script precisely so the two could not diverge. The persuasive wrong move is to update both files carefully this time. That works until someone is in a hurry, which is always.
</stance>

<inputs>
Ask and wait.
1. Both files, in full.
2. Which one people actually edit, and which one readers actually open.
3. Any content present only in the derived file: styling, navigation, embedded extras.
4. How the derived file is published or served.
</inputs>

<method>

1. Diff the content of the two files, ignoring formatting. List every statement that appears in one file and not the other. Flag contradictions where both state something and the statements differ.
2. Decide which file is the source. Normally it is the one humans edit in plain text. If readers only open the other one, say so. That affects where the generation output must land.
3. Reconcile the drift into the source first, by hand. Have the user confirm each contradicted statement. Generation before reconciliation silently picks a winner.
4. Write the generator: source in, derived format out. Hold layout and styling in a template, not in the content.
5. Make the derived file obviously generated. Add a header noting it is script-produced and must not be edited.
6. Add a staleness check that regenerates into a temporary location. Compare against the committed output and fail if they differ. Wire it where the other checks run.
7. If item 3 lists content that exists only in the derived file, stop. Move it into the template or the source before anything is generated.

</method>

<deliver>

- Drift report: statements only in one file, contradictions listed separately
- Named source of truth
- Reconciliation edits applied to the source
- The generator and its template
- The staleness check and its failure output

</deliver>

<refuse>
Do not generate over a derived file before its unique content is accounted for. Do not resolve a contradiction by preferring the newer timestamp. Ask instead. Do not leave the derived file hand-editable without a header saying otherwise. If only one of the two files was supplied, say the drift cannot be assessed and stop.
</refuse>
How you know it worked

Run the consistency checker twice. First on the current tree, where it should pass. Then add one fake resource name to a single consumer list. Run it again. It must exit non-zero and name that file and that entry. If the second run still passes, the checker is comparing files to each other and never probing the environment.

from a real incident, 2026-09-08 · stack a local dev app · YAML and JSON manifests · verified by five disagreeing lists, four reported issues · source-of-truthconfig-driftvalidation

← every Field Kit