Step 4 - Adjust
Goal: turn the draft into a config you would sign your name to, and drive --check to green with a UNKNOWN count you have deliberately zeroed.
You are still editing files under .alloy-output/survey/your-repo/draft/ - nothing is committed. Change the draft, re-check, repeat.
The check loop
alloy survey . --check --name your-repo--check validates and dry-runs the draft: it exits non-zero on any error, and it prints the enumeration - units per kind, unmatched candidates, the coverage: line, and any warnings. You want two things before you stop:
- Exit 0 - no structural errors.
- A green enumeration that matches your repo's reality - the right units, under the right kinds, with the unmatched count explained.
Add --json when you want to diff the inventory precisely.
Triage every UNKNOWN
For each candidate in the UNKNOWN set, pick one - there is no third option:
- It is a documentable unit → add a unit definition that captures it. Do not exclude something you actually want documented.
- It is not → add a
coverage.excludeentry with a rationale a reviewer could disagree with.
Re-run --check. Repeat until UNKNOWN is zero because you decided each case, not because the accounting stopped looking.
Split a bundled kind
If step 3 turned up a bundle - a kind whose definition spans two populations - split it. Sample its members from the check enumeration (take ones you did not have in mind when you wrote the definition), test each against the membership test, and when they do not all pass, break the kind in two with definitions that each partition cleanly. Where a scanner can read a package identity, prefer an identity predicate (a matchPackage) so a candidate that matches no kind lands in unmatched and forces a decision, rather than being silently absorbed by a path-only catch-all.
If you have a defensible reason to keep the bundle for now, record that decision in follow-ups.md with the evidence - the same standard as an exclusion rationale.
Try a second decomposition
If step 2's report named a viable alternative grain, it is cheap to try it: swap the units:/scanners: block to the other shape, run --check under it, and compare the unit sets. Keep the diff. Choosing the grain from two real enumerations beats choosing it from an argument, and the rejected shape plus its coverage delta belongs in follow-ups.md so your reviewer can veto the grain too.
Fix the warnings you own
- STALE exclusion → the path matches nothing. Correct the glob or drop the entry.
- Missing
coverage.reconcile→ a rule pack enumerates named files; setreconcile: trueon the source so its dropped-source risk is accounted. TODO-set-repoand similar → these are yours to resolve or consciously leave; do not fabricate a value to silence a warning.
When to stop
Stop when --check exits 0, the enumeration is the set of units you actually want, UNKNOWN is a deliberate zero, and every exclusion reads like a decision. That draft is ready to become your corpus config.
Next: step 5 - Commit and install.