§Open
10 defect(s) with no recorded repair.
§High findings
§Knowledge tools and workflow API
B03-R1
- Status
- Open
- Revision
c0734040
A subsystem can report status 'mapped' with zero unledgered paths, zero absent files and zero stale entries while most of its scoped files have never been examined.
Observed behavior
Root cause
§Medium findings
§MCP core, persistence, and lifecycle
B02-R1
- Status
- Open
- Revision
c0734040
A durable write can block the server indefinitely.
Observed behavior
git rev-parse synchronously with no timeout, so an unresponsive git — a network-mounted worktree, a credential helper waiting on input, a filesystem that has stopped answering — hangs the whole stdio server with no diagnostic, because spawnSync blocks the event loop and the transport is single-threaded.Root cause
timeout and no killSignal to spawnSync. The two probes that were identified as hang risks — the Codex parent ps in codex-host.ts and the git remote get-url origin in project.ts — both carry STARTUP_PROBE_TIMEOUT_MS with killSignal SIGKILL, and codex-host.ts's own comment states the reason ("an unresponsive ps would hang activation with nothing to diagnose", naming finding B02-2). The same reasoning applies with more force to resolveWorkspaceCommit, which by its own docstring "is paid on every durable write" rather than once at startup, but the bound was added only to the startup probes.§Knowledge tools and workflow API
B03-R2
- Status
- Open
- Revision
c0734040
A finding can be promoted to verified-fixed while its recorded fix_sha names a commit at which the repair does not exist, so the resolution record misattributes the repair to the wrong commit and nothing in the custody chain detects it.
Root cause
B03-R3
- Status
- Open
- Revision
c0734040
When a file's content moves but every claim written against it still holds, the conspectus has no action that records the move.
Observed behavior
Root cause
B03-R4
- Status
- Open
- Revision
c0734040
A finding's severity cannot be amended after it is filed, so an adversarial pass that re-grades one can record the re-grade in a resolution note, a disposition and the survey artifact while the findings.severity column keeps the original grade — leaving the published index and the store's own column disagreeing about the same finding.
Root cause
B03-R5
- Status
- Open
- Revision
23884334
An evidence row's locating coordinates are stored unchecked, so a disposition can be evidence-backed by a citation no reader can open.
Observed behavior
Root cause
§Diff-aware materializer
B04-R1
- Status
- Open
- Revision
c0734040
The projection read-back's per-row stale-marker expectation set is empty for every real conspectus, so a projection that drops every stale marker still passes that part of the state axis; and the index page's stale reading is drawn from the same dead source.
Root cause
B04-R2
- Status
- Open
- Revision
c0734040
A clean publish can go red on the read-back's coverage axis with dangling anchors whose only distinguishing property is the length of the record prose beside them: shortening five long rationales returned all seven missing anchors and the next publish was green on all three axes.
Root cause
§Packaging, installer, validation, and product docs
B05-R1
- Status
- Open
- Revision
c0734040
The server identifies itself to every MCP host as 0.2.0-beta.1 while the package it ships from is 0.2.0-beta.2, and stamps that wrong version into the immutable binding receipt the setup documentation tells users to read back when verifying an installation.
Root cause
§Low findings
§Embedded research surveys and platform trials
B07-R1
- Status
- Open
- Revision
c0734040
A research refresh or snapshot verification hangs indefinitely when GitHub, npm, the shadcn CLI, or a child detector stalls.
Root cause
§Carried obligations
14 inherited obligations carried forward from an earlier store and still undecided. An inherited defect is an obligation to re-find it, rule it out with evidence, or mark it repaired at a commit — not a defect this survey confirmed, and not counted among the findings open above.
§B02-R1 · High · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-02
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
A git invocation on the server's startup path can block forever. If git rev-parse --show-toplevel hangs — a slow network filesystem, an unresponsive credential helper, a very large repository, a stale lock — the server never reaches a usable state and gives no diagnosis, because execFileSync blocks the Node event loop for the whole call.
Root cause, as archived. index.ts:108 gitRoot calls execFileSync("git", ["rev-parse","--show-toplevel"], { cwd, encoding, stdio }) with no timeout and no killSignal. It is reached four times before the store is bound: twice from assertWorkspaceMatchesLaunch (index.ts:128, :129), once for a Codex parent workspace (:174), and once at :180 as the default workspace selection — taken whenever there is no --workspace argument and no AMANUENSIS_WORKSPACE or CLAUDE_PROJECT_DIR, which is the documented Codex and Claude activation shape. The repair that bounded this class covered project.ts, where all six subprocess sites carry STARTUP_PROBE_TIMEOUT_MS and killSignal: "SIGKILL", and codex-host.ts, which defines the constant. index.ts imports neither and was left unbounded. This is the repository's recorded recurrence of a repair scoped to the symbols a finding named rather than to the defect class.
§B02-R4 · High · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-02
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
Under Codex Desktop, the user-scoped registration launches the server with a process cwd of /. With no --workspace argument, no environment pin, and no --cd on the parent command, workspace resolution falls through to process-cwd-non-git and binds the filesystem root as project local:/ with storage path /.amanuensis. The skill's workspace-mismatch rule then stops the session, so every Codex Desktop session is unusable with the registration the installer writes by default, and a first write would attempt to create a store at the filesystem root. Observed 2026-09-13 23:36 in a Desktop session started in /Users/nfeldman/research and reproduced by direct launch; the pre-merge server binds identically.
Root cause, as archived. parseArgs treats any directory that is not inside a Git repository, including /, as a legitimate non-Git workspace and never fails closed. The Codex activation contract adds a parent-process --cd recovery that only Codex CLI provides; Codex Desktop launches the server from an app-server process at / without --cd, so the recovery returns null. The server never requests MCP roots from the client, although the Codex binary implements the roots protocol, so the one channel through which Desktop could name the task repository is unused. The A22 real-host harness and the A25 evidence cover the CLI surface only; ADR-0021 recorded the Desktop case as an unverified counterpoint.
§B03-R1 · High · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-03
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
A finding id can be re-minted by a rebuilt store and silently satisfy an external reference that was made against a different finding. Discarding a store makes every amanuensis:<finding_id> reference fail, which is loud and correct; re-minting one of those ids makes a closed defect resolve again, with nothing anywhere reporting that the referent changed.
Root cause, as archived. finding_id is caller-supplied (findings.ts:103, requireString), its only uniqueness constraint is the primary key within one store, and it carries no store generation, no binding id and no creation revision that a reader could compare. dev/pecia-resolve-finding.mjs answers a reference by opening whatever database is at .amanuensis/memory.db at the moment it runs and asking for the finding's current resolution state; it has no way to ask "is this the store that id was minted in". The Pecia ledger currently holds 22 records carrying such references, eight of them on closed defects. This rebuild avoided the collision by choosing a distinct id namespace (<SID>-R<n>), which is a convention a person followed, not a property the system has — the same rebuild run with the conventional ids would have re-created B02-1 and B03-1 with different meanings.
§B04-R1 · High · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-04
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
A default describe_locus call on a surveyed file returns standing, a census, and no account at all — items: [] in every one of the eight sections — while declaring itself over budget. The tool the server instructions name first, and that the skill tells an agent to call before reading a file, answers "29 things are recorded here" and serves none of them.
Root cause, as archived. The response budget is WIRE_BUDGET + WIRE_BUDGET_PER_OPTIONAL_SECTION * optionalRequested (locus.ts:1574) — 8192 bytes plus 4096 for each optional section the caller names — and it is measured by responseBytes against the whole emitted envelope, which carries the payload twice because jsonResult emits both a text block and a duplicate structuredContent. So the allowance grows only when a caller asks for extra sections, while the fixed cost does not shrink: measured on this store, the scaffolding for a locus with nothing recorded is already 6860 wire bytes (84% of 8192), and one examined owner plus its omission ledger adds about 2752 against 1332 of headroom. Naming sections: ["structure"] does not help, because structure is a default section and adds no allowance. The same call naming three optional sections is bounded at 20480, comes in at 20310, and serves the account in full — which is how the committed dogfood receipt passes §12.4 assertion 1: it records budget_bytes: 20480 for all three of its loci.
§B04-R2 · High · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-04
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
The adversarial pass cannot record a negative outcome when the survey is conducted at a single revision. record_claim_challenge accepts only survived; overturned and superseded are unreachable. A phase whose whole purpose is to overturn claims can, in the normal case, only ever agree with them — and the Mapped prerequisite that requires an outcome on every claim is therefore a gate that cannot turn red.
Root cause, as archived. Three checks compose into a closed loop. (1) record_claim_challenge refuses an overturned or superseded outcome without a validity_event_id, with the message "an overturning that closed no interval overturned nothing". (2) Such a row is written only by invalidate_claim (event_type invalidated) or supersede_claim (superseded), and the handler checks the event type matches the outcome. (3) Both of those call requireStrictDescendant(at_sha, valid_from_sha), which throws when boundary === validFrom. A survey records each claim with ref_sha equal to the revision it is reading, so valid_from_sha is HEAD and no at_sha the survey can supply is a strict descendant of it. Reproduced three times during this survey while trying to correct a claim I had recorded myself; the only route that worked was reset_subsystem, which discards the entire phase. spec.md §12.1 mandates rebuilding at one revision, so this is the mandated case, not an unusual one.
§B01-R1 · Medium · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-01
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
The phase references have drifted from the tools they describe, with nothing checking them. phase-4-adversarial.md instructs the coordinator to do one thing the server refuses and one thing the server has since replaced.
Root cause, as archived. Two concrete drifts, both in the reference that specifies the adversarial pass. First, it lists overturned as an available outcome for a claim found "wrong at the current revision" — exactly the case invalidate_claim rejects, because closing a claim requires a strict descendant of its valid_from_sha and a survey records claims at the revision it reads (B04-R2). Second, it instructs recording a survived outcome as a field note, on the reasoning that "no claim row changes, so the outcome has to be recorded explicitly or it is indistinguishable from a claim nobody looked at" — true before record_claim_challenge and the claim_challenge_outcomes table existed, and the exact problem they were added to solve. The repository checks generated prose against its source in three places and even holds SKILL.md's hand-written evidence ladder to the vocabulary contract; nothing holds the phase references to the tool surface they describe.
§B02-R2 · Medium · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-02
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
The gate that certifies "activation-path probes are time-bounded" passes while an unbounded probe sits on the activation path. Its green is true of what it measured and is read as true of the path.
Root cause, as archived. test-startup-bounds.mjs imports exactly two modules — dist/codex-host.js for discoverCodexParentWorkspace and dist/project.js for resolveProject — and drives them against a deliberately slow git placed ahead of the real one on PATH. Its denominator is therefore the set of subprocess calls reachable from those two entry points. dist/index.js is never loaded and parseArgs is never called, so index.ts:108's unbounded execFileSync (finding B02-R1) is outside anything the gate can fail on. Grepping the gate for index.ts, index.js, gitRoot and parseArgs returns nothing. This is the project's recorded zero-denominator class in its milder form: not an empty denominator, but one drawn so that it excludes the live defect.
§B02-R3 · Medium · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-02
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
The server tells every host it is 0.2.0-beta.1 while the package it is built from is 0.2.0-beta.2. A user cannot determine which version they are running, and a bug report naming the version names the wrong one.
Root cause, as archived. SERVER_VERSION at mcp-server/src/index.ts:27 is a hand-written string literal, not read from package.json, and nothing checks the two against each other. At 7c1c1a9 the literal is "0.2.0-beta.1" and mcp-server/package.json declares "0.2.0-beta.2". The literal is not decorative: it is the version in the MCP handshake the host receives, it is passed to resolveProject, and it is stamped into every per-process repository binding receipt. This session's own live binding receipt reports serverVersion "0.2.0-beta.1" from this checkout. The same fact is stated in five places and three more of them agree with the literal rather than the package — README.md:78, mcp-server/README.md:18, and mcp-server/README.md:118, which pins an install to @gruetech/amanuensis@0.2.0-beta.1 — while HISTORY.md has no 0.2.0-beta.2 entry at all. There is no single source and no drift check for any of them, unlike the vocabulary, the tool inventory and the roadmap, which all have one.
§B03-R2 · Medium · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-03
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
A clean-slate rebuild has no supported path for carrying an unresolved finding forward. Discarding a conspectus discards its open defects with it, and nothing tells the systems that referenced them that the referents were destroyed rather than resolved.
Root cause, as archived. The destructive operation is supported and well built — the skill authorizes "reinit survey", dev/rebuild-self-conspectus-store.mjs performs it with a snapshot, a process boundary and a read-back — but it is a discard, and nothing in the product exports, migrates, or re-mints the findings that were open when it ran. There is no export tool for open findings, no import path into a fresh store, and no way to record in the new store that a finding is inherited from a discarded one. Observed concretely in this run: 13 Open findings and one Unverified fix were preserved only because this session wrote a JSON export to a directory outside the repository, by hand, before running the procedure. Nothing in the tooling asked for that or would have noticed its absence. The seam this leaves broken is S-10: 22 Pecia records still name ids the store no longer holds, and the honest disposition for each has to be reconstructed from an out-of-tree file.
§B04-R3 · Medium · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-04
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
add_claim accepts a claim_key whose slug does not identify the subject, and the writer only learns the rule from a gate that runs long after the record is durable — at which point the record cannot be corrected without discarding the whole structural phase.
Root cause, as archived. The stable-key rule lives on the wrong side of the seam. FILE_ANCHORED_CLAIM_KEY (claims.ts:52) matches only the category and its trailing slash, so the server validates that a key is a key-type, state-container or flow claim and never what it names. dev/test-rebuild-coverage.mjs:keyShapeFailure recomputes the stable key as the slug of the whole path:symbol pair and requires exact equality, with a comment recording that a slug built from the symbol alone once made two Config types collide and silently shortened a subsystem's inventory. Both were exercised here: the server accepted B-02/state-container/openDatabase, which the gate's rule refuses. Because claim_key carries a unique index and is what makes a later reading supersede rather than duplicate, an unstable key is not cosmetic — it is a silent collision across files. The correction path compounds it: invalidate_claim and supersede_claim both need a strictly later commit (B04-R2), and supersede_claim preserves the claim_key that is the wrong field anyway, so reset_subsystem — which discards every claim, disposition, edge and ledger row for the subsystem — is the only route.
§B04-R4 · Medium · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-04
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
A hung git invocation inside a tool handler blocks that call indefinitely. Because the calls are synchronous and block the Node event loop, the whole server stops answering, not just the one request.
Root cause, as archived. Revision resolution runs git rev-parse from the handler path with no timeout and no killSignal. In this subsystem that is two call sites in tools/xrefs.ts, three in tools/claims.ts and two in standing.ts. Across the whole of mcp-server/src there are about sixty subprocess call sites and only two modules mention a timeout at all — project.ts (six sites) and codex-host.ts, which are the startup-path modules the earlier repair covered. The exposure is broader than the startup case because requireResolvedSha deliberately resolves live on every durable write with no memoization, so every claim, evidence row, disposition and finding pays a subprocess.
§B05-R1 · Medium · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-05
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
A clean publish, its promotion to docs/, and the published site can all be green while the overview's thesis slot shows the placeholder "No thesis section is recorded; add a 'What is this codebase?' section to entry-point.md." The clean-slate rebuild of 2026-09-13 produced exactly this on the public site: the survey was complete and the thesis existed, but under the heading "What does this system do?", which the renderer does not recognize.
Root cause, as archived. The heading contract exists in two places that never meet: the skill's artifact template prescribes "What is this codebase?" as prose, and read_thesis extracts by that exact heading, but register_artifact and rehash_artifact validate nothing about an entry-point artifact's sections, and the publish read-back axes compare projection against store without asserting the thesis slot is filled. A variant heading therefore passes every gate and reaches readers as a placeholder.
§B07-R2 · Medium · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-07
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
dev/test-rebuild-depth.mjs cannot be satisfied by a genuine clean-slate rebuild. It requires the rebuilt conspectus to carry the previous survey's concern codes, and to mint finding ids in exactly the shape that lets a stale external reference silently re-resolve.
Root cause, as archived. Two literals bind a future rebuild to the identities of the store it replaces. CHECKLIST_CONCERNS = ["BV-1","CC-1","EV-1","GT-1","RC-1","ZD-1"] (line 104) is the discarded survey's calibrated checklist, and the gate turns red when those codes are not active — so onboarding Phase 4, whose job is to derive concerns for this codebase, is refused for doing it. And the finding assertion new RegExp("^" + id.replace("-","") + "-\\d+$") (line 598) mandates B02-1 and rejects any namespace that would stop a rebuilt store re-minting an id the Pecia ledger already references (B03-R1). That second constraint caught this session directly: minting B07-1 to satisfy the gate collided with an archived finding of the same id that Pecia record pc-861e still names, and the claim had to be withdrawn by a third reset_subsystem. A milder third instance: record-rebuild-depth.mjs reads checkpoints labelled Depth batch N while record-rebuild-coverage.mjs reads Rebuild batch N, so one integrated rebuild — which is what the skill runs — records batches for one gate and none for the other.
§B07-R1 · Low · Undecided
- Carried from
store-legacy-7e0595ffa9f84f2bat7c1c1a9f5689, recorded there as Open - Subsystem there B-07
- Outcome
undecided— nobody here has re-found it, ruled it out, or recorded a repair
dev/test-activation-evidence.mjs exists in the tree and never runs in CI, with nothing recording whether that is deliberate.
Root cause, as archived. Enumerating all 106 gate files against .github/workflows/test.yml shows exactly four unreferenced. Three are performance suites whose exclusion from a correctness list is legible. The fourth is a correctness gate by name with no stated reason for being absent. The repository's own convention — several recent gates assert their own presence in the workflow as a red condition — exists precisely so this cannot happen silently, and this file predates that convention.