mirror of
https://github.com/gastownhall/beads.git
synced 2026-09-14 20:17:24 +08:00
362eecc6bf
* test(migration): seed and assert the wisp plane on the v1.1.2 upgrade lane The migration-test harness has never seeded a wisp. Its shared fixture is three issues, a dependency, a label and a comment, and thirteen version lanes assert its exact `length == 3` shape — so the plane that 1.3.0's chain actually rewrites (wisps, wisp_dependencies, wisp_comments, leases, events and the ignored-migration cursor) reaches the candidate empty, and every migration in main 0054-0066 plus ignored 0012-0025 runs as DDL over zero rows. Add a separate `run_wisp_plane_upgrade` lane in its own workspace, dispatched after the shared embedded lane the way the v0.55.4 second lane already is, so no existing assertion changes. It seeds two issues and five wisps covering the open, closed, blocked-by-issue, blocked-by-wisp and conditional-blocks classes, plus a wisp comment, a wisp label, an issue-blocked-by-wisp edge through dependencies.depends_on_wisp_id, and a file:// Dolt remote published with the old binary. There is no `bd dolt sql`, so plane state is read with the already-pinned external Dolt v2.1.8 CLI as a read-only oracle. `dolt sql -q` can exit 0 on failure, so every read is decided by its CSV payload rather than its status. Assertions and the trap each one guards: - wisp survival and row counts gc must not collect a fresh closed wisp - updated_at stability 0059/ignored-0015 derived-state restamp - is_blocked truth table + bd blocked the wisp-aware blocker predicate - dolt_ignore superset the #5947 read-before-write clobber - dolt_status clean migrations must not leave dirty tables - events row count across 0062 the drop/commit/recreate flip - leases + granted_node present the #5366 contradicted-cursor replay - unblock on close blocks vs conditional-blocks release - journal shape + wisp writability 0064/0066 and 0060 storage_class - full-fingerprint second open the ignored track, which `Schema already at vN` cannot see at all That last one matters most: MigrateUp reports `applied` from the main track only and never adds appliedIgnored, so the harness's existing no-op check is structurally blind to an ignored-track replay. The fingerprint is the only guard there is. Extend the pinned-runtime gate and the workflow's Dolt install step to the wisp-capable versions, which now need that binary as an oracle. Cache keys are untouched: corpora are seeded fresh per run and the cache holds only release binaries keyed by asset checksum. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(migration): extend the wisp lane to v1.1.0 and the pre-split v1.0.1 regime v1.1.2 alone only proves the post-split regime. v1.0.1 is the one source in the corpus that still stores wisp dependencies in the legacy single-target shape (issue_id, depends_on_id) and has no ignored-migration cursor at all, so it is the only lane where the candidate has to perform the ignored/0003-0005 split, the 0047 delegate repair and the 0058 heal on populated rows, and bootstrap the ignored cursor from nothing rather than find both already done. Add verify_wisp_dependency_split: the three split target columns exist, the legacy column is gone, and each seeded edge lands on the right target — wisp-on-issue and conditional-blocks in depends_on_issue_id, wisp-on-wisp in depends_on_wisp_id, and the issue-on-wisp edge in the main dependencies table's depends_on_wisp_id. Mis-homing those rows is the "duplicate primary key given" hazard class in migrations/README.md, and it is invisible to every count-based check. Make verify_no_restamp regime-aware, because which migrations replay is a property of the source cursor. 0059 and ignored/0015 self-assign `updated_at = updated_at`; their predecessors 0046, 0047 and ignored/0007 do not. A v1.0.1 store replays all of them, so every non-closed row legitimately moves. A v1.1.x store has 0046/0047 behind its main cursor, so issues must not move at all — but its ignored cursor says 0011 while leases.granted_node does not exist, the sentinel disbelieves the cursor, and the ignored series replays anyway (#5366), dragging in unguarded ignored/0007. What is gated in both regimes is the part that is unconditionally true: closed rows never move, because every recompute is scoped `WHERE status NOT IN ('closed', 'pinned')`. That bites the moment one forgets its scope. The tighter guard on everything else is the idempotence fingerprint, which requires a second open to move nothing at all. Record the per-version capability probe results as a table rather than leaving them as assumptions, and run bd doctor quick on every wisp lane instead of only the ones with a remote. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(smoke): add a tolerant wisp-plane scenario to the release gate cross-version-smoke.yml runs upgrade-smoke-test.sh as the release gate, and all six of its scenarios work entirely in the versioned plane. The wisp tables therefore reach the candidate empty, and 0054-0066 plus ignored 0012-0025 only ever run as DDL over zero rows — the same blind spot Scenario 6 was written to close for the dependencies split. Scenario 7 seeds a wisp with the old binary, gives it a blocker edge so the is_blocked recompute has real work to do, upgrades, and then checks the surfaces that break when the replay is wrong: the wisp is still listed, the blocker queries stay wisp-aware without erroring, the wisp is still writable through the migrated storage_class default, and doctor quick is happy. The matrix reaches back thirty releases on a tag push, so a binary that cannot create a wisp or cannot produce a parseable id passes with a SKIP instead of failing. Same tolerant, grep-based, dependency-free style as the rest of the file: no jq, no Dolt CLI. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(migration): cover the #5816 dirty tracked wisp-table state #5816 is still open: an ignored-named table that is tracked at HEAD *and* dirty, with ignored migrations pending, hard-locks the open. Nothing in either upgrade harness has ever constructed that state, so the containment surface is untested. It is not reachable from clean OSS lineage — every release since v0.63.3 registers the dolt_ignore patterns before creating the tables — so the scenario builds it deliberately: force-add and commit the wisp tables through the pinned Dolt CLI, then dirty one again with an ordinary old-binary wisp write. That is the shape real clones from forks and older-behavior lineages arrive in, and it is the only place this file issues DML through the oracle. Because the bug is open, the scenario deliberately does not gate on whether the candidate accepts or refuses. It gates on what must hold either way: the command terminates rather than hard-locking, and no wisp rows are lost. A refusal additionally has to name the dirty tables instead of failing opaquely. Carries a TODO(#5816) to tighten to must-succeed once the fix lands. Observed on the current candidate: a clean refusal in about a second naming `wisps`, with all rows intact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(migration): add v1.2.2 to the corpus and make the lane dispatch array-driven v1.2.2 is the tag field upgrades actually start from — the recovery release that superseded the accidental v1.2.1 — and it has never been in this corpus. It is the v1.1.2 tree re-tagged, so it adds no new storage regime; it closes the "the exact tag in the field was never tested" gap for the price of one matrix job. Adding it exposed a latent trap: the dispatch loop carried its own hardcoded copy of the embedded-Dolt version list, so a version added to EMBEDDED_DOLT_VERSIONS in lib/versions.sh was silently routed into the server-Dolt bridge lane instead, and failed there with a confusing "candidate list did not refuse with explicit migration is required". Dispatch on membership of the array that already declares the corpus, so the list exists once. Asset checksum verified against the published beads_1.2.2_linux_amd64.tar.gz. No existing cache-identity string changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>