Documents / Reference / ref-1509d5dbb4c3
Discovery probe log — PROBE-1..N and the delta pass
The executed probes behind the gap register: what was run, what came back, and what it proved.
Run log — append-only¶
PHASE 0/1 — frame + evidence inventory¶
2026-07-26 FRAME README.md, CLAUDE.md, docs/adr/* → 00-frame.md written
2026-07-26 INVENTORY evidence ranking below
Evidence available (ranked per extraction.md §1)¶
| Rank | Source | Available? | Notes |
|---|---|---|---|
| 1 | Production behaviour / user work | NO | No telemetry in product; no user access this session |
| 2 | Code, DB schema, migrations | YES | 105 files / 6 919 LOC; alembic 0001+0002 |
| 3 | Tests (acceptance/E2E) | YES | 28 test files incl. tests/entry_points/test_e2e_*.py |
| 4 | Config, flags, jobs | YES | pyproject.toml, env vars (DOCIR_*), daemon idle timer, embedding scheduler |
| 5 | Tickets, logs, analytics | NO | GitHub issues not fetched (non-interactive); no logging of business events |
| 6 | SME statements | NO | Single maintainer, not interviewed |
| 7 | Written docs | YES, treated as claims | README, CLAUDE.md, 10 ADRs, 4 CONTRACT.md, CHANGELOG, docs/AGENT_GUIDE.md |
Consequence: the two highest-value evidence ranks (1, 5) are missing entirely. Every
"frequency" and "actual impact" statement in 05-gaps.yaml is therefore unknown rather
than measured. Recorded as issue-e183d47cdee1.
PHASE 2 — extraction¶
2026-07-26 P1 struct entry_points/cli/app.py, dispatch.py → 27 CLI commands, 18 wire commands
2026-07-26 P1 struct alembic/versions/0001,0002 → 7 tables + 1 FTS5 virtual table
2026-07-26 P1 struct documents/domain/{schema,entities,vo} → Document aggregate, Schema, DocId, RelatedRef
2026-07-26 P1 struct documents/infra/{profiles,default_schema} → core + 5 profiles, 12 types
2026-07-26 P2/P3 documents/application/services/* → DocumentService, MaintenanceService call chains
2026-07-26 P2/P3 tags/application, indexing/*, agents/* → per-module behaviour + ordering
2026-07-26 P2/P3 platform/{persistence,filesystem,transport}, entry_points/daemon
2026-07-26 P4/P5 all of the above → BR-001..BR-072 drafted
2026-07-26 READ tests/** (28 files) → cross-check of P4; encoded intent
2026-07-26 SKIPPED tach.toml, scripts/check_contract_sync.py → out of scope per 00-frame.md
2026-07-26 SKIPPED assets/, docs/PUBLISHING.md, .github/ → out of scope per 00-frame.md
2026-07-26 SKIPPED platform/persistence/alembic/env.py → migration machinery, no business rule
Empirical probes (evidence rank 1-substitute: executed the real CLI)¶
Store fixtures under the session scratchpad; all runs --no-daemon, real SQLite, real files.
PROBE-1 clone->reindex->add store1 → CONFIRMED id collision (GAP-003)
PROBE-2 get/query after PROBE-1 store1 → CONFIRMED first doc invisible to all read paths
PROBE-3 check --strict on 2 new docs → exit 1 from `orphan` alone (GAP-006)
PROBE-4 context w/ resolved neighbour → CONFIRMED inactive filter bypassed via graph (GAP-004)
PROBE-5 context --limit 3, 3x out-deg 2 → returned 9 docs (GAP-005)
PROBE-6 delete --force w/ incoming ref → CONFIRMED dangling ref written to canonical file (GAP-007)
PROBE-7 update a doc holding dangling ref → CONFIRMED accepted, ref re-persisted (GAP-007)
PROBE-8 decision --related issue → CONFIRMED permanent `layering` warning (GAP-008)
PROBE-9 delete then add → id NOT reused (counter monotonic) — no gap
2026-07-26 PROBE-10 6x concurrent --no-daemon add → all returned adr-0002 (GAP-009)
2026-07-26 PROBE-11 same race WITH the daemon → adr-0002..0007, unique — scopes GAP-009
2026-07-26 PROBE-12 schema validate on a typo'd transition target → {"valid":true} (GAP-010)
2026-07-26 PROBE-13 agent install --agent <typo> → [], exit 0, no files (GAP-024)
2026-07-26 PROBE-14 context on unrelated query → returns a doc, score 0.0328 (GAP-017)
2026-07-26 PROBE-15 all five profiles merged → 15 types, no prefix collision — NO gap
2026-07-26 PROBE-16 delete then add → id not reused — NO gap
PHASE 3/4 — modeling + formalizing¶
2026-07-26 MODEL 01-actors.yaml → 8 actors (2 of them absent-but-implied: ACT-007, ACT-008)
2026-07-26 MODEL 02-flows/ → 5 flows, 41 hotspots, 3 off-system step clusters
2026-07-26 MODEL 04-glossary.yaml → 13 terms, 10 with recorded conflicts
2026-07-26 FORMAL 03-rules.yaml → 45 rules (EARS), 3 decision tables, 5 marked `disputed`
PHASE 5 — gap detection¶
Coverage checklists from gap-checklists.md §2 iterated mechanically against every flow and
the document / tag entities. Result: 39 gaps — 6 blocking, 20 material, 13 cosmetic.
Checklist items that produced findings: bulk import/export (issue-20933967697b), merge/deduplicate
(issue-cc61d038cf8f), delete + compensating action (issue-fd547a293d01), every-state-has-an-exit (issue-b47a1203baa2), concurrent
transition by two actors (issue-389dc5dac58a, issue-be95d3e242a3), duplicate submission / idempotency (issue-389dc5dac58a),
admin override + audit (issue-0783d236d565), support diagnosis tooling (issue-476b4e188fab), notifications (issue-b4f441c7210f),
time/timezone (issue-7e16dfe2521c), volume limits (issue-f6a5d0b86806), observability (issue-e183d47cdee1), migration of data
created under older rules (issue-ed49c1d03894).
Checklist items examined and found adequately covered (recorded so coverage is not
overstated): create validation (BR-001..BR-005), read visibility (BR-028, BR-029), field
mutability by state (BR-005), transfer of ownership (--set-owner), retention (git holds
history), permissions (N/A per adr-90e994d931cc), rounding/currency/tax (no money in this domain).
Smell scan (gap-checklists.md §3, automated regex over all 45 rule statements): 0 hits.
PHASE 7 — adversarial self-review¶
Ran against my own register, not the code. Four defects found and fixed:
SELF-1 GAP-013 was hedged ("advanced and committed... or not"). Re-read repositories.py:55 —
next_number only *flushes*, so the counter rolls back with the transaction while the
already-written file survives. Rewritten as a concrete third duplicate-id path.
SELF-2 GAP-012 was severity:material but meets my own blocking rubric ("touches data loss").
Raised to blocking; register re-sorted.
SELF-3 BR-034 has four conditions and no decision table — violates quality gate §9.
Table added (verified against runner.py:36-48).
SELF-4 Q/BR/GAP cross-references were inconsistent after renumbering. Reconciled by script;
verified no dangling or undefined ids in either direction.
Claims I attempted to refute and could not: issue-b7ddde3ce860, issue-8c37bf22ba3c, issue-996b567e5131, issue-9cb85759076d, issue-389dc5dac58a,
issue-b47a1203baa2, issue-93152f7b9213, issue-b8220546282c — each is reproducible by the probe recorded above.
Claim I did refute and narrowed: an early reading that docir context --limit overflows in
every case. PROBE-4 (--limit 1 → 1 result) shows it overflows only when selected documents
have outgoing edges to documents not already selected. issue-996b567e5131 states that actual condition.
Quality gates (SKILL.md §9)¶
[x] Every actor appears in >=1 flow 8/8
[x] Every flow has unwanted-behaviour rules per failure point
BR-001..003, 010..012, 018, 043, 061, 064, 070, 071
[x] Every rule has an evidence pointer and a status 45/45 (verified by script)
[x] Every rule with >2 conditions has a decision table BR-003, BR-005, BR-034
[x] Smell scan clean 0 hits across 45 statements
[x] Every glossary term has exactly one definition 13 terms; 10 conflicts recorded as gaps
[x] Every hotspot resolved into a rule/gap/assumption 41/41
[x] Coverage log lists what was not examined below
[x] Adversarial pass run and findings addressed 4 found, 4 fixed
Coverage report — what was NOT examined¶
Not examined at all (out of scope per 00-frame.md, or no business rule inside):
tach.toml, scripts/check_contract_sync.py, .github/workflows/, assets/,
docs/PUBLISHING.md, pyproject.toml packaging metadata,
platform/persistence/alembic/env.py, platform/embedding/fastembed.py (optional dependency,
excluded from the project's own type-check and coverage).
Examined shallowly (read for structure, not line-by-line; rules here are lower-confidence):
platform/transport/{protocol,client,messages}.py, entry_points/daemon/socket_executor.py,
entry_points/cli/{body_input,rendering}.py beyond the trim logic,
modules/agents/{domain,infra}/** beyond the service, modules/agents/infra/templates/skill.md.
Evidence classes entirely unavailable this run (see 00-frame.md): production behaviour,
support tickets, logs, analytics, and any SME statement. Ranks 1, 5 and 6 of the evidence
hierarchy are absent — which is why frequency is unknown on almost every gap and why every
rule is status: assumed rather than confirmed.
Consequence for the reader: this register is a draft until the maintainer confirms it.
An agent-produced rule register is not valid elicitation until the source agrees with it
(questioning.md §5).
Follow-up session — fixes and their consequences (2026-07-26)¶
Implemented at the maintainer's direction, each verified against the real CLI before the gap record was closed.
FIX GAP-003 reindex restores the id counter; + IdGenerator skips indexed ids;
+ create refuses to overwrite a file already holding the id → resolved
FIX GAP-013 same change; a crash mid-write can no longer be overwritten silently → resolved
FIX GAP-009 next_number is one atomic upsert (was read-modify-write in Python);
busy_timeout set explicitly → resolved
FIX GAP-005 --limit is a hard ceiling; --expand N reserves neighbour slots,
unused ones backfilled; expansion breadth-first across seeds → resolved
NEW --id-style on `docir init`, defaulting to `random` (BR-073, BR-074)
DOC packaged agent guide corrected: `docir reindex --all` does not exist → GAP-040
Attribution was tested, not assumed: each fix was reverted in isolation and the new tests
re-run, to confirm they fail against the old behaviour (assert 9 == 3 for issue-996b567e5131;
8 concurrent adds colliding for issue-389dc5dac58a).
Findings produced BY these changes (2026-07-26)¶
GAP-040 the shipped agent guide told agents to run a flag that does not exist; nothing
validates the template against the CLI. Typo fixed, guard still missing.
GAP-041 the counter restore reads an all-digit random id (0.36% of them) as sequential.
Latent: no symptom while the type stays `random`.
GAP-042 random ids are ~3x longer and ride in every skeleton and every edge; the token
cost of the new default is unmeasured (see GAP-001).
Rules restated rather than left stale: BR-006 (id allocation is style-dependent, not
counter-only) and BR-007 (uniqueness) move disputed → confirmed. BR-073/BR-074 added for
schema-wide id_style inheritance and the init default.
Blocking gaps still open: issue-9cb85759076d, issue-476b4e188fab, issue-e183d47cdee1.
FIX GAP-041 counter restore now keyed on the schema's declared id_style, with a
suffix-length guard for ids left behind by a style switch → resolved
FIX GAP-006 CheckIssue carries a severity derived from its kind; --strict gates on
errors only; --strict-all preserves fail-on-anything → resolved
NOTE: the existing test asserted the old behaviour as intent, so the tests
could never have caught this — only running the tool did.
FIX GAP-012 `docir check --fix` re-issues duplicate ids (oldest keeps it) and drops
dead edges; malformed/unknown-type returned as needing a human → resolved
GAP-007 becomes recoverable but is still not prevented — stays open.
NEW found while testing: `_as_list` accepted only `list`, but `dataclasses.asdict`
preserves tuple fields, so the table renderer showed "nothing to repair" while
--json printed the fix. Caught only because the human path was exercised
separately from the JSON one. Both are now asserted in the same test.
Blocking gaps still open: issue-e183d47cdee1 only (nothing measures whether docir works).
FIX GAP-001 benchmarks/ — 20-doc corpus, 12 judged tasks, recall/precision/MRR +
payload size per strategy, run against both embedders → resolved
NEW GAP-043 the measurement's own headline: the DEFAULT embedder is lexical, not
semantic, so `context` ~= `search` unless the `embeddings` extra is on.
README:42 claims "retrieval by meaning" for a config most users lack.
Measured (2026-07-26, 20 docs / 12 tasks, recall@5):
context 0.88 default vs 0.96 fastembed · search 0.85 both · graph expansion +0.07 under
both · context 430 tokens vs 3 240 to read every body (7.5x).
FIX GAP-043 docs-honesty pass: README table, command table, agent guide and CLAUDE.md
now say which configuration each retrieval claim describes. No code
change — the code was right, the copy was not. → resolved
OPEN QUESTION deferred: should fastembed be the default? Left undecided;
it is a dependency-weight call, not a correctness one.
FIX GAP-043 fastembed is now a hard dependency and the default; the hashing embedder
becomes the DOCIR_EMBEDDER=deterministic fallback. README states the
measured cost (~64 MB model, ~240 MB deps) instead of a caveat. → resolved
NEW GAP-044 found while implementing that flip: nothing recorded which model produced
a vector, and mismatched widths RAISE. The switch would have broken every
existing store on first `docir context`. model_id is now written and
honoured; foreign vectors fall out of ranking and are recomputed. → resolved
Follow-up — verifying the default flip outside this machine (2026-07-27)¶
CHECK uv.lock in sync with the new required dependency, committed → clean
CHECK CI workflow → passes, but see below
NEW GAP-045: the default embedder path was excluded from every gate (ty, coverage,
no tests) while CI installed 240 MB and ran none of it. The exclusions were
correct when the adapter was opt-in and became a hole when it became the
default; nothing re-checks an exclusion when its premise changes. → resolved
Lifting the ty exclusion surfaced a real diagnostic on the first run.
FIX GAP-036 `docir import` adopts existing markdown and preserves the number the
filename implies, so historical cross-references survive adoption.
Verified on docir's own ADR corpus. → resolved
Two of my own test expectations were wrong, not the code: a title of
"2026 is the year..." must NOT be de-numbered (only a number followed
by punctuation is a label), and asdict returns tuples, not lists.
FIX import now reports skipped files. Found by pointing it at `analysis/`: 12 files in,
7 imported, 5 dropped with no mention — including 05-gaps.yaml and 06-questions.yaml.
My own test had asserted non-markdown was *ignored*, never that it was *reported*.
FIX GAP-004 one `_is_visible` predicate now serves both `context` paths; the ranked
GAP-019 loop and graph expansion can no longer filter differently. Expansion also
follows incoming supersedes/contradicts, successors first. → resolved
Maintainer answered Q-005 "hidden" (not "returned but flagged") and Q-017
"yes, follow it backwards".
Attribution tested, not assumed: each half was reverted in isolation and only its own test
failed (_is_visible → the resolved-neighbour leak; the incoming lookup → the backwards
successor). The third test, the --include-resolved escape hatch, passed under both reverts,
which is what makes it an independent check rather than a restatement of the first.
Findings produced BY these changes (2026-07-27)¶
GAP-046 the benchmark cannot see either fix. Both change retrieval semantics; every
number was byte-identical either side (recall@5 0.96 fastembed / 0.88
deterministic). corpus.yaml has no supersedes edge and no inactive document,
so the two behaviours `context` most depends on are unmeasurable. The corpus
was deliberately NOT edited: re-basing it would break comparability with every
figure recorded before today, and that is the maintainer's call.
NEW benchmarks/run.py printed `embedder: deterministic (default)` from
os.environ.get(..., "deterministic (default)") — a label, not the resolved
object. The default flipped to fastembed in ADR-0011 and this line did not,
so every run since has reported a configuration it did not measure. It was
reporting "deterministic" while scoring 0.96, the recorded fastembed figure.
`Container` now carries the built embedder and the harness prints its model_id.
The shape is issue-0ff355fa21dd's again, one layer up: a default changed and the thing describing it
did not. There it was a test exclusion; here it was the measurement's own header — inside
the harness built to settle issue-f01a7a585fc1, which was itself a docs-honesty gap.
FIX GAP-046 corpus re-based to 23 docs / 14 tasks: a supersedes-linked decision pair
plus a resolved issue. Loader learned typed edges and `status_path`.
The harness now moves under these fixes. → resolved
Measured by reverting each fix against the new corpus:
context recall@5 0.93 -> 0.96 (fastembed), 0.89 -> 0.93 (deterministic).
A conclusion this re-base weakened, recorded rather than buried. adr-ab9c454b760c's headline
number — context 0.96 with the model vs 0.88 without — becomes 0.96 vs 0.93 on the new
corpus, because the two new tasks depend on the relation graph and graph expansion helps
both embedders equally. The ADR's decision still holds, but the evidence for it had to move:
at --expand 0, which isolates the ranking from the graph, the hashing embedder scores
0.80 against plain search's 0.83 — it ranks below the lexical index it is meant to be
complementing — while the model scores 0.87. README, CLAUDE.md and benchmarks/README.md now
quote that pair and say why. Re-basing a benchmark can invalidate the argument the previous
baseline was built to support; the fix is to re-derive the argument, not to keep the corpus
that flattered it.
FIX GAP-008 layering check reads a dependency allowlist (`depends_on`, `refines`)
instead of exempting supersedes/contradicts. `relates_to` — every bare
id — no longer violates. PROBE-8 replayed: `[]` where it reported a
permanent violation; `:depends_on` on the same edge still flags. → resolved
Q-006 implemented on its recorded assumption, not on an answer.
Third instance of the same trap, now worth naming: test_layering_violation built a
default-kind edge and asserted a violation, so the suite encoded the defect as intent and
could never have caught it. issue-9cb85759076d had it (test_check_strict_gates_ci asserted the
unusable gate), issue-0ff355fa21dd had it in a different form (an exclusion whose premise had
expired). In all three the defect was found by running the tool and reading the output as a
user would, never by reading or running the tests. A test written from the implementation
tests that the implementation is itself; only a test written from the intended behaviour can
disagree with the code.
_SUCCESSOR_KINDS and the layering set have now diverged, as the issue-5bfbc6f2699d comment predicted
they should be free to: {supersedes, contradicts} and {depends_on, refines} share
nothing. Keeping them separate cost one duplicated frozenset and avoided coupling two
unrelated rules through a shared constant.
Follow-up — the shipped guide is now checked against the CLI (2026-07-28)¶
FIX GAP-040 test_agent_guide_matches_cli.py resolves every `docir ...` in the
packaged guide against the Typer command tree. 29 invocations.
Attribution: three defects injected (unknown flag, unknown
subcommand, unknown top-level command), each caught. → resolved
REWORD the guide said "One `docir import`-style bulk pass" — a backticked
command that deliberately does not exist. Prose, not an exemption:
an agent runs a backticked command whatever the sentence says.
The guard shipped broken twice before it worked, and neither defect was visible by reading it. First: the inline-span regex paired backticks across the whole document, but a
every pair after it. It reported a healthy-looking 28 invocations and did not contain the one
line the test exists to catch; the injected `reindex --all` passed. Second: after fixing
that, an unknown word fell back to the parent group, so `docir schema dump` validated
against `docir schema`.
Both were found the same way — by injecting the bug the test claims to catch and watching it
pass. A test written against a real corpus that happens to be clean cannot distinguish
"nothing is wrong" from "nothing is checked".
The guard-the-guard has the same disease in miniature: it first asserted `len(INVOCATIONS)
>= 20`, which both defects satisfied. A count cannot say *which* line went missing. It now
names six invocations that must be found, each reachable from a different part of the
document — fenced block, inline span, table cell, indented sub-list.
This is the fourth appearance of the family recorded here (GAP-006, GAP-045, GAP-008, now
GAP-040), and the sharpest: the other three were tests that asserted existing behaviour was
intended. This one asserted nothing at all while appearing to assert a great deal.
## Follow-up — forced delete compensates for what it breaks (2026-07-28)
FIX issue-fd547a293d01 delete --force strips the edge from every referencing document in
the same transaction and reports them ("deleted X; unlinked from Y").
PROBE-6/PROBE-7 replayed: file reads related: [], no dangling
finding, a later update has nothing to re-persist. → resolved
Deviates from the proposed tag rm --force pattern on one point:
updated is NOT advanced. Copying it wholesale would have
reproduced issue-9ed4905e0db8, which is open against the tag path for exactly
that. Follows check --fix instead.
**The fix invalidated five tests, and that is the interesting part.** Each used `delete
--force` as a cheap way to *manufacture* a dangling edge before asserting something about
`check` or `check --fix`. That route is now closed, so they build the state the way it
actually occurs: remove the target's file as a merge from a branch that deleted it would,
then reindex.
`test_check_detects_dangling_reference` in `test_merge_safety.py` is the one worth naming.
Its comment already claimed to simulate "a cross-branch delete after a merge" — but it used
the CLI shortcut, so the merge-safety test was not exercising a merge. The comment described
the intent and the code did something easier; nothing flagged the divergence because the
assertion still passed. A convenience path used as a fixture had quietly become the thing
under test.
GAP-007 moves from *recoverable* to *prevented*. `check --fix` stays as the recovery path
for edges broken outside the CLI — which, after this, is the only way left to break one.
NEW 05-gaps.yaml issue-e183d47cdee1 carried a duplicate resolution: key, and five entries in
06-questions.yaml (issue-96b03701503b/003/004/007/012) carried duplicate answered/authority/
answer keys with the trailing copy set to null. YAML keeps the last key, so the
primary deliverable parsed with four answered BLOCKING questions reading as
unanswered and issue-e183d47cdee1's resolution reading as absent. Only the prose was ever
read; nothing parsed these files. Duplicates removed, answered_note folded into
answer; both files now round-trip through yaml.safe_load with the intended values.
REVERT issue-20933967697b docir import built, then removed the same day, before committing.
Two reasons: random-ids-by-default removes its only unique capability, and it
reported imported 2, failed 0 over a file holding three decisions (one
superseded, one rejected) plus a file whose body said "DRAFT — do not rely on
this". A command that makes adoption look finished is worse than no command.
issue-20933967697b returns to OPEN; the reasoning is recorded there so it is not rebuilt
naively. The agent guide now carries the review-then-add workflow instead.
## DELTA PASS — 2026-07-29, v0.7.0 (39 commits since the original run at 560aea5)
Scope: the surface *added or changed* since v0.2.1, not a re-derivation. The existing
register was appended to, never rewritten (SKILL.md §1.6). 37 of 46 recorded gaps had been
resolved; the question was what the fixing itself introduced.
FRAME delta only: 34 source files changed, +1951/-265; 8 new CLI flags INVENTORY same evidence ranks as the original run — 1, 5 and 6 still absent EXTRACT P1 via the Typer command tree (authoritative, not the docs) DETECT 7 empirical probes against the real CLI, listed below
### Probes
DELTA-PROBE-1 docir --home X init → store created in CWD, X untouched issue-638068ed09a6
DELTA-PROBE-2 init --force-schema (no --force) → silent no-op issue-9417ffd5306d
DELTA-PROBE-3 store field on read paths → absent on query/search/context issue-c2b4e38e76d9
DELTA-PROBE-4 query --stale --include-archived → correct; archived excluded by default — NO gap
DELTA-PROBE-5 check --fix with unknown-tag → correctly returned in remaining — NO gap
DELTA-PROBE-6 tag rename X X --merge → registry entry deleted, docs keep the tag issue-9bbca6c0f434
DELTA-PROBE-7 add --id in a random store → adopted; next id still random — NO gap
Three of seven probes found nothing. Recorded so the coverage is not overstated: the
stale/archived interaction, `check --fix`'s handling of the new finding kinds, and
cross-style id adoption are all correct.
### What the delta pass was for
**Two of the four findings were introduced by the fixes themselves**, which is the argument
for running one at all:
- GAP-048 (self-merge corrupts the registry) came from the GAP-028 merge, four commits
earlier. Its tests asked "does merging two tags work?" and never "what if they are the
same tag?". It shipped in 0.7.0 and manufactured precisely the `unknown-tag` state that
the GAP-016 work had taught `check` to detect — one fix creating the condition another
fix had just learned to report.
- GAP-050 came from the GAP-023 fix, which reasoned about writes and did not ask whether
reads have the same question. GAP-049 came from the GAP-026 fix.
**A feature added to close a gap is new surface, and its degenerate cases are unexamined by
construction** — the tests written alongside it are shaped by the gap it was closing.
GAP-047 is different: it predates the original run and that run missed it. `init` is the one
command that builds its own home rather than using the resolved settings, so it fell outside
a review that traced `Settings.resolve`. Worth remembering that "every command does X" is a
claim to verify per command, not per resolver.
### Coverage — what this pass did NOT examine
Unchanged since v0.2.1 and not re-read: the daemon transport and lifecycle, the embedding
scheduler, `lint --deep`, the agents module beyond the template, and Alembic. The nine
cosmetic gaps left open from the original run were not re-examined either; they were
assessed for priority on 2026-07-29 (see the entries) but not re-derived from code.
## Note on paths (2026-07-30)
This document was `analysis/99-log.md` until the discovery bundle was folded into docir's own store. The `analysis/...` paths in the text above describe where the run wrote its output at the time; those files are documents in this store now — see `docs/README.md` for the map. The gap issues that cite this log link to it as a typed edge.