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]>
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 everytask_snapshotscolumn. It is the task's highest-seqrow, skipping apollrow whoseread_atis at or before theatof the task's latestselfrow. A task with noselfrow takes its latest row. tasks_opennow readstask_currentinstead of picking the latest row itself. Its columns are unchanged.task_external_changesis unchanged. It already ignores a read withread_atat or before the latestselfrow, 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:
- The broker moves a task to
in-progress. - A stale read still shows
todoand is written. - 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
digestline after the open-time check; task_currentandtasks_openshown forvikunja:3/41right after the stale board read;- a new section, "current snapshot", with a read whose
read_atequals theselfrow'sat(skipped), the two poller comparisons, the person's move (now current and external), and a check thattask_currenthas 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_currentis the plain latest row): the stale read shows as current onvikunja:3/41(bucket 12) and onvikunja:3/46, and the current-based poller comparison says "no write". Caught on four lines. >widened to>=(a read at the same instant as theselfrow counts):vikunja:3/46shows 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.