fix(panel): a second press ends the gesture it replaces
Found by reading the arming path back after the G5 checkpoint, not by a failing row. `arm_accepted_gesture` overwrote an already-armed latch, so a dropped `Up` --- one lost to an outbox that closed under a stall --- was followed by the next press silently discarding the first gesture's record, without counting it as a cancellation. Inert on this base, where records are only counted. Once `panel-pointer-replay` attaches a child release to each record, the discarded one leaves a button held down with nothing left to release it, and the arming code that decides this is this slice's. Mutation: restore the plain overwrite -> the new row alone. Also records three CI-red observations from the slice-completion gate, which is the first entry on this lane with a MEASURED confound instead of the standing uncontrolled one. Three wall-clock-deadline rows red in one run --- criterion_1 by 0.12%, a PTY lifecycle race, and a 5s child -exit deadline --- all green in isolation, the last in 0.15s against its 5s deadline. `uptime` during the run went 14.02 -> 28.35, from an unrelated turso test suite on the same machine with one binary at 693% CPU. Not a controlled experiment, but the same evidence U9's synthetic -load control was meant to produce, and it points at load. Two process traps are recorded with them, because both were made here. The Bash tool caps a command at ten minutes and SIGTERMs it, which the gate reports as `FAILED (exit 143)` on whatever stage was running and which reads exactly like a real failure. And `pkill -f <pattern>` kills the invoking shell when the pattern appears in its own command line, so the intended target survives while the operator believes it died --- and here `pkill -f "cargo test"` would have destroyed an unrelated project's build. Identify by PID. Verified: `cargo fmt --check`; `cargo clippy --workspace --all-targets -- -D warnings`; the four §5b G5 rows. The full protocol gate follows on a quieter machine; the run described above is not evidence for this tree and is recorded as an observation only. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
This commit is contained in:
parent
419b078c0f
commit
bf4ffe0995
|
|
@ -287,7 +287,12 @@ from #171 and #215.
|
||||||
half (G1–G4), outbound family selection, inbound family gating, the
|
half (G1–G4), outbound family selection, inbound family gating, the
|
||||||
GPU's negotiated family enum, and the nine family-gate rows
|
GPU's negotiated family enum, and the nine family-gate rows
|
||||||
(G6a–b, G7a–b, G8). **Full `--protocol` gate green at `3c06176`.**
|
(G6a–b, G7a–b, G8). **Full `--protocol` gate green at `3c06176`.**
|
||||||
In progress since, uncommitted: G5's accepted-gesture latch.
|
Then three more: G5a's trigger and its latch, the wheel exemption
|
||||||
|
with exhaustion and mapped coalescing, and the receiver rows.
|
||||||
|
**Every row this slice owns is now witnessed** — G0, G1–G4a, G5a plus
|
||||||
|
latch substrate, G6–G8, G9a–c, G10/G10a–c, G11a, G13a–b, G14a–b, G15
|
||||||
|
— with G4b, G5b–e/g/i–p, G6c, G7c, G11b and G12a–b left to the replay
|
||||||
|
lane per §5b's split table.
|
||||||
- **PROTOCOL-BEARING — v25, and it runs alone.**
|
- **PROTOCOL-BEARING — v25, and it runs alone.**
|
||||||
`ADVERTISED_PROTOCOL_VERSION` stays pinned at **20**.
|
`ADVERTISED_PROTOCOL_VERSION` stays pinned at **20**.
|
||||||
- **Why it exists.** A `PanelPointer` names a cell and nothing on the
|
- **Why it exists.** A `PanelPointer` names a cell and nothing on the
|
||||||
|
|
@ -465,6 +470,35 @@ from #171 and #215.
|
||||||
(2026-08-15, plain `cargo test --lib`, not a gate step). Isolated
|
(2026-08-15, plain `cargo test --lib`, not a gate step). Isolated
|
||||||
rerun green. Same budget as the occurrence above, now seen in two
|
rerun green. Same budget as the occurrence above, now seen in two
|
||||||
different selectors on one branch in one day.
|
different selectors on one branch in one day.
|
||||||
|
- **Three wall-clock-deadline rows red in ONE run, under a MEASURED
|
||||||
|
foreign load** (2026-08-16, log `20260816T063330Z`). Steps
|
||||||
|
`04-lib-crdt` and `09-sweep-crdt`. Fragments:
|
||||||
|
`criterion_1_end_of_line_typing_completes_sub_frame_per_keystroke`
|
||||||
|
— "per-keystroke orchestrator time **1.001196ms** exceeds 1ms",
|
||||||
|
**0.12% over**, the smallest margin any budget on this lane has
|
||||||
|
failed by; `m6_1_pty_mode_lifecycle_started_then_exited` — "must
|
||||||
|
observe stdout 'done'"; and
|
||||||
|
`ctrl_c_on_launcher_group_does_not_reach_spawned_daemon` — "child
|
||||||
|
did not exit within 5s". All three green in isolation, the last in
|
||||||
|
**0.15s against its 5s deadline**, a 33x margin.
|
||||||
|
- **This is the first entry on this lane with a NAMED confound rather
|
||||||
|
than the standing uncontrolled one.** `uptime` during the run:
|
||||||
|
load average **14.02 → 28.35**, from an unrelated `turso` test
|
||||||
|
suite on the same machine (`./verify_task_state.sh
|
||||||
|
turso-without-rowid`, target dir `/opt/target`, one test binary at
|
||||||
|
**693% CPU**). It is not a controlled experiment, but it is the
|
||||||
|
same evidence U9's synthetic-load control was meant to produce, and
|
||||||
|
it points at load. U9 stays owed; its value is now lower.
|
||||||
|
- **Two process traps this cost, both worth carrying forward.** The
|
||||||
|
Bash tool caps a command at 10 minutes and SIGTERMs it, which the
|
||||||
|
gate reports as `FAILED (exit 143)` on whatever stage was running —
|
||||||
|
indistinguishable from a real failure in the summary line. Run the
|
||||||
|
protocol gate under `setsid` and watch the log. And `pkill -f
|
||||||
|
<pattern>` kills the invoking shell when the pattern appears in its
|
||||||
|
own command line, so the intended target survives and the operator
|
||||||
|
believes it died. **Both mistakes were made here**; the second
|
||||||
|
nearly killed an unrelated project's build, because
|
||||||
|
`pkill -f "cargo test"` would have matched it. Identify by PID.
|
||||||
- **Three consecutive full-gate runs, three DIFFERENT unrelated
|
- **Three consecutive full-gate runs, three DIFFERENT unrelated
|
||||||
failures** (composition budget in `04-lib-crdt`, then composition
|
failures** (composition budget in `04-lib-crdt`, then composition
|
||||||
again in `10-sweep-crdt`, then this in `08-sweep`), against a diff
|
again in `10-sweep-crdt`, then this in `08-sweep`), against a diff
|
||||||
|
|
|
||||||
|
|
@ -2497,6 +2497,47 @@ Two consequences are recorded rather than fixed:
|
||||||
later and leaving that one out would be an inconsistency inside a
|
later and leaving that one out would be an inconsistency inside a
|
||||||
single function rather than a clean deferral.
|
single function rather than a clean deferral.
|
||||||
|
|
||||||
|
#### What the slice actually landed, row by row
|
||||||
|
|
||||||
|
Recorded because the split table above states the *intent*, and a
|
||||||
|
reader auditing this later needs the *outcome* — including the two
|
||||||
|
places where writing the witnesses changed the design.
|
||||||
|
|
||||||
|
**Landed here:** G0 (wire shapes, positions, field order, accumulated
|
||||||
|
pins), G1–G4a (the authoritative key, document and terminal halves),
|
||||||
|
G5a plus the latch substrate, G6a–b/G7a–b/G8a–e (both directions, all
|
||||||
|
four wrong-family quadrants, forged identity), G9a/G9b/G9c, G10 and
|
||||||
|
G10a–c, G11a, G13a–b, G14a–b, G15.
|
||||||
|
|
||||||
|
**Still the replay lane's**, unchanged: G4b, G5b–e, G5g, G5i–p, G6c,
|
||||||
|
G7c, G11b, G12a–b.
|
||||||
|
|
||||||
|
Two corrections the mutation pass forced, both of which had passed
|
||||||
|
their first review as written:
|
||||||
|
|
||||||
|
- **G10a proved nothing about zero.** Asserted with a generation
|
||||||
|
already held, zero is also *lower* than it, so the nondecreasing
|
||||||
|
clause did the refusing and deleting the zero check left the row
|
||||||
|
green. Zero is only isolable before any authority exists — which is
|
||||||
|
also the case the framing names, a sender that never initialised the
|
||||||
|
field. Split into its own row with that setup.
|
||||||
|
- **G11a's exhaustion latch had no proven job.** The overflow path
|
||||||
|
already returns before storing the ceiling snapshot, so the next read
|
||||||
|
re-takes the changed arm and the band stays down without any latch.
|
||||||
|
Measured, the two are alternatives: only removing both resurrects the
|
||||||
|
band. The latch is kept, and now earns its place through `peek`,
|
||||||
|
which honours it so the peek and the authoritative read agree that an
|
||||||
|
exhausted session has no key rather than reporting the ceiling.
|
||||||
|
|
||||||
|
One witness-shape note, since it recurs: the two G10b rows call
|
||||||
|
`panel_mapping_is_current` directly. A wheel has **no
|
||||||
|
dispatcher-visible effect on this base** — a document panel focuses on
|
||||||
|
`Down` only, and no panel pointer coordinate is consumed anywhere — so
|
||||||
|
a row asserting focus for a wheel would be green whatever the gate did.
|
||||||
|
Each row carries a press leg alongside, which does have an effect, to
|
||||||
|
show the predicate is wired into the production arm rather than merely
|
||||||
|
correct in isolation.
|
||||||
|
|
||||||
### Coherence impact (`COHERENCE.md` §20)
|
### Coherence impact (`COHERENCE.md` §20)
|
||||||
|
|
||||||
- **Journey steps touched: 5** (document-panel editing and selection)
|
- **Journey steps touched: 5** (document-panel editing and selection)
|
||||||
|
|
|
||||||
|
|
@ -7189,6 +7189,60 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// §5b — SUBSTRATE: a second accepted press ENDS the gesture it
|
||||||
|
/// replaces rather than overwriting it.
|
||||||
|
///
|
||||||
|
/// Found by reading the arming path back, not by a failing row: a
|
||||||
|
/// dropped `Up` — one lost to a closed outbox under a stall — is
|
||||||
|
/// followed by the next press, and a plain overwrite discards the
|
||||||
|
/// first gesture's record without counting it. Inert on this base,
|
||||||
|
/// where records are only counted; once replay attaches a child
|
||||||
|
/// release to each record, the discarded one leaves a button held
|
||||||
|
/// down with nothing left to release it.
|
||||||
|
#[test]
|
||||||
|
fn g5_substrate_a_second_press_ends_the_gesture_it_replaces() {
|
||||||
|
let fid = FrontendId(777);
|
||||||
|
let (mut editor, mut semantic_states, mut render, _document, panel, epochs) =
|
||||||
|
panel_session_at(PROTOCOL_VERSION, fid);
|
||||||
|
let buffer_id = editor.core.borrow().windows[&panel].buffer_id;
|
||||||
|
let generation = stamped_generation(&semantic_states, fid);
|
||||||
|
let press = || mapped_pointer(fid, epochs, buffer_id, generation);
|
||||||
|
|
||||||
|
dispatch_panel_event(
|
||||||
|
&mut editor,
|
||||||
|
fid,
|
||||||
|
PROTOCOL_VERSION,
|
||||||
|
&mut semantic_states,
|
||||||
|
&mut render,
|
||||||
|
press(),
|
||||||
|
);
|
||||||
|
assert!(semantic_states[&fid].has_accepted_gesture());
|
||||||
|
assert_eq!(
|
||||||
|
semantic_states[&fid].panel_gesture_cancellations(),
|
||||||
|
0,
|
||||||
|
"fixture: the first press cancels nothing"
|
||||||
|
);
|
||||||
|
|
||||||
|
// The `Up` never arrives; the next press does.
|
||||||
|
dispatch_panel_event(
|
||||||
|
&mut editor,
|
||||||
|
fid,
|
||||||
|
PROTOCOL_VERSION,
|
||||||
|
&mut semantic_states,
|
||||||
|
&mut render,
|
||||||
|
press(),
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
semantic_states[&fid].has_accepted_gesture(),
|
||||||
|
"the new gesture is armed"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
semantic_states[&fid].panel_gesture_cancellations(),
|
||||||
|
1,
|
||||||
|
"and the one it displaced was ENDED, not dropped on the floor"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// §5b — SUBSTRATE for the framing's G5p: per-frontend gesture
|
/// §5b — SUBSTRATE for the framing's G5p: per-frontend gesture
|
||||||
/// ownership.
|
/// ownership.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -728,6 +728,13 @@ impl SemanticRenderState {
|
||||||
/// per §5b's split table, because the release it denies does not
|
/// per §5b's split table, because the release it denies does not
|
||||||
/// exist on this branch.
|
/// exist on this branch.
|
||||||
pub fn arm_accepted_gesture(&mut self, gesture: AcceptedPanelGesture) {
|
pub fn arm_accepted_gesture(&mut self, gesture: AcceptedPanelGesture) {
|
||||||
|
// A second accepted press while one is already armed means the
|
||||||
|
// first gesture's release never arrived — a dropped `Up`, or an
|
||||||
|
// outbox that closed under a stall. END it rather than
|
||||||
|
// overwrite it: overwriting discards the record silently, and
|
||||||
|
// once replay attaches effects to that record the child is left
|
||||||
|
// holding a button down with nothing left to release it.
|
||||||
|
self.cancel_accepted_gesture();
|
||||||
self.accepted_gesture = Some(gesture);
|
self.accepted_gesture = Some(gesture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue