Files
stack/agents/darkwing/work/slice1-proto/proto-v3b-notes.md
T
jason.woltjeandClaude Opus 5.5 48d76de7c6 docs(slice1): schema v3b, current snapshot view (darkwing)
Lead decision 59. task_current picks each task's current snapshot,
skipping a poll row whose read_at is at or before the latest self row's
at; tasks_open reads it. Prototype on Node 24 and 26, two mutants
caught, and Dewey's fixture replayed: tasks_open now differs from v3a
only on #42 (in-progress). The notes add an S3 poller rule: compare a
read against task_current, not the raw latest row.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-04 22:33:09 -05:00

4.3 KiB

Slice 1 prototype, v3b (lead decision 59)

Darkwing, 2026-10-04. Dewey's mockup check found the case, recorded in agents/dewey/work/wui/SLICE1-VIEWS.md section 8. A board read that started before the broker's own move is written, because its digest differs from the latest row. It then becomes the latest snapshot, and tasks_open shows the old bucket until the next tick. Sage's ruling keeps the row as evidence and puts the rule for "current" in the schema.

schema-v3b.sql is a full schema that replaces v3a. It isn't a migration, and the v1 to v3a files are unchanged. diff schema-v3a.sql schema-v3b.sql shows the whole change:

  • New view task_current: one row per task, with every task_snapshots column. It is the task's highest-seq row, skipping a poll row whose read_at is at or before the at of the task's latest self row. A task with no self row takes its latest row.
  • tasks_open now reads task_current instead of picking the latest row itself. Its columns are unchanged.
  • task_external_changes is unchanged. It already ignores a read with read_at at or before the latest self row, and it only reports a task whose latest row is a poll, so a row it reports is also that task's current row.

Counts: tables 8, triggers 36 (the prototype prints 35 after its tamper check drops one), views 5. Schema digest (the meta value the prototype stores at create time): 52514a1173bef256ac262b397321bd5cf16f6a903ea2de40e25db895154fc692.

A rule for the S3 poller

Today the poller writes a poll snapshot when the read's digest differs from the task's latest row. It has to compare against task_current instead. Otherwise a stale row can hide a real change. In this sequence:

  1. The broker moves a task to in-progress.
  2. A stale read still shows todo and is written.
  3. A person really moves the task back to todo.

The next read shows todo, which matches the stale latest row, so the poller doesn't write it. The view goes on showing in-progress, and task_external_changes never reports the person's move. Compared against task_current, the read differs and is written, and both views come out right. The prototype shows both comparisons on vikunja:3/46. This is my row (S3), and it applies to addendum B section 5. It isn't a reason to skip the stale write; with the comparison fixed, keeping the row costs nothing.

Prototype

proto-v3b.mjs is proto-v3a.mjs with these changes:

  • the header, the temp directory prefix and the schema file name;
  • a digest line after the open-time check;
  • task_current and tasks_open shown for vikunja:3/41 right after the stale board read;
  • a new section, "current snapshot", with a read whose read_at equals the self row's at (skipped), the two poller comparisons, the person's move (now current and external), and a check that task_current has one row per task.

Results: proto-v3b-node24.txt (Node 24.21.0 in the node:24 image, no network, the directory mounted read-only) and proto-v3b-node26.txt (Node 26.8.1 on the host). Both use SQLite 3.53.4, and the outputs differ only in the version line. Against proto-v3a-node26.txt, every v3a line is unchanged. The new lines are the digest, the two views after the stale read (bucket 13, in review, not the stale read's 12, in progress), the new section and the view count of 5.

Mutants, each run with the same script in ~/darkwing-scratch/v3b:

  • The rule dropped (task_current is the plain latest row): the stale read shows as current on vikunja:3/41 (bucket 12) and on vikunja:3/46, and the current-based poller comparison says "no write". Caught on four lines.
  • > widened to >= (a read at the same instant as the self row counts): vikunja:3/46 shows the stale read. Caught on two lines.

Dewey's fixture

fixture-replay.mjs loads mockups/slice1/data.js (sha256 aed3616f…, Dewey's uncommitted working file, read-only) the way checks/slice1-verify.mjs check 15 does, without the browser, into both schemas. All 72 rows insert in both. tasks_open differs only on #42: todo in v3a, in-progress in v3b. task_external_changes and urgent_inbox are the same in both. Check 15 found v3a differed from the page on #42 alone, so v3b agrees with the page on every row. Output: fixture-replay.txt. Dewey's check still pins schema-v3a.sql d55e41fd; moving it to v3b is Dewey's change.