Post-freeze record, not an analysis (roadmap §8 permits verdict and schedule records;
this is a schedule record). It plans the remaining work only. Everything already built is
recorded in DONE.md; the open board is TODO.md; the
release gate is RELEASE.md. Where this document and those disagree,
RELEASE.md wins on what “done” means and TODO.md wins on current status.
100% = v1.0.0 tagged on main by 2026-12-01 (KC-4) with every box in RELEASE.md
ticked — including the [HUMAN] ones — and TODO.md holding nothing but v2.0 (KC-5) items
and consciously deferred work.
Two things are not in that 100% by design, and the release notes say so instead of hiding it:
| Deliberately outside v1.0 | Why | Re-entry trigger |
|---|---|---|
| WP-IN11 contingent outbox | JSONL self-reconciles (probe) | sub-second liveness need, or hooks-only data |
| WP-A1…A7 + A10 alerting (v2.0) | best-path §6.1: off the critical path | KC-5 only — 14 consecutive days of real use + ≥3 friction-log entries wanting alerts |
| Phase 1.5 animated room, context-layer feed | cosmetic / experimental | never, unless asked |
Measured on 2026-09-08 (HEAD 40f1524 + 133 uncommitted files, +15 161 / −1 068):
[~] board row.Calendar: 12 weeks to KC-4. KC-2 (2026-09-14) and KC-3 (2026-10-12) sit inside that window and are both already satisfiable — they need ticking on the date, not work.
Each row has a recommended default so the answer can be a single word. Recording the
answers in TODO.md (a dated line under the WP row) is the sign-off.
| # | Decision | Recommended default | Unblocks |
|---|---|---|---|
| D1 | Commit + push the 133-file tree (the 2026-08-25 → 09-08 defect and honesty waves) | Yes, now — CI must be green on a pushed commit before anything else is layered on | Wave 0 |
| D2 | NODE-PIN fork — (a) pin Node 22 or (b) support 26 | (a): add .nvmrc = 22, tighten engines.node to >=22 <23, say so in README. (b) costs a native rebuild + CI matrix for no v1.0 value |
L6 |
| D3 | Retention values (OPEN-1/2/3) | DASHBOARD_RETENTION_EVENTS_DAYS=90 · token_usage never pruned in v1.0 (keep NO_RETENTION for that table; the acknowledgeCostLoss refusal stays) · backups DASHBOARD_RETENTION_BACKUP_DAYS=30, _KEEP_MIN=7 |
L9 |
| D4 | WP-U13 — does outcomeCause get a dashboard surface? (~2 real error agents in the corpus) |
Yes, minimal: the cause as text on error rows in the Live view and the session tree, no new view, no colour |
L5 |
| D5 | WP-U14 — CD-5 contract for unknown SSE event types | Closed union: add a typed ingest-failed arm, delete GenericRealtimeEventSchema; an unknown type is dropped client-side and counted, never rendered. Document in docs/site/usage/api.md |
L4 |
| D6 | SS-1 wording — how loud is a never-connected stream? | Chip reads ○ reconnecting (attempt N) from the second failed attempt on; N comes from a real SseClient channel, not a view-local flag |
L3 |
| D7 | The two KC-0 physical acts — do or waive | Do them in Wave 3: the 14-day friction log doubles as the KC-5 evidence base, so it is not wasted motion. If waived, write the waiver into RELEASE.md §0 before tagging |
Wave 3 |
| D8 | LABEL-ME commit caveat — spike/ is git-excluded, so committed annotations lose their substrate |
Commit the filled annotations/human/ files plus a README note; CI keeps reporting “substrate unavailable” honestly, and the local ratified number is recorded in DONE.md with date and n |
L10 |
Coordination protocol as at the top of TODO.md: one lane = one agent = its path list;
lanes in a wave are disjoint; TODO.md / DONE.md / WORKLOG.md / PROJECT-STATE /
CLAUDE.md are orchestrator-only; no agent runs git. Every lane ends with the seven gates
green (gate:spawner · typecheck · lint · format:check · web build · test at
100/100/100/100 in all five packages · gate:licenses) and a fails-before proof for any
defect it closes.
| Lane | Owner | Paths | Exit |
|---|---|---|---|
W0-A — CHANGELOG [Unreleased] for the uncommitted tree |
agent | CHANGELOG.md |
every user-visible change since 0.3.0 listed under Added/Changed/Fixed, in the file’s existing voice |
| W0-B — decision batch D1…D8 | Ivan | TODO.md (dated lines) |
eight one-word answers recorded |
| W0-C — commit + push on D1 | Ivan (“commit” / «пушвай») | — | CI success on the pushed SHA (gh api …/actions/workflows/ci.yml/runs?branch=main&per_page=1) |
| KC-2 tick | orchestrator, on 2026-09-14 | TODO.md KC table |
Phase 1–2 exit gates re-verified green; zero velocity rebases used |
Eight disjoint lanes, dispatched together once W0-C is green.
| Lane | Paths (write) | What closes | Proof |
|---|---|---|---|
| L1 cost-summary contract | apps/server/src/api/queries.ts, packages/shared/src/schemas/cost.ts, apps/server/test/api-cost*.test.ts |
getCostSummary() returns sessionCount (total, not the slice) and hasMore; wire schema updated |
a corpus of COST_TOP_N + 1 sessions serves hasMore: true and the exact count |
| L2 cost-flow truth | apps/web/src/views/layout/cost-flow.ts, apps/web/src/views/chart-summary.ts, apps/web/src/views/CostView.tsx, matching tests |
hubIsWhole checks both sides (entering and leaving); describeCostFlow owns the hub disclosure; CV-5’s hedge becomes a statement using L1’s sessionCount (runs after L1 lands) |
a hub with unbalanced ribbons can no longer earn the all cost label — fails-before by revert |
| L3 SSE attempt channel (D6) | apps/web/src/sse.ts, apps/web/src/views/LiveView.tsx, apps/web/src/Shell.tsx, tests |
SseClient reports failed attempts with a count; the chip wording per D6 |
attempt 1 and attempt 40 are distinguishable in the DOM |
| L4 realtime contract (D5) | packages/shared/src/schemas/realtime.ts, apps/server/src/realtime/*, apps/server/test/realtime-bridge.test.ts, docs/site/usage/api.md |
typed ingest-failed arm; generic arm removed; unknown-type client rule documented |
acceptingArms reports exactly one arm for every event the server can emit; mutation of each arm is killed |
| L5 outcomeCause surface (D4) | apps/web/src/views/LiveView.tsx, apps/web/src/views/SessionsView.tsx, tests |
the six causes render as text on error rows, NULL renders as nothing (not “ok”) |
the agent-outcome-errors fixture shows each cause verbatim |
| L6 NODE-PIN (D2) | .nvmrc, package.json (engines), README.md, docs/site/usage/getting-started.md |
the repo declares only what its native binding can load | node -v on v26 fails the engines check loudly at install, not at test time |
| L7 gate docs | SECURITY.md, docs/site/security/model.md, docs/site/contributing/licensing.md |
the two scripts/ gates described as widened (roots, manifests, file counts as check-no-spawner prints them) |
numbers in the docs equal the gate’s own output on the same tree |
| L8 BENCH-SHAPE rerun | apps/server/bench/, docs/measurement/ (new cold-replay-2026-09.md) |
corpus-scale.ts --records/--record-bytes at the real shape (26.19 MiB/session, 51 sessions, 2477 subagent transcripts); the number written down with its command line |
the measured band replaces the synthetic 34.87–39.92 s in TODO.md/DONE.md (orchestrator) — Ivan ratifies by ticking, the agent only measures |
| Lane | Paths | What closes |
|---|---|---|
| L9 retention wiring (D3) | apps/server/src/retention/, apps/server/src/index.ts, apps/server/src/config.ts, docs/site/operations/backup-restore.md, docs/site/usage/configuration.md, tests |
the runner invoked on the daily backup timer with the signed policy; a dry-run report logged at boot; the token_usage refusal untouched; WP-D10 → [x] |
| L10 LABEL-ME kit (D8) | packages/test-fixtures/annotations/README.md, a read-only renderer under packages/test-fixtures/annotations/tools/ |
one page per claim: the parent line, the child line, the join path the parser used, the raw JSONL evidence — so a human judges each of the 60 claims in ~20 s. Reads spike/, never writes it |
| L11 time-to-understand kit | docs/measurement/time-to-understand-log.md (pre-filled session picks only) |
five real sessions chosen by size class, the server launch line, the log rows ready for a stopwatch |
| KC-3 tick | orchestrator, on 2026-10-12 | P0-1/2/3 green on main and ci required by branch protection (gh api …/branches/main/protection) |
No new features in this window. Agents take only defects the friction log raises; at most one velocity rebase (roadmap §5).
| Act | Owner | Budget | Records |
|---|---|---|---|
Fill the 60 claims in annotations/human/, run pnpm --filter @agenthropic/core exec vitest run test/hierarchy-gate.test.ts |
Ivan | ~45 min | n, errors, Wilson lower bound → DONE.md; PROVISIONAL label dropped everywhere it appears (RELEASE.md §0, phase0-verdict.md, parser-spec.md §3, README) |
Stopwatch run per docs/measurement/time-to-understand-protocol.md on the five sessions |
Ivan | ~30 min | signed rows in time-to-understand-log.md → RELEASE.md §6 |
| Friction log, 14 consecutive days of real use | Ivan | passive | best-path §9 dates; entries become Wave-3 defect lanes; the same 14 days are the KC-5 evidence |
| Install one free rival dashboard, ask it the five questions | Ivan | ~1 h | result in the friction log; if it answers ≥4/5, say so in the release notes — the tag decision stays Ivan’s |
| Defect lanes from the log | agents | as needed | each one: fails-before proof, seven gates, WORKLOG |
| Lane | Owner | What |
|---|---|---|
| R1 mechanical release pass | agent | RELEASE.md §1–§3, §5 automated proof, §6 dollar-trace proof — every command run, real exit codes pasted into the WORKLOG |
| R2 docs truth pass | agent | README.md, docs/site/guide/roadmap.md (the “as built” box), docs/analysis/PROJECT-STATE-* snapshot, docs/analysis/README.md bar paragraph, CHANGELOG.md [1.0.0], DONE.md v1.0 milestone entry, package.json 0.3.0 → 1.0.0 |
| R3 human boxes | Ivan | RELEASE.md §0 (KC check, LABEL-ME ratified or PROVISIONAL stated, the two acts done or waived), §4 COPY-with-attribution review, §5 live backup→restore drill on the real DB, §6 usability signature |
Ivan: release commit, v1.0.0 tag, push. Orchestrator, post-tag: CI green on the
tag ref, Pages deploy green, badges resolve, DONE.md closed, TODO.md reduced to the
KC-5 items — and the public write-up the roadmap asks for either way.
The critical path is not code. It is D1 → Wave 3’s 14 days → R3. Start the log on 2026-10-13 and the buffer week survives; start it on 2026-11-09 and it does not.
NO_RETENTION stays the
default; the values are documented, not executed).RELEASE.md already requires.