I recorded the dispatched run's proptest red as "a DETERMINISTIC red",
"not like anything else in this registry --- a property violation with a
concrete witness, not a load artefact", and proposed committing the
proptest seed as the first step. All of that was wrong, and it was wrong
for a plain reason: I recorded a finding without checking whether main
already documented it.
src/buffer.rs:3005 carries an #[ignore]d deterministic fixture,
crdt_undo_of_an_identity_replace_reports_a_no_op_edit_carrying_an_op,
that reduces this exact case. The shrunken input is a randomly sampled
recurrence of it: Replace(5, 1, " ") replaces the trailing space with
itself, a textual no-op but a real CRDT delete-plus-insert, so Undo
emits a version-advancing operation with no visible text change.
Committing the seed was a second error. It duplicates a deterministic
fixture that already exists and would only make a disputed assertion
fail permanently instead of occasionally.
The fixture already verified what I would have re-derived: content stays
correct, replicas stay converged because the op IS broadcast and neither
crdt_op consumer short-circuits on an empty range, and the cursor does
not jump.
The entry now frames the actual decision --- whether a visible text delta
and a CRDT-version delta are independent dimensions of Edit --- and the
evidence a lane owes: that forward textual no-ops still produce no
operation, that any permitted empty-text undo operation carries valid
bytes and preserves remote replay convergence, and an explicit
disposition of derive_replacement_edit reporting the empty range at the
buffer end rather than the edit site.
The interruption is bounded and does not reorder the roadmap. GUI arc 1b
remains the next product lane.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
D3 PASS. Dispatched run 33307137965 on main: all 14 jobs started and
concluded success or failure, none skipped, cancelled or timed_out. The
run's own conclusion was failure, which D3 permits by design --- its
contract is that the matrix RAN, not that it passed.
D2 PASS, with every guard exercised rather than assumed. A reached
in_progress; B was dispatched while A ran; the REQUIRED OVERLAP WAS
OBSERVED, A in_progress and B pending, so this is not the vacuous
version that passes when A finishes first; headSha(A) == headSha(B) ==
7b82e14, so the two really shared ci-<sha>; and A concluded success, not
cancelled. B was cancelled afterwards by hand to save macOS minutes, and
its fate is not part of D2.
An unplanned observation is worth more than either witness: a main PUSH
run was already in_progress at 7b82e14 when the first dispatch was
issued, and the dispatch QUEUED BEHIND IT rather than cancelling it,
starting only once the push finished. That is the same-SHA
push/dispatch interaction the framing described and no witness covered.
The first dispatch also immediately found a red on main, which is what
the lane was built for --- and it is not like anything else in this
registry. rope_matches_crdt_projection_after_arbitrary_edits failed a
proptest assertion at src/buffer.rs:3120, "no-op edit must have crdt_op
= None (Undo)", and SHRANK to a four-operation minimal input. That is a
property violation with a concrete witness, not a load artefact. It is
recorded as its own lane with the selector, the assertion, the shrunken
ops, the regression seed, and the reason a local pass is not evidence:
no .proptest-regressions file is committed, so the failing case is not
replayed and one green local run means nothing.
Not investigated here. This lane's scope was one workflow key.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Recorded together, because the control is what the occurrence owed.
The occurrence: Test (macos-latest / lua54) on head d9cc0fa, 1984 passed
and 1 failed, panicking at src/async_runtime.rs:2444 with R1's required
fragment. THIS IS R1 despite the new Lua flavor --- the row records
luajit and this is lua54, and flavor is not part of signature matching.
The selector and the fragment are, and both match.
The control: the same job at the branch's EXACT merge base 2e9f62b,
rerun the same hour, green at 1985 passed and 0 failed. Both logs were
preserved before the rerun, so neither result is reconstructed from a
conclusion --- the selector is read as "... ok" in the control's own log.
What that green control establishes is carefully bounded. It does NOT
establish environmental cause and does NOT retire R1; it shows only that
the merge base can pass the same job in the same hour. A RED control
would have established that the branch did not introduce the occurrence,
and that inference is simply unavailable here. R1 remains live either
way under its measurement-design disposition.
Records that R1's assertion omits its measurement --- the same class #244
fixed, and a line my discarded sweep had surfaced --- and that it is
deliberately NOT fixed here. Adding the elapsed value would sharpen the
next failure's evidence and repair nothing about the measurement design
this row is about: that a thread::sleep(15ms) is asserted by comment to
mean the worker picked the job up. That belongs to the async-runtime
lane with the rest of Q#MCI3.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Adds workflow_dispatch: to ci.yml. One key, no inputs, and no job,
matrix, step, permission or timeout changes --- a dispatched run does
exactly what a push run does.
THE SCOPE IS ONE REGISTRY ROW, and the framing took three revisions to
get that right. CI never invokes scripts/gate --- zero occurrences ---
so every local-gate red already has a merge-base control that needs no
CI at all: the exact failing command, with its flags, at the recorded
merge base, in a separate worktree. U11 alone needs this trigger,
because it is macOS-specific and this project has no Mac. When it
recurred on #243 the only contemporaneous main-side control available
was a re-run of a run eight days old.
What this is NOT: it does not run scripts/gate, does not vary R7's gate
conditions, and does not select U9's alternate test commands. Those need
their own changes. This is infrastructure they would build on.
The concurrency interaction is stated at its real strength: once a
dispatched run is in_progress, a second same-SHA dispatch will not
cancel it. cancel-in-progress: false protects a RUNNING run and not a
pending one, and a main push and a dispatch at the same SHA do share
ci-<sha>. A PR run never shares a dispatch's group at all, so no
PR-involving test exercises the predicate.
D1 passes and bites pre-merge: the working-tree file parses and
workflow_dispatch is a key under `on`; dropping it fails the assertion.
The witness looks up both 'on' and the boolean True, because YAML 1.1
parses `on:` as a boolean and a naive d['on'] raises before checking
anything.
D2 and D3 are OWED POST-MERGE and recorded as such --- GitHub offers
workflow_dispatch only for a workflow already on the default branch, so
neither can run before this lands. D2 carries a void-and-retry rule so
it cannot pass when the two runs never actually overlap, and D3 requires
each job to conclude success or failure rather than merely not-skipped.
Framing docs/ci-manual-dispatch-framing.md revision 3, approved.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Merged 2026-08-29 at approved head 7b50682, merge commit a85205a, via
--match-head-commit. 14/14 CI green on that head, 8-stage local gate
green on it too.
Records what the lane exposed beyond its own change. THREE rows in one
session were written to assert a condition without keeping what would
explain its violation: the two parse budgets this fixes, and U13's
`let (out, _, _)`, which throws away a child's success status and stderr
so its failure cannot distinguish wrong-but-successful output from a
refused invocation. U13 is not this lane's to fix, but three instances
make it a pattern rather than an oversight, and each one costs a review
round to establish nothing.
Also records R7's sixth and seventh occurrences, the bounded observation
window that stops its ratio drifting with review activity, and the
correction that seventeen green out-of-gate runs are not exclusions ---
nothing outside the gate has ever reproduced R7, so matching one gate
condition at a time outside it cannot isolate an in-gate cause.
Per the standing rule, this absorption does not advance any canonical
base to its own commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
The head-exact review gate reached sweep with six green stages, then
`skipped_directories_are_reported_with_a_reason` observed empty child
stdout. The durable failure cannot say why because the row discards the
child status and stderr.
Record the exact signature, the structurally unrelated branch diff,
and the isolated-selector and full-binary green reruns at their actual
strength: intermittence only. Diagnostic hardening remains a separate
lane.
The four-run observation window contains two green in-gate runs, so it
cannot be described as ending at the first green. Name it directly as
the first four in-gate runs; the timestamps continue to define the
boundary exactly and later verification gates remain excluded.
The previous commit recorded "in-gate 2 failures in 4 runs" and named
the final verification gate. Re-running the gate on that very commit
made both wrong: a fifth in-gate run, green, and a new log id. Every
docs fix forces a re-gate, and the re-gate invalidates the docs fix.
R7's window is now explicitly the four in-gate runs of 2026-08-29 up to
and including the first green, plus the 17 out-of-gate runs taken
between them. Later verification gates are excluded by definition. A
ratio that grows with review activity measures review activity, not the
phenomenon.
The ledger stops naming the head and log id at all. It records that
every review round ends with a green head-exact gate and points at the
PR body for the current values --- which is the same reason SS5b stopped
recording an ahead-count: a line naming a moving value is stale the
moment it is written, and that lane learned it twice.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Four stale claims, all in durable documentation that would have shipped
as written.
The framing still said "AWAITING APPROVAL. Nothing implemented" while
the ledger and the PR both said otherwise.
R7's status line said SIXTH OCCURRENCE while the body below it recorded
the seventh. Its tree-exclusion bullet said the observing lane's diff is
two docs; the lane carries three. And its cumulative figure said in-gate
is 2 failures in 3 runs, which omitted this lane's final head-exact
verification gate --- a fourth in-gate run, green. The figure is 2 in 4,
and the fourth is named so a reader can tell which run it was.
Active-work carried the same stale docs count and the same 2-in-3, and
recorded neither PR #244, nor the final head 2d76984, nor the gate log
20260829T152824Z-673477. It now carries all three, with the gate's
result read from its eight stage logs rather than inferred from stage
exits.
The sweep that found the last 2-in-3 also printed "(none = consistent)"
unconditionally, which is the read-success-from-absence shape this
project keeps catching. It now prints the hit count and only claims
CLEAN when that count is zero.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
The gate run immediately after the seventh occurrence passed all eight
stages with zero failures anywhere, R7's selector included. So "in-gate
always fails" is false, and the previous entry --- written before that
run --- is corrected rather than deleted.
The correction that matters is a reasoning error, not a data one. I
called seventeen green out-of-gate runs "four hypotheses excluded". They
exclude nothing: NOTHING outside the gate has ever reproduced this
failure, so matching one gate condition at a time outside the gate
cannot isolate an in-gate cause. All those runs establish is that none
of the four conditions reproduces it BY ITSELF.
Stated at the strength it carries: in-gate is 2 failures in 3 runs,
out-of-gate is 0 in 17. Suggestive, and not a clean split.
The method follows from that and is written down for the next
occurrence: varying conditions outside the gate cannot answer this
question, so the gate's ambient root, its exported environment, and
process state across stage boundaries each need a gate run with that one
thing changed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
The next gate run of the same worktree reproduced R7 immediately --- same
selector, same three fragments --- and that run's other seven stages were
green, sweep included and complete, so the pair is not confounded by the
truncation that marred the sixth.
Two consecutive in-gate failures is new for a row whose prior five were
spread across lanes and months, so it prompted a narrowing. Seventeen
green runs at the failing head on the failing worktree exclude four
hypotheses: the selector being flaky (3 isolated), the gpu binary's own
concurrency (6 full runs), the gate's isolated TMPDIR (6 runs under a
gate-shaped 61-character path, tested because this project already knows
socket-path length matters), and residue from the m4 stage the gate runs
immediately before gpu (2 back-to-back pairs).
So the discriminator is inside scripts/gate versus outside it, and it is
not the TMPDIR, not the preceding stage, and not the binary's
concurrency. The row does not guess at what remains --- the gate's
ambient root, its exported environment, and process state carried across
stage boundaries are named as uneliminated, not as suspects.
Causal status stays UNRESOLVED, but the question is sharper than it was:
previous entries compared trees and lanes, and this one locates the
difference in the runner.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
The gpu stage failed with all three of R7's required fragments ---
`transient sequence must attach`, `Handshake(Io(`, `BrokenPipe` --- at
pmacs-gpu/src/attach.rs:1889, 283 passed and 1 failed. Isolated selector
green three times afterwards, which is this row's established control.
The tree exclusion is as strong as the fifth occurrence's: this lane's
entire diff is src/async_runtime.rs, tests/m4_acceptance.rs and two
docs. No pmacs-gpu file is touched, and the change is two assert!
message strings.
Records the run's other half honestly. The gate was in a background task
killed at 314s and 07-sweep.log ends in Terminated, so the run is NOT a
gate result. Stage 6 is evidence because it completed and reported;
stage 7's absence is evidence of nothing. Distinguishing those is the
same rule the handoff already carries about timeout-wrapped gates.
Causal status unchanged: UNRESOLVED. A sixth lane touching a sixth
unrelated surface saw the same three fragments, which strengthens
"not lane-correlated" and settles nothing else.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Both `duration_ms < 100` assertions --- src/async_runtime.rs and
tests/m4_acceptance.rs --- now print the observed value and the budget.
Neither budget moves.
dispatch_parse_round_trips_a_rust_source_file redded twice on
macOS/lua54, as U11 and again on #243, and BOTH margins were
unrecoverable: the message said only "trivial parse should be fast", so
the second red could not be compared with the first. A 1ms overshoot and
a 900ms overshoot are different failures that produced identical logs.
U11 predicted that cost in writing, and it came true once.
D1 and D2 are verified against REAL PANIC MESSAGES, by forcing only the
comparison bound to 0 in a scratch build:
trivial parse should be fast: took 0ms against a 100ms budget
200-line parse should be quick: took 11ms against a 100ms budget
The second is the stronger demonstration --- a non-zero observed value
cannot be mistaken for a literal.
That scratch panic proves only half. It exercises a budget of 0 while
printing 100ms, so it says nothing about the committed threshold. D3
carries that half separately by pinning the literal 100 in both files.
The two are a proof together and neither substitutes for the other.
The framing withdraws revision 1's claim that the async_runtime
assertion was the codebase's sole measurement-omitting one. It was not:
tests/m4_acceptance.rs:244 is the same measurement against the same
budget. The claim is withdrawn rather than repaired, because a sweep
wide enough to be complete also catches `Instant::now() < deadline` loop
guards and `eval::<bool>` turbofish, while one narrow enough to be
accurate proves nothing about completeness. This is not an
assertion-hygiene audit.
workflow_dispatch was split out per the ledger's own recorded decision;
it and U9's still-unrun discriminating control remain separate lanes.
Framing docs/parse-budget-diagnosability-framing.md revision 2, approved.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Merged 2026-08-29 at approved head b8c51b7, merge commit 6c9bae6, via
--match-head-commit so the merge is provably of the reviewed head. 14/14
CI green on that head and the 16-stage local gate green on it too, with
HEAD and a clean worktree captured before and after.
Acceptance 48 is implemented: panel selection, terminal mouse reporting
and the vertical wheel replay, and the gesture ends correctly, which was
the larger half. The horizontal document-panel wheel stays a named
deferral to GUI Stage 1b B1-B3.
GUI arc 1b is unblocked and rebases onto this merge.
U12 arrived with the merge rather than needing separate absorption.
Records two owed follow-ups, both their own lanes. ci.yml has no
workflow_dispatch, so a merge-base control could only be had by
re-running a week-old job --- that shaped the entire U11 recurrence
handling. And dispatch_parse_round_trips_a_rust_source_file has now
redded twice on macOS/lua54 and passed on rerun both times, with
async_runtime.rs byte-identical to main throughout, while BOTH margins
are unrecoverable because the assertion omits the measured value.
Intermittence is established; cause and magnitude are not, and a third
occurrence will be no better until that one-line fix lands.
Per the standing rule, this absorption does not advance any canonical
base to its own commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
The block said Q5 was unwitnessed, acceptance-suite shaped, and owed. It
sat immediately above the row that witnesses and closes Q5 through the
extracted seam, so the source carried two rulings and the stale one
first.
Written when the gap was real and left behind when it was filled. Q5's
own doc still records that it was owed through tasks 18 and 19, which is
history rather than a standing claim.
Swept for siblings: the remaining "owed" mentions all describe a release
the gesture record owes a child, and the two "unwitnessed" mentions both
say a PAST round was wrong to claim it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Head-exact gate at 6142acc: fifteen of sixteen stages green, including
sweep, m4, gpu, diff-check and all eight touched acceptance suites. The
red was 04-lib-crdt, where composition_overhead_under_ten_percent
(1.247x against a 1.10x budget) and
setsid_escapee_is_not_reaped_and_teardown_reclaims_readers failed
together. Both green on isolated rerun.
Filed as U12 rather than folded into U6 or U9, because both of those
instruct it: U6 says one of its selectors redding without the other is a
separate incident, and this is composition_overhead alone for the second
time; U9 is the same budget-plus-PTY shape but in 11-sweep with a
different PTY selector.
src/process.rs is not touched by this branch at all. src/editor.rs is,
but only in the panel-replay paths, not in composition.
The row does NOT claim load caused it. It records that the run was
knowingly taken on a machine that was quieter but not quiet --- load
11.04 at the start, 27.79 five-minute at the end, two foreign python
processes throughout, an apt install shortly before --- which are
conditions, not a mechanism.
Four incidents in this family now, and the discriminating control U9
named remains unrun: pin test-binary concurrency to 1, and separately
load a lone --lib binary.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
`!messages.is_empty()` could be satisfied by any unrelated semantic
message, so the row asserted an ordering against a frame it never
confirmed was there. It now requires the unwritten messages to contain
InstanceMessage::PanelFrame(PanelFramePayload::Absent) --- the successor
frame whose own transition raised the release.
The assertion bites: suppressing that payload while keeping the
cancellation fails the row, where the emptiness check would not have
noticed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Closes the gap recorded through tasks 18 and 19. The third drain sits
inside the daemon's per-frontend frame loop, which no unit row could
enter, so it was written down as owed rather than assumed covered by its
neighbours.
The seam is now `project_semantic_frame`, extracted from that loop. It
returns its messages UNWRITTEN, and that is what makes the ordering
assertable: a caller holding them has by construction not sent the
successor frame, so a release already delivered at that moment provably
precedes it rather than merely arriving alongside it.
The row arms a gesture on a reporting terminal, takes the panel away so
publish_absent_panel cancels from inside projection, calls the seam, and
asserts the child already has the release while the successor frame is
still in the caller's hands.
It bites its own drain and no other: removing the drain from the seam
fails Q5 while Q1-Q4 stay green on the effect and detach drains.
Grid sessions no longer reach the drain at all --- they hold no panel and
no gesture --- which is tighter than the previous per-fid call.
Also folds in the reported prose typo, and records the gate's
precondition: a foreign C++/java build has been at load 114+ through
this work, and the three wall-clock rows that redded under it were green
in isolation every time. Running the gate into that would manufacture
another U6/U9/U10 rotating-red incident.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Answers review of c37c066.
ABSENT WAS MISSING. The approved G5b table has five transitions, not
four, so the matrix was 16 quadrants where it should be 20. Added, and
it earns its place twice: as the fifth row, and as a CONTROL on SS5b's
own cancellation --- removing that cancel now fails the Absent quadrants
while the four this lane added still pass.
The quadrant count is asserted in the row. A loop that quietly stops
covering a combination passes exactly as loudly as one that covers them
all, which is the same read-success-from-absence shape as a test filter
that matches nothing.
G5m ASSUMED its composites. Both scenarios asserted one release without
ever checking the mapping moved, so either would pass as a
single-cause transition wearing a composite's name. It now peeks the
generation before and asserts it advanced after --- peeked, because
reading through the authoritative accessor would advance the key and
manufacture the very second cause the row is meant to observe. The
assertion bites: a same-size geometry change does NOT move the mapping,
and substituting one fails the fixture.
The doubled P12 rustdoc line is back and removed again. I wrote the note
about this exact seam after the first occurrence and then spliced
through it a second time. The crate-wide sweep is now a real check
rather than a grep I improvised: every `///` line containing a second
`///` that is not a URL.
Machine note: a foreign C++ build was running at load 114 during the
final verification, and three wall-clock rows redded under it ---
m6_2_pty_streaming_respects_byte_ceiling,
composition_overhead_under_ten_percent and
full_buffer_summary_flatten_scales_on_large_grammar_file --- each green
in isolation. The gate still wants a quiet machine.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Answers review of e2b080f. The transition detection was sound; the rows
proving it were not.
G5b(a)-(c) and G5m stopped at has_pending_release() or a cancellation
count. Both pass while delivery or recorded-domain routing is broken,
and the mutation that parks a release and never delivers it proves it:
it now fails all three rows and previously failed none. Every quadrant
drains explicitly and asserts the effect --- exact release bytes for a
reporting terminal, the cleared empty selection for a document, and an
empty slot afterwards.
The matrix is now the table the framing asks for: four transitions x two
families x two targets, sixteen quadrants. All four earlier rows used
the legacy terminal fixture, so the mapped legs and every document leg
were simply absent.
G5m takes both composites the framing names --- changed-size geometry,
which moves the epoch AND the mapping generation, and a buffer
replacement that also moves the mapping --- rather than the one
wrong-shaped combination it had.
One quadrant asserts less and says so: for window replacement on a
document the window the gesture belonged to is gone, so the completion
has nothing left to clear and the ending is the whole effect. Written
into the row, because a silently absent assertion is how a quadrant
stops testing anything.
Two fixture facts the failures taught: the document legs press at row 0
because foreign_edit replaces buffer contents without refreshing the
window's cached line index, so only the first display row resolves to a
byte and a press that anchors nothing does not arm; and cargo check
--lib does not compile #[cfg(test)] code, which is why a missing test
helper passed a check and failed the build.
Corrects two records. The ledger had the mutation labels reversed ---
dropping the BUFFER comparison misses the buffer transition, not the
window one. And semantic_render still told readers these transitions
were left armed on this branch, which was true of SS5b and false here
since the matrix landed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Task 19. SS5b wired Absent and left the other four transitions armed,
inert while nothing consumed the latch and defects the moment
cancellation gained an effect.
Three are visible in the producer, where the declaration is built: the
side WINDOW replaced, its BUFFER replaced, and the GEOMETRY epoch moved.
The last needed a retained geometry_epoch on PanelPresentation, because
nothing else the producer holds moves with a same-size geometry change
--- not the panel epoch, not the identity, and on a legacy peer not a
mapping key either --- so the transition was invisible and a live gesture
survived a grid it no longer belonged to. DETACH cancels in the
dispatcher, before any teardown, because it is the transition with no
later opportunity of any kind.
The release follows the RECORDED domain, so a buffer replacement pays
the child the gesture was pressed on rather than whatever occupies the
panel now.
G5b(a)-(d), G5m and G5j, each reading the child's byte stream or the
document's selection rather than the latch. The mutations discriminate
exactly: dropping the window half of the identity check fails only the
buffer leg, dropping the buffer half fails only the window leg, dropping
the geometry check fails only that leg, and dropping detach's cancel
fails only detach.
G5m survives all four, and correctly --- two coincident causes take the
same latch, so one release, and removing either cause still leaves one.
G5j's two legs differ and the row proves it: an empty selection is
cleared without moving point, while a real dragged region survives
anchor-and-cursor exact. Clearing every selection fails the second leg,
which is the mutation that matters --- ending a gesture is not a reason
to discard what the user selected.
Machine note: a foreign java build was running at 213% CPU during this
work, and the wall-clock budget row composition_overhead_under_ten_percent
redded twice under it, green in isolation both times. Functional rows
are unaffected; the gate should wait for a quiet machine.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
The Q6 rewrite spliced its replacement text ending with P12's heading
while the slice it replaced began with the same line, concatenating both
copies onto one line. Neither cargo fmt nor clippy reflows doc comments,
so nothing downstream noticed.
Swept the rest of the crate for the same shape; the only other hit is a
`file:///` URI inside a legitimate doc line.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Answers review of ab8ddae. The entry drain could not close this: it
looks for an OWED release, and a gesture that is still LIVE owes nothing
yet. Arming was what cancelled it, and arming runs after the replacement
press has already reached the target --- so a second press with the first
never released put `old press, new press, old release` on the wire. Two
presses outstanding, then a release arriving for the wrong one.
The Down arm now ends the live gesture and drains it before applying the
replacement, so the child sees `old press, old release, new press`.
The invariant moved to where it is relied on. arm_accepted_gesture now
asserts that neither a live gesture nor an owed release remains, at the
point of ARMING rather than inside cancellation --- arming is what the
ordering protects, and checking during cancellation cannot see the case
where nothing has been cancelled yet. The defensive cancel stays for
release builds, because parking late is recoverable and overwriting is
not.
Q6 was rewritten, because the old one never sent a second press while
the first was live and so could not observe any of this; its final
assertion also ran after a further cancellation. It now expects the
exact bytes `release(1,2), press(2,4)` in that order.
Both layers are witnessed separately. Reverting the ordering trips the
new debug assertion at the point of arming; reverting it AND compiling
that assertion out --- which is what a release build does --- fails the
byte-order assertion instead, with the child receiving only the new
press.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Task 18. Cancellation now PARKS the record instead of returning it into
a context that drops it: two of the three cancellation sites --- the
mapping-generation advance and publish_absent_panel --- run inside frame
production, where no target effect can happen, so the gesture ended with
the child still holding its button.
A SLOT, not a queue. The latch holds at most one gesture per frontend,
so at most one release can be owed, and the bound is structural rather
than a cap someone chose. Overwriting a still-parked release is a
debug_assert rather than a silent loss --- a backstop, since the ordering
is what actually prevents it.
Three drains, each against a specific way the release would otherwise
arrive too late or not at all: before any subsequent panel-pointer
effect, before detach teardown (the next statement in that arm drops the
state holding the record), and at the projection seam between
render_frame returning and its messages being written.
Q1, Q2, Q3, Q4 and Q6, each biting its named mutation with the run
counts checked. The mutations discriminate: dropping the park fails all
three delivery rows; removing the effect-drain spares Q4, which has its
own; removing the detach drain hits Q4 alone. Q3 asserts ORDER rather
than arrival, and the mutation that keeps the drain but moves it after
the press effect fails exactly that assertion, with the child's stream
coming back press-then-release.
Q5 IS OWED, AND RECORDED AS SUCH. The projection-seam drain needs a row
that drives the real per-frontend frame loop; these rows call
render_frame directly and never enter it. The seam still matters --- a
cancellation with no following panel event and no detach would let the
successor frame overtake the release its own new mapping required --- so
it is written down as unwitnessed rather than treated as covered by its
neighbours.
Two fixture facts worth keeping: the Q rows cancel through Absence
rather than a mapping advance, because a terminal panel's key tracks its
screen and anchor, not its buffer, so a foreign edit does not move it;
and the helper re-shows AND re-declares the panel, because a panel left
Absent fails the inbound ladder and the row would then be observing the
ladder rather than the slot.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Answers review of 557ea6d. Capturing the outcome and asserting it LAST
makes the focus assertion reachable: removing the buffer check accepts
the press, an accepted press activates the panel before it replays, and
the row now fails on focus --- WindowId(3) against WindowId(2).
I had recorded this as a limit of the type boundary, claiming no
mutation could reach the effect assertions because the daemon applies
only on Accepted and the disposition gives Refused no target. That was
wrong. The obstacle was that the row asserted the refusal BEFORE
dispatch and aborted there. Ordering, not architecture.
The classification is still checked, at the end, so the row cannot go
vacuous if it ever stops testing a refusal.
Controller and byte assertions stay documented as defence in depth, and
now for an accurate reason: the mutation that reaches them routes
through a document buffer, which touches neither.
Also replaces failure text that still described an out-of-range anchor,
which this fixture stopped using when its refusal lever became a foreign
buffer.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Answers review of 9028e1b.
P2 recorded `active_frontend`, which is which FRONTEND is current, not
which window has focus. Focus is `views[&fid].active` and `focus_window`
moves it, so the row would have watched a panel steal focus without
noticing. It now records the focused window, and asserts up front that
the panel does not already hold it --- otherwise "focus did not move to
the panel" asserts nothing.
P2's refusal lever also changed, because the old one could not exercise
what the row claims. An out-of-grid cell with the row bound removed
becomes `on_chrome`, so the press classifies Consumed and still reaches
no target: the row bit on its own precondition while focus was never
touched. A foreign buffer at an in-content cell is the refusal whose
mis-gating actually yields Accepted.
And the row now says what is falsifiable about it. Removing the buffer
check makes the press Accepted and P2 fails --- but on the precondition,
which fires first, so the focus, controller and byte assertions cannot
fail under that mutation and no other mutation reaches them: the daemon
applies only on Accepted, and the disposition enum gives Refused no
target to apply. They are defence in depth against a future refactor,
labelled as such rather than presented as coverage.
The ledger claimed every row reads a target effect and never the latch
alone. That was false. P9 and P10 read the LATCH, and correctly so ---
the defect they fence is a record existing for a gesture that never
began, so the record is the artifact, and an effect assertion would not
distinguish their mutations. The line now separates effect rows from
arming-gate rows and names P2's third case.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Answers review of 2ea39aa. Two of my claims were wrong and the code
disproved them.
WIDE PANELS HAD DEAD POINTER INPUT. A panel deliberately does not
inherit the terminal's per-axis PTY caps (Bet B5'), and the renderer
clamps through terminal_projection_size so a band wider than
MAX_TERMINAL_COLS paints correctly. Pointer routing passed the RAW panel
width, and view_status_for_size refuses anything over the cap --- so on
exactly those panels every click inside the visible terminal resolved to
None while the band looked perfectly normal. Routing and the recorded
viewport now go through the same clamp, with P12 as a POSITIVE control
at MAX_TERMINAL_COLS + 128.
P10 IS REACHABLE, and my note saying otherwise was wrong. I claimed
anchor_at resolves every in-grid cell of a live view, "measured, not
assumed". I had measured ROWS and generalised to cells. anchor_at
refuses coord.col >= row.cells.len(), and the fixture's band is 80
columns over a 20-column child, so columns 20..79 are painted padding
inside accepted content. The row exists now and the begin_selection gate
is witnessed rather than excused.
THE DISPOSITION IS AN ENUM. As {outcome, Option<target>} the invalid
pair --- refused, yet carrying a target --- stayed representable inside
editor.rs, so my "the type makes it impossible" was also wrong. Refused
now holds no target at all. ResolvedPanelTarget is public as a type and
opaque as a value: every field stays private, so the daemon hands the
disposition back rather than reading a derivation out of it.
P2 also now asserts what it observes: the classification is Refused, and
focus and terminal-controller ownership are preserved. A misclassified
press focuses the panel and claims the controller BEFORE its
out-of-range anchor fails, so byte and latch assertions alone stayed
green through exactly that bug.
MY MUTATION HARNESS WAS READING SUCCESS FROM SILENCE. `cargo test --lib
"r4_p\|g5k_"` is a literal substring filter, not a regex: it matched
nothing and ran ZERO tests, and I read the absence of failures as
"the mutation did not bite". One whole round proved nothing. The harness
now prints the run count and says so loudly when it is zero. Re-run
properly, all three fixes bite their named rows.
Also updates the ledger's witness list, which omitted P2, P9, P11, the
recorded viewport and the exact-byte strengthening.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Answers review of 48057d7. The G5k routing fix held; the record still
leaned on ambient state in three places.
TerminalLocal now records the accepted content VIEWPORT. Replay fetched
the current panel_grid_size and returned when it was None --- which is
exactly what a hidden or absent panel produces, so a cancellation could
not finish the drag it was cancelling, and a size-changing cancellation
would have finished against the successor's geometry.
A press that anchors NOTHING no longer arms. The document path returned
Some(Document) unconditionally even when panel_cell_byte found no byte,
and the terminal path returned Local while discarding begin_selection's
answer. Both now report what actually began.
The child rows assert EXACT BYTES rather than a count: a wrong event or
encoding passed the old length checks. The literals are written out
rather than built with the encoder's own formula, which would only
assert that the encoder agrees with itself. G5k(b) pins the ruling that
the SGR framing comes from the record while the modifier bits still
report live state, so its release carries code 4 rather than 0.
New rows: P2's effect half (a refused press reaches no target), P9 (a
document press that anchors nothing does not arm), P11 (a recorded local
completion still runs with the panel HIDDEN, which is what the recorded
viewport is for).
THREE ROWS IN THIS ROUND WERE VACUOUS BEFORE THE MUTATIONS CAUGHT THEM,
and the fixtures now assert their way past each cause. The panel grid in
this fixture is FOUR rows, so content is rows 0..=2: my first P9 and P10
cells were out of grid and refused before reaching the path they claimed
to test, and P9's earlier cell clamped to byte 0 instead of failing to
anchor. Both rows now assert the disposition is Accepted before
asserting anything about the effect.
P10 IS DELIBERATELY ABSENT AND RECORDED AS UNWITNESSED. The
begin_selection gate has no reachable false branch through the daemon:
classify has already established the buffer is the side window's live
terminal, and anchor_at resolves every in-grid cell of a live view ---
measured on the fixture, not assumed. The gate is kept as insurance and
the gap is written where the row would have been, rather than covered by
something that would pass whether or not the gate existed.
P2's effect half is likewise not falsifiable by any mutation I could
construct, because a Refused disposition carries no resolution, so no
path can apply it. That is a stronger guarantee than a test, and it is
stated rather than dressed up as coverage.
Also corrects the last false ledger tense.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Answers review of 39b6fa7. The three-state disposition was sound; the
record and effect half downstream of it were not.
apply_panel_pointer returned a bare bool, so the record carried neither
the resolved target nor the reporting contract, and the daemon drove
accepted Drag/Up back through the mode-sensitive adapter. That adapter
re-reads Shift, the scrollback position and the child's mouse modes on
every event --- which is G5k's named mutation verbatim. A press reported
to the child followed by a release re-evaluated after the child turned
reporting off leaves that child holding a button down; the reverse
transition sends a child an Up for a Down it never saw. The recorded
completion had the same defect and additionally re-derived the current
side window, returning when it had changed --- precisely the transitions
task 19 must terminate, so the completion they need was the one thing
that refused to run.
The press now resolves a PanelGestureDomain --- Document{window},
TerminalChild{window, buffer, modes} or TerminalLocal{window, buffer}
--- and the record carries it. Tails and completions route through
replay_panel_gesture_in_domain, which gates on nothing: not Shift, not
the scroll position, not the child's current modes, not the panel's
current identity. apply_terminal_gesture reports which way it routed so
the domain is measured where the branch is taken. Arming now requires an
effect: a press the target refused records nothing.
G5k(a)-(d) plus P3's reporting leg, P4 and P5. Every row reads a TARGET
EFFECT --- the child's byte stream in order, the terminal drag state, or
the document selection --- never the latch. Each bites its own mutation,
and G5k's four legs all fail under the framing's own named mutation
applied verbatim.
Two seams exist because nothing else exposes what the child received: an
opt-in child-input tap, off by default, and a drag-state read.
Also corrects the recovery ledger, which still said implementation was
paused and the bool collision unfixed.
Records for the ci-red registry rather than hiding it: during this work
composition_overhead_under_ten_percent and pty_mode_child_sees_a_tty
redded together in one --lib run at load 21 and each passed in isolation
immediately after --- U9's signature, and neither path is touched here.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Replaces the panel dispatcher's `bool` with a three-state
PanelPointerOutcome decided BEFORE any target effect, and moves the
gesture lifecycle into one table in the daemon.
The old shape could not express the rule it needed. It validated,
classified and mutated in one pass, so an Up or Drag with no accepted
Down had already reached the child or the selection by the time the
daemon consulted the latch. classify_panel_pointer now returns the
disposition and carries the resolution it was decided from;
apply_panel_pointer acts on that same resolution, so the editor stays
the only authority and the daemon never re-derives chrome, target kind
or content bounds.
The table: a chrome press begins nothing; a left tail with no live
record is inert; an Accepted release performs the ordinary in-content
completion and takes the record; a Consumed release did not reach
content, so it terminates from the record at the gesture's last valid
content cell. Never both --- that is P5.
apply_terminal_gesture now returns whether the gesture REACHED THE
CHILD, so the latch is armed from the effect result rather than from a
prediction about the modes. complete_panel_gesture routes both terminal
domains back through that same shared path, which is what keeps "what a
release does" from having a second implementation.
Four witnesses, each reading a TARGET EFFECT and not the latch, and
each biting its own mutation: P1 chrome press (classify chrome as
Accepted), P3 chrome release on a terminal (drop the recorded
completion), P7 orphan release (remove the Up live-gate), P8 orphan
drag (remove the Drag live-gate).
Two of those rows were vacuous when first written and are recorded here
because the mutations are what caught them. P8 dragged over an EMPTY
panel buffer, so panel_cell_byte returned None and point could not move
whether the gate was there or not. P3 was written against a document
panel --- but R-c lets document chrome Up fall through to content, so it
classifies Accepted and never reaches the Consumed path it claimed to
test; it now uses a terminal panel, on the legacy arm, because reading
the live mapping generation ADVANCES the key and SS5b wired a key
advance to cancel the live gesture, so the mapped fixture destroyed the
gesture it was trying to complete.
Adds view_is_dragging_for_test, the observable that separates a
delivered completion from a latch that merely emptied.
Also re-homes a doc paragraph that described peer_uses_mapped_panel_family
while sitting above update_accepted_gesture; deleting the latter's doc
with the function made the misplacement visible.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Make the three-state panel-pointer result a pre-effect disposition and
replace the competing latch matrices with one complete lifecycle table.
Accepted tails now require a live gesture, accepted release replay and
record-driven termination are mutually exclusive, and the witnesses
cover stale tails plus immediate and later duplicate completion.
Place projection-raised release delivery at the enforceable daemon
boundary after semantic rendering returns and before its messages are
written. Keep the arm invariant as a backstop behind pointer, detach,
and frame-order witnesses.
Split horizontal-wheel ground truth by terminal reporting/local and
document targets. Record the missing document-panel effect explicitly
under GUI Stage 1b B1--B3, update that framing's surface scope, and
synchronize the active-work checkpoint.
Four blocking gaps, all of them cases where revision 14 asserted a
guarantee its own mechanism did not provide.
1. Q#BP-R4's release half was bookkeeping in an effect's clothes. It
ruled that a chrome Up "consumes" the latch and claimed this stops a
child being left button-down. It stops nothing: update_accepted_gesture
does `let _ = state.consume_accepted_gesture()` at daemon.rs:1067, and
terminal chrome returns at editor.rs:2862-2870, BEFORE
apply_terminal_gesture at :2899. P3/P4 asserted only that the latch
empties, so they would have passed while the child heard nothing ---
the failure looking fixed because the bookkeeping looked right. Now
ruled as TERMINATE, with a per-target completion effect (child release,
or local terminal-selection completion, or the document completion SS5b
already assigned here), a no-duplicate leg, and P3 written explicitly
against the latch-only assertion.
2. The pending-release slot had an invariant and no ordering. The seam
replays before it arms (daemon.rs:2608-2616), so a check inside
arm_accepted_gesture could only fire after the new press had already
reached the child. Drain order is now part of the ruling: before any
subsequent panel-pointer effect, before detach teardown, before the
next frame --- with an old-release-before-new-press row that reads the
child's byte order, and the invariant demoted to a backstop.
3. The ground truth was knowingly false, and the workflow requires
scouting before framing. RE-MEASURED at 2c0d3ff instead of deferred.
Two clauses the old table called MISSING are DONE on this branch ---
panel selection and terminal mouse reporting --- the vertical wheel
works, and the horizontal wheel turns out to be an UNRULED gap sitting
in a catch-all arm with no comment. Revision 15 names it rather than
ruling it, because inventing a ruling inside a re-measurement is how an
unexamined default becomes a decision. The 72da24a table is kept as
history.
4. "This lane MOVES the grade" was wrong against the authoritative
scorecard. Step 5/GPU is floored Partial by 5(a) IME, so completing
5(c) cannot lift it, and step 8 is already Works on all three columns.
The draft had read this section's MISSING column as if it were the
scorecard; COHERENCE.md is the only thing that decides grades.
Also drops a false TUI claim --- dispatch_semantic_panel_pointer has
exactly two callers, both FrontendEvent arms, so only semantic legacy and
mapped peers reach it --- and clears two merged-state contradictions: SS5b
no longer says "Nothing implemented", and the lane no longer says the v26
correction is owed by 1b while the block below records SS5b making it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
The ledger listed the merge's duplicate-SS5b defect but not the worse
one: the merge commit does not compile and its message asserts that it
does. Recorded with the bisect consequence spelled out, so a reader
crossing that range knows why the build fails there.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
The merge commit b758c2e DOES NOT COMPILE, and its message says
"Workspace compiles clean, all targets, no warnings". That claim is
WITHDRAWN. It was true of the tree I checked and false of the tree I
committed.
What happened: I staged the conflict resolution, ran cargo check, hit
`cannot find value mods in this scope` at the mapped arm, edited
src/daemon.rs to bind it, re-ran cargo check clean --- and then
committed without re-staging that file. The verification and the commit
were of different trees. This is the same defect class as gating one
step of an edit-then-commit chain and leaving the next ungated: a
commit that does not depend on the edit it claims.
The fix itself is unchanged from what was verified. SS5b left `mods` in
`..` on PanelPointerMapped; the mapped family carries the same
modifiers, so leaving it there gives a v25 session the inverted Shift
behaviour that parent 48 R-a fixed for v24.
Verified at THIS commit, after staging: cargo check --workspace
--all-targets, no errors and no warnings.
Not amended away. b758c2e stays in history with its false claim
standing and this withdrawal attached, because erasing a bad record is
worse than carrying a corrected one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Revision 13 blocked this lane on a protocol-bearing mapping generation.
That slice merged as #242 (47b5463), so the block is DISCHARGED and
revision 13 stands as history rather than as a gate.
Also fixes a defect I introduced in the merge b758c2e: it kept BOTH
copies of SS5b, this branch's stale pre-split one and main's
authoritative one. I discarded the uncommitted stub edit as obsolete
and missed that its deletion half was still owed. Exactly one SS5a and
one SS5b now remain.
Q#BP-R4 is new, and the merge created it. SS5b and this lane agreed on
`bool` while disagreeing on its meaning --- accepted-as-a-gesture versus
consumed-here --- so a press on the band's mode line currently ARMS the
accepted-gesture latch for a gesture that never began in content. That
is the defect class SS5b's review round four fixed, re-entering by merge
rather than by edit.
RULED: a three-state PanelPointerOutcome (Refused/Consumed/Accepted),
with an asymmetric latch rule --- arm only on Accepted + Down(Left),
consume on any Up(Left) that was not Refused, because a button-up ends
the gesture wherever it lands while a refused release cannot be known
to concern it at all. The asymmetry is what earns the third state: it
makes all three outcomes behaviourally distinct at the latch, so P1-P4
each have something to bite. A two-state bool with the corrected
meaning would be right today and would let the next author restore the
collision without touching a test.
Revision 14 also takes the rows SS5b's split table assigned here, rules
a bounded per-frontend pending-release SLOT for the cancellation record
SS5b leaves nowhere to wait --- with the no-arming-over-pending
invariant asserted rather than assumed --- and records that the four
transitions SS5b left inert become defects the moment this lane
attaches effects.
Records a re-measurement obligation with evidence rather than
suspicion: every production anchor in SS5a has moved, four of them
measured here, and the DONE/MISSING verdicts are not assumed to have
survived a dispatcher SS5b rewrote.
Coherence: journey steps 5(c) and 8(b), and unlike SS5b this lane MOVES
the grade --- it supplies what SS5a's own table lists as missing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Merged rather than rebased, by decision: the lane's 12 commits include
10 framing revisions that all touch the same 800-1000 line doc regions,
so a rebase meant twelve rounds of large-block conflict resolution ---
the operation that produced a committed diff3 marker on the last lane.
One pass instead, with all 12 commits preserved.
Resolutions:
- src/daemon.rs --- took main's structure whole, both inbound arms with
the latch gated on the dispatcher's answer, and threaded replay's
`mods` through both call sites. `mods` is newly BOUND in the mapped
arm, which SS5b left in `..`; the mapped family carries the same
modifiers, so leaving it would have given a v25 session the inverted
Shift behaviour that parent 48 R-a fixed for v24.
- pmacs-gpu/src/main.rs --- additive throughout: both new struct fields
(`gesture_last_content_cell`, `last_pointer_generation`), both resets
at each site, and both test blocks.
- src/editor.rs --- auto-merged; the merged dispatcher keeps SS5b's
`#[must_use]`, its four rejection paths and its `-> bool`, plus
replay's `&mut self`, `mods`, chrome/mode-line handling and terminal
gesture application.
- docs/active-work.md --- the active replay lane above main's corrected
#239/#240/#242 headers.
- docs/bottom-panel-framing.md --- 5a then 5b. The paragraph arguing
the v25->v26 bump should be "recorded as required rather than made"
is marked superseded: SS5b made it and merged as #242.
Workspace compiles clean, all targets, no warnings.
THE MERGE SURFACES A SEMANTIC COLLISION THE FRAMING MUST RULE ON, and
it is not resolved here. The two branches give the dispatcher's bool
different meanings: for SS5b `true` means the gesture was ACCEPTED, and
it drives the accepted-gesture latch; for replay `true` means the event
was CONSUMED HERE, including chrome swallows. So a press on the band's
mode line now returns true and ARMS the latch --- a gesture that never
began in content, which is the defect class SS5b's review round four
found and fixed. Recorded, not patched, because which rows own the
answer is a framing question and the next revision owes it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
SS5b merged as #242 (47b5463) at approved head 61f0faf, via
--match-head-commit so the merge is provably of the reviewed head.
PROTOCOL_VERSION is now 25. panel-pointer-replay is unblocked and is the
next step in the arc.
#239 (ca92796) and #240 (72da24a) both merged on 2026-08-13 and the
ledger has been calling them OPEN for a week. Their blocks are kept for
their reasoning, relabelled for their status.
#240's block gains the postscript it earned: its TMPDIR isolation was
the thing I defeated during SS5b review round 4 by running the CRDT
sweep by hand, outside scripts/gate. Two m4_24 base-resolution rows
failed, I reported them as pre-existing and proposed CI as the arbiter,
and the actual cause was /tmp/.git being inherited as an ancestor
project root. Through the gate, both pass.
Adds U11 to the red registry, the row deferred during #242's review so
that no docs commit would invalidate that PR's head-exact gate evidence.
It carries the exact selector and panic fragment, both attempt IDs, the
1960/1 counts, and the fact that the margin is unrecoverable because
duration_ms is omitted from the assertion message --- which is why a
recurrence owes a merge-base control rather than a comparison. The four
exact-head local passes, the two macOS/luajit greens and the identical
async_runtime.rs blob are recorded as narrowing evidence and explicitly
not as causality.
Per the standing rule, this absorption does not advance any canonical
base to its own commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Two consecutive scripts/gate runs at 70b334d, worktree verified clean
before and after each run, were 15/16 green apiece. Run A redded
13-sweep on dired_open_renders_10k_entries_under_200ms at 263.961465ms
against a 200ms budget; run B redded 15-sweep-crdt on
criterion_1_end_of_line_typing_completes_sub_frame_per_keystroke at
1.044609ms against a 1ms budget. Each red is green in the other run,
and both are green isolated at load 9.34.
That excludes the tree more strongly than U7 could: not "the diff
touches no render path" but the SAME COMMIT passing and failing each
row. Neither failing path is touched by the branch under test.
It does NOT establish load as the cause --- load was not sampled during
either failing step, and the row says so rather than borrowing a
reading taken elsewhere in the run.
Honours both escalation rules it trips. U7 says a repeat of one of its
selectors is a separate incident, and run A repeated one; U6 says one of
its pair redding alone is a separate incident, and run B did that. Both
are filed here rather than appended. The row also declines to pick
between the repeat and the rotation, because both are true of these
observations.
Closes one rival U7 left open: per-worktree gate target directories mean
no sibling shared this one.
Names the standing discriminating control U9 already specified and which
remains unrun --- pin test-binary concurrency to 1, and separately load a
lone --lib binary --- and asks that this family stop consuming review
rounds until it runs.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
The branch was two behind, not one --- 24e4039 and 5f2015c both landed
on main after the first rebase. Rebased onto 5f2015c cleanly, no
conflicts; both commits picked up are docs-only.
The previously recorded 16-stage green ran about a minute BEFORE
3d08255 was committed, which makes it worktree evidence rather than
head-exact evidence. This commit is the last content change before the
gate is re-run, so the run that follows measures the head that is
proposed for merge.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Both inbound panel-pointer arms discarded the bool from
dispatch_semantic_panel_pointer and called update_accepted_gesture
unconditionally. The ladder authenticates the SENDER; only the
dispatcher re-derives the TARGET, so an event can clear every rung and
still be refused --- for an out-of-grid coordinate, an absent side
window, or a buffer that is no longer the one in the side window.
A rejected Down therefore ARMED the latch, so a later authority loss
counted a cancellation for a gesture that never began, and once replay
attaches effects it would deliver a release to a child that was never
pressed. A rejected Up CONSUMED a real armed gesture, so the authority
loss that should have ended it found nothing armed and that child holds
the button down for good. A rejected Down on top of a live gesture was
worse again: arm_accepted_gesture ends what it overwrites, so it also
counted a spurious cancellation.
Both arms now gate on the return. The dispatcher is #[must_use], so the
class cannot recur silently --- clippy runs with -D warnings, making a
future discarded answer a build failure rather than a review finding.
Four rows, g5_substrate_a_refused_{press_never_arms,
release_never_consumes}_on_the_{legacy,mapped}_arm. Each drives the
refusal from a coordinate one past the last grid row and ends in a
positive control differing only in that coordinate; without the control
a row would pass just as well if an unrelated rung had dropped the
event. Mapped rows read the generation through the validator's own
accessor so a mapping-rung refusal cannot masquerade as a dispatcher
refusal. Three mutations, each biting its named rows: ungating the
legacy arm fails exactly the two legacy rows, ungating the mapped arm
exactly the two mapped rows, and relaxing the dispatcher's >= to > fails
all four.
Also removes a committed diff3 ancestor marker this file carried since
8c9afde --- the only one in the branch's 32 commits, and invisible to a
clean-worktree `git diff --check`.
Also withdraws the claim that the local CRDT sweep could not go green.
The full 16-stage gate is green, sweep-crdt included. The two m4_24
failures came from running that sweep outside scripts/gate, where it
inherited TMPDIR=/tmp; /tmp/.git exists on this machine and project
detection walks upward, so both base-resolution rows resolved against
the wrong root. That is the exact hazard #240's isolation exists for.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Rebased onto f13506c at 3e68b76 --- 31 ahead, 0 behind, clean, signed.
One conflict, in this file, where main's merged-#241 block and this
lane's own first-commit block landed at the same position; both kept.
No code file overlapped: #241 touched scripts/, tests/common/ and two
suites, while this lane touches the protocol, daemon and GPU sources.
The blocker is gone --- #241 fixed the sweep-crdt defect this lane was
held behind.
Gate run in two labelled pieces, because 16 stages exceed the session's
10-minute command cap and the guard rightly forbids the backgrounding
that would evade it: 14 stages green (plain gate plus all six
--acceptance suites, at load 5.28), build-crdt green, and sweep-crdt red
on exactly two rows --- m4_24_bare_string_glob_stays_relative and
m4_24_d3_fallback_base_is_the_smallest_attachment_dir.
Those two are PRE-EXISTING and local-only: they fail identically at
current main f13506c, and they passed in CI on #241's Test (crdt) job.
Also records that an earlier attempt is not evidence. I wrapped it in
`timeout 580` to fit the command cap, which killed the sweep mid-run and
reported it as a stage failure --- the same self-inflicted shape as the
SIGTERM truncation in the probe lane, and it should not be read as a
result.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
The held lane still identified the teardown framing as revision 8, so
the approved state was not portable from this branch. Revision 9 adds
the total run classifier, the void budget, the endpoint verdict table,
the bisect-step policy and counterbalanced ordering --- none of which a
reader arriving here would have found.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Two state pointers were wrong. It named ledger tip fb40d88 while the
branch was four commits past it, and identified the teardown framing as
revision 5 on one line and revision 8 on the next.
The tip pointer is removed rather than corrected. A literal SHA naming
this branch's own head is stale the moment the next commit lands ---
which is precisely how it came to say fb40d88 --- so the ledger now
points at the branch head itself and says why.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Two corrections.
- This ledger still said 72da24a being an ancestor of the passing
7599661 while failing today is something "no source-monotonic cause
explains". Withdrawn: the two observations differ in commit AND
environment AND time, so they are non-comparable and support no
causal conclusion of any kind. Different commits can
deterministically produce different outcomes, so the pair says
nothing about determinism either.
- It identified the teardown lane's framing as revision 5; the
portable lane is revision 7.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Two statements this ledger still carried after 3313d8a said withdrew
them.
- The reduction entry still said the artifacts "are byte-different".
Historical byte identity is UNKNOWN and is not claimed: target dirs
have been overwritten, so a hash computed today is the current
occupant's. What is established is differing Cargo suffixes, hence
differing metadata hashes, hence different compilations --- enough
to void the comparison, and all that is asserted.
- The onset entry still called the window the sharpest lead and
called for bisecting it. Cleanliness was captured at neither
endpoint, so the first move is reproducing 7599661 and 724b785
clean in isolated target dirs, and deciding from that.
Also corrects the onset counts here to match the manifest: per test copy
the 17 sweep-crdt logs are 13 both-copies-ok, 1 where neither copy
executed (the stage died compiling pmacs, error[E0308]), and 3
both-failed --- not "three earlier reds on unrelated rows".
And narrows the ancestry note. 72da24a being an ancestor of the passing
7599661 while failing today shows only that outcome is not determined by
commit alone. It does not discriminate an environmental change, a
source/environment interaction, or a fix before 7599661 with a
regression before 724b785; an ancestor outside the interval says nothing
about whether the interval regressed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
Three corrections to what this ledger still asserted.
- It called the reductions a "bisect". They were not: no run isolated
a variable, because the subsets and the sweeps executed different
Cargo compilations.
- It said those compilations were "byte-different". Withdrawn --- the
bytes a historical run executed are not knowable now, since target
dirs have been overwritten and a hash computed today is the current
occupant's. What IS known is the differing Cargo suffixes, i.e.
differing metadata hashes, which is enough to void the comparison
and is all that is claimed.
- The onset was described as a bisectable window. It is not. Reflog
and commit times put HEAD at 7599661 during the last green ---
3c06176 landed 40s after that run finished --- and at 724b785
during the first red, since 5174f73 landed 08:45:41 after that run
ended 08:42:01. Cleanliness was captured at neither endpoint.
Decisively, 72da24a is an ANCESTOR of the passing 7599661 yet fails
today, and no source-monotonic cause produces that. Reproduce clean
endpoints before considering a bisect.
Also corrects the onset counts: per test copy the 17 sweep-crdt logs are
13 both-copies-ok, 1 where neither copy executed (the stage died
compiling pmacs with error[E0308]), and 3 both-failed. "14 passes" and
"the earlier reds failed on unrelated tests" were both wrong --- one of
those runs never reached the test at all.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai