Night Review — 2026-04-25
Reviewer: Opus (external architecture/stewardship review, read-only)
Scope: commits since 3283c90 and .agent/runs/* for waves 2 and 3.
Not a patch — a judgment call.
1) Direction
Yes — the trajectory is right. Three things validate it:
- Bug triage → harness → fix → regression test closes in one wave. BUG-3 was named in
sonnet-explorer-cvl(wave 1), diagnosed + patched inopus-current-bugs(ContentEditor.tsx:handleDragEndidMap remap,b9ee2d1), covered by a unit test in the same commit, and then locked in by a Playwright regression insonnet-devtest-reliability(commit15a88a6on its worktree). That's the "user journeys are the acceptance criteria" contract fromrewrite-test-architecture-plan.mdactually working. - BUG-2 was deferred for the right reason.
opus-current-bugs.md:122-144refused to ship a REST-only rebroadcast because silent LWW in a CV editor is strictly worse than forcing a reload. That's the kind of judgment the plan calls for on §226-231 ("prefer browser evidence; no plausibility merges"). - The wave-3 CVL sync patch is the right minimum.
opus-cvl-crdt-sync.mdships the protocol extension, receiver guards, and feature-flag plumbing — OFF by default, still hiding behind the sametest.fail()— without committing to Yjs yet. The projection module fromsonnet-crdt-projectionhas the Y.Doc shape ready, andsonnet-do-persistencehas the persistence decision documented. The handoff surface is clean.
The one place the trajectory is weakest is platform migration cadence: sonnet-platform-skeleton landed in wave 1 and has had no follow-up in waves 2 or 3. That's fine deliberately (current-app bugs first), but if checkpoints 2-4 of the rewrite plan don't resume by end of next week, "rewrite" risks drifting into "fix current app forever."
2) Code changes — strong / weak / risky
Strong
- BUG-3 fix (
src/components/cvl/ContentEditor.tsx, +9 lines). Root cause correctly identified (idMap applied to sections but not toopenSections/regenSelection). Fix is minimal, local, no state-shape change, no protocol change. Unit test (tests/unit/ids.test.ts) locks theSet<string>-follows-content invariant, and the new Playwright regression (adjacent drag of two "Summary" sections, wave-3 Sonnet) exercises the real disambiguation rename path end-to-end. - BUG-4 fix (
src/components/cvl/index.tsx, +28 lines).pendingPreviewRef+ companion effect gated oncompilingis the correct coordination primitive here; the obvious naive alternative (addingcompilingto deps) would compile-loop. The report calls that out explicitly (opus-current-bugs.md:104-108). - Playwright harness separation (
sonnet-e2e-main,b9ee2d1). Two configs (playwright.config.tsvsplaywright.known-bugs.config.ts) withtest.fail()on the two-tab sync test means fixing the bug trips CI automatically without breaking the green suite in between. That's strictly better than either "known-broken test clutters the green run" or "known bug isn't tested at all." - Wave-3 CVL sync guard logic (
src/lib/cvl-sync.ts, ~100 LOC, 13 unit tests). The four apply-decision gates (shape / lang / stale version / saving) are pure functions with unit coverage. When the Yjs slice replaces the JSON broadcast, the guards are the only thing worth preserving — they're already in a shape that survives the rewrite. db:bootstrapscript. Usingwrangler d1 execute … --file=schema.sqlinstead of renaming existing migration files is the safe call: renames would desync thed1_migrationstracking table in prod. The mutual-exclusion caveat withdb:migrateis documented atsonnet-devtest-reliability.md:92-94.
Weak / worth fixing
isSectionExpanded()point-in-time helper (e2e/helpers/cvl.ts). The report flags this itself: it returnslocator.isVisible()(snapshot), not an expectation. Future contributors will use it in an assertion after drag and flake. Either delete it or rename toisSectionExpandedNow()+ a doc comment.span.rotate-90as expand-state signal in the regression test. Works today because Tailwind JIT keeps the class, but a CSS refactor would silently neutralize the assertion. Add adata-testid="section-body"or a stablearia-expandedattribute next pass; it's 3 lines.headerduplicate singletons in default data (BUG-5 triage).opus-current-bugs.md:170-178concluded no action, which is defensible for the immediate merge, but the follow-up (position-prefixed ids for fixed singletons, or one-shot dedupe on load) wasn't captured as a task anywhere. It'll resurface.
Risky
- Protocol extension piggy-backing on
settings_update.payload.cvDoc(wave-3 Opus). Backwards-compatible today because Dashboard/Kanban branch on specific keys. But now any future consumer must also knowcvDocis a side-channel. Once Yjs replaces this path, remove the JSON broadcast entirely — do not leave it as a fallback "just in case."cvl-sync.tsmodule header should own that deletion commitment. - Version counter semantics (
cvl-sync.tsrisk table row 5). The workspace version counter increments on any settings write, soincoming.version <= localVersioncan race with a concurrent Dashboard settings change and drop a valid cvDoc apply. The mitigation ("no worse than status quo") is honest, but if this feature ever gets turned on before Yjs lands, add a per-bucket version or a vector clock forcv_profile/cl_profilefirst. .claude/worktrees/*still present and tracked as git worktrees (git worktree listshows three)..agent/wave1-status.md:24-26flagged this in wave 1 and no one has resolved it. These worktrees contain wave-1 Sonnet prototypes that are technically orphaned — if anyone prunes them without movingprototype/crdt/out, the CRDT projection module is lost. Action: either migrate the wave-1 prototypes toprototype/in the main tree or document their status inownership.md.- MIG-1 unresolved at the migration level.
db:bootstrapis a workaround, not a fix. If a future migration adds a second column toworkspaces, the ordering issue recurs for any dev who already has a local D1. Numeric prefixing new migrations from here (0005_…) without renaming the existing four is the cheap durable fix; none of the wave reports commit to it.
3) Codex as orchestrator/steward — 8/10
Evidence:
- Disjoint scopes, every wave.
.agent/tasks/wave{1,2,3}-*.mdname owners, files, read scopes, and validation targets. No observed overlap across worktrees.git worktree listshows each wave owns its own branch. - Sequencing is coherent. Wave 1 discovered; wave 2 fixed + harnessed; wave 3 regression-locked + prerequisite-patched toward CRDT. Each wave's deliverables were prerequisites for the next wave's task brief.
- Refusal discipline. Wave 2 refused BUG-2 and MIG-1 rewrites; wave 3 refused a live CRDT cutover. Both refusals came with documented rationale, not silence. That's the hardest part of stewardship and it's present.
- Model routing is correct. Opus used for the BUG-2 defer-decision, the CRDT vertical-slice option selection, and the whole-document-broadcast safety analysis. Sonnet used for bug fixes with known root causes, Playwright harness, and testid additions.
ownership.md:46-54codifies the rule and the actual routing matches it. - Reports are structured consistently. Every
.agent/runs/*.mdhas Files Changed / Validation / Risk / Recommendation. That's what makes reviews cheap. Paid off tonight — I reviewed five reports in the time it would take to re-read one codebase-wide diff.
Docked two points:
.claude/worktrees/*violation unresolved across three waves (wave1-status.md:24-26). Steward flagged it and then didn't act on it. Minor, but it's a steward's own rule.- No rollup status doc.
.agent/ownership.mdlists who's doing what but there's no single place that tracks "which of the 6 rewrite checkpoints are we at." Reviewers and future agents have to reconstruct it from 10+ files. A one-pagewave-status.mdupdated after each wave would cut onboarding time meaningfully.
Not 9-10 because the steward hasn't yet been tested on the harder case (multi-agent merge conflict, production incident, a report that's wrong-on-its-face). Everything so far has been well-scoped. Real score comes after friction.
4) Should Opus be the orchestrator?
No. Keep Opus as high-risk / amorphous reviewer. Reasoning:
- Opus's leverage tonight came from judgment calls, not coordination: "defer BUG-2," "choose gated JSON broadcast over Yjs-now," "reject the naive BUG-4 dependency-array fix." Those decisions saved the project from regressions that would have surfaced in production. Coordination work (scope splitting, worktree assignment, report formatting) is routine and Codex is already doing it at 8/10.
- Orchestration is ~80% bookkeeping. Putting Opus on bookkeeping means Opus isn't available for the next "should we really do X" moment. The cost is paid in the moments where the answer isn't obvious.
- The current arrangement is the recommended structure in
rewrite-test-architecture-plan.md:189-204(Steward + Opus reviewer + Sonnet workers). It's working. Don't break working things.
Where Opus should be pulled in more:
- Before each wave launch, not just during. Ask Opus to sanity-check the wave task briefs for hidden assumptions before Sonnet workers start (5-min read, catches wrong scopes cheap).
- At merge time for anything touching the realtime protocol, schema, or LLM cascade. The three leakiest abstractions.
- When any report recommends "defer" or "do not merge." That's the highest-leverage review moment.
Where Opus should stay out:
- Routine bug fix merges.
- Report formatting, task file creation, worktree assignment.
- Playwright/unit test authorship.
5) Next 6-12 hours — priorities
Ordered by leverage:
- Merge wave 3 into main. Both wave-3 patches are validated, narrow, and disjoint. Opus worktree: feature OFF by default, 13 unit tests, pure functions — zero production behavior change. Sonnet worktree: two testid additions + one e2e regression test + one new npm script. No shared source files between them. Order doesn't matter.
- Manual 2-tab smoke of
cvl_sync=1in the merged branch before deciding anything else about CRDT.localStorage.cvl_sync = '1'in two Chrome tabs against a workspace that exists in prod D1 (the local D1 can't exercise the realtime worker). Verify reorders / text edits / variant toggles propagate, and thatsaveState==='saving'drops actually trigger under a rapid-edit race. If this passes, wave 4 can commit to Yjs or extend the JSON broadcast; if it fails, find out why before launching wave 4. - Clean up
.claude/worktrees/*. Moveprototype/crdt/(projection module) toprototype/at repo root. Remove the three wave-1 worktrees viagit worktree remove. Add.claude/to.gitignore(the CLI will keep creating it; that's fine as long as it's not tracked). Updateownership.mdto note the new location. This closes a 3-wave-old inconsistency. - Draft wave 4 task briefs. Two candidates:
opus-crdt-vertical— Yjs vertical slice usingprototype/crdt/projection.ts+ persistence plan fromsonnet-do-persistence.md. Gate offcvl_sync=2(distinct from JSON fallback).sonnet-platform-skeleton-advance— take the wave-1 Vite+Hono skeleton to Checkpoint 2 (deploys to preview, reads workspace data). This is the rewrite-plan's dormant track. Opus reviews briefs before launch.
- Follow-up task for header singleton dedupe (BUG-5 residual). Low priority but capture it before the context evaporates. Position-prefixed ids (
header@0,header@1) or a one-shot dedupe on load. - Do not turn
cvl_syncon in production. Not until (a) the manual smoke passes, (b) the per-bucket version concern is addressed or deemed acceptable, (c) at minimum one full cycle of the known-bug test flipping from expected-fail to expected-pass in CI. If a user asks why two-tab sync still requires reload — the answer is "by design until CRDT lands; patch is shipped but gated."
Summary
Tonight's work is strong: two user-facing bugs fixed with narrow patches, e2e harness with a smart known-bug isolation pattern, CRDT prerequisite patch shipped with pure guards + feature flag + 13 unit tests, and the fresh-dev bootstrap issue resolved without risking prod migration history. Direction is right; Codex is stewarding well (8/10); Opus is best kept as the judgment-call reviewer it already is. Next 6-12 hours: merge wave 3, smoke the CVL sync flag manually, clean up the .claude/worktrees leftover, and draft wave 4 with a real Yjs vertical slice.