docir — design documents Graph

Documents / Reference / ref-cb2beaa41604

Probe log — second discovery pass, 2026-07-30

What was executed against the CLI in the 0.8.0+ pass, what it returned, and the four areas deliberately not reached.

ref-cb2beaa41604referenceactive#docs#testing
View as Markdown◉ View in graph

Every probe below was executed against a throwaway store built by docir init, with DOCIR_EMBEDDER=deterministic unless stated. Frame: ref-0f48dc93d435. Predecessor log (v0.2.1): ref-1509d5dbb4c3.

Daemon transport and lifecycle — unexamined by the previous pass

text
PROBE-D1  daemon start / status                         serves, reports pid + socket   — NO gap
PROBE-D2  SIGKILL the daemon, leave stale pid + socket  next `add` respawns, exit 0    — NO gap
PROBE-D3  two stores side by side                       one socket each, no cross-talk — NO gap
PROBE-D4  DOCIR_REQUEST_TIMEOUT=0.001 on a write        Python traceback, exit 1         GAP-052
PROBE-D5  `daemon stop` after SIGKILL                   reports stopped, status clean  — NO gap
PROBE-D6  900 KB body over the socket                   round-trips byte-exact         — NO gap

D2 and D6 are worth stating positively, because both are load-bearing claims nobody had executed: the daemon really is disposable — a kill -9 leaves a stale pid file and a stale socket, and the next command respawns through them without the user seeing anything — and the length-prefixed framing really does survive a payload far larger than one socket read, which is the reason it is length-prefixed rather than newline-delimited.

D4 is the finding. The message the client raises is correct and names its escape hatches; it is never rendered, because runner.execute wraps only the construction of the executor in the handler that maps a DocirError onto its exit code, and the dispatch call sits outside it.

Embedding scheduler

text
PROBE-E1  `embed --flush` with nothing dirty            {"embedded":0}, idempotent     — NO gap
PROBE-E2  read the store under a different embedder     similarity absent, no error      confirms ADR-0011
PROBE-E3  `add --wait-embeddings`                       exit 0, vector present         — NO gap

E2 is the behaviour adr-ab9c454b760c promises and is worth pinning here: switching DOCIR_EMBEDDER does not raise dimension mismatch. The foreign-model vectors are ignored, context returns rows with similarity absent rather than zero — absent meaning "no current vector", which is why --min-score does not filter them — and embed --flush recomputes both documents, after which similarity is present again. Verified in both directions.

Reads, schema and adoption

text
PROBE-R1  --offset 99 / --offset -1                     0 rows / exit 2 with a message — NO gap
PROBE-R2  --limit 0 / --limit -3                        exit 2 with a message          — NO gap
PROBE-R3  --set-related <self>                          accepted; check reports a cycle  GAP-053
PROBE-R5  `lint --deep` on a small corpus               exit 0, no findings            — NO gap (smoke only)
PROBE-R6  agent install x2, update, update on nothing   idempotent; `[]` when nothing  — NO gap
PROBE-R7  `init` inside an existing store's tree        nested store, silent            GAP-054
PROBE-R8  switch the schema profile with docs present   `unknown-type` x2, left in
                                                        `check --fix` remaining        — NO gap

R8 confirms the documented behaviour exactly: disabling a profile that has documents leaves them with a type the schema no longer knows, check reports unknown-type, and --fix declines to guess and returns them in remaining. The first attempt at this probe was wrong and is recorded because the correction matters: it used decision documents, which are in the frozen core and therefore survive any profile change. Only a profile-owned type (issue, architecture) demonstrates the case.

R6: docir agent update with nothing installed returns [] and exits 0. Recorded and judged not a gap — an empty result is the honest answer, and unlike issue-b8220546282c's silent no-op on a typo, nothing here was mistyped. Noted so the judgement is visible rather than assumed.

What this pass did NOT examine

  • Alembic migrations. Probing the upgrade path needs a store pinned at an older revision, which nothing in the repo produces. Fresh-store migration runs on every probe above and works; upgrade-from-old is untested here and was untested by the previous pass.
  • lint --deep beyond a smoke test. Its O(n²) similarity comparison and its scope-creep heuristic were not exercised on a corpus large enough to say anything.
  • The 38 assumed rules in ref-32cb4f874fbe. Out of scope by decision: re-deriving them from the same code produces the same assumptions. They need a human who can say what was intended — the finding archived issue issue-b928ad676595 records.
  • The ranking constants. benchmarks/ measures them; reasoning about them here would add nothing.

What the pass suggests about where defects live

All three findings are in the seam between a component and its caller, not inside either: an exception that crosses the transport boundary and lands outside the handler; a write path that produces the state the check path reports; a store-creation rule that is correct in isolation and silent about its neighbour. The previous pass reached the same conclusion from a different direction — "a feature added to close a gap is new surface, and its degenerate cases are unexamined by construction". Degenerate cases at boundaries is where to look next.

The two areas the pass skipped

The second round listed Alembic's upgrade path and lint --deep as not reached. Both were then reached.

Alembic — no defect, and thesis #1 demonstrated end to end

text
PROBE-A1  a fresh store reports revision 0002, relations carry `kind`   — NO gap
PROBE-A2  walk the store back to 0001, run any command                  upgrades to 0002, exit 0
PROBE-A3  what the dropped columns cost                                 owner, verified and the
                                                                        edge kind come back empty
PROBE-A4  `docir reindex`                                              restores all three from
                                                                        the files; check clean

The upgrade fires automatically on the next command and needs no user action. A2-A4 are the important pair read together: dropping the columns loses the values, and reindex puts every one of them back — owner platform-team, verified 2026-07-30, and the supersedes kind that had reverted to the relates_to server default — because the markdown files are canonical and the index is a projection. That is the product's first thesis, executed rather than asserted, and nobody had run it before.

Read A3 carefully and do NOT record it as data loss: the downgrade is artificial. A real 0001 store predates typed edges and staleness entirely, so its edges were all relates_to and it had no owner or verified to lose — the server defaults migration 0002 chooses are exactly right for the data that actually exists at that revision. The loss here was manufactured by downgrading a store that already held 0002 data, which no user can do.

Also observed: there is no alembic.ini. run_migrations builds the config in Python and points script_location at Path(__file__).parent / "alembic", so alembic cannot be driven against a store by hand (alembic current, alembic history, alembic downgrade). Recorded and judged not a gap: a second declaration of the script location is exactly the drift the programmatic resolution exists to prevent, and the recovery story for this product is reindex, not hand-run migrations.

lint --deep — two findings

text
PROBE-L1  `lint --deep` over the 99-document store    21 findings in 5.2s
          14 `duplicate`, every pair already linked                        GAP-055
          7 `scope-creep`, 5 of them reference registers                   GAP-056

The runtime is worth recording: 5.2 seconds for the O(n²) comparison over 99 documents, which is well inside anything a person would notice, and the first number available for the ceiling the README warns about.

Both findings are the same shape as defects this project has already fixed once — a heuristic that fires on correct usage (orphan under --strict, the layering exemption list). Every one of the 21 findings against the product's own corpus is unactionable, which makes lint --deep a command nobody runs twice.

Still not reached

The 38 assumed rules and the ranking constants, unchanged from the second round and for the same reasons.

To amend: Re-verify: