Commit Graph

1558 Commits

Author SHA1 Message Date
Levi Neuwirth cf63f63a07
docs(framing): Stage 1 revision 16 --- the replay lane becomes a hard prerequisite
Answers review of revision 15. Still framing only; no code. Three of
the four changes correct 15's own reasoning.

**THE PANEL PREREQUISITE IS NOW IN THE TOPOLOGY, NOT A FOOTNOTE.** The
defect is exactly "frontend emits, receiver discards", so 15's
emission-only panel witnesses would have reproduced the blind spot that
let it sit undetected --- passing rows meaning nothing about whether a
panel wheel scrolls. SS3 now reads `1a` -> panel-replay lane -> `1b`:
the lane MERGES FIRST, 1b REBASES onto its merge commit (its base moves
off `72da24a`), and 1b carries an END-TO-END panel-wheel EFFECT
witness.

15's rationale "it is not input work" was wrong --- replay covers
terminal mouse reporting and click-to-focus, which is input work. The
accurate reason is breadth and ownership: acceptance 48
(`docs/bottom-panel-framing.md:1719`) has `PanelPointer` driving
listview row selection, panel selection, terminal mouse reporting and
click-to-focus. A wheel is one gesture in that set.

**DIVIDER AND BACKGROUND MUST BANK NOTHING.** 15 gave them the panel
cell's residual, which manufactures the very surface-switch jump B1
forbids: motion banked over an inert target, then spent the instant the
pointer enters a cell, so a gesture that scrolled nothing completes a
tick on arrival. They discard and reset both axes; any state kept there
must be incapable of combining with cell input. A crossing witness
pins it --- background partial plus cell partial must not reach a tick
--- and its mutation is precisely 15's error.

**THE DISCRIMINATING SETUP BELONGS TO EVERY LIFETIME ROW.** 15 stated
it for L3 alone. With the cursor inside the manually scrolled viewport,
`follow_left` returns that same origin, so held authority and released
authority produce IDENTICAL state and the row passes either way. L1,
L2, L4, L6, L7 and L8 now share L3's cursor-outside setup. L2 becomes a
HEIGHT-ONLY GPU resize, so it invokes the real follow without moving
the clamp. L7 splits: 7a widens the viewport, 7b SHRINKS THE CONTENT
--- clause 3 promises re-clamping on geometry AND content, and widening
witnesses only the geometry half.

**THE MUTATION TABLE NOW OBEYS SS6.** 15's heading promised "own rows
and no others"; SS6 of this same document says that promise is false
and cannot be made true, and requires instead that a mutation bite its
named rows with dependents NAMED. Rewritten that way, with the
legitimate dependents listed per mutation.

Ledger: checkpoint was still "revision 14", and described the snap-back
as next-paint without the TUI/GPU split that 15 established. Both
corrected, and the prerequisite recorded as a blocker with the rebase.

Also records CI-red signature **U10**. The first gate run of this tree
red on `composition_overhead_under_ten_percent` in `03-lib` at 1.343x,
and the SAME RUN's sweep passed it, on a documentation-only diff. Worth
a row beyond the usual: U9 asked whether sweep test-binary concurrency
was the discriminator, and this occurrence runs that comparison in the
opposite direction and gets the opposite result --- red at low
concurrency, green at high. That retires the candidate without
supplying a cause; two occurrences pointing opposite ways across one
variable means the variable is not the discriminator, nothing more.
U9's synthetic-load control is still the useful experiment and is still
unrun.

Gates: all nine green under `env -u TMPDIR`, log 20260814T082533Z.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
2026-08-31 21:14:35 +02:00
Levi Neuwirth a330658feb
docs(framing): Stage 1 revision 15 --- B1 fully ruled, and three defects in 14
Answers review of revision 14. Still framing only; no code. Revision
15 DOES change two B-row contracts, B1 and B3; 14 claimed none changed
and that was false.

**I CITED A TEST FIXTURE AS A PRODUCTION HANDLER.** Revision 14 named
`src/daemon.rs:6683` as the panel's `ScrollUp` arm. It is inside
`#[cfg(test)] mod tests`, opened at `:3740`. The wrong citation hid a
real defect: the production path,
`dispatch_semantic_panel_pointer` (`src/editor.rs:2674`), validates the
coord, resolves the side window, focuses when the gesture activates,
and returns WITHOUT REPLAYING ANYTHING. Its own doc says replay is
parent acceptance 48 and lands in Stage 2B-3. So a panel wheel is dead
today on BOTH axes --- a pre-existing violation of an already-ruled
contract, which is why panel inertness was never an available answer.

Ruled: 1b does NOT absorb the replay. 1b owns the frontend half ---
per-panel residual, both axes emitted --- and replay is repaired in a
prerequisite lane. It is already scoped to 2B-3, it is not input work
(selection, listview rows, child SGR reporting, and it needs the GPU
band), and the defect predates this slice. 1b's panel rows therefore
witness EMISSION ONLY and must say so rather than implying a scroll the
user cannot yet see.

**B1 IS NOW RULED, NOT HALF-RULED.** Revision 14 left two cells reading
"must be ruled", which is a question wearing a table's clothes. The
terminal answer was derivable all along: the SGR encoder already
carries `ScrollLeft` as 66 and `ScrollRight` as 67
(`src/terminal/input.rs:126`), and its guard returns `None` unless
reporting is on --- so a non-reporting terminal is horizontally inert,
matching the TUI, and no new arm is needed. Divider and background now
CONSUME both axes, because falling through to the document contradicts
`PanelBackground`'s own doc that the band owns the pixel. Chrome shares
the document's scrolling and residual, stated so it is a choice rather
than a leak.

**THE GPU PRESERVATION WITNESS WAS VACUOUS.** "The next paint" is
TUI-only. The GPU's `render()` (`:9881`) goes straight to
`render_to_view` and never calls `horizontal_follow`; the follow
reaches it only via `ensure_caret_painted`, whose callers are cursor
paths and geometry paths (`resize`, `apply_font_facts`,
`reflow_dynamic_code_geometry`). A GPU wheel-then-paint row would have
stayed green with the overwrite mutation restored. Preservation is now
specified per frontend: TUI drives a real paint, GPU drives a real
same-cursor geometry re-follow.

Release must move the cursor OUTSIDE the manual viewport. Inside it
`follow_left` returns the same origin, so the row would pass whether or
not release happened.

**FIVE CLAUSES HAD THREE WITNESS SHAPES; THEY NOW HAVE EIGHT.** 14 left
unconstrained: point and selection staying put, clamp-absorbed motion
not arming authority, geometry/content changes re-clamping while
PRESERVING authority, and wrap/buffer replacement clearing the LATCH
rather than merely zeroing the origin. The existing wrap-origin rows
cannot see a stale latch surviving wrap then truncate. Six mutations,
each failing its own rows.

Clause 3's direction was backwards: a WIDER viewport lowers the maximum
origin, so widening re-clamps downward. 14 said "narrower".

Ledger: three false claims removed. The 1b entry arrived in the SECOND
commit, not the first --- recorded rather than quietly fixed, because a
lane claiming compliance it did not achieve is what the #171/#215
correction exists to catch. The entry no longer says all six targets
have horizontal answers. And the arc block said five slices remain, 1a
is next, and v23; it is four, 1b, and v24.

Gates: all nine green under `env -u TMPDIR`, log 20260814T075217Z.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
2026-08-31 21:14:21 +02:00
Levi Neuwirth e94ce85be1
docs(framing): Stage 1 revision 14 --- Q#S1-11 ruled B, and two holes closed
Answers review of revision 13. Still framing only; no code.

**Q#S1-11 IS RULED (B), VIEWPORT ONLY.** (A) is not viable in 1b and
the vertical precedent does not reach it. `scroll_window` can carry
point because it is TUI-side, where the editor owns the cursor.
`OwnCursor` is "pmacs-gpu's own cursor position, MIRRORED from
`CursorByte`" --- a read-only reflection --- and the only wire operation
that positions it, `dispatch_pointer`, sets `active_frontend`, calls
`break_command_chain`, and by its own comment moves point or changes
selection on every kind. Carrying point from a wheel therefore needs a
NEW wire operation, which contradicts 1b's non-protocol scope. (A)
would not even be self-consistent: GPU vertical scrolling already does
not carry point.

**And "do not carry" alone is not a ruling** --- it leaves the origin's
lifetime undefined, which is the part that decides whether the feature
works. Five clauses, all of them the ruling: viewport only; an
EFFECTIVE move arms authority; repaint, same-cursor follow, resize and
vertical wheel preserve it while geometry and content changes CLAMP
rather than release; a genuine cursor-position change releases it; wrap
and buffer replacement clear it and pin zero.

**THE HAZARD LANDS ON THE NEXT PAINT, NOT THE NEXT CARET EVENT.**
Revision 13 said caret event and understated the exposure:
`horizontal_follow` is the FIRST act of `prepare_window_cursor_visible`,
which `paint_frame` runs every frame. The origin is overwritten by a
redraw with no input at all. Witnesses must therefore drive real call
sites on both frontends --- a helper unit test cannot see a follow that
runs inside `paint_frame` --- and a TUI cross-axis row is required
because vertical wheel DOES carry point there. Both mutations named:
follow ignores authority, and authority never releases.

**B1'S "SURFACE" IS NOW ENUMERATED.** Two facts made the gap real:
quantization and the zero return happen at `:3074`, BEFORE the panel
(`:3090`) and terminal (`:3112`) branches, so a sub-tick delta is
discarded before anything knows where it was going; and
`PointerSurface::Elsewhere` conflates document, terminal, minimap and
chrome, so the existing classifier cannot name what B1 needs. Six
targets are tabulated with a residual owner and a horizontal answer
each. The horizontal gap is NOT a wire gap --- `MouseKind::ScrollLeft`
and `ScrollRight` already exist and round-trip --- it is a missing
handler, so each target must be ruled emit-and-handle or explicitly
inert. Without the table, one global accumulator passes every
per-surface row that tests one surface.

Recorded while measuring: a wheel over the panel divider or the band's
background scrolls the DOCUMENT today, though the enum says the band
owns the pixel.

**B3 TAKES B7'S EXACT BOUND.** "Content bounds" was vaguer than B7's
saturated widest-line-minus-viewport rule, for the same bound on the
same rule, and B7 is exact precisely because the loose version blanks
the viewport. Stated in the GPU's column grid, since
`horizontal_follow` already reckons there and re-multiplies to snap the
offset --- a pixel clamp would break the snap the shared rule depends
on. Narrow-buffer and final-column-visible rows added; a clamp at full
content width must fail.

Ledger: the minimal 1b recovery/checkpoint entry, plus three lane
headers that were lying --- #240 and #239 were still marked OPEN, and
the arc header still said 1a was next. The #239/#240 absorption stays
deferred and is a separate lane.

Gates: all nine green under `env -u TMPDIR`, log 20260813T211645Z.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
2026-08-31 21:14:12 +02:00
Levi Neuwirth ce982e6701
docs(framing): Stage 1 revision 13 --- 1b ground truth, and Q#S1-11
Adds SS2a, measured at `72da24a`. No B-row contract changes. Awaiting
approval; nothing is implemented on this branch yet.

Every 1b anchor was stale, which was the expected result --- 1-pre's
router extraction moved the wheel path wholesale and `main.rs` is now
21,435 lines. `main.rs:2061` holds `PanelCell`, `:3337` an
`attach_client` line, `:3373` a bare brace; `dispatch_mouse` is
`editor.rs:3207`, not `:3052`. Those are renumbered in a table.

Three findings are not renumbering.

**THREE ROWS SAY "NOTHING EXISTS" WHERE SOMETHING DOES.** B3's "no
horizontal scroll to clamp" --- the GPU has `code_scroll_left` and its
own `horizontal_follow`; what is missing is a WHEEL-driven one, so B3
adds a second writer to an existing field. B5's "no I-beam" is true,
but `apply_panel_cursor_icon` already sets `CursorIcon::Default`
everywhere that is not the divider, so an I-beam written as its own
site would be clobbered by that else branch. B4's "no middle-click
path" --- 1-pre built the landing site and named this very row in its
doc comment. Each contract is unaffected; each implementation shape is
not.

**AND B7 RE-OPENS A QUESTION ANOTHER FRAMING DEFERRED.** This is the
one that needs a ruling. `horizontal_follow` documents the premise
"there are no explicit scroll commands, so every viewport move
originates here, and Q#HS4's snap-back hazard cannot arise". B7 IS an
explicit horizontal viewport move, and the horizontal-scroll framing
says in terms that such commands "are what re-opens Q#HS4".

The hazard is not hypothetical --- it is why `scroll_window` carries the
cursor with a VERTICAL wheel scroll: without it the auto-scroll pass
snaps the origin back and the wheel "would feel stuck after one notch".
A wheel-driven `view_left` that does not carry the cursor gets the
identical bug one axis over, on BOTH frontends, since the GPU's
`horizontal_follow` has the same shape.

B7's contract does not mention the cursor, so its mutations cannot
detect this: a clamp row and a wrap row both pass against a viewport
that snaps back on the next caret event. Q#S1-11 is raised OPEN with
two candidate answers, and either way B7 needs a witness the table
lacks --- scroll sideways, trigger a caret-follow, assert the ruled
behaviour.

Also worth having: B7's wrap clause is already implemented for the
caret-follow path, and B1/B2 share one witness, the four lines in
`apply_wheel` that round to whole lines and discard both the remainder
and the x delta. `code_scroll_residual` is NOT a wheel accumulator ---
it is the caret-follow pixel residual --- and reusing it would be a
defect.

Gates: all nine green under `env -u TMPDIR`, log 20260813T202304Z.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
2026-08-31 21:13:55 +02:00
Levi Neuwirth 0ec13b3953
docs(ci-reds): U16's third occurrence, and the first on `main`
The post-merge gate of the docs-only absorption commit redded at
`07-sweep` with U16's exact signature. Same selector, same panic site,
both required fragments.

It is the first occurrence on `main`, which removes the last attribution
question this row could have had --- the first two were on a branch
whose diff touched nothing under `src/packages/`, and this one has no
observing branch at all.

Three occurrences in about eleven hours, against eight consecutive green
`--lib` runs earlier the same morning. That is the closest this row has
to a rate and it is still not a measurement, because nobody has counted
runs and failures over a fixed window. Isolated reruns green three
times, which per the rerun rule establishes intermittence only.

The structural fix belongs to `file_io`: a version-suffixed child
inherits a cwd that a `TempDir` then deletes, and no care inside the
mutating test can close a process-wide window.
2026-08-31 21:02:45 +02:00
Levi Neuwirth 90238fbe51
docs(lane): #246 merged as 78346de
Merged at the approved head `093d677` via `--match-head-commit`, 14/14
CI green and the eight-stage local gate green on that exact commit.

The lane block keeps its full review history rather than collapsing to
a one-line "merged": ten rounds, four on the framing and six on the
implementation, and almost every finding in the later six was against a
RECORD rather than against code.
2026-08-31 20:56:49 +02:00
Levi Neuwirth 78346de19a
Merge pull request #246 from levineuwirth/crdt-identity-undo
Key the crdt_op shape invariant on provenance, not on the Edit's shape
2026-08-31 20:56:09 +02:00
Levi Neuwirth 093d677c05
docs(ci-reds): U19's title repeated the claim its body withdraws
The heading said "a terminal bell never arrives within a 5s poll" while
the body two paragraphs down withdraws exactly that: the evidence shows
the bell was not OBSERVED within five seconds, not that it never came. A
title is the part most readers keep, so it was the worse place to leave
it. Retitled to match.

U16 said its reds and greens were "across two days". Every run the row
cites --- both reds and every green --- is 2026-08-31, which the
sentences immediately above it already said twice ("again the same day",
"returned within the day"). Corrected in both files.
2026-08-31 20:28:58 +02:00
Levi Neuwirth 03204cc8af
docs(ci-reds): U19 WAS rerun, and three more overstatements withdrawn
U19 said "no rerun was performed on this selector". The very next gate
run was one: it passed in `03-lib`, `04-lib-crdt` and the exact
`07-sweep` context it failed in, at ea786a2. So did U16's selector,
after its second occurrence. Both rows now record those passes and
classify as intermittent. Writing "no rerun was performed" in the same
commit whose gate reran it is the kind of claim this file exists to
catch.

U19 also overstated three things. The evidence shows no bell was
OBSERVED within five seconds --- not that one "never comes", and not
that scheduling cannot explain it. "Three orders of magnitude of slack"
does not hold against the 200ms budget it cited: 5s is 5000x of 1ms but
only 25x of 200ms, so the distinction from the budget family is one of
degree. And adding an elapsed value later cannot make a future margin
comparable with THIS unmeasured one --- that margin is gone for good; it
only makes future failures comparable with each other.

R7 kept a sentence reconstructed before the renumbering: its "prior five
spread across lanes and months" were eight, and not evenly spread ---
three of them fall on one branch on 2026-08-15. The line census skipped
occurrence five, whose block never captured a line; it is now marked
unrecorded rather than guessed or omitted.

U16's introduction still said it was "worth more than its one
occurrence" while its status said second.
2026-08-31 20:17:45 +02:00
Levi Neuwirth ea786a2878
docs(ci-reds): U16 reproduced, and U19 is new
The gate verifying the R7 renumbering redded twice in `07-sweep`.

`cache_survives_across_fetcher_instances` is **U16's second
occurrence** --- same selector, same panic site, both required
fragments. It is the first time that row has reproduced, and it settles
an earlier withdrawal in the right direction: claiming "the window is
narrow" from eight green runs was wrong, and the failure came back
within the day. The child-inheritance chain stays a candidate; this
occurrence demonstrates it no more than the first did.

`terminal_bell_baseline_suppresses_history_and_delivers_each_new_bell_once`
is new, recorded as U19. It is a deadline but not the budget family's
kind: those assert work finishes in 1ms or 200ms, while this asserts an
event arrives at all inside FIVE SECONDS. Folding it into that family
would blur the one distinction those rows have.

Like R1, its assertion has `Instant::now()` in hand at the panic and
reports none of it, so the margin is unrecoverable and a future
occurrence will not be comparable to this one. That is the second place
in this codebase where the same omission costs the same thing.
2026-08-31 19:47:09 +02:00
Levi Neuwirth 7ce03018f8
docs(ci-reds): R7 has TWELVE occurrences --- absorb the two owed ones
`docs/active-work.md` recorded two full-fragment R7 occurrences from
2026-08-15 (logs 20260815T095532Z and T100719Z, `attach.rs:1728`) under
a heading saying they were "owed to the registry by whichever branch
merges second". Both branches merged. Nothing carried them across, and
they sat there for sixteen days, so R7's count read two low even after
yesterday's renumbering.

With those absorbed and the duplicate "fourth" fixed, the sequence is:
August 29 = ninth and tenth, August 30 = eleventh, August 31 = twelfth.
The parse-budget lane block, which still said sixth and seventh, is
updated too.

The deferral itself was reasonable --- this file has been bitten by two
branches inventing the same row id --- but not discharging it was not.
The lesson recorded is narrower than "absorb faster": an entry parked
under "owed to the registry" needs an owner named in the same sentence,
or it belongs to nobody.

The summary cell's line-specific claim was also incomplete: occurrences
one through FOUR report `attach.rs:1680`, not the first three.

And U18 over-corrected. `GONOSUMDB` is a real Go variable ---
`go help environment` documents `GOPRIVATE, GONOPROXY, GONOSUMDB` as
module prefixes "that should not be compared against the checksum
database", which is exactly the step that failed. It is technically
applicable; whether the authentication tradeoff is acceptable is a
different question. Discarding a real knob while correcting an invented
one is its own error and is recorded as one.
2026-08-31 19:40:57 +02:00
Levi Neuwirth 28c2ad4463
docs(ci-reds): renumber R7 by date, and five corrections
R7 carried TWO blocks numbered "fourth" --- D3 on 2026-08-11 and TMPDIR
isolation on 2026-08-13 --- so every later ordinal was one low. The new
red is R7's TENTH, not its ninth. Renumbered by date, with the duplicate
recorded in the status cell rather than silently fixed. The summary cell
said "three occurrences" and now states the total, keeping the
`attach.rs:1680` fact as the line-specific claim it always was.

U9's selector was named wrong in yesterday's correction. The row names
the CANONICAL pty test (`src/process.rs:3967`), not
`raw_mode_disables_kernel_echo` (`:3945`) --- and U9's own "relation to
U2" cell turns on exactly that distinction, so getting it backwards
would have undercut the row the paragraph was correcting.

The arithmetic was still wrong in two places. There are 121 result lines
and the doc-test groups are numbers 120 and 121, not 121 and 122; and
U9's table cell still asserted the strict 119-to-121 alternation that
the paragraph below it retracts.

U18 listed three outage options and all three were wrong. `GONOSUMCHECK`
is not a Go environment variable --- that sentence invented it.
`GOFLAGS=-mod=mod` selects module update mode and does not bypass
checksum-database authentication. And a version-suffixed `go install`
ignores vendor directories, so "a vendored gopls" needs a different
installation path. No replacement knob is named, because none was
verified.

The ledger called uncontrolled foreign load "the same evidence U9's
synthetic-load control was meant to produce" and said "U9 stays owed",
both of which contradict the correction below them. And its lane heading
said four registry rows moved while listing eight.
2026-08-31 17:26:47 +02:00
Levi Neuwirth 7d819902ff
docs(ci-reds): R7's ninth occurrence
The gate verifying the previous commit redded at `gpu` with all three of
R7's required fragments, same selector and same line. Other seven stages
green; the observing commit is documentation only.

It adds a count and nothing else, which is the honest description. The
eighth occurrence's method note says the remaining candidates must be
varied inside the gate, one per run, and that is not this lane's work.
The loadavg reading is recorded as a condition, not a cause --- R7 is
not a budget row.
2026-08-31 16:25:11 +02:00
Levi Neuwirth 65b40897bd
docs(ci-reds): fix the serial-run arithmetic, U9's scope, and add U18
Three corrections to yesterday's correction, and one new row.

The serial-binary measurement was stated as "119 Running and 121 result
lines alternate strictly", which cannot be strict --- the count itself
gave it away. Precisely: 119 ordinary targets each report before the
next starts, and the two extra result lines belong to `Doc-tests pmacs`
and `Doc-tests pmacs_protocol`, which cargo labels differently and runs
last.

The replacement premise did not describe U9 either. Both U9 selectors
live in the ROOT LIB TARGET --- `m6_1_pty_raw_mode_disables_kernel_echo`
(src/process.rs:3945) and `composition_overhead_under_ten_percent`
(src/editor.rs:9717) --- and the sweep runs that target first, finishing
it in about 12 seconds. The sweep's later minutes cannot reach them.
What survives: the sweep re-runs the lib target late in the overall gate
invocation, under unmeasured machine state.

Two stale references to U9's void control are corrected, including the
ledger's claim that a synthetic-load run would "either implicate load or
clear it". It would not: with concurrency fixed at 1 there is no second
arm, so a red shows load is sufficient and a green shows nothing.
Non-reproduction never clears anything under this file's own rerun rule.

U18 is new and a new class. `Test (ubuntu-latest / luajit)` died in
toolchain setup before any cargo command ran: `go install gopls@v0.16.2`
hit an HTTP/2 INTERNAL_ERROR from sum.golang.org while verifying
x/telemetry. Every other row here is a test that failed; this is
infrastructure the workflow depends on failing to answer, and it
presents as a red check indistinguishable from a real one.
2026-08-31 16:17:43 +02:00
Levi Neuwirth a7c4b3adec
docs(ci-reds): U9's control is VOID --- cargo runs test binaries serially
U9's "structural difference worth testing next" claimed that
`cargo test --workspace` runs many test binaries concurrently while
`--lib` runs one, and derived its discriminating control from that:
"pin test-binary concurrency to 1". The premise is false. Cargo runs
test TARGETS serially, one executable at a time, so that concurrency is
already 1 and the control pins nothing.

Measured in this project's own gate logs rather than asserted from the
cargo book: `20260831T093655Z-857818/07-sweep.log` alternates `Running`
and `test result:` strictly --- 119 to 121 markers, ZERO cases of one
binary starting before the previous reported. The pattern is `RTRTRT`.

That falsifies a premise two rows rested on, so U12's family paragraph
is corrected too. What survives is smaller and still true: a sweep is a
long sequence of binaries, so a budget inside it runs at an arbitrary
point in a multi-minute step. The family still should not consume review
rounds --- but it now needs a control someone has to design.

U17 no longer claims `--test-threads=1` exercises U9's control. It is a
different knob: it serializes test FUNCTIONS within one executable. Its
candidate mechanism is narrowed to match --- removing sibling test
functions removes ONE source of contention, which supports neither
"fastest" nor "narrowest".

R6's block drops two overclaims: a PR run CAN show the identical red
(only the main dispatch establishes it on the merge base), and this was
not the dispatch key's first use --- #245's D2/D3 dispatched three runs
right after it merged. It is the first use for a live merge-base
control.
2026-08-31 15:07:22 +02:00
Levi Neuwirth 088f24e1bb
docs(ci-reds): U16's real mechanism is child inheritance; narrow U17
Five corrections, all mine.

U16 stopped at "the window exists", which misses why restoring the cwd
does not close it. `run_git` calls `run_git_inner(None, ...)`, and that
sets `current_dir` only when `cwd` is `Some` (fetcher.rs:329-330), so
the spawned git INHERITS the parent's temporary cwd. The parent then
restores its own --- which does nothing for a child that already has its
working directory --- and the TempDir drops underneath it. The restore
is not merely too early; it is irrelevant to the child.

U16 also offered a serial guard around `set_current_dir` tests as a
structural control. That does not protect an unguarded test that spawns
a child, because the child outlives the guard. The options that work are
removing the cwd mutation, running that test in a subprocess, or
serializing the whole lib-test binary.

And U16 said 8 green runs showed the window was narrow. They do not.
Non-reproduction establishes intermittence and nothing else; nothing
here has sized this candidate's window.

U17 claimed no PR run can show its failure. A PR run exercises the same
test and could fail identically; what only a main-side run establishes
is that it fails ON MAIN, with no observing branch to suspect. And its
`got ok` does not prove the supersede arrived late --- it proves the
predecessor completed successfully before cancellation took effect,
which a timely supersede whose cancellation lost the race produces
identically.
2026-08-31 11:36:49 +02:00
Levi Neuwirth 4aa3853ebe
docs(ci-reds): R6 recurs with fragments, and its control finds U17 on main
The macOS lua54 leg redded on PR #246 with
`acc28_child_input_and_the_c_c_escape_work_unchanged_in_a_panel`. It is
a full three-condition match for R6 --- selector, flavor, and BOTH
required fragments (`timed out waiting for` + `/ready`) --- 26 days
after the first occurrence.

The log was read BEFORE anything was rerun. U3 named that lesson and U8
recorded its fourth violation; this is the first time it was followed on
a macOS job at the moment it mattered, and the fragments exist because
of it.

Rather than argue from an unrelated diff, a merge-base control was
dispatched at `aae5b35` --- the first real use of the
`workflow_dispatch` key #245 landed, and exactly the case U11 motivated
it for. The macOS legs came back GREEN, so the inference the control
could have supplied is unavailable. Recorded as a null result, the way
R1's row had to record its own. What each outcome would mean was written
down before the result was seen.

The control was not otherwise clean: `Test (crdt)` failed on `main`,
which is U17. It fails the opposite way to R1 and R5 --- not a missed
deadline but a predecessor that had already completed --- and the job
runs `--test-threads=1`, the condition U9's still-unrun control names. A
red on the merge base is invisible to any PR run.
2026-08-31 11:28:11 +02:00
Levi Neuwirth e87d22796d
docs(ci-reds): U16 --- a git invocation with a deleted working directory
The sweep step redded on `cache_survives_across_fetcher_instances` with
`fatal: Unable to read current working directory`. Not a budget test,
and not a load story.

It is the only row in this file that arrives with a named candidate
mechanism inside the test suite. `src/file_io.rs:434` calls
`std::env::set_current_dir` --- process-global state --- inside a test
running in one of libtest's parallel threads, points it at a `TempDir`,
and lets that `TempDir` drop. Every other test in the binary shares that
cwd for the window, and after the drop it is a deleted directory, which
is exactly what git reported.

Recorded as a candidate with a citation, not a demonstrated chain: 8
full parallel `--lib` runs did not reproduce it, which says the window is
narrow rather than absent. The row names the two controls that would
settle it and runs neither --- the structural fix is `file_io`'s, not a
CRDT invariant lane's.
2026-08-31 10:37:23 +02:00
Levi Neuwirth 169ea1892c
docs(ci-reds): four subsystems, and U7 already had a load number
Two precision errors, both mine.

U14 said "four selectors in three unrelated subsystems". They are four:
the async runtime, the optimistic-echo orchestrator, editor composition,
and the LSP dispatch seam. U6's own row treats its two selectors as
unrelated subsystems, so the `04-lib-crdt` pair is two of the four here,
not one. The `what is NOT` row said three as well.

U15 claimed to be the load number "U6 and U7 have each wanted since
2026-08-09". Half of that was wrong: U7 has carried a load average
(12.9 / 23.9) in its job/flavor field since that date. What U7 records
as unmeasured is narrower --- whether the shared `CARGO_TARGET_DIR` and
its sibling builds PRODUCED that load. So 34.04 is the first
contemporaneous reading for a U6 occurrence and a second data point
beside U7's, not the registry's first. The row title oversold it too.

U15's disposition list also omitted U15.
2026-08-31 10:30:15 +02:00
Levi Neuwirth dd3f3db839
docs(lane): name every gated head, not just the last one I wrote down
The gate line named `2c24303` while the branch head was `6ddce0f` ---
the same staleness review caught one round earlier, when it named
`db24ae3`. Naming one commit reproduces the defect on the next commit.

It is a table now: one row per gated head, so the next update adds a row
instead of rewriting a sentence, and the staleness is stated rather than
waiting to be found again.
2026-08-30 22:50:46 +02:00
Levi Neuwirth 6ddce0ff29
docs(ci-reds): split U15 out of U14, and stop overstating the load
Three corrections, all mine, all caught in review.

U14 claimed a second occurrence for a run whose selector set had
ROTATED --- `full_buffer_summary_flatten` and `dired_renders_10k_entries`
in place of `grep_supersede` and `acc34_purge`. This file's own matching
rule requires the exact selectors to match, so that is a new incident.
It is now U15. The `04-lib-crdt` pair the two runs share is recorded
where it belongs, as U6's own occurrence; U6 goes from one occurrence to
five, four of them on 2026-08-30.

U14 also said "three unrelated tests". There are four selectors.

And the load claim went too far. `/proc/loadavg` was read once, after
the second run, so there is no series to correlate against; the margins
are not monotonic (`composition_overhead` ran 1.182x, 1.592x, 1.527x,
and reports two different values within the second run); and an earlier
version said a load average of 34 "explains it without any help". What
34.04 establishes is severe unrelated load present CONTEMPORANEOUSLY
with one multi-red run --- a measured confound, not a measured cause.
That is still worth more than U6 and U7 have had since August, and it is
worth exactly that much.

The lane block also still carried the withdrawn "opposite way to R7"
claim and named `db24ae3` as the gate head. It now names `2c24303` and
log 20260830T193305Z-4167110.
2026-08-30 22:19:03 +02:00
Levi Neuwirth 2c2430332e
docs(ci-reds): U14 gains the number U6 and U7 have wanted since August
The gate redded again in the same three stages, with a partly rotated
selector set --- one of them being a U7 selector. This time
`/proc/loadavg` was read at the failure: 34.04, with the CPU saturated
by an unrelated `lean` workload on this shared machine and no cargo,
rustc or gate process of mine left running.

U6 and U7 have each recorded, since 2026-08-09, that the load confound
"was not measured, so it is a rival explanation, not a finding." It is
measured now, and the margins move with it monotonically across three
runs of one unchanged tree: 1.343883ms, then 1.689259ms, then
2.269247ms, against a 1ms budget. A regression does not get 69% worse
between two runs of the same tree.

This retires nothing. The budgets are still wall-clock assertions whose
measurement design nobody has defended --- R1's disposition, applied to
five more tests. What changes is that "one loaded machine" is now a
measured explanation rather than a plausible one.
2026-08-30 20:04:58 +02:00
Levi Neuwirth ff9e1cbf0b
fix(crdt): allow match_same_arms, and record why the gate missed it
The enumeration is the contract. Clippy's `match_same_arms` would
collapse the three `Ok(())` rows into one alternation, which is exactly
the conflation this lane exists to remove --- it would stop the table
from showing that `(forward, empty, None)` and `(history, empty, Some)`
are valid for OPPOSITE reasons.

The lint reached CI rather than the gate because the gate's clippy step
runs default features, so `#[cfg(feature = "crdt")]` code is never
linted locally. Five consecutive green gate runs could not see it. The
gap is recorded in the ledger; fixing it means adding a second clippy
flavor to shared gate infrastructure, which is its own lane.
2026-08-30 19:56:50 +02:00
Levi Neuwirth e0fcfe3e9b
docs(ci-reds): U14, and U6's direction claim withdrawn within the hour
The gate run verifying revision 5 redded three unrelated tests in three
stages: a 50ms supersede budget in `lib`, U6's pair in `lib-crdt`, and
an LSP readiness race in `sweep`. Recorded as U14, because the
co-occurrence is the signature --- three subsystems failing in one run
is far less likely than one loaded machine, and no selector reds twice.

It also falsifies something I had committed an hour earlier. U6's
second-occurrence block said the row "runs the OPPOSITE way to R7",
resting on both failures being out of gate while `04-lib-crdt` was green
in four gate runs. The next gate run redded `04-lib-crdt` with exactly
that pair. Four green stages were a run of four, not a property. The
claim is withdrawn in place rather than edited away, and U6's status
moves to a third occurrence: three in one afternoon, twice out of gate
and once in.

U14 also declines an R1 match it could have claimed. The `lib` failure
carries R1's required fragment but a different selector, and this
registry matches on both. Worth noting separately: the sibling test
already reports the elapsed value R1's row records as missing from its
own assertion --- the cheap half of what R1 defers is written next door.
2026-08-30 19:28:10 +02:00
Levi Neuwirth 099b5a7383
docs: narrow R7's causal claim, and record U6's first reproduction
R7's eighth-occurrence write-up said the gate's ambient root, TMPDIR and
cross-stage process state were "now the only place the difference can
be". That is wrong. The paired runs exclude the SOURCE TREE and nothing
else: scheduler load, kernel and socket timing, page cache pressure and
whatever else the machine was doing also varied between them, and a
BrokenPipe on a socket handshake is exactly what those can drive. The
three remain the candidates worth varying one at a time --- because they
are the ones this project can vary --- not an exhaustive causal set.

U6 gained a second occurrence, and for the first time it REPRODUCED:
both selectors, both fragments, two consecutive runs. Margins recorded
per U11's lesson --- 1.343883ms against 1ms, and 1.182x against 1.10x.

Its asymmetry runs the opposite way to R7's: both failures were out of
gate, while the same command as `04-lib-crdt` was green in all four of
this lane's gate runs. Whatever the two rows share, it is not a
direction.

Framing revision 5 and the lane block are updated to match, including
the stale "AWAITING APPROVAL. Nothing implemented." header and the gate
line that named a commit the branch had already moved past.
2026-08-30 19:19:35 +02:00
Levi Neuwirth b3c90a7949
fix(crdt): enumerate the invariant over three axes, not two
Review found the predicate conflating the two things this lane exists to
separate. It called every empty-range/zero-insertion edit `version_only`
and then accepted `(History, empty, None)` through a wildcard arm ---
which contradicts the lane's own ruling that the op must survive, and
contradicts the public contract's "carries Some, and must".

The rule is now a full enumeration over provenance x text delta x
crdt_op. An EMPTY TEXT DELTA is a shape, not a verdict: both paths reach
it, and `crdt_op` is what separates them.

  forward + empty + None   valid, a syntactic no-op
  forward + empty + Some   invalid, the original bug
  history + empty + Some   valid, a version-only edit
  history + empty + None   invalid, the version advance is gone

C5 asserts all four rather than two. Both new quadrants were
mutation-checked and both fire; neither is caught by the proptest,
because no generated input reaches either --- which is the same reason
C5 was a directed injection to begin with.

The public `Edit` doc was also factually false. It said forward
`apply_edit` never produces the empty-delta shape while C2b proves all
three forward empty forms do. It now names the shape and says which path
yields which `crdt_op`.
2026-08-30 19:19:35 +02:00
Levi Neuwirth c597f9c3e4
docs(ci-reds): R7's eighth occurrence, and the pair that discriminates
Two consecutive gate runs on one worktree, minutes apart. Heads differ
by a single commit touching a single markdown file. The first was all
eight stages green; the second redded at `gpu` with all three of R7's
required fragments, and at `sweep` with the same single test.

The fifth occurrence excluded the observing tree relative to `main` by
having a documentation-only diff. This pair excludes it relative to the
immediately preceding GREEN RUN OF THE SAME GATE on the same worktree,
which is strictly sharper --- whatever varies across that green/red
boundary, it is not the source tree.

No ratio is claimed from it. Folding verification gates into the
2026-08-29 window is exactly the drift that window was bounded against.
Five isolated selector runs were green, which per this file's own rerun
rule and the seventh occurrence's correction establishes intermittence
and excludes nothing.
2026-08-30 18:08:19 +02:00
Levi Neuwirth 96bf2c3dfd
docs(lane): the identity-undo lane is taken, and corrects its own block
The block claimed the fixture had verified that "replicas stay converged
--- the op IS broadcast". That was inspection of the call sites, not
execution: nothing had ever replayed the op on a replica, and text
equality alone cannot see a lost version advance. It also called the
buffer-end range location "genuinely arbitrary either way"; the census
rules it, and finds it weakly preferable.

Both corrections are recorded in place rather than quietly dropped,
along with what each review round caught and the two mutation
asymmetries the framing asserts.
2026-08-30 17:56:05 +02:00
Levi Neuwirth db24ae3010
fix(crdt): key the crdt_op shape invariant on provenance
`undo_crdt_mode` and `redo_crdt_mode` diff two ropes. When the operation
being inverted was an identity replace, those ropes are equal, so the
derived edit has an empty range and zero insertion — while still
carrying the `crdt_op` that `crdt.undo()` produced. The proptest read
that shape as "a no-op edit with an op" and redded.

The behaviour is right; the invariant was mis-scoped. It now takes
`(OperationClass, &Edit)`:

- a FORWARD version-only edit must carry no op, unchanged in strength
  and still unreachable, because the three syntactically empty `EditOp`
  forms short-circuit at `is_no_op_edit` before the CRDT path exists;
- a HISTORY version-only edit may carry one, and must, or the version
  advance the replicas need is lost.

Implements `docs/crdt-identity-undo-framing.md` revision 4, C1-C9.

The two contracts worth naming here:

C3 replays the history op on a REMOTE replica seeded with the forward
ops, asserting materialized text AND version vector. Text alone does not
discriminate: dropping the op leaves the text identical. The existing
round-trip proptest excludes history ops precisely because replaying one
onto an unseeded replica is ill-posed; seeding is what makes this well
posed.

C4 is three witnesses because the obvious one is vacuous. C4a counts the
broadcast, since "unchanged" is also what a missing broadcast produces.
C4b executes the census. C4c pins the style-span guard with a synthetic
INTERIOR empty edit — at the buffer end, where the real history edit
lands, deleting that guard changes nothing, so the mutant would have
survived.

Also updates the public `Edit` contract, which enumerated three shapes
and had no fourth, and the fixture's own doc comment, which presented
convergence as verified when nothing had replayed it.
2026-08-30 17:48:21 +02:00
Levi Neuwirth 5fedd15a3d
docs: frame the identity-replace undo lane
A CRDT-version delta and a text delta are independent dimensions of
`Edit`. The invariant that says otherwise was written for
`is_no_op_edit`, a forward pre-check that `undo_crdt_mode` and
`redo_crdt_mode` never reach.

Approved at revision 4, after four review rounds. What the rounds
changed, since the record is worth more than the conclusion:

- revision 2 answered the question instead of posing it, and narrowed
  what the existing fixture actually established (broadcast reachability
  is by inspection, not replay);
- revision 3 completed §4's consumer census rather than deferring it,
  and two of its results corrected the framing's own claims: `TextView`
  is not buffer-attached at all, and two consumers already carry
  explicit empty/empty guards written for other reasons;
- revision 4 replaced C9's file-set-and-count guard, which a same-file
  substitution walks straight through, with an exact `(file, impl
  target)` assertion scoped to in-tree implementations.

Three witnesses exist because a green suite is not evidence that a suite
RAN: re-ignoring a fixture (C1), dropping a loop parameter (C6), and
adding an unclassified consumer (C9) are all silent under ordinary
assertions.
2026-08-30 17:41:16 +02:00
Levi Neuwirth aae5b3514a
docs: the dispatched red is known #157, not a new defect
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
2026-08-30 14:07:31 +02:00
Levi Neuwirth 2b60895e0b
docs: discharge #245's owed witnesses, and record what the first dispatch found
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
2026-08-30 13:48:19 +02:00
Levi Neuwirth 7b82e145d2
Merge pull request #245 from levineuwirth/ci-manual-dispatch
Run CI on demand: workflow_dispatch
2026-08-30 12:42:18 +02:00
Levi Neuwirth c21eee6e49
docs(ci-reds): R1 occurrence on #245, with its merge-base control
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
2026-08-30 12:02:01 +02:00
Levi Neuwirth d9cc0fa58a
ci: run the workflow on demand, on any ref
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
2026-08-30 10:53:04 +02:00
Levi Neuwirth 2e9f62b579
docs: absorb #244 --- parse budgets report their measurement
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
2026-08-30 00:04:45 +02:00
Levi Neuwirth a85205a9f6
Merge pull request #244 from levineuwirth/parse-budget-diagnosability
Parse budgets report the measurement that failed
2026-08-30 00:04:17 +02:00
Levi Neuwirth 7b50682eac
docs(ci-reds): record empty prune-output sweep red as U13
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.
2026-08-29 22:53:36 +02:00
Levi Neuwirth 756c2b87df
docs(ci-reds): bound R7 window without misnaming its endpoint
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.
2026-08-29 19:15:41 +02:00
Levi Neuwirth 054a427e74
docs: bound R7's observation window so the tally stops re-counting itself
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
2026-08-29 18:11:02 +02:00
Levi Neuwirth acd6cee693
docs: reconcile the lane's records with its final state
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
2026-08-29 18:02:52 +02:00
Levi Neuwirth 2d769846dc
docs(ci-reds): R7 --- a third in-gate run was green, and my "exclusions" were not
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
2026-08-29 17:27:43 +02:00
Levi Neuwirth 68a16f9058
docs(ci-reds): R7 seventh occurrence, and four hypotheses excluded
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
2026-08-29 17:18:53 +02:00
Levi Neuwirth 45d438ccb3
docs(ci-reds): R7 sixth occurrence, and a gate run that is not a result
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
2026-08-29 16:59:10 +02:00
Levi Neuwirth 493e8ee36b
feat(async): parse budgets report the measurement that failed
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
2026-08-29 16:43:37 +02:00
Levi Neuwirth 355777990f
docs: absorb #243 --- panel-pointer replay is merged
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
2026-08-29 12:37:58 +02:00
Levi Neuwirth 6c9bae6948
Merge pull request #243 from levineuwirth/panel-pointer-replay
Panel-pointer replay (parent acceptance 48)
2026-08-29 12:37:10 +02:00
Levi Neuwirth b8c51b75ed
docs(panel): drop the obsolete "Q5 is owed" block
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
2026-08-28 10:39:28 +02:00
Levi Neuwirth 642f2ddd00
docs(ci-reds): U12 --- gate run 1 was 15/16, red on the budget+PTY family
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
2026-08-21 14:39:05 +02:00
Levi Neuwirth 6142acc203
test(panel): Q5 names the successor frame it orders against
`!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
2026-08-21 14:26:32 +02:00