Skip to content

Corpus audit log

Historical record of the corpus audit passes, moved here verbatim from the readiness block of docs/status/project-state.yaml on 2026-08-19 so the state file carries status rather than history. Each pass's figures are as recorded when it ran and are not updated; the current gate census is derived from the registry and reconciled by make docs-check against the milestone map, and the living readiness verdicts are in the readiness review.

Readiness summary as recorded at 2026-08-19

Milestones 0 through 9 are complete and implementable from the corpus. The owner authorized automatic memory formation, the self-authored-skills tranche, provider-neutral public-web access, and authenticated browser automation in Milestone 10, with thirty-four registered gates across the four workstreams. Scheduling, routing, and general-purpose subagents remain deferred directions. Milestones 5, 6, and 8 moved into the covered set when docs/plan/http-api-and-streaming.md, docs/plan/sandbox-isolation.md, and docs/plan/skills.md were written; the review's original findings are retained in the review itself. No subject in the plan now lacks a document. Milestone 3's three named gaps closed when model-gateway.md and event-log-and-persistence.md gained the provider-metadata key discipline, the provider-profile schema, and the redacted trajectory export; its verdict is now ready. Milestone 4's two named gaps closed on successive passes: builtin-tools.md designed the four remaining builtins and sandbox-isolation.md gave WorkspaceHandle a provenance record, then policy-and-approvals.md defined the principal scope vocabulary, its grammar, the exact-match subset test, and the scope set stamped on the run. Its verdict is now ready. Milestone 7's surviving gap closed when context-engine.md gave history selection a predicate: seeding reads the log below a sequence pinned on the run, and assembly retains a contiguous suffix chosen by a deterministic cut. Its verdict is now ready. Milestone 8's surviving gap closed when tool-system.md gave MCP authentication a declared scheme, a closed set of five, write-time validation, a bounded re-authentication ladder, and a constructed stdio child environment. Its verdict is now ready. Milestone 9's surviving gap closed when knowledge-documents.md and ADR-0033 gave the other half of its title a design: the document model, ingestion as a tool, deterministic chunking, the index, visibility as the isolation predicate, passage retrieval with its own budget class, and twelve gates in a new fourteenth registry area. Its verdict is now ready. No milestone now carries a named gap. The last plan section that no specification expanded, Section 29's Device model, is expanded by multi-device-and-surfaces.md and ADR-0034 as an audit of the seam rather than a design. The plan defers the area twice, so the document checks that the deferred work lands additively, finding eight places that already hold the shape and five that do not, and places the four Section 29.6 items under the existing port rule. It declares no gates, so the gate census is unchanged. The last unanswered readiness question, whether Milestone 10 needed acceptance criteria, was originally answered by treating it as an open direction; the later owner authorization and memory criteria supersede that operational conclusion without weakening the other entry conditions. The re-measure corrected the review's own subagent count, which named five requirements as undesigned when five of the nine are supplied now, and it surfaced one conflict, that the single active run per session index leaves only the dedicated child session branch of Section 27.6 implementable. That conflict is recorded, not resolved, because resolving it is Milestone 10 work. A closing pass then tried to falsify the claim that the corpus is complete and names no unresolved blocker. It raised ten findings; checking each against the sources confirmed eight and cleared two, and one of the eight reversed a verdict an earlier pass had recorded. The approval routes belong at Milestone 5 with every other route, and what Milestone 4 owes them is the service behind them and the CLI that calls it. Seven of the eight are corrected here: two cross references that pointed at the wrong place, one description of a sibling document the sibling had outgrown, one sentence that still read as though Milestone 10 added no gates of its own, the missing outward pointer from Section 31, the approval milestone split, and one tool name the registry grammar cannot hold, which is registered as skill.manage. The eighth is recorded rather than fixed. No tool, route, or command reaches the MemoryStore list, edit, and delete methods, so the one Milestone 9 acceptance criterion about inspecting and deleting memories has nothing behind it to test. Choosing that surface is Milestone 9 design and this pass makes no Milestone 9 decisions. A structural audit then compared every gate declaration against its registry row. The milestone tokens agreed on all one hundred and seventy three rows, but thirteen rows across four tables carried a truncated identifier, which the grammar this corpus sets does not admit and which two of its own hard gates cannot be implemented against. All thirteen are now written in full. Nine of the twelve gates were restored from spellings attested elsewhere in the corpus, and three were completed from their declaration titles, which is the one naming decision this pass made and is recorded as a question. The same audit found two worked examples in the evaluation harness naming gates the registry does not hold, and two milestone counts in one of them that disagreed with the census; both are corrected. The gate census is unchanged: one hundred and seventy two registry entries, the same four kind totals, the same per milestone counts. A second structural audit then ran three of the milestone map's own hard gates by hand, the ones over the registry that the identifier pass did not cover. Every numbered item in every hard gates section carries exactly one milestone token, one hundred and seventy three items across fifteen sections. The alias arithmetic holds per specification and not only in aggregate: each specification's gate count less its declared aliases equals the entries citing it, on all fifteen. The anchor check does not hold as written. It requires every registry entry to name a hard gates anchor, and the two entries the engineering plan owns have no such section, because that document is organized by milestone and declares them in Milestone 0's acceptance criteria. They now name the Milestone 0 heading instead, which the built site confirms, and the gate is read as its own title states, that a spec field resolves. The milestone order gate is recorded as asserting against the build sequence table, which passes on all nine specifications whose sequences carry milestones. The census is unchanged at one hundred and seventy two registry entries. A third pass audited the evaluation case registry, which had never been read against itself. The case table places eleven cases at Milestone 1, cases 1 through 11, and five live statements say so, but three others said ten and one said a Milestone 1 checkout fails twenty of the twenty five when the figure is fourteen. All four are corrected and each now names the range, so the count is checkable against the table. The section heading promised gates the table does not carry and now names the kind column it holds. Ninety five of the one hundred and seventy two registered gates declare kind case against thirty one enumerated cases, and six cases are tied to a named gate anywhere, so the enumeration is a floor and the binding is recorded as an open question. The two remaining map gates that can be run today were run and pass: every identifier matches the grammar and uses one of the fourteen areas, and the written census is what the registry derives, per milestone and cumulative. A fourth pass audited the event type catalogue and the error taxonomy, the two enumerated registries that state their own totals. Six declared event types sat outside the fifty one the corpus called closed: mcp.server.reauthenticated, knowledge.document.ingested, and four eval events. The first two are session scoped and are now in the consolidated list, which stands at fifty three. The four eval events are declared on the harness rather than on a run, and events.session_id is NOT NULL, so they have no row in events as the schema stands. That is the same constraint multi-device-and-surfaces.md records for device lifecycle events and leaves open; both documents now name each other and one open question covers both. Three event names in live prose do not exist and are replaced by the Section 6.8 names they meant. The error taxonomy is twenty nine classes rather than thirty one, because the eight the runtime loop classifies include two that Section 13 already lists, and the two phantom classes the API spec invented to make its own arithmetic close are gone. A fifth pass audited the tool registry. The corpus declares eighteen model callable build time tools and the builtin roster is eight of them, so builtin-tools.md now names the other ten, scopes its classification table and registration steps to the eight it owns, and imports the rule that makes the count of eight correct. Eight of the eighteen declare no ToolSpec fields anywhere, which registration step six reads, and that is recorded as a conflict rather than closed. The control tool table listed context.compact, which is a span name and not a tool anywhere in the corpus; context.update_working_state holds that row instead and the set is still four. Two more live sentences called skill_manage a control tool against the same document's own table. The domain partition row that labelled memory and skill as control domains is split. readiness.md said the agent facing memory surface is two tools and that both read, and memory.remember is a third and it writes. A sixth pass audited the route registry. The API document specifies fourteen routes in its http fences and its scope table had thirteen rows. The missing row is the one route the document adds, GET /v1/sessions/{id}, so session.read sat in the closed scope vocabulary with no route requiring it. That document's own hard gate five walks the route table and fails the build on a route that declares no scope, so it declared a gate its own table would fail. Its overview said it adds nothing to the API surface that Section 16 did not already put there, which its own specification of that route, its resolution row eight and its decision twenty all contradict. Thirteen is what the document inherited and fourteen is what it leaves; the sum is now stated and five live sentences in four documents that closed the API at thirteen are corrected. One of them numbered the next CLI noun fourteenth when the CLI is twelve commands and the document that owns that census calls the next one a thirteenth. The CLI census is otherwise sound. A seventh pass audited the database schema. The corpus declares twenty two tables across seven documents and no document enumerates them; the only statement of the size is event-log-and-persistence.md calling it roughly twenty tables, which is hedged and defensible. The sharp defect is in the API document, which said the runs table has fourteen columns and that GET /v1/runs/{run_id} returns nine of them. Section 15 declares fifteen columns, four other documents add eleven more, and the JSON body immediately below the sentence has thirteen top level keys. The overview of the same document called it twenty three columns, which is Section 13's error class count. Both are corrected and the split is now stated rather than counted: thirteen out and thirteen withheld, with every Section 15 column in the body but the two lease columns and every later addition withheld. readiness.md summarized the idempotency resolution as two tables when the API document resolves it as one table and one column. tool-system.md and policy-and-approvals.md both add origin_trust and idempotency_class to tool_invocations and only the first was cross referenced. Two questions are left open: whether the memory, knowledge and device stores should get DDL, since they are the only storage declared as Pydantic models and prose, and whether any document should own a table census. An eighth pass audited the port census. The corpus declares forty seven Protocol blocks naming forty three distinct types. Four blocks re declare a type an earlier document declared and four of the types are application services of the API document, which leaves thirty nine ports. runtime-loop.md said four ports were declared under a heading that declares five; four is the number of code fences, since Clock and IdFactory share one, and the same document declares CancellationToken later, so it declares six in all. The larger defect is that the ports table in bootstrap-and-composition.md left eight declared Protocols unassigned: SkillRepository, SkillPackageStore, Extractor, Chunker, KnowledgeStore, WorkspaceHandle, ArtifactWriter and CredentialResolver. That table exists so the first implementer does not invent a layout the second disagrees with, and the harness gates on a walk of agent_core/ports/ that demands one contract module per Protocol, so where the eight live decides which contract suites exist. All eight are assigned. Six went into existing modules under the document's own rule and two new modules were added, ports/knowledge.py and ports/credentials.py, which are the reversible part and are flagged as such. The table now names thirty nine ports across fourteen modules. Three rows still name no type and are left as questions: ports/telemetry.py, which no document declares a Protocol for, the formation half of the memory row, which is prose while the retrieval spec beside it declares five, and the MCP row.

Ninth pass, the types. The corpus declares one hundred and forty four distinct types across one hundred and fifty nine declarations, so thirteen types are declared more than once. Four of the thirteen have identical member sets and cannot mislead. Of the nine that differ, eight already say they differ, by an unchanged fields comment inside the fence, an introducing sentence that names what is extended, a supersession paragraph, or in one case a whole reconciliation section. The ninth, ProviderReasoningItem in model-gateway.md, said nothing. The plan declares three fields and the gateway declares six, and opaque_payload becomes provider_payload with no sentence recording the rename anywhere in the corpus. The field is persisted through RunCheckpoint.conversation, so the two declarations would have written two different keys into the same stored JSON. The missing paragraph is added. The plan side of the rename is left as that document's ninth open question, beside its sixth, which asks the same thing about tool_calling and vision. Separately the ModelCapabilities reconciliation, which is complete and correct, sits three hundred and fifty six lines below the fence that needs it, so a pointer was added under the fence.

Tenth pass, the values. Twenty eight enum declarations, twenty seven distinct names, and one duplicate whose two member sets are identical. Sixty five dotted member references were checked against their declarations and exactly one was dangling: runtime-loop.md named StopReason.STOP, which model-gateway.md does not declare, on the paragraph that triggers the empty turn retry path. It is now StopReason.END_TURN. Two further findings are the same species one level down, a vocabulary declared in one place and enumerated differently in another. SandboxMechanism is declared nowhere, so the Settings comment in bootstrap-and-composition.md was the authoritative enumeration by default and it listed three values where six other places say four; fake is added, and startup check 4 now refuses it in production beside docker, which the seventeenth requirement of sandbox-isolation.md already asked for and which matters because fake executes nothing. The trajectory export in event-log-and-persistence.md labelled a successful run SUCCEEDED, which is the tool invocation spelling and exists nowhere at the run level; it is now COMPLETED, tied to the terminal subset of RunStatus by a sentence under the fence, because the export is persisted, versioned, and read by consumers who are not us. SuspensionKind is recorded and not changed: it is never declared, its members appear in trailing comments in two spellings, and the open hand-off question should produce the declaration. A numeric constants cross-check over retry counts, approval expiries, lease and heartbeat intervals, and token budgets found no conflict.