Typing an opener inserts the closer with the cursor between; typing a
closer over its twin steps over it. Q#AP1: the nine built-in pair
chars leave both optimistic classifiers (shared charset in
pmacs-protocol) and round-trip through dispatch, so the opener and the
hook's closer are adjacent daemon-peer undo units, dispatch CUA
type-over applies, and skip never paints a transient duplicate.
Q#AP9: exact one-shot typed-edit provenance. EditorCore's
apply_active_edit now returns the effective Edit; the dispatch
fallback arms a per-frontend record (codepoint + requested vs
effective ranges + post-cursor + clean verdict) that insert primitives
complete and the daemon's optimistic CRDT arm builds directly. The
record is takeable exactly once via pmacs.editor.take_typed_edit()
during the one after-edit fan-out, then cleared — paste, programmatic
edits, manual hook runs, nested re-runs, rejected edits, and stale
this_command all observe nil, and transformed / relocated /
context-switched source self-inserts fail closed with a status.
pair.lua (loaded BEFORE lsp.lua — ordering contract in editor.rs):
per-language pmacs.pair.sets with a conservative default (no ' or `),
EOL/whitespace/closer insertion predicate, reactive skip-over-close,
rejected/transformed intercept outcomes with context-guarded
translate-and-clamp cursor repair.
Acceptance: 32 dispatch-driven cases (predicate, skip, per-language
sets, non-typed provenance incl. production-shaped paste, type-over,
undo/redo grain, intercept outcomes on both the source and reaction
edits, context-switch probe, record lifecycle, frontend isolation) +
first-didChange ordering against the fake LSP's sighelp mode via a
new PMACS_FAKE_LSP_CHANGE_SINK replay file. Six two-replica CRDT
cases pin dispatch-route convergence with cursor-between, undo/redo
walking the pair on both replicas, both mixed-history undo models as
named substrate limits, and the optimistic custom-char route
(closer-broadcast-before-opener convergence, degraded cross-peer
undo). TestDaemon gains spawn_with_config for init.lua-extended pair
sets.
Framing: docs/auto-pairing-framing.md (revision 3).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VoiEyuPjoBhvwACf8HAnLB
First milestone of the M11 semantic-frontend arc
(docs/semantic-frontend-protocol.md). Wire-format scaffolding only —
no producer or consumer; mechanically identical to the M10.5 CRDT
wire declaration, and non-breaking by the same slice-membership +
per-session-filter argument.
- PROTOCOL_VERSION 2 -> 3; SUPPORTED_PROTOCOL_VERSIONS [1,2,3]. v0.1
and v1.0 binaries keep connecting unchanged (membership, not
strict equality).
- semantic_render capability bit on FrontendCapabilities,
InstanceCapabilities, NegotiatedCapabilities (#[serde(default)];
instance default false until the M11.2 projection seam).
negotiate_capabilities AND-combines it and enforces the
semantic_render => crdt_replica dependency as a CapabilityMismatch
(a semantic session is also a text replica), never a silent
degrade. PMACS_INSTANCE_SEMANTIC_RENDER env override added.
- InstanceMessage SemanticFrame family: StyleSpans, Decorations,
InlineAdornments, BlockAdornments, FoldState, ResourceOffer.
FrontendEvent::Viewport. Supporting types: ByteRange, StyleSpan,
Decoration/DecorationKind, InlineAdornment/AdornmentPlacement/
AdornmentContent, BlockAdornment, ResourceBody. All byte-anchored;
no pixels cross the contract boundary.
- Grid TUI (frontend.rs) and daemon apply_event drop the new family
silently — the "declared, not yet wired" posture CrdtOp held
between M10.5 and M10.8. Stale v1.0 version-pin tests updated to
the v1.1 truth; negotiation matrix + postcard round-trips added.
Lib + integration suites green on both the default and crdt feature
flavors; clippy -D warnings clean on both.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Post-ship-gate completion of M10.10 (optimistic local edit
application, Path β). The milestone core landed in 45be65b
"M10.10 ship gate"; this commit completes the frontend keystroke
path and absorbs Day-5 corrections.
Completes:
- optimistic::frontend_event_for_keystroke — keystroke orchestrator
(classify_key predicate → mirror-ready check → CrdtOp or Key
fallback per Refinement 4 graceful degradation).
- BufferMirror cursor tracking (active_buffer, cursor_byte_pos via
CursorByte) + char-boundary-aware delete helpers (prev/next_char_len)
so multibyte backspace/delete don't trip loro's mid-codepoint
rejection.
- buffer.rs: crdt_state accessor (was test-only) now production —
daemon's BufferSnapshot export path uses it.
Day-5 corrections:
- packages/manifest.rs: fix pre-existing M8-era proptest generator
that produced ".."-containing entry paths the parser correctly
rejects (segment-structured regex; stale regression seed removed).
Out of M10.10 scope; absorbed so future milestone sweeps see clean
output instead of a known-failing test requiring prose.
- tests: extract inline PTY/daemon helpers to shared tests/common/
module (m5_5, m5_8 now import; no coverage change — m5_5 retains
19 m10_10 tests). tests/common/ added (required for compilation).
Audit history (M10.10-AUDIT.md is gitignored internal-only; this
message is the sole version-controlled record):
M10.10 PASSES within Path β scope (end-of-line optimistic visual
paint; mid-line/delete-forward round-trip; full CRDT-op exchange
across the text-input scope). The initial audit verdict was WRONG —
optimistic-apply was structurally unreachable in the production
binary (build_capabilities advertised crdt_replica: false). Six
post-audit review rounds surfaced 28 findings (F5–F32) beyond the
framing pass's original 4. Six M10-era discipline additions emerged,
each empirically grounded: end-to-end-exercise check (bidirectional
scope), composition-consistency check, verification-milestone premise
check, library-API verification check, forward-pointer-comment
hygiene, methodology-composition check.
Scorecard adopts Option C dual methodology: layer (a) framing-pass
accuracy is 7/8 milestones-not-findings AND 2/8 findings-as-failures
— the 5/8 spread is the density diagnostic (M10.10's defining
characteristic; neither number alone is honest). Layer (c): 7/8 and
6/8 (M10.8 inherited-gap cluster). Budget honesty: 5-day
pre-authorization covered anticipated implementation surprises (K1,
Risk #6 a); Finding 3 was a third surprise absorbed via compression,
not structural slack; the six post-audit rounds were entirely
unbudgeted and are the milestone's dominant cost. M10.10's density
is partly forecastable — it is the only M10 milestone with all three
of: architectural reversal, multi-milestone integration, and
verification depending on incomplete cross-milestone wiring.
Ship-gate clean on clean checkout (cargo clean + rebuild): luajit+crdt
1364/1364, luajit 1211/1211, lua54+crdt 1364/1364, lua54 1211/1211,
m5_5 daemon-e2e 36/36, perf 1MB=1.1ms vs 10ms gate, clippy 0 across
feature combos, fmt clean. One transient flake observed
(async_runtime::supersede_cancels_in_flight_job_within_50ms — timing
test starved under concurrent compile load, non-reproducible in
isolation, known infra pattern, not an M10.10 regression).
Next: M10.11 (two-laptop acceptance) inherits all six discipline
additions; v1.0 ships after M10.11.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>