Readiness¶
This document answers one question: can an implementer open this corpus and start writing code, and if so, how far can they get before the corpus runs out?
The original answer was that Milestones 0 through 5 were implementable from the documents alone and Milestones 6 through 10 were not. The historical findings below retain that answer because they explain why the missing specifications were written. The present answer is different: Milestones 0 through 14 are complete, and Milestone 15 operational hardening is the next sequential, fully specified milestone. Milestones 16, 17, 19, 20, 22, 23, and 29 completed as separately authorized parallel workstreams; Milestones 18, 21, and 24 through 31 are authorized parallel workstreams in progress, each with a complete design and registered gates. Milestone 32 was authorized on 2026-10-02 with a proposal; Phase 1 on 2026-10-03 added its detailed contracts and twenty-four registered gates. Runtime operations and offline comparisons are implemented; verification remains incomplete.
Milestone 5 crossed that boundary after this review was written, and it crossed because of it. The finding was that the API had a plan section and no specification below it, and the finding is kept below rather than deleted, because it is the evidence for why http-api-and-streaming.md was written and the record of what writing it turned up.
This document owns no requirement. It states what is covered and what is not, and where it finds a conflict between two documents it names the conflict rather than deciding it. The two exceptions are recorded under Decisions, and both are placements rather than requirements.
What was checked, and how¶
Every #### Implement bullet, every acceptance criterion, and every
subsection heading under Milestones 0 through 11 in
engineering-plan.md was taken as a work item
and traced to the document that designs it. An item counts as
covered when some specification states its mechanism in enough
detail that two implementers would build the same thing. It counts as
partial when the seam exists — a type is named, a column is
declared, a check site is identified — but the algorithm, the schema,
or the signature behind it does not. It counts as absent when no
document outside the plan expands it at all.
Three things are deliberately not treated as evidence of absence.
- A plan section is a design. Section 16 specifies nine HTTP endpoints with methods, paths, headers, and request and response bodies. That it lives in the plan rather than in a spec changes what a reader must open, not whether the thing is designed. The distinction still matters and is reported, because every other milestone's mechanisms were expanded once more after the plan stated them, and the expansions found real conflicts each time.
- An explicit deferral is not a gap.
builtin-tools.mdhas a section titled "The two tools this document does not design" — six when this review ran, four of which have since been designed — that names each one, assigns it a milestone, and lists what it still owes. That is a smaller and better-understood hole than an item nobody has looked at, and it is scored separately. - A reserved seam is not an omission where the document says so.
tool-system.md:2165states that device tools are "a reserved seam, not a design". The seam is the decision.
The gate census in milestone-map.md was used as an independent check on every verdict below. It was derived mechanically from the specifications, the plan, and the map, without reference to this review, and where the two disagree the disagreement is reported rather than smoothed.
The verdict¶
| M | Subject | Verdict | Gates | What stands between it and code |
|---|---|---|---|---|
| 0 | Repository and engineering foundation | Ready | 13 | Nothing |
| 1 | In-memory vertical slice | Ready | 28 | Nothing |
| 2 | PostgreSQL persistence and durable worker | Ready | 16 | Nothing |
| 3 | Model adapters and normalized streaming | Ready | 15 | Nothing |
| 4 | Policy, approvals, and tool lifecycle | Ready | 22 | Nothing |
| 5 | HTTP API and SSE | Ready | 11 | Nothing |
| 6 | Isolated execution and artifacts | Ready | 11 | Nothing |
| 7 | Context budgeting and working state | Ready | 7 | Nothing |
| 8 | Skills and MCP integration | Ready | 17 | Nothing |
| 9 | Long-term memory and knowledge | Ready | 26 | Nothing |
| 10 | Memory maturation, self-authored skills, web access, browser automation | Complete | 38 | Tenant activation remains roadmap item B1 (ADR-0061) |
| 11 | Scheduled runs | Complete | 23 | Nothing |
| 12 | Notifications and device identity | Complete | 20 | The Apple push key and capability are owner actions outside the corpus |
| 13 | General-purpose subagents and delegation | Complete | 21 | Nothing; the delegating re-run scored above the failed single-agent trajectory, and tenant activation stays default-off |
| 14 | Inbound surfaces and pairing | Authorized | 21 | Nothing in the corpus; the Telegram bot and its private token file are owner actions outside it |
| 15 | Operational hardening | Authorized | 16 | Nothing in the corpus; the bucket, the age identity, the first escrow, and the first off-host rehearsal are owner actions outside it |
| 16 | Memory evaluation and lifecycle | Complete | 20 | Nothing in the corpus; the public datasets are owner-supplied local files and the live arm needs a funded provider key |
| 17 | Memory read API and browser | Complete | 10 | Nothing; the owner decided on 2026-08-23 to expose the three provenance fields, so the projection carries twenty-six fields |
| 18 | First-class email integration | Authorized | 17 | Nothing in the corpus; OAuth consent and the real-mailbox smoke are owner actions outside it |
| 19 | Conversational schedule creation | Complete | 5 | Nothing; the surface is deliberately limited to approved one-time creation |
| 20 | Calendar recurrence and conversational schedules | Complete | 6 | Nothing; ADR-0073 fixes the monthly, yearly, and recurring-tool semantics |
| 21 | Adaptive memory distillation | Authorized | 31 | Nothing in the corpus; the three-arm live evidence for the production tuple was published on 2026-09-03 |
| 22 | Persona surface and curated belief promotion | Complete | 14 | Nothing; ADR-0079 fixes the human-only promotion boundary |
| 23 | Conversational schedule lifecycle | Complete | 12 | Nothing; ADR-0080 and ADR-0088 fix discovery, approval, lifecycle, and update semantics |
| 24 | SMS through the owner's iPhone | Authorized | 12 | Nothing in the corpus; the physical-iPhone verification is an owner action outside it |
| 25 | WhatsApp business surface | Authorized | 12 | Nothing in the corpus; the Meta ceremony, template approval, and live-number smoke are owner actions outside it |
| 26 | Client modes and adaptive email experience | Authorized | 32 | Nothing in the corpus; the private quality evaluations and two-account acceptance need the owner |
| 27 | Bland calling and public reception | Authorized | 14 | Nothing in the corpus; the provider dashboard and live-call checks are owner actions outside it |
| 28 | People and relationship memory | Authorized | 36 | Nothing in the corpus; every gate binding is still pending, and quality evaluation needs the owner |
| 29 | Chat thread folders | Complete | 17 | Nothing; ADR-0110 adds the typed-judgment port and its matcher |
| 30 | Advisory approval layer | Authorized | 5 | Nothing in the corpus; threshold calibration and the enforce decision need the owner |
| 31 | Email unsubscribe assistance | Authorized | 20 | Nothing in the corpus; the real-mailbox smoke is an owner action outside it |
The gate column is the count of registry entries whose milestone
field names that milestone. Its correlation with the verdict column is
the strongest single piece of corroboration in this review, and it was
not constructed to produce that correlation. When this review was
written Milestone 5 registered one gate and Milestone 6 registered
none, which is what a corpus looks like when nobody has written down
what those milestones must be true of. Milestone 5's eleven are the
ten the API specification declares plus the one it already had, and
they arrived with that document rather than being added to it
afterwards, which is the same correlation running the other way.
Milestone 6's eleven arrived the same way, from
sandbox-isolation.md, and took one of the two
zeros in the table that belonged to a milestone doing real work.
skills.md took the other, giving Milestone 8 ten; the
seven that bring it to seventeen came later in two passes — four from
the one that noticed build step 9 of the tool system had nothing
observing it, and they are the reason the mock-server gap this table
first named is gone, then three more with the authentication design
that closed the other half of the same milestone.
Its six at Milestone 10 were a different case when first measured: they were
the authoring loop's gates, registered against a milestone whose own acceptance
criteria did not yet exist. The later authorization added five automatic-memory
gates and an explicit completion contract. Milestone 11 follows the same
discipline with twenty-three scheduling gates arriving with its detailed
design, including explicit contract, migration, erasure, and isolation gates.
Milestone 3's eleven became fifteen the same way: two from
model-gateway.md and two from
event-log-and-persistence.md, each
pair arriving with the design that closed one of this section's named
gaps rather than being added to make a count look better. Milestone
9's fourteen became twenty-six on the same principle and by the
largest margin, when the knowledge half of that milestone acquired a
design to be true of.
Milestone 0: ready¶
Thirteen registry entries, every deliverable expanded.
development-toolchain.md and ADR-0025
specify the Makefile target bodies, the compose service, the CI
workflow, and why docker compose up -d postgres and alembic upgrade
head remain two commands.
bootstrap-and-composition.md and
ADR-0024 specify the secret scanner — five rule families, a report
that never prints what it matched, an allowlist whose entries require
prose — and add four static checks to the import-boundary walk, all
four of which are true of an empty repository.
evaluation-harness.md supplies the four
harness gates. The map supplies six of its own, all of them statements
about documents rather than about a running system.
event-log-and-persistence.md supplies
the thirteenth, and it is the one gate here that belongs to a later
milestone's subject: the migration-graph walk registers at Milestone 0
because Milestone 0 already requires that an empty Alembic migration
runs, and a walk that only begins once twelve revisions exist has
already missed the branch it exists to prevent.
Nothing here is blocked. This is the milestone the corpus has been examined against most often, and it is the one with the least left to decide.
Milestone 1: ready¶
Twenty-eight registry entries, the largest count of any milestone, and every implement bullet has a body. The twenty-eighth arrived later, with sandbox-isolation.md: the composition root refuses to build the development sandbox mechanism when the environment is production.
The three bullets ADR-0024 found empty — in-memory repositories, the
inline run dispatcher, the minimal context builder — now have one.
The in-memory tier is five real adapters running the same contract
suites as their PostgreSQL counterparts, with a checked-in capability
table so a skip is a reviewed fact. RunDispatcher has one method and
one postcondition that both adapters satisfy. The context builder is
build-sequence step 1, and its test asserts both halves rather than
the half that a builder which never changes anything would also pass.
Two things about this milestone are worth stating because they are easy to misread as problems.
Forty-one gates are green before Milestone 2 begins, thirteen of them against a repository with no agent in it. The current registry total is derived in the milestone map, not restated here. That is not a sign that the gates are weak. It is the consequence of building the in-memory tier as real adapters rather than as test doubles: the invariants that hold for the slice hold for the durable system, and they can be asserted four milestones before the durable system exists.
Cancellation arrives here rather than at Milestone 5. Section 21
lists cancellation under Milestone 5 and
runtime-loop.md proposes splitting it. The map
resolves the split: a lazily evaluated deadline and a SIGINT handler
are Milestone 1 because both need only Clock and the process, and
CancelReason divides by dependency across Milestones 1, 2, and 5.
This is the one placement in the whole reconciliation that overrides a
milestone the plan states rather than one it leaves silent, and it is
recorded as an open question in
questions-for-review.md.
Milestone 2: ready¶
Sixteen registry entries. Nine of eleven implement bullets were
covered on the first pass by
event-log-and-persistence.md and
runtime-loop.md: the append-only event store, the
projections and their rebuild, FOR UPDATE SKIP LOCKED claim,
lease_epoch fencing, checkpoint and resume, the reaper, and the
transaction-hygiene gate ADR-0024 separated from its Milestone 0
check.
Two bullets were partial, and both were tooling rather than
architecture. Both are closed now, in the document that already owns
the schema and the gate.event.* area rather than in a twentieth
specification, and recorded as
ADR-0031.
- The SQLAlchemy adapter had no ORM surface. The schema was
fully specified, table by table, but no document stated whether
mappings are declarative or imperative, where the session factory's
boundary sits relative to the unit of work, or what the repository
method bodies look like against it. ADR-0024 fixed the one
property that could be checked without any of that — a factory is
constructed, never a session, and no
AsyncSessionexists at module scope. "The ORM surface" answers the rest, and answers it by elimination rather than by preference: declarative mapping of a domain type fails rule 1 on the import walk, imperative mapping fails rule 7 silently, and what survives is a separate row class per table, two hand-written translation functions beside it, and a repository constructed with a live session that never commits.gate.structure.orm_confinedasserts the confinement. - Alembic had no authoring conventions.
engineering-plan.md:1769says "Create Alembic migrations for at least these tables" anddevelopment-toolchain.md:217supplies themake migratetarget. Between them there was no statement of naming, no branch policy, no rule for data migrations versus schema migrations, and no design for how the composition root asserts the revision it refuses to start without — which ADR-0024 decision 6 requires and does not specify. "Authoring migrations" supplies all four: a linear graph with one head, slugged file names that carry no order, structural and data revisions kept separate, andEXPECTED_REVISIONas a constant rather than a head computed at runtime from the migrations that shipped alongside the code.
Closing the second bullet surfaced a defect this review had missed. Two of Section 24's criteria — migrations upgrade from a clean database, and migrations upgrade from the previous revision — are conditions of every milestone, and nothing evaluated either of them. That is the same class of finding the milestone map produced by counting gates, arrived at from the opposite direction, and it is why four of the five gates added here observe migrations rather than the ORM.
One milestone conflict is reported and not resolved here. The plan
places "Usage token classes and cost-source precedence in the schema
(Section 6.5)" in Milestone 2 at engineering-plan.md:2663, while
model-gateway.md designs it and sequences it to
Milestone 3, and the map follows the gateway. The schema column can
exist a milestone before anything writes to it, so this is a question
of whether the migration ships early or the whole item ships late; it
does not change what gets built.
Milestone 3: ready¶
Fifteen registry entries. model-gateway.md is one of the more complete specifications in the corpus: both provider adapters, the normalized streaming event set with the exact field mappings pinned for Anthropic Messages and OpenAI Responses, retry classification, the reasoning-state handling ADR-0007 requires, and the usage and cost model.
Three items fell short, one of them completely.
- Provider response metadata is designed nowhere.
provider_metadataappears exactly once in the entire corpus, as adict[str, Any]field atengineering-plan.md:1347. No document states which keys go in it, whether the set is open or closed, whether it is persisted, or where. It is absent from themodel_callsschema. A field of that shape with no key discipline is where provider-specific data accumulates until something depends on it, which is the failure mode ADR-0002's provider-neutrality argument exists to prevent. - Declarative provider plugins have no document schema. Section 10.7 and ADR-0012 establish that a new OpenAI-compatible provider should be addable without code, and the gateway specifies how a profile is consumed. What no document states is the profile document's own schema — its fields, its required set, its validation, and what happens when a profile names a capability the adapter cannot satisfy.
- Minimal redacted trajectory export has no design. See Section 31 below; this is the production half of a section whose consumption half is fully specified.
What closed it¶
All three, in documents that already owned the subject.
Item 1 is closed by model-gateway.md, which makes
provider_metadata a closed set: a declared field list, a persisted
column on model_calls, and exactly two readers. The discipline is
the point, not the field — an open dictionary is where
provider-specific data accumulates until something depends on it, and
a closed one cannot. It registers gate.model.metadata_closed.
Item 2 is closed in the same document, which gives the provider
profile a document schema, a required set, a rule table the loader
enforces, and a stated answer for a profile that claims a capability
its adapter does not have. Its gate,
gate.model.profile_valid, is a corpus gate rather than a case,
because one invalid profile proves only the rule it violates and the
rule table has a row for each.
Item 3 is closed by
event-log-and-persistence.md and
ADR-0032,
which choose the format, make the export an artifact rather than a
table, specify redaction as three stages that fail closed, and design
the consent record the corpus had asserted four times and never
defined. It is covered below under Section 31, and it registers
gate.event.export_redacted and gate.event.export_consent.
Four gates for three gaps, all at Milestone 3, which is the same correlation the verdict table reports: a milestone acquires gates when somebody writes down what it must be true of. The verdict is ready.
Milestone 4: ready¶
Twenty-two registry entries.
policy-and-approvals.md covers the
deterministic decision function, the hardline set, profile compilation
and freezing, policy_version, the approval record and its lifecycle,
expiry, resume revalidation, and the injection corpus.
tool-system.md covers the execution pipeline
end to end. The thirteenth entry arrived later, with
sandbox-isolation.md: a property test over
WorkspaceHandle.resolve, which acquires its first callers at this
milestone. The last nine arrived later still, from the two passes that
closed the two gaps below.
Two things were outstanding.
Four builtin tools were classified but not designed, and the
document said so. builtin-tools.md named workspace.read_text,
workspace.write_text, workspace.list_files, and
demo.external_write, assigned each to Milestone 4, and listed what
each still owed: path resolution and traversal rejection, encoding and
binary-file rules, the checksum algorithm, the listing's limit and
ordering, and the WorkspaceHandle the execution context already
carries. It also fixed two constraints in advance rather than leaving
them to be noticed — the reader lowers output_trust to
EXTERNAL_UNTRUSTED for any file whose provenance in the run is not
established, and the establishing set is what this run's
workspace.write_text produced.
That was a bounded and well-understood hole, but one consequence was worth stating plainly: the Milestone 4 acceptance criterion "Path traversal is rejected" and eval case 19 both stood on an algorithm that no document then contained. A rejection rule is exactly the kind of thing that is written three different ways by three implementers, two of which are subtly wrong.
Principal scopes were half-designed. The Principal model lived
only at engineering-plan.md:585, the policy spec identified where
scopes are checked, and nothing stated the scope vocabulary, its
grammar, or the comparison algorithm — whether a scope was an opaque
string, a hierarchy, or a pattern. Relatedly,
bootstrap-and-composition.md:655 named ApprovalService as one of
the services build returns, and no document gave it a method
signature.
What closed it¶
Both, on two passes.
The traversal half closed first and separately.
sandbox-isolation.md specifies
WorkspaceHandle.resolve as a five-step containment rule, says for
each step why it rejects rather than normalizes, and registers
gate.sandbox.workspace_containment at this milestone — the
thirteenth entry counted above. The sentence about an algorithm no
document contained was true when it was written and stopped being
true with that document, which is why it is now in the past tense.
What remained was the tool half, and
builtin-tools.md now designs all four: the
prohibition that no workspace. tool resolves a path at all, strict
UTF-8 with a NUL byte as the binary test, a SHA-256 checksum over the
encoded bytes, a listing capped at a thousand entries and ordered so
that a truncated one is a prefix of the full one, six JSON schemas,
four reason codes, and demo.external_write's record as the
structured result the pipeline already persists.
Two of its answers are more than transcription. Provenance became a
property of the workspace rather than a repository query, because
ToolExecutionContext deliberately carries no database session:
WorkspaceHandle gains one method and one enum, write records
TOOL_WRITTEN in the same operation that writes the bytes, and
Milestone 6's SANDBOX_WRITTEN is defined two milestones early so
that it cannot later be treated as establishing trust. And the reader
has no size-limit failure of its own, deferring instead to the
execution pipeline's excerpt-and-artifactize step, because a second
ceiling is a second truncation policy to keep in agreement with the
first.
Six gates, all at Milestone 4: gate.builtin.handle_only,
gate.builtin.text_only, gate.builtin.write_idempotent,
gate.builtin.listing_stable, gate.builtin.provenance, and
gate.builtin.demo_records.
The scope gap closed on the pass after that one, and half of it had
already closed on its own.
http-api-and-streaming.md gave
ApprovalService the three-method Protocol the composition spec had
been naming without one, and enumerated the nine scopes the API
checks. What was left was the tool half — the five more that appear
as ToolSpec.required_scopes on the builtin roster — and the three
questions no document had answered: what a scope is, how two of them
are compared, and where a worker gets the set.
policy-and-approvals.md answers all three
in one section. The vocabulary is one closed set of fifteen strings
rather than an API namespace and a tool namespace, because
artifact.read and artifact.write are two actions on one resource
and not two vocabularies that happen to collide. A scope is an opaque
string compared by exact match, the check is a set difference and
all-of, and there is no hierarchy, no wildcard, and no prefix rule —
so run.write does not satisfy run.read, and a tool that means
both declares both.
The closed list has one deliberate seam. An MCP tool's
required_scopes are operator-declared, so a list closed against
them is a list the operator routes around. The rule is that a
declared scope is legal if it is one of the fifteen or its first
segment is mcp and its second is the server id. That lets an
operator classify a remote tool's risk without letting one borrow
session.write, which is the escalation worth blocking: a
requirement that reads as a restriction and grants.
The worker's copy is a stamp. runs.principal_scopes is written at
submission and PrincipalResolver.for_run reads it rather than a
principal table, because a worker holds no credential, and
re-deriving would make the runtime loop's "takes effect on the next
run" depend on queue latency rather than on submission order. It is
a Milestone 2 column with a Milestone 4 reader, which is the shape
ADR-0032
already chose for the consent stamp and for the same reason.
Three gates, all at Milestone 4: gate.policy.scope_grammar,
gate.policy.scope_match, and gate.policy.scope_stamped. Both
named gaps are closed, so the verdict changes with them.
Milestone 5: ready¶
Eleven registry entries. There was one when this review was written — the fewest of any milestone that adds work — and that number was the finding.
Section 16 of the engineering plan, at
engineering-plan.md:1943-2159, designs the API more thoroughly than
a summary of this milestone's coverage would suggest. At the time of the
Milestone 5 review it specified nine endpoints with methods, paths, and where
relevant headers; ADR-0050 later added the authoritative session list and
delete contracts without changing that milestone's gate census. The section
also specifies
request and response JSON for session creation, message submission,
and approval resolution; the SSE frame format with id, event, and
data lines; the reconnect rule that replays persisted events after
Last-Event-ID and then continues streaming; the five cooperative
cancellation observation points; the error envelope; and the
readiness constraint that a probe must not call a provider.
What did not exist was any expansion of that section. No
detailed-design specification covered the API layer. The only HTTP
routes designed outside the plan were three: the two approvals reads
at policy-and-approvals.md:1263-1264 and the resolve at
policy-and-approvals.md:1291, and one reference in
runtime-loop.md:1296 to POST /runs/{id}/input that routed to an
endpoint it did not design.
That matters more than it would for a milestone whose plan section was merely a summary, because every comparable section in this corpus was expanded exactly once and every expansion found conflicts the plan had not noticed. ADR-0024 found two outright milestone contradictions in the bootstrap path. The milestone map found three gates declared twice and a required field absent from most of the corpus. There is no reason to believe Section 16 was the one section that would survive expansion unchanged, and several specific reasons to believe it would not. It did not: the expansion found nine contradictions and recorded each of them in a table of its own.
Six things were visibly unsettled inside it.
- The error envelope has one worked example and no code list. A stable error contract is the part of an API that clients depend on hardest and that is most expensive to change after release.
- Request IDs are an implement bullet and nothing else. No document states where the identifier comes from, whether a client may supply one, how it reaches the event log, or its relationship to the trace identifier the observability section requires.
Idempotency-Keyhandling is named in two places and specified in neither. It appears as a header atengineering-plan.md:2035and as an implement bullet, and the idempotency port the map schedules at Milestone 1 is a tool-call concern rather than an HTTP one. Whether these are the same mechanism is undecided.- The SSE consumer side is one sentence. ADR-0010 chose
PostgreSQL
LISTEN/NOTIFY, and event-log-and-persistence.md designs the producer side completely. How a connected client's stream is fed from that channel, what happens when a notification is missed, and how replay hands off to live streaming without a gap or a duplicate are the substance of eval case 22, and they are forwarded to Section 16 rather than designed. - API authentication is designed only at its refusal. ADR-0024
fixes that production startup fails without configured
authentication and puts the mode and token in
Settings. Token format, validation, the mapping from a credential to aPrincipal, and rotation are all undecided. - The cancel endpoint is distinct from the cancellation
mechanism.
runtime-loop.mdspecifies the token, the six observation points, and theeffect_sent_atrule completely. What turns an HTTPPOSTinto an observation by a worker in another process is not specified. The worker half is — the poller, its cadence, and its query are all inruntime-loop.md. It is the API half that is missing, and it is one column write.
The verdict on that evidence was that coding could reach this milestone and should not enter it until an API specification existed, and that this was the single most valuable document not yet written. It exists now. http-api-and-streaming.md and ADR-0028 settle all six. The code list is the error taxonomy already in the corpus, snake-cased, rather than a second vocabulary that would have to be kept in step with the first. Request identifiers get four rules, of which the load-bearing one is that an identifier a client supplies is never trusted with anything. The two idempotency keys are separated as two mechanisms that share an unfortunate name, with different scopes, tables, and milestones. The consumer side of the stream is specified down to the subscribe-before-read handoff that makes replay gapless and duplicate-free. Authentication is specified at what it produces and not only at what it refuses. And the cancel path gets the one sentence it was missing.
The same document supplies response bodies for the twelve routes that had none, and declares ten hard gates, which is what took this milestone's gate column from one to eleven. The verdict is ready.
Milestone 6: ready¶
Eleven registry entries. There were none when this review was written
— the only zero in the table belonging to a milestone that does work
— and eight of twelve implement bullets had no
design outside the plan: the container-backed execution adapter,
workspace lifecycle, resource limits, no-network execution,
sandbox.run_command, the filesystem artifact store, artifact
metadata and content endpoints, and workspace cleanup.
Section 28 of the plan is not empty — engineering-plan.md:4672-4749
states a six-item threat model that assumes model-generated code is
hostile, and is recorded as ADR-0008. But it was not expanded, and
two specifications pointed at the expansion as though it already
existed. tool-system.md:1086 constrains MCP server URLs by "the
egress allowlist the sandbox spec establishes", and there was no
sandbox spec.
bootstrap-and-composition.md:205 and :183 assign ownership of
ArtifactStore and ExecutionEnvironment to the engineering plan
itself, which is the corpus recording that nothing below the plan owns
them.
Two bullets are covered. Output truncation and artifactization are
specified at tool-system.md:737, and the programmatic orchestration
bridge Section 8.5 requires is specified from tool-system.md:1538.
Two further items deserved naming.
- The plan demands a red-team test with no case behind it.
engineering-plan.md:4747requires a container-escape attempt as a security test. The twenty-five-case table contains no such case and no Milestone 6 security row. sandbox.run_commandwas placed at two milestones.builtin-tools.mdsaid Milestone 5 wherebuiltin-tools.md:1520now says Milestone 6; the plan's Milestone 6 implement list contains it. The map follows the plan. This was reported rather than resolved, because the right answer depended on a sandbox specification that did not exist: if the tool can ship against the development mechanism at Milestone 5 and gain container backing at Milestone 6, both documents are right about different things.
The zero in the gate column was worth dwelling on. Milestone 6 is the milestone whose failure mode is a container escape, and it was one of two milestones that registered no gate at all. Every invariant its work strengthens was registered against an earlier milestone, which meant the gate registry contained no statement that becomes true because the sandbox was built.
What closed it¶
sandbox-isolation.md and ADR-0029 exist now, and they settle the eight uncovered bullets, both named items, and the zero.
The eight types the corpus referenced and never declared are declared:
EnvironmentSpec, ResourceLimits, EnvironmentHandle,
ExecutionCommand, ExecutionResult, ArtifactMetadata,
ArtifactRef, and the FileChange and KillReason that
ExecutionResult needs, together with WorkspaceHandle,
ArtifactWriter, and CredentialResolver from
ToolExecutionContext. That removes the last of the
referenced-and-undeclared types the API specification named as
remaining. The egress allowlist tool-system.md:1086 depends on by
name gets a grammar, an owner, and two enforcement points, of which
the address denylist runs first and no allowlist entry can waive it.
Workspace lifecycle is settled by a rule rather than a mechanism —
the workspace is a cache held for a worker's lease, not state held
for a run — which makes cleanup and crash-resume the same operation.
Resource limits become numbers with operator ceilings. Artifacts get
a derived storage key, a checksum verified on the way out, and a
retention rule.
Item 1 is closed by harness case 26, a security case at Milestone 6
registered as gate.sandbox.escape_denied, added without renumbering
any of the twenty-five. Item 2 is closed against builtin-tools.md:
Section 8.2's "only after the sandbox milestone" is Milestone 6, and
the spec's Milestone 5 was an off-by-one against a milestone list in
which 5 is the HTTP API. The tool does not ship early against the
development mechanism, because the development mechanism refuses to
run in production and a tool that only works in development is not a
milestone deliverable.
The zero is closed by thirteen gates in a new twelfth registry area,
sandbox, of which eleven are Milestone 6. One is Milestone 1, where
the composition root learns to refuse the development mechanism, and
one is Milestone 4, where WorkspaceHandle acquires its first
callers. The verdict is ready.
Milestone 7: ready¶
Seven registry entries and the best per-bullet coverage of any milestone
in the second half. context-engine.md covers
seven of eight implement bullets fully: the token budgeter, the
compaction boundary, the structured working set, the deterministic
assembly and prefix_sha256, the two regions, trust labeling in
assembled context, and the recall trace as a second consumer.
Two shortfalls.
- History selection had an order but no predicate. The yield order and the floor were specified. What decided that a given turn was in or out was not, which is the part that determines whether the result is stable across two runs with the same input.
- Long-session evaluation has a gate and no case. The twenty-five-case table carries milestones 1, 2, 4, 5, and 6 and nothing else. There is no Milestone 7 row, so three of this milestone's acceptance criteria have no case backing them. The harness specifies how to add cases and the gate exists; what does not exist is the case.
What changed. Shortfall 2 was closed first.
evaluation-harness.md case 28 gives this
milestone its first row: the fifty-turn session with one distinct
prefix_sha256, which is gate.context.prefix_stability given
something to run.
What closed it¶
Shortfall 1 was closed on a later pass, and it turned out to be two questions wearing one name. Which items are in the request is decided twice — once when a run seeds from the session and once on every assembly — and the two decisions read different inputs, so a single predicate could not have covered both.
context-engine.md answers the seeding half with a
cut rather than a rule about content. The session-history projection
is a live read model that advances on a timer, so reading it for "the
session's history" returns whatever has been applied at the moment of
the call. That matters more than it looks: seed_checkpoint has two
call sites, the second being the rebuild the Milestone 2
dispensability gate forces, and the two can be hours apart. The seed
now reads the log below runs.seed_event_sequence, the session
sequence of the user.message.created event the run answers, written
in the transaction that already allocates it. Projections were already
required to be deterministic over a log prefix; pinning which prefix
is what converts that into a statement about seeding, and it needs no
gate of its own, because the dispensability gate is the test and it
only tested anything once the cut was fixed.
The assembly half is answered by making the retained set a contiguous
suffix — one cut index, computed by a backward scan against
history_tokens, floored at the compaction boundary, moved later past
any tool pair it would split, and taken after the never-yield items
have been subtracted. select_history returns the index rather than
the list, so contiguity is carried by the return type instead of by a
test someone has to remember to write, and TokenEstimator.estimate
picks up a purity requirement it was missing: approximate was always
allowed, but an estimator that answers differently on two identical
calls moves the cut, which is the whole failure.
The argument against the obvious alternative is the part worth keeping. A relevance ranking over past turns would be a second retrieval system beside the one the corpus already has, and it would make a missing turn ambiguous between a selection defect and a ranking miss. History is recency and in-turn recall is relevance; the two stay separate so that either can be tested.
One gate, at Milestone 7: gate.context.history_cut, a property gate
for the same reason gate 1 is. Both named shortfalls are closed, so
the verdict changes with them.
Milestone 8: ready¶
Seventeen registry entries: ten from skills.md, which was written after this review and closes the half that was missing, and seven added later still for the MCP half. The verdict below is the review as it stood, followed by what changed.
MCP is substantively covered. tool-system.md
designs nine of eleven bullets: server configuration and lifecycle,
tool discovery and namespacing, the trust labeling that makes MCP
results EXTERNAL_UNTRUSTED, failure isolation, timeouts, and the
reserved-domain collision rules. Two are partial: authentication
configuration has a credential_ref column and no auth scheme and no
refresh or re-auth path, and the mock MCP server the "Mock MCP
server tests" implement bullet requires is never designed, with no
MCP fixture format in the harness and no Milestone 8 row in the case
table. The bullet, not a criterion: this review said "acceptance
criteria" and the acceptance criteria say nothing about mocks.
Skills had no specification below the tool system. The stronger
claim this review first made — that skills have no specification at
all — was wrong, and the correction matters because it changes what
had to be written. tool-system.md:1469-1516 draws the line between
a skill and a tool, fixes the metadata block at four fields, puts
required_tools checking at load rather than at authoring, assigns
trust by author, and classifies skill_manage. That is real design.
What was missing was everything underneath it: no package format, no
manifest schema, no types, no storage, no reference grammar, no
context accounting, and no gates. The acceptance criterion "A
selected skill is version-pinned in the run" at
engineering-plan.md:2909 had no design behind it — and no document
outside the plan and ADR-0013 mentioned SKILL.md, which was true
and remains the sharper of the two observations.
Section 30, self-improving skills, compounded this. It is referenced from eleven places in the corpus as though the mechanism it describes were settled.
What changed. skills.md supplies the package format,
the manifest schema, the SkillRef grammar, two tables and an
archive, the session-open catalog with its caps, skill.load and its
stickiness, two new context classes, the authoring loop at Milestone
10, and sixteen gates in a new skill area — ten of them here. It
also corrects skill_manage's classification, which
tool-system.md had called a control tool while giving it a write
scope, and settles the scope's spelling. Harness case 27 gives this
milestone its first row in the case table, so the clause above about
having none is true only of the review as it stood.
The MCP half was closed on a later pass, after the milestone map's
census made it visible that build step 9 of the tool system was the
only step in that document with no gate observing it.
tool-system.md gains three gates —
gate.tool.mcp_pipeline_parity, gate.tool.mcp_disconnect, and
gate.tool.mcp_sdk_confined, the last of which promotes the "no
direct dependency on MCP SDK types" criterion from prose to a walk
over the import graph — and
evaluation-harness.md gains a fourth fixture
kind, the scripted MCP server, plus gate.harness.mcp_no_socket and
cases 29 and 30. The mock server the implement bullet asked for is
that fixture kind: authored YAML, loaded at collection time, no socket
and no subprocess.
One named gap survived, and it was the smaller one: authentication
configuration still had a credential_ref column, no auth scheme,
and no refresh or re-auth path. It was a Milestone 8 implementation
question rather than a design hole in the corpus, because the broker
that resolves the reference is specified and only the scheme it
resolves was not.
What closed it¶
The gap was a column with no counterpart. credential_ref says where
a secret is; nothing said what the reference resolves to, and the
broker cannot infer it, because a bearer token and an OAuth client
secret are both opaque strings and a resolver that guesses between
them eventually presents a client secret as a bearer token to a server
that logs its Authorization headers.
tool-system.md closes it by making the scheme
configuration rather than inference: a closed set of five — none,
bearer, header, oauth2_client, and env — declared in the
mcp_servers row beside the reference, with auth_name,
token_endpoint, and token_scopes for the schemes that need them.
The scheme lives in the row rather than inside the secret for three
reasons that each stand alone: validating configuration would
otherwise require dereferencing a secret, secrets rotate and protocols
do not, and the scheme appears in operator-facing errors and in
mcp.server.disconnected, which is a place the emitter is forbidden
to look for secrets.
Because the scheme is a column it is validated when the row is written
rather than when the server is dialled, which turns most of this into
a configuration error a human sees before anything connects: a scheme
outside the five, header naming Authorization, env naming a
tier-0 variable, an oauth2_client token endpoint the egress
allowlist does not permit, and the transport cross-check that rejects
env over HTTP and headers over a pipe.
The refresh half is a bounded ladder that routes through the recovery
table already in the spec rather than around it: one re-authentication
per server per session, one retry and only where recovery permits,
UNCERTAIN rather than a retry for a non-idempotent call whose
watermark is set — a 401 arriving after mark_effect_sent says
nothing about whether the effect landed — and unavailable with
tool.server_unauthorized thereafter. Expiry is checked when a header
is built rather than on a timer, because a background refresh is a
second clock that keeps tokens alive for idle connections and removes
none of the 401 path anyway.
The env scheme dragged in the sharper question, which is what else
is in a stdio server's child environment. It is constructed — the
synthesized sandbox tier plus the one declared variable — rather than
inherited, and it is a gate rather than a paragraph because
inheritance is the default behaviour of every process-spawning API in
the standard library, and what would be inherited is the worker's
database URL and every provider key.
What is deferred is said out loud. The user-delegated flows need a
browser redirect, a callback URL, and a per-principal token store, and
conversation.ask_user suspends a run for text, not for a redirect. A
server that requires one fails to connect with tool.auth_unsupported,
which is a refusal a reader can find rather than a connection that
hangs.
Three gates, all Milestone 8, dividing by what each needs in order to
run: gate.tool.mcp_auth_config over the validator with no server and
no broker, gate.tool.mcp_reauth_bounded against a server that
returns 401 on demand, and gate.tool.mcp_stdio_env_built against a
child process whose environment can be read back. The named gap is
closed, so the verdict changes with it.
Milestone 9: ready¶
Twenty-six registry entries, the second-largest count, and the three specifications behind them are among the most complete documents here. memory-formation-and-consolidation.md covers the autonomous formation loop, the tiers, the provisional tier and its promotion rules, contradiction handling, and cross-project belief carry-forward. memory-retrieval-and-ranking.md covers retrieval, ranking, the snapshot budget, and the recall trace with its two consumers. knowledge-documents.md covers the other half of the milestone's name.
Several items remain partial.
The remaining partials are: session history and artifacts as retrieval sources
(named as sources, not designed as such); expiration (a policy with no sweep
job in the corpus reviewed here); and the external memory provider port
(named, no contract). The fourth partial this review originally recorded —
the persona and identity surface over AgentSpec.instructions, with no
statement of how a formed belief reaches the instruction text, or whether it
may — is resolved by persona-surface.md and ADR-0079:
a formed belief reaches the instruction text only through the owner's
explicit affirmation of a governed nomination, and never otherwise.
The human-editable surface gap identified by the readiness review is now
closed through the CLI decision in ADR-0045. agent memory list, get, edit,
and delete call the governed service and expose full provenance and lifecycle
metadata; listing can include inactive beliefs and filter by source session.
agent memory formations exposes consolidation policy, watermark, and outcome
counts; agent memory diagnose --session joins the flag, watermark, provider
selection and attempt audits, consolidations, and resulting beliefs; and
agent memory replay --session --confirm reprocesses original source events
through the same principal-scoped formation service. agent memory trace
exposes the authenticated principal's persisted retrieval diagnostics. Boundary
and repository tests cover the commands, tenant/principal isolation, ordering,
session filters, and provenance-preserving replay. The HTTP route set remains
unchanged.
One item was absent, and it was the larger one. Knowledge documents had no design. The milestone's own heading is "Long-term memory and knowledge retrieval", the separate-stores subsection distinguished memory from knowledge, and no document stated what a knowledge document is, how one is ingested, chunked, indexed, or scoped, or how retrieval over it differs from retrieval over memory. The memory specs were explicit that they cover memory; nothing covered the other half of the milestone's name.
What closed it¶
The gap was a name with no referent. Milestone 9 promised knowledge retrieval, Section 18.4 said knowledge is not memory, and the corollary — that a store which is not memory needs a document model, an ingestion path, an index, a scope predicate, and a retrieval path of its own — was never drawn. What made this the larger of the two gaps is that a reader could not tell whether knowledge was a missing document or a missing decision.
knowledge-documents.md and ADR-0033 draw the corollary. A knowledge document is a thing a principal admitted so that later runs can quote passages from it verbatim and cite them, which is a different answer to a different question than a belief: a belief answers what is true, and the unit of retrieval is the claim; a document answers what does the source say, and the unit of retrieval is the passage. That distinction is what forced a fourteenth specification rather than a section in either memory document, both of whose scope lines say beliefs and episodes. The trajectory-export precedent, which rejected a fourteenth spec once already, applies a test rather than a quota — does the new document own what it needs, or borrow it — and knowledge owns ten things and borrows four, where trajectory export borrowed almost everything.
The design decisions that carry the most weight elsewhere in the
corpus are four. Ingestion is a tool, knowledge.ingest, rather than
a route or a CLI noun, because the Milestone 5 API baseline was closed at
fourteen routes and an artifact is not uploaded through it in 0.1; ADR-0050's
later list and delete routes do not add an upload surface, and ADR-0120's later
chat attachment upload feeds knowledge only for files the owner sends. Ingestion requires USER
origin trust, so an agent cannot admit what it fetched. The secret
scan blocks an ingest and the injection scan does not — a credential
in a permanent corpus is unrecoverable, while instruction-like text is
survivable by labelling, which is what instruction_like on the chunk
and TrustLevel.KNOWLEDGE on the rendered block are for. Chunking is
deterministic under a chunker_version and carries no overlap,
because the chunk id is the citation and heading paths give back the
context overlap was buying. And visibility ∈ {principal, project,
tenant} replaces principal_id as the isolation predicate, which is
the exact inverse of the carry-by-default rule the memory layer took
for beliefs — a document is shared unless it is scoped, a belief
travels unless it is pinned.
Twelve gates in a new fourteenth area, knowledge, all at Milestone 9:
eight cases, three property gates over chunk stability, verbatim
extraction, and citation resolution, and one corpus gate with a floor
on passage recall and a ceiling on noise. They take Milestone 9 from
fourteen registry entries to twenty-six, and the corpus from one
hundred and sixty to one hundred and seventy-two. The named gap is
closed, so the verdict changes with it.
Milestone 10: complete; activation evidence remains separate¶
The project authorized automatic memory formation, the independently
deliverable self-authored-skills tranche, provider-neutral public-web access,
and authenticated browser automation. The six registered gate.skill.*
entries and fifteen automatic-memory, inspection, and provider gates form the
first two delivery contracts. Routing remains a deferred direction on the
plan's roadmap; general-purpose subagents were authorized as Milestone 13 on
2026-08-20. Scheduling moved to the separately authorized Milestone 11 on
2026-08-19.
The readiness review originally found this milestone structurally unlike every other one in the plan. The repository owner explicitly authorized it on 2026-08-17 and selected memory maturation as the first workstream. Thirty-eight registry entries belong to Milestone 10: six for skill authoring, fifteen for automatic memory formation, inspection, and governed provider assistance, seven for public-web access, and ten for authenticated browser automation. Authorization permitted implementation; the passing delivery evidence now makes it complete.
When this review was written, it had no #### Implement heading and no
#### Acceptance criteria heading. It opened with "These are separate optional
extensions" and divided into scheduling, a second model provider with routing,
subagents, and a #### Gate for multi-agent work — which is an entry
condition stating when subagents may be built, not a statement of what
is true once they are. Milestone 9 also lacks an #### Implement
heading but does have acceptance criteria. The 2026-08-17 authorization adds a
memory-maturation implement subsection and five criteria; the other extensions
retain the structure assessed here.
At the time of the original review, all seven scheduling requirements were undesigned. scheduling.md and ADR-0059 supersede that verdict without rewriting the historical finding. Of six routing considerations, data residency and evaluation performance have no design; the other four are at least touched by the model gateway's routing section. Of nine subagent requirements, five had none when this section was written — the explicit objective, restricted context, child deadline, separate trace, and artifact references rather than a full transcript — and two more were partial.
That subagent count is now stale, and it is the only verdict in this
review that later documents overtook. Re-measured against the corpus
as it stands, five of the nine are supplied. parent_run_id is a
Section 15 column at engineering-plan.md:1824, and the sibling join
at runtime-loop.md:1253 reads it. Restricted context is
context-engine.md:511, where runs.seed_event_sequence is nullable
for child runs because they "seed from a parent's concise
instruction rather than from session history", together with the
child-run recall class at memory-retrieval-and-ranking.md:96, which
gets fifteen beliefs against an interactive run's forty. The
restricted tool set is tool-system.md:1053: "the registry resolves
the child's set through specs_for_session with the child's
principal, not the parent's". The child deadline is
runtime-loop.md:1261: "the parent's deadline_at is copied onto
every child at creation". The concise return is the sibling join
plus the EXTERNAL_UNTRUSTED label the returned result carries at
tool-system.md:1049. Two are partial: the explicit objective has a
carrier but no schema, since delegate.run is a control tool at
tool-system.md:990 and no input type for it exists anywhere, and
the child budget is additive by engineering-plan.md:679 while no
rule derives a child's own limits. Two still have none — the
separate trace and the artifact references, stated at
engineering-plan.md:3310 and engineering-plan.md:3311 and picked
up by no specification.
Re-measuring surfaced a conflict the stale count was hiding.
event-log-and-persistence.md:818 declares a unique index on
session_id where status is not one of COMPLETED, FAILED, or
CANCELLED, to enforce Section 27.5's one active run per session. A
parent suspended on a child waits in WAITING_FOR_APPROVAL carrying
a typed suspension kind, which runtime-loop.md:290 chose over an
eighth state, and that is not one of the three — so a child run in
the parent's own session cannot be inserted. Section 27.6 offers both
placements, "the parent's session or a dedicated child session per
policy", and only the second survives the index, with no policy
written to choose between them. It is recorded here rather than
resolved: resolving it is Milestone 10 work, and this review
authorizes none.
The measurement above is preserved as the pre-Milestone-13 baseline
it was. Milestone 13 closed it:
subagents-and-delegation.md supplies
the brief schema the explicit objective lacked, the rule that derives
a child's own limits from the parent's remainder, and the
delegations ledger that carries the separate trace and the artifact
references, and ADR-0063 resolves the recorded session conflict by
always materializing a dedicated child session, leaving the
one-active-run index untouched.
The historical verdict was that this was a direction rather than a milestone.
The authorization and new memory-maturation acceptance criteria changed that
operational verdict. All thirty-eight Milestone 10 gates, the cumulative
registry, hosted CI, and the final review passed on final head 90e9142, so the
milestone is complete. Skill-authoring activation is roadmap item B1 rather
than a completion condition (ADR-0061); routing remains deferred; subagents are
Milestone 13; scheduling is outside this milestone.
The owner separately authorized provider-neutral public-web access on
2026-08-18. web-access.md now covers its port, two tools,
capability-level provider selection, fixed egress targets, credential handling,
trust labels, bounds, failure vocabulary, and acceptance criteria. Seven formal
gate.web.* checks now cover that contract, taking the registry to 190 entries
without changing the Milestone 9 verified gate ceiling.
The owner separately authorized provider-neutral authenticated browser
automation on 2026-08-19. browser-automation.md covers
its threat model, provider port, read/write tool split, profile and login
lifecycle, isolation, origin confinement, standing grants, uncertainty rules,
scheduler handoff, delivery slices, and acceptance criteria. Ten formal
gate.browser.* checks now cover that contract, taking the registry to 204
entries without changing the Milestone 9 verified ceiling. All ten resolve to
executable profile-lifecycle, authentication, grant, provider, policy, trust,
revision, origin, and uncertainty checks.
The later Milestone 11 scheduling design raises the complete registry to 227
and, after final verification, advances the verified gate ceiling through 11.
Open question 4 below closes the remaining half of this, which was whether the missing criteria are an omission or a choice. They are a choice. Each of the four parts carries an entry condition and a must-have list already, and two of those conditions gate on evidence rather than on a date: a scheduler comes "only after durable on-demand runs are reliable", and subagents come "only when evaluation evidence shows that a single agent fails". Acceptance criteria are a promise about a delivery, and a promise cannot be made about work that must not start until evidence arrives. What Milestone 10 is missing is the heading, not the content the heading would hold.
Milestone 11: scheduled runs complete¶
The scheduling entry condition is now true: Milestone 2's durable worker and queue, Milestone 4's policy and approvals, and Milestone 5's authenticated HTTP surface are complete. The owner authorized the work as Milestone 11 on 2026-08-19 rather than changing Milestone 10's established completion contract.
scheduling.md closes every gap the original review named. It defines a versioned schedule and immutable occurrence, the recurrence and civil-time algorithm, the four-table schema, the atomic materialization transaction, a current-principal directory, exact schedule scopes, lifecycle and cancellation semantics, bounded misfires, no-overlap behavior, dedicated sessions, async priority and admission, the eight-route API, default-off deployment requirements, metrics, and twenty-three hard gates. ADR-0059 records why those mechanisms reuse PostgreSQL and the ordinary run path.
The readiness verdict is therefore Complete. There is no unnamed design
choice in the delivered contract. All twenty-three scheduling gates and the
227-gate cumulative registry passed, and hosted CI plus the final review passed
on final head 90e9142. Production scheduling remains default-off until
explicitly activated.
Milestone 12: notifications and device identity complete¶
notifications-and-devices.md closes the half
of Section 29 it was written for. It defines the Device registry with a
client-minted installation identity, per-device muted kinds, and a live-token
uniqueness rule; the durable outbox written in the triggering transaction
through a savepoint-wrapped hook on the single terminal writer and the
scheduling accountant and materializer; the closed five-trigger catalog; the
content-free payload; claim-lease dispatch with staleness checks, a closed
retry schedule, and token invalidation; the APNs adapter behind a
PushTransport port a fake satisfies; the notify role and its credential
confinement; three scopes and seven routes including the offline inbox; the
Apple client's registration and deep-link duties; process-event lifecycle
audit; and twenty hard gates across the device and notify areas. ADR-0062
records why two ports replace the NotificationService name, why the
broadcaster stays, why registration replay has a separate principal-scoped
repository, and why the push key lives in one role.
The readiness verdict is therefore Complete: all twenty notification and
device gates and all 247 cumulative gates pass, with the full PostgreSQL, Apple,
and hosted CI lanes green on the recorded 4f0c7c4 candidate. There is no
unnamed design choice between the corpus and the implementation. Production
APNs activation was completed on 2026-08-23 as an external owner action, after
repository completion: a signed TestFlight build registered a physical iPhone
as a production APNs target and the authenticated test-notification route
delivered the Test notification alert. The activation does not change the
milestone's repository completion contract or its default-off design boundary.
Milestone 13: subagents and delegation, complete¶
subagents-and-delegation.md supplies the four
items this review measured as partial or absent under Milestone 10 and
resolves the conflict it recorded: the structured brief as the objective's
schema; the rule deriving a child's limits from the parent's remainder with
cost reserved at materialization; the delegations ledger as the carrier for
the separate trace and the artifact references; and a dedicated child session
always, so the one-active-run index is neither widened nor contended. The
rest was already decided — the control-tool contract, the CHILD_RUN
suspension in place of an eighth state, the post-terminal join, the untrusted
result label, the brief-seeded child context — and the document cites each
decision rather than restating it. It honours the gate for multi-agent work as
written: construction is authorized, activation requires a capability scenario
admitted from a real failed trajectory and a two-arm case 32, and twenty-one
hard gates in the delegate area cover the rest. ADR-0063 records the
decisions.
The readiness verdict is therefore Complete: there was no unnamed design choice between the corpus and the first red tests, the owner's failed trajectory was admitted as the capability scenario, and the delegating re-run scored above it. Pull request 72 passed hosted CI and a clean final review on 2026-08-27; recorded on 2026-09-28, that advanced the verified ceiling to Milestone 13 and 268 gates.
Milestone 14: inbound surfaces and pairing, complete¶
inbound-surfaces.md gives pairing its home and
endpoint, builds the session-key resolver the seam audit called the one
genuinely new mechanism in Section 29, and attributes the origin on the write.
A Surface is a Milestone 12 device with an empty capability set; a
least-privilege surface role polls Telegram and holds the bot token and
nothing else; an unknown sender is rejected before any content is stored; a
paired sender's message becomes an ordinary run through the submission
function the HTTP API uses, as a USER message for the bound principal with
scopes intersected fresh; notifications travel the Milestone 12 outbox and
replies a separate surface-reply outbox back to the chat. The document states the trust rule the
audit left open and bounds it to the owner's own pairing, leaving a
third-party label to the roadmap. Twenty-one hard gates in the surface
area; ADR-0064 records the decisions.
The readiness verdict is therefore Complete: there was no unnamed design choice between the corpus and the first red tests. The one gap the corpus left, a per-run surface budget for admission, became the owner's ADR-0064 amendment on 2026-09-28. The owner's production smoke passed on 2026-10-06, and pull request 153 passed hosted CI and a clean final review on 2026-10-07; recorded on 2026-10-09, that advanced the verified ceiling to Milestone 14 and 289 gates.
Milestone 15: operational hardening, authorized and specified¶
operational-hardening.md turns the deployment
page's accepted "unrecoverable" into recoverable within a backup window: a
declared, encrypted, off-host daily backup of the database, the artifact
store, and the browser-profile ciphertext with a manifest and a manual secret
escrow; a restore rehearsal with a five-part verdict run on the host, in CI,
and by the owner from the off-host copy; a host health check on a closed
signal list delivering deduplicated alerts through the Milestone 12 outbox
with a dead-man's switch and an external uptime check for the states that take
the outbox down; cloud and host firewall, SSH hardening, proxy rate limits, and
a loopback-only structural gate; a code-only rollback that refuses to cross a
schema boundary without an override and never downgrades; and systemd
watchdogs for the worker roles. Sixteen hard gates in the ops area; ADR-0065
records the decisions and amends ADR-0046.
The readiness verdict is therefore Authorized: there is no unnamed design
choice between the corpus and the first red tests. What remains outside the
corpus is the owner's bucket and scoped key, the age identity, the first
escrow, and the first off-host rehearsal.
Milestone 16: memory evaluation and lifecycle complete¶
memory-evaluation-and-lifecycle.md gives
memory the one thing its twenty-nine safety gates never provided, which is a
number. A checked-in multi-session corpus of labeled beliefs and probes across
eight categories drives real formation and real retrieval through the
composition root on the in-memory tier under a fixed clock, a scripted model,
and sequential identifiers, so two runs of a commit agree byte for byte; the
metrics are integers, the checked-in baseline is compared exactly rather than
within a tolerance, and a behavior change therefore cannot land without
re-recording the baseline in the same change where its delta is reviewable. An
opt-in live arm pairs a with-memory and a without-memory run over the same
probes, scores them with checked-in labels, token-bounded matching, and one
exact abstention phrase rather than with a model judge, derives every threshold
from counts inside its own artifact, stops before crossing a pre-admission
ceiling of USD 4.00, and publishes evidence that re-validates itself and is
never overwritten. Three public long-horizon datasets are read from a local
path under their own licenses and never vendored, contributing an
evidence-provenance recall metric that distinguishes recalling the right fact
from recalling it for the right reason. The document then implements the
lifecycle the two Milestone 9 memory specifications describe and the code never
grew: the profile document as validated configuration, operator-tier trace
expiry, lexical parity between the two store adapters, episode paging, project
scope on the consolidation and query-former paths, time-decayed reinforcement
with a bounded forgetting sweep, usage feedback that Milestone 21 supersedes
to change utility and last_used_at without resetting evidence decay or
raising confidence, the recall delta and its correction lines, established
working-state facts entering formation at affirmed authority, conflicts
committed flagged and surfaced instead of silently resolved, and re-derivation
as an explicit operator action. Nineteen hard gates in the memory area;
ADR-0069 records the decisions.
The readiness verdict is therefore Complete: the milestone finished on 2026-08-23 with all twenty gates passing and hosted review clean, and no unnamed design choice stood between the corpus and the first red tests. The owner's own copies of the three public datasets and provider credentials for opt-in future live-arm reruns remain external activation inputs, not repository design gaps.
Milestone 17: the memory read API and browser, complete¶
memory-read-api-and-browser.md closes the
last gap in the memory story that the corpus had named and never filled: the
belief store is inspectable only from a terminal on the host, and the person
the beliefs are about does not have one. The document specifies two GET routes
under /v1/memories — a keyset-paginated list and a detail read — one exact
scope, memory.read, and one default-off flag, AGENT_MEMORY_API_ENABLED,
following the schedule and notification routers exactly. Every request carries
its sensitivity ceiling explicitly and the server filters strictly below it;
omitting the ceiling is a validation error rather than a permissive default,
which is ADR-0045 decision 11's rule restated for a route. A belief above the
ceiling, a belief in another principal's store, and a belief that does not
exist are one indistinguishable not-found, which extends the cross-tenant-404
rule to sensitivity so that transparency does not become a disclosure path.
The list filters by status, belief type, subject, source session, and text,
with the text arm calling the same two lexical helpers both store adapters
already share, so parity holds by construction and is asserted by a browse
contract suite that runs against the in-memory and PostgreSQL tiers alike. The
MemoryView projection is an explicit exposure list rather than an exclusion
list, withholding tenant identity, the retriever's internal utility, and the
cursor's store position outright. Three operator-tier provenance fields —
formation_run_id, consolidation_policy_version, and origin_scopes — were
withheld as a recommendation pending the owner's sign-off; the owner decided
on 2026-08-23 to expose them instead
(docs/status/questions-for-review.md, Milestone 17 section), so the
projection now carries twenty-six fields rather than twenty-three. The
native Apple client browses at full parity by declaring the restricted
ceiling, an owner decision taken over the conservative lower ceiling on the
grounds that a silently filtered list teaches its reader the platform forgot
something it did not. Ten hard gates in the memory area, which now spans four
declaring specifications; ADR-0070 records the decisions and supersedes
ADR-0045's route-set closure for inspection only.
Two exclusions are preconditions rather than preferences and the document says
so. Recall-trace viewing waits on a defect: PostgresTraceStore.for_turn
selects by turn identifier with no tenant or principal predicate, and no route
can reach traces until that is fixed and observed by the trace store's contract
suite. Consolidation and formation audit routes remain a candidate for a later
round on their own, separate exposure question — model selection, watermarks,
and attempt audits. Writes over HTTP are excluded outright and stay on the
governed agent memory command line.
The readiness verdict is therefore Complete: there is no unnamed design choice left outside the corpus, all ten gates and the Python, PostgreSQL, and native Apple lanes passed, and the hosted CI and final review conditions were satisfied by dev-to-main pull request 58 on 2026-08-24. Pull request 64 then added end-to-end PostgreSQL pagination and native navigation coverage with the same hosted lanes green. The provenance trio's exposure question is resolved rather than outstanding.
Milestone 18: first-class email integration, authorized and specified¶
email-integration.md takes the email half of roadmap
item B11 on that item's own entry condition — owner intent, expressed
2026-08-24, with email arriving as MCP servers — and ADR-0071 records the
authorization. The mechanism is three first-party stdio servers in one
package beside agent_core, split by side effect because the tool system
classifies at the server level: a read server at
NETWORK_READ/LOW/READ_ONLY, a write server at
EXTERNAL_WRITE/MEDIUM/NON_IDEMPOTENT, and a send server at
EXTERNAL_MESSAGE/HIGH/NON_IDEMPOTENT. The default matrix already sends
every write and send to approval, so the milestone adds no policy rule; what
it must add is one arm on the deterministic host_on_allowlist condition,
which today recognizes only the web and browser fixed provider targets and
therefore denies every read-only MCP call, the adapter's own read_resource
included. The design names that repair, ADR-0071 decision 5 owns it, and gate
5 observes it.
Credentials follow the seam stdio servers already have: one env-scheme
broker reference per server resolving to a JSON document the server alone
understands, because Gmail's refresh-token grant is not the oauth2_client
client-credentials exchange and is not forced into it. A one-time bootstrap
ceremony obtains the three consents and writes owner-only files that enter
through file-backed settings references, the browser-profile shape. Two owner
decisions of 2026-08-24 bound the surface: no server exposes permanent
deletion — trash, reversible for thirty days, is the write server's strongest
verb — and the Google OAuth client runs in production publishing status so
refresh tokens outlive the testing-status seven-day clock. Monitoring is a
documented recipe over Milestone 11 schedules and Milestone 12 notifications
rather than new runtime. Seventeen hard gates live in the email area after
ADR-0085 adds four for operator-managed multi-account composition;
calendar, Gmail push, interval recurrence, the email Surface, and the email
notification transport stay on the roadmap where B11, B5, B3, and B4 hold
them.
ADR-0085 extends the authorized scope to one or more operator-managed Gmail accounts for the configured principal. The existing credential triplet remains the backward-compatible single-account configuration; a bounded versioned manifest composes three separately credentialed servers per account, retains the legacy ids for the default account, and makes every other account explicit in the tool name. Public self-service OAuth and per-principal token storage remain undesigned and out of scope.
Two things the specification states rather than glosses. A stdio server is a
child of the worker and inherits its network position, so no platform
mechanism confines gmail_mcp to Google: the confinement is the package's own
endpoint constants, refused redirects, and gates, and host-level egress
enforcement is named as a deployment precondition the milestone does not
require. And because the two write servers are NON_IDEMPOTENT and Gmail can
commit before answering, a failure after dispatch resolves UNCERTAIN rather
than a retryable failure, generalizing the rule the adapter already applies to
a post-watermark 401.
The readiness verdict is Authorized: the specification, the ADR, the registry entries, and the census row land together, and the three shared-file overlaps this milestone carries — the policy condition, the configuration surface, and the MCP adapter's non-idempotent failure mapping — are named in the ADR rather than discovered in review.
Milestone 19: conversational schedule creation, complete¶
scheduling.md closes the
specific gap between two already delivered capabilities: Milestone 11 exposed
schedule creation only through HTTP, while Milestone 12 delivered push for
terminal run outcomes. The new schedule.create tool gives the model one
governed way to reach the existing application service. It accepts a title,
instruction, and exact aware instant, creates only once cadence, and is
registered only when both existing scheduling flags are on.
The tool is EXTERNAL_WRITE, high risk, conditionally idempotent, requires
exactly schedule.write, and always waits for approval under the existing
policy matrix. It delegates no scopes to the future run, applies finite
per-occurrence limits, routes through ScheduleService.create, and preserves
the existing idempotency key. Past or naive instants fail validation, and a
retry returns the original schedule rather than creating a duplicate. The
notification path is unchanged: the scheduled run reaches an ordinary
terminal event, and the Milestone 12 outbox wakes the client with its existing
content-free payload.
The readiness verdict is Complete: ADR-0072, the five new
gate.schedule.* entries, and the Milestone 19 census row specified the whole
surface, and pull requests 64 and 66 delivered it with hosted CI and a clean
review. Recurring creation and every other schedule lifecycle operation
remain HTTP-only rather than becoming implicit parts of the model tool.
Milestone 20: calendar recurrence and conversational schedules, complete¶
The owner authorized the calendar-recurrence part of roadmap item B5 on 2026-08-27 after identifying daily, weekly, monthly, and yearly schedules as core personal-agent behavior. scheduling.md and ADR-0073 widen the closed cadence union with monthly numbered-day and explicit last-day rules plus yearly month/day rules. Missing numbered dates are skipped, February 29 fires only in leap years, and impossible yearly pairs are rejected. Both new kinds retain the existing IANA-zone fold, gap, no-early, no-overlap, bounded- misfire, revision, occurrence, authority, and materialization contracts.
The same design widens schedule.create compatibly: the existing future at
instant remains valid, while a caller may instead supply exactly one daily,
weekly, monthly, or yearly cadence object. The ordinary approval, exact
schedule.write scope, conditionally idempotent non-parallel classification,
empty delegated scopes, finite limits, direct ScheduleService.create call,
and content-free outcome notification remain unchanged. The HTTP create and
update routes accept the same widened domain union without a new route, table,
migration, scheduler, or queue.
The readiness verdict is Complete: ADR-0073, six new
gate.schedule.* entries, and the Milestone 20 census row specified the complete
surface, and pull request 74 delivered it with hosted CI and a clean review. Arbitrary cron or RFC 5545 input, interval multipliers,
continuous-session recurrence, dependency graphs, and delegated scopes remain
explicit deferrals rather than unnamed choices. Lifecycle tools entered
Milestone 23 on 2026-09-02.
Milestone 21: adaptive memory distillation, authorized and specified¶
The owner authorized this parallel workstream on 2026-08-31 with an explicit product correction: memory formation is dramatically too timid, and a marked increase in useful recall is worth accepting a few provisional false positives when unsupported claims fade without later evidence. The current corpus and provider policy cannot represent the motivating direct observation, "User is building a personal AI agent," or the useful tentative hypothesis that the user likely has software-development experience.
adaptive-memory-distillation.md closes the
mechanism gap. It persists grounded integrated episodes, fixes the provider path
at three batched calls, blinds anticipation from the evidence it predicts,
distills direct observations and explicitly tentative hypotheses, raises the
bounded candidate capacity, and separates evidence time from citation time.
The completed formation@7 and formation@8 policies remain frozen controls;
formation@9, retrieval@3, and lifecycle@2 are new versioned behavior, and
the repaired provider-assisted formation@10 of ADR-0086, with the compiled
policy binding of every bundled artifact, is designed in the same document.
The trust boundary is narrow rather than a general suppression rule. Invalid or foreign provenance, assistant-as-user attribution, credentials, PII beyond explicit policy, promoted untrusted instructions, isolation failures, and durable corrections still form nothing. ADR-0090 adds a typed communication exception after a production Gmail run formed zero memories: repository-owned, principal-scoped Gmail and SMS events may form only channel-attributed, tentative, local, sensitive hypotheses, while paired-surface owner messages use the existing owner-assertion lane and arbitrary external content remains barred. Ambiguity, inference, ongoing state, and sensitivity permitted by policy instead affect derivation, confidence, longevity, expiry, and viewing ceilings. This is the specific distinction the prior designs did not make strongly enough.
The readiness verdict is Authorized: ADR-0077 and ADR-0090, thirty-one new
gate.memory.* entries, the Milestone 21 census row, a nine-step build
sequence, explicit migration and erasure rules, and a comparative corpus
contract specify the whole workstream before production-code changes begin.
Reinforcement learning, fine-tuning, semantic retrieval, pgvector, external
memory providers, general temporal graphs and a public write API remain outside
this milestone; persona editing entered as Milestone 22 (ADR-0079), and
Milestone 32 now authorizes whole-store consolidation and grounded connections
with a detailed design and registered gates (ADR-0169).
Milestone 22: the persona surface, complete¶
On 2026-09-01 the owner authorized Milestone 22, the persona surface and curated belief promotion, as a seventh parallel workstream. The feature is ADR-0014 decision 5's deferred persona/identity surface — the one memory partial this review had left standing, because no document said how a formed belief reaches the instruction text, or whether it may.
persona-surface.md answers it: a persisted, versioned,
principal-scoped document of entries renders as a new Region A prefix row at
trusted-configuration trust, directly after the agent instructions, capped
and pinned per context plan, with an empty persona rendering no bytes at
all; and the only path across the trust boundary is human — an owner edit,
or the owner's explicit affirmation of a nomination the governed
consolidation service raised from its strongest direct, durable,
corroborated beliefs. Declines are durable, promotion links rather than
consumes, and a promoted belief leaves the session-open snapshot while its
entry stands. The write surfaces are the agent persona CLI, six
/v1/persona routes behind a default-off flag with an exact scope pair, and
a native editor; the memory read API gains no verb, and secret refusal and
injection scanning guard the row's content on the way in and the way out.
The readiness verdict is Complete: ADR-0079, fourteen new
gate.persona.* entries in an area of their own, the Milestone 22 census
row, a five-step build sequence, and the entry-condition adjustment recorded
in the ADR specified the workstream, and pull request 82 delivered it.
Automatic promotion at any threshold, belief writes over HTTP, and per-agent
persona variants remain excluded.
Milestone 23: conversational schedule lifecycle, complete¶
On 2026-09-02 the owner authorized conversational pause, resume, and delete after a failed briefing auto-paused and the agent honestly reported that it had no scheduling tool with which to resume it. scheduling.md and ADR-0080 add the missing model boundary without changing recurrence, persistence, materialization, or the HTTP control plane.
On 2026-09-04 the owner expanded this workstream to conversational
modification. ADR-0088 adds schedule.update: a closed title, instruction,
and cadence patch whose stable identity, expected revision, exact
schedule.write authority, approval, immutable revision, and idempotent
recovery are fixed before implementation. The application service, rather
than the model, carries forward every hidden execution-authority and limit
field.
The model first uses bounded, summary-only schedule.list discovery to obtain
the stable ID and current revision for one principal-owned schedule. It then
uses approval-gated schedule.pause, schedule.resume, or schedule.cancel
with only that ID and expected_revision. Titles are never mutation keys;
ambiguity asks the owner. Existing exact scopes, optimistic concurrency,
no-backfill resume, state-idempotent lifecycle methods, and schedule/run
cancellation separation remain authoritative. Conversational “delete” means
terminal cancellation and preserves the retained audit history.
The readiness verdict is Complete: ADR-0080, ADR-0088, twelve total
gate.schedule.* entries (five added by schedule update), the Milestone 23
census row, a three-step build extension, closed schemas, and explicit failure
and retry behavior specified the workstream, and pull requests 89 and 98
delivered it.
Occurrence and run history
tools, hard deletion, delegated scopes, new cadence kinds, native lifecycle
controls, and model control of execution authority or limits remain excluded.
Milestone 24: SMS through the owner's iPhone, authorized and specified¶
device-channel-and-sms.md designs the first
concrete slice of Section 29's device channel with the use case roadmap
item B7 was waiting for. The seams it lands on were already cut:
ToolSource.DEVICE, the reserved device. name domain, forced untrusted
device output, the device field on the policy input, and the
tool.device_offline outcome. The design adds the DeviceChannel port
with a push-wake adapter, capability-derived registration as the third
tool source, the owner-tap send boundary for device.sms.send, and the
device-authenticated ingest route feeding a standing triage session
through existing run machinery.
Two widenings ride with it explicitly rather than silently — Milestone 12's trigger catalog grows a sixth content-free entry, and tool-system's registration closes at three sources instead of two — and the platform constraint that iOS cannot send or read SMS programmatically is carried as design substance: the compose-sheet tap is the approval, and ingest is best-effort Shortcuts glue the document says so about.
The readiness verdict is Authorized: ADR-0081, the twelve new
gate.device.* entries, and the Milestone 24 census row specify the
whole surface. Presence-based routing, hand-off, automatic replies, and
any silent send path remain outside it.
Milestone 25: WhatsApp business surface, authorized and specified¶
whatsapp-surface.md extends the Milestone 14
surface seam with the channel that forces the corpus's first inbound
third-party HTTPS: the Meta Cloud API delivers by webhook only, so the
design pays the price ADR-0071 named — a signed, loopback-bound listener
in the surface role behind one proxy location — deliberately and once.
The adapter itself is the additive extension inbound-surfaces.md
anticipated: a second push provider, the same pairing, the same scope
ceiling, the same reply pipeline, with idempotency generalized from the
Telegram integer offset to a string external_update_id by the
amendment ADR-0082 records.
The design also owns the platform's twenty-four-hour window rather than discovering it in production: freeform replies inside, one approved content-free utility template outside, refusal with a closed reason code otherwise. What cannot proceed before Milestone 14 exists is stated plainly, and what proceeds now — the documents, the gates, the Meta ceremony with its review lead time — is the part with calendar risk.
The readiness verdict is Authorized: ADR-0082, the twelve new
gate.whatsapp.* entries, and the Milestone 25 census row specify the
whole surface. Personal-account access stays on the roadmap as B13
behind a risk-acceptance ADR, and nothing here amends Milestone 14's
acceptance criteria.
The three plan sections no specification expanded¶
Sections 29 through 31 were the only major sections of the
engineering plan with no outward cross-reference paragraph. A scan of
engineering-plan.md:4751-4908 for links to other documents returned
nothing when this review was written, where every other major section
acquired one during the specification work. Two of the three were
genuinely unexpanded; the third was half-expanded from the consuming
side. All three carry the paragraph now, and what follows is the
finding in each case and what closed it.
Section 28 was the fourth, and it is expanded now, by sandbox-isolation.md, which gives it the outward paragraph the scan looked for. It was the highest-consequence gap in the corpus while it lasted — the only unexpanded section whose failure mode was an escape from the trust boundary rather than a feature that does not work — and it is covered above under Milestone 6.
29. Multi-device operation and the shared core¶
Eighty-seven lines, ADR-0011, four inbound consuming references, and
no expansion. The section's core claim is defensible without one —
because PostgreSQL is the source of truth and devices are API clients,
sharing is a consequence of the existing architecture rather than a
new mechanism. What it introduces beyond that is the Device concept
and four named ports for capabilities that are inherently local to one
machine, and none of the four has a contract.
tool-system.md:1621 does open a "Device-scoped tools" section, and
tool-system.md:2165 states that device tools are "a reserved seam,
not a design". That is an explicit deferral rather than an oversight,
and it is the right call for a Milestone 10-adjacent concern. What it
left behind was a model with no home.
multi-device-and-surfaces.md and
ADR-0034 close it, and they close it as an audit rather than a design,
because Section 29.8 defers its own subject and a specification that
wrote the four contracts would be building the deferred thing. What
an audit produces instead is the answer to the question a deferral
leaves hanging: whether the Device lands additively when it lands.
Eight places in the corpus already hold a device-shaped hole and need
no edit — the DEVICE tool source, forced untrusted output at
registration and its enforcement in the composition root, the
reserved device. domain, ExecutionTarget.kind with device_id
beside it, the single authorization gate that already names the
device channel, tool.device_offline as a row of the availability
table rather than an exception to it, and idempotent approval
resolution that cites Section 29 by name. Five do not, and naming
them is the point of the exercise: attach is a third registration
source and not at session open; device lifecycle events have no
session to be charged to against a NOT NULL column; a capability
hand-off is a fourth suspension kind against a closed two-value
vocabulary; no client is attributed on a write, which matters for
inbound content rather than for tool output; and
NotificationService is a port name appearing twice in the corpus
with no mechanism, transport, or durability behind it, which
LISTEN/NOTIFY does not supply and was never meant to.
The strongest result is the one that costs nothing. Section 29.4's
per-device scopes read like a second evaluation path and are not one.
The scope set is captured at submission and stamped on the run, and
PrincipalResolver.for_run reads that stamp and never a table, so
narrowing is an intersection computed once at submission and the
policy engine is never told that a device exists. The constraint
travelling with it is that a device. scope prefix would mean
rewriting the fifteen-string grammar and the gate that asserts it,
and the device. that already exists is a tool-name domain rather
than a scope prefix. Three conflicts between Section 29 and later
specifications are named and resolved in the specifications' favour,
one of them the question tool-system.md:1635 reserved by name —
whether a device tool may be advertised in a session opened while the
device was absent — which resolves against the pinned prefix on the
same precedent that governs an MCP catalog change mid-session. None
of it is 0.1 work, and 29.8's own scope paragraph is already
satisfied: reads and writes are principal-scoped and served from the
core, and a second client attaching and replaying is
gate.api.replay_exact at Milestone 5.
30. Self-improving skills¶
Forty-three lines, ADR-0013, eleven inbound consuming references, and no expansion. The reference count is what made this notable. Ten other documents treated the skill mechanism as settled and built on top of it, and the mechanism did not exist below the plan. Combined with the Milestone 8 finding, this was the largest undesigned area in the corpus and the one with the most load already resting on it.
skills.md and ADR-0030 close it. Section 30's six
subsections keep their content: 30.1's milestone placement, 30.2's
two authoring paths, 30.3's six governance guarantees — versioning,
provenance, gating, restricted review, injection resistance, and
sandboxed scripts — 30.4's metadata-only loading rule, 30.5's rollout
criterion, and 30.6's constraints are each carried forward rather
than reinterpreted. Two citation errors are corrected in the process.
One is this review's: the version-pinning criterion is at
engineering-plan.md:2909, and the line this review first named was
an MCP configuration bullet a few lines above it. A line-number
citation into the plan is correct only until the plan is next edited,
which is why every citation in this corpus is now recorded in
docs/status/citation-ledger.yaml and checked by
scripts/check_citations.py rather than remembered. One the corpus
carried: policy-and-approvals.md attributes the policy-and-approval
gating requirement to Section 30.4, which Section 30.3 states.
What remains open is a threshold for 30.5's eval delta, which is a
number nobody has yet had the data to choose.
31. Trajectory capture and export¶
Twenty-two lines, ADR-0016, and the only one of the three with real
design outside the plan — on one side.
evaluation-harness.md fully specifies the
consumption path: the conversion from a captured run to a case, the
source: trajectory marking that keeps promoted cases distinguishable
from authored ones, the agent eval promote command, and a hard gate.
The production path had nothing. The export format the section names as an example — ShareGPT or messages — was not chosen. The redaction rules that make the acceptance criterion "no secrets, raw reasoning, or restricted PII" checkable did not exist, and neither did the consent gate that criterion also requires. Redaction of raw reasoning in particular interacts with ADR-0006 and ADR-0007, which forbid persisting it in the first place, so the two documents needed to be read together by whoever wrote this.
event-log-and-persistence.md and
ADR-0032 close it, in the document that already owns the log the
export reads and the gate.event.* area, rather than in a fourteenth
specification. The format is one versioned JSON document in the
messages shape, with ShareGPT left to a consumer as the rename of a
role vocabulary that it is. The export is written into the artifact
store under a new TRAJECTORY_EXPORT origin, which supplies content
addressing, an authorized read path, and the expires_at sweeper a
governed export needs and a new table would have had to grow.
Redaction is structural exclusion, then pattern replacement reusing
the committed-secret scanner's five rule families and the log
processor's key-name families, then a verification scan that raises
and writes nothing rather than redacting a second time. The
ADR-0006 interaction resolves in the simplest available direction:
reasoning is never persisted, so the builder has nothing to redact
and the exclusion is structural. Consent becomes a record — granted
per principal, evaluated at run start and stamped on the run,
withdrawn backward across every run and every artifact already
produced, with the deletion routed through expires_at and the
sweeper so the rarest governance operation runs on the most exercised
code. agent run export is a subcommand rather than a thirteenth
top-level command, on the precedent
evaluation-harness.md set with agent eval.
That leaves none. Every part of Sections 29 through 31 is expanded by a specification now. The last of the three is expanded as an audit rather than a design, which is the only shape available for a section whose own scope paragraph defers it, and the audit is what turns "defer this" into a list of what deferring it will cost.
What the evaluation suite does not reach¶
The twenty-five initial cases carried milestones 1, 2, 4, 5, and 6, and so did the twenty-sixth, added later by sandbox-isolation.md. The twenty-seventh, added by skills.md, was the first Milestone 8 row. Milestones 3, 7, 9, and 10 had no case rows at all, which was this section's finding.
For Milestone 3 that is defensible and stays: provider adapters are covered by contract suites and live smoke tests rather than by end-to-end cases, and the harness says so. Milestone 10 keeps its empty row deliberately, since the authoring loop is an optional extension. Milestones 7 and 9 were real gaps and lined up exactly with the gaps found by reading the specs: Milestone 7 had a long-session gate with no case behind it, and Milestone 9's memory criteria are stated in terms of evaluation improvement — "Memory improves defined evaluation cases without increasing policy failures" — against a case set that contained no memory case. Milestone 8's gap was half of one, its MCP side having a bullet and no row.
All three are closed. Cases 28 through 31 were added to
evaluation-harness.md on the pass that
followed the milestone map's census, which is what made the three
holes countable rather than merely noticed. Case 28 is the fifty-turn
prefix-stability run at Milestone 7. Cases 29 and 30 are the MCP round
trip and the mid-call disconnect at Milestone 8, both against a
scripted server fixture. Case 31 is the memory delta at Milestone 9,
and it needed a mechanism the harness did not have: a case that
declares two arms and asserts a relation between them rather than a
number, because "without increasing policy failures" is a comparison
and no single run can express it. That mechanism — arms, carry,
and delta — is also what case 27 had been describing in prose
without a schema to write it in.
Two additional holes were worth naming because a criterion existed
and nothing could check it: the container-escape red-team test
Section 28 demands, and the path-traversal algorithm case 19
exercises but no document specified. Both are closed by
sandbox-isolation.md — the first by case 26
and gate.sandbox.escape_denied, the second by the five-rule
containment function WorkspaceHandle.resolve and the property gate
gate.sandbox.workspace_containment over generated paths.
The harness was not at fault. It specifies how cases are written, what the assertion types are, and how a case declares its milestone. What was missing was cases, which are cheap to add once the mechanisms they exercise are designed and impossible to write before — which is exactly why they arrived last, and why two of the four needed a schema change rather than only a table row.
Conflicts this document resolves¶
This document resolves none. It reports four and defers each to the document that owns the subject. Three have since been resolved by the documents they were deferred to, and each resolution is recorded under the conflict it settles.
sandbox.run_commandat Milestone 5 or Milestone 6. The spec against the plan's Milestone 6 implement list. The map follows the plan. Resolution belongs to the sandbox specification, because whether the tool can ship against the development mechanism before container backing exists is a sandbox question. Resolved there in the plan's favour: the development mechanism refuses to start in production, so a tool that only works against it is not a milestone deliverable, and the spec's Milestone 5 was an off-by-one against a list in which 5 is the HTTP API.builtin-tools.md:1520now says Milestone 6.- Usage token classes and cost-source precedence at Milestone 2 or
Milestone 3.
engineering-plan.md:2663againstmodel-gateway.md:2005andmilestone-map.md:1918. The map follows the gateway. Nothing is built differently either way; only the migration's timing changes. Idempotency-Keyand the idempotency port. Named as an HTTP header at Milestone 5 and as a tool-call port at Milestone 1. Whether these are one mechanism or two is undecided, and belongs to the API specification. Resolved there as two: two scopes, two milestones, a table and a column, one unfortunate name.- The container-escape test and the case table.
engineering-plan.md:4747requires a test the harness's case set does not contain. Belongs to the sandbox specification and the harness together. Resolved by both: the case set gains a twenty-sixth row, a Milestone 6 security case backed bygate.sandbox.escape_denied, and none of the twenty-five is renumbered. The same shape repeated four more times afterwards, for cases 28 through 31, and the rule held each time: the case set grows at the end and Section 20's own numbering never moves.
Decisions¶
- Coverage is judged against the whole corpus, not against the
specifications alone. A mechanism designed in the engineering
plan and nowhere else is covered, and is reported as
plan-only so the distinction stays visible. The alternative —
scoring Section 16 as absent because no file under
docs/plan/other than the plan expands it — would have produced a Milestone 5 verdict that is false in the way that matters, since an implementer reading Section 16 can build most of that milestone. - An explicit deferral scores as partial, not absent.
builtin-tools.md's six-tool section andtool-system.md's device-tool seam both name what they do not design. A hole somebody has measured is a different object from one nobody has looked at, and collapsing the two would make this document less useful precisely where the corpus is most self-aware. - The gate census is treated as independent evidence. It was derived mechanically before this review began and was not consulted while tracing implement bullets. Where it agrees with a verdict, that agreement is reported as corroboration; where it would disagree, the disagreement would be reported. It does not disagree anywhere.
- This document reports conflicts and resolves none. The milestone map owns scheduling and the specifications own their requirements. A readiness review that also decided things would become a document other documents have to be reconciled against, which is the problem the map was written to solve.
Open questions for review¶
- Is the API specification the next document, or does the API get built from Section 16? Answered by writing it. The recommendation was that it should be the next document, on the evidence that every other section expanded exactly once and every expansion found a conflict. The counter-argument was real: Section 16 is more detailed than the sections that turned out to hide contradictions, HTTP has stronger conventions than composition roots do, and the six unsettled items listed above are individually small. The expansion found nine contradictions, which settles it on evidence rather than on the prediction.
- Does the sandbox specification precede Milestone 5, or follow
it? Milestone order says it follows. Two arguments say it should
come first:
tool-system.md:1086already depends on an egress allowlist it establishes, and it is the only undesigned area whose failure mode is a security boundary rather than a missing feature. Writing it early costs nothing except the order in which two documents get written. Answered by writing it early. The expansion found the egress allowlist had no grammar and no owner, that eight types the corpus referenced were never declared, and thatbuiltin-tools.mdhad the tool at the wrong milestone — none of which would have surfaced by building Milestone 5 first. - Should Milestone 6 acquire gates before it is built? The map
reported the zero rather than inventing entries, which was right.
But a sandbox with no registered invariant is a different kind of
zero from a Milestone 8 with no registered invariant, and the
sandbox specification is the natural place to fix it. It did:
thirteen gates in a new
sandboxarea, eleven of them at Milestone 6. Milestones 8 and 10 kept theirs until skills.md, which closed both the same way and for the same reason: there is something designed there now to assert about. - Does Milestone 10 need acceptance criteria, or is it correctly an open direction? The original review answered “open direction” because it was the only milestone with neither an implement list nor acceptance criteria. The owner authorization on 2026-08-17 supersedes that operational answer for memory maturation and adds five criteria without converting the evidence gates for the other extensions into calendar promises. The re-measure that produced the answer also corrected this review: five of the nine subagent requirements are designed now, by documents that landed after the verdict above was written.
- Is knowledge retrieval a Milestone 9 deliverable or its own milestone? Answered by designing it: a Milestone 9 deliverable, sequenced after the memory half. Splitting it out would have made Milestone 9 shippable against what was actually designed, and that was the argument for it. The argument against won on a dependency: knowledge retrieval reuses the fusion, the ranking shape, the budget mechanics, and the trace record that memory-retrieval-and-ranking.md establishes, so a separate milestone would have been a milestone that cannot start until the previous one finishes — which is what a build step inside a milestone already is. Twelve gates now sit where the split would have been.
Milestone 26: client modes and adaptive email experience¶
The owner approved the complete proposal, USD 20/day and USD 200/rolling thirty-day aggregate automatic-email budgets, and implementation as a new parallel milestone on 2026-09-11 under ADR-0092. The canonical email-experience.md declares thirty-two blocking gates. Its readiness verdict is Authorized and specified; implementation in progress. No pending implementation or private quality evidence is marked complete, and the milestone does not move the verified sequential ceiling. It reuses the Gmail MCP boundary, shared agent/persona/memory, ordinary durable worker and approval lifecycle while explicitly extending the email application surface and evaluated semantic source policy. Live owner judgments, account smoke and production delivery remain external verification requirements rather than design omissions.
Milestone 27: Bland calling and public reception¶
The owner approved bland-calling.md on 2026-09-11 under ADR-0097. Fourteen gates are registered. This independent workstream remains in progress; calling is active in production, and the provider dashboard checks, the remaining live checks, and the two pending gate bindings are still required.
Milestone 28: People and relationship memory¶
The owner authorized the complete People implementation plan on 2026-09-15 under ADR-0100. people-and-relationships.md specifies 36 registered gates for identity, temporal relationships, cross-session history, governed formation/retrieval, source-aware correction and erasure, and a shared native People surface. This admits only the People-specific B6 residue. Gate bindings remain pending until executable implementation evidence lands; no quality or production requirement is marked complete by admission.
ADR-0101 makes all implemented People features available by default. Pending quality measurements do not gate runtime functionality or release.
Milestone 29: Chat thread folders, complete¶
The owner authorized thread-folders.md on 2026-09-16
under ADR-0102. Twelve gates are registered in a new gate.folder.* area for
the additive schema, folder invariants, move semantics, closed proposal
eligibility, the bounded open set, durable decline, withdrawal, grounded
grouping with a deterministic fallback, atomic acceptance, exact scopes under
the flag, content-free prompts and logs, and native degradation. The design
touches no roadmap item: it adds no embedding, no retrieval arm and no memory
read. Every gate is bound to an executable check as of 2026-09-16, and pull
request 118 delivered the milestone with hosted CI and a clean review.
ADR-0110 amended the milestone on 2026-09-19. typed-judgment.md
designs the typed-judgment port, its value types, the TypeSafe Jev adapter's
fixed egress, call-time credential, bounds, retries and sanitization, the
default-off selector, and the data classes the vendor may receive, and
registers four gates in a new gate.judgment.* area.
thread-folders.md designs the judgment matcher and
registers a thirteenth folder gate. The amendment touches no roadmap item: it
registers no model profile, so B2's model routing stays deferred, it adds no
embedding, so B6 is unamended, and the policy advisory layer stays in B8 until
its own policy ADR. The four gate.judgment.* gates and
gate.folder.judgment_matching are bound to executable checks as of
2026-09-20, and pull request 127 delivered them with hosted CI and a clean
review on 2026-09-21. The readiness verdict is therefore Complete.
Milestone 30: Advisory approval layer¶
The owner authorized the advisory layer on 2026-09-19 under ADR-0111, which is
the policy ADR roadmap item B8 names as its entry condition; B8's other half,
general standing approval grants, stays deferred.
policy-and-approvals.md already designed the
layer's requirement and now designs its first implementation: the
PolicyAdvisor port, the composite engine, the consulted class, the three
questions and the any-signal mapping, the restated input hardening, the
redacted state, the pipeline's deterministic recovery policy, the
advisory.mode knob, the escalation's wire shape, and the two metrics. Five
gates are registered in the existing gate.policy.* area at Milestone 30. The
design depends on the typed-judgment port of
typed-judgment.md and diverges on the record from the
plan's sequencing table, which named the model gateway. One correction is
recorded rather than absorbed: the specification's claim that the layer
composes without changing any caller does not hold for an advisor whose
answer can differ between calls. Every gate is bound to an executable check
as of 2026-09-20. ADR-0111's amendment of the same day moves observing to an
environment flag, because any profile change moves the policy version the
memory-formation release evidence is bound to. The milestone does not move
the verified ceiling.
Milestone 31: Email unsubscribe assistance¶
The owner requested email-unsubscribe.md and decided
its surfaces, consent model, egress and fallbacks on 2026-09-19 under
ADR-0112. Twenty gates are registered as gate.email.unsubscribe_* in the
existing email area for the closed read contract, authenticated eligibility,
the server-derived destination, the fixed request, public-HTTPS egress, the
approval floor, exact gesture consent, by-value batch approval, idempotent
recovery, the closed mailto path, fixed label actions, the deterministic
census, durable owner decisions, honest outcomes, flagged and scoped routes,
confined Chat tools, privacy under adversarial mail, persistence parity, the
native experience, and integrated release evidence. The design touches no
roadmap item: every action keeps its approval, nothing runs unattended, and
no new Google permission is requested. Its one posture change, a dedicated
public-HTTPS egress transport for a single tool, is owned by ADR-0112
decision 5. Nineteen gates bind executable checks as of 2026-09-20. ADR-0165
adds three gate.email.spam_* gates on 2026-10-08 for the suspected-spam flag,
Gmail's sender check, and thread-level Report spam, designed in the same
document. Integrated release evidence remains pending, and the milestone does
not move the verified ceiling.
Milestone 32: Memory reconsolidation (dreaming), implemented; verification incomplete¶
The owner authorized whole-store revisiting, belief merging and grounded connections on 2026-10-02 and instructed engineering to begin on 2026-10-03. memory-reconsolidation.md and ADR-0169 define bounded durable maintenance, source content revisions, atomic operations, reversible equivalence membership, extractive summaries, grounded hypotheses, dependency invalidation, owner inspection/undo and evaluation arithmetic.
The runtime is implemented; verification remains incomplete. Twenty-four gates are registered: two bind the frozen yardstick, while twenty-two runtime/release gates remain pending. Recorded offline comparisons and owner judgments preserve failed precision and answer-lift results against frozen synthetic development and holdout corpora and unchanged M16 controls. Unattended activation stays off. ADR-0174 authorizes daily proposals and individually approved application; its supervised production deployment remains pending. Milestone 21's open evidence remains open and the verified ceiling stays 14.
Milestone 33: General memory recall, authorized; implementation in progress¶
The owner authorized the October 11, 2026 plan under ADR-0178. General memory recall defines twelve gates and the sequence from category-independent candidate repair to measured semantic search, contextual query formation, governed source recovery and answer use. No quality threshold is reported as passed by authorization. Frozen M16/M32 evidence remains unchanged; optional-channel activation and production delivery remain pending.