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 in opus-current-bugs (ContentEditor.tsx:handleDragEnd idMap remap, b9ee2d1), covered by a unit test in the same commit, and then locked in by a Playwright regression in sonnet-devtest-reliability (commit 15a88a6 on its worktree). That's the "user journeys are the acceptance criteria" contract from rewrite-test-architecture-plan.md actually working.
  • BUG-2 was deferred for the right reason. opus-current-bugs.md:122-144 refused 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.md ships the protocol extension, receiver guards, and feature-flag plumbing — OFF by default, still hiding behind the same test.fail() — without committing to Yjs yet. The projection module from sonnet-crdt-projection has the Y.Doc shape ready, and sonnet-do-persistence has 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 to openSections / regenSelection). Fix is minimal, local, no state-shape change, no protocol change. Unit test (tests/unit/ids.test.ts) locks the Set<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 on compiling is the correct coordination primitive here; the obvious naive alternative (adding compiling to 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.ts vs playwright.known-bugs.config.ts) with test.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:bootstrap script. Using wrangler d1 execute … --file=schema.sql instead of renaming existing migration files is the safe call: renames would desync the d1_migrations tracking table in prod. The mutual-exclusion caveat with db:migrate is documented at sonnet-devtest-reliability.md:92-94.

Weak / worth fixing

  • isSectionExpanded() point-in-time helper (e2e/helpers/cvl.ts). The report flags this itself: it returns locator.isVisible() (snapshot), not an expectation. Future contributors will use it in an assertion after drag and flake. Either delete it or rename to isSectionExpandedNow() + a doc comment.
  • span.rotate-90 as 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 a data-testid="section-body" or a stable aria-expanded attribute next pass; it's 3 lines.
  • header duplicate singletons in default data (BUG-5 triage). opus-current-bugs.md:170-178 concluded 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 know cvDoc is 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.ts module header should own that deletion commitment.
  • Version counter semantics (cvl-sync.ts risk table row 5). The workspace version counter increments on any settings write, so incoming.version <= localVersion can 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 for cv_profile / cl_profile first.
  • .claude/worktrees/* still present and tracked as git worktrees (git worktree list shows three). .agent/wave1-status.md:24-26 flagged 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 moving prototype/crdt/ out, the CRDT projection module is lost. Action: either migrate the wave-1 prototypes to prototype/ in the main tree or document their status in ownership.md.
  • MIG-1 unresolved at the migration level. db:bootstrap is a workaround, not a fix. If a future migration adds a second column to workspaces, 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}-*.md name owners, files, read scopes, and validation targets. No observed overlap across worktrees. git worktree list shows 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-54 codifies the rule and the actual routing matches it.
  • Reports are structured consistently. Every .agent/runs/*.md has 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.md lists 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-page wave-status.md updated 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:

  1. 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.
  2. Manual 2-tab smoke of cvl_sync=1 in 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 that saveState==='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.
  3. Clean up .claude/worktrees/*. Move prototype/crdt/ (projection module) to prototype/ at repo root. Remove the three wave-1 worktrees via git worktree remove. Add .claude/ to .gitignore (the CLI will keep creating it; that's fine as long as it's not tracked). Update ownership.md to note the new location. This closes a 3-wave-old inconsistency.
  4. Draft wave 4 task briefs. Two candidates:
    • opus-crdt-vertical — Yjs vertical slice using prototype/crdt/projection.ts + persistence plan from sonnet-do-persistence.md. Gate off cvl_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.
  5. 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.
  6. Do not turn cvl_sync on 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.

Source: wiki/content/archive/2026-05/agent-runs/opus-night-review.md