Commit Graph

252 Commits

Author SHA1 Message Date
Levi Neuwirth 821835b8c5 Frame one-command GPU invocation broker
Record the approved managed-launch contract, daemon lifecycle and process-group rules, strict GPU CLI behavior, headless acceptance seam, and the complete acceptance matrix before implementation.
2026-07-23 09:51:22 -04:00
Levi Neuwirth e316ba3a27 docs: record Vterm Stage 3 landing
Advance canonical state to protocol v19, close the Vterm lane and roadmap arc, preserve the cross-PR integration lesson, mark PR #91 landed, and point machine-local housekeeping at the durable policy.
2026-07-22 19:54:14 -04:00
Levi Neuwirth 27120e7540 docs(vterm): record the deleted framing/tab-width branches
vterm-stage3-framing (superseded; content carried on vterm-gpu) and
tab-width-parity (merged via #137) were deleted with authorization —
worktree + local ref + githubsucks ref, origin tracking pruned. The
-framing branches for each are kept. Retires the now-dangling
superseded-lane recovery entry.
2026-07-22 19:13:02 -04:00
Levi Neuwirth 3c4d969aba Merge canonical main into vterm stage 3
Integrates canonical `main` @ 2625ec7 after PR #137 (tab-width parity)
merged. The agreed order was #137 first, this lane second: #137 was
approved and FROZEN at 5b23e11, and "frozen" is incompatible with
"rebase onto the resulting main" — landing it second would have broken
its freeze and voided its approval.

Integrated by MERGING main into the branch rather than rebasing, matching
repo precedent (Merge canonical main into vterm-tui, ... into modeline
detection). A rebase would have force-pushed away the review anchors on
the two completed review rounds of #135.

Main had also moved past this lane's base by #133/#134/#136, so the
integration surface was wider than the #135/#137 overlap: src/
semantic_render.rs was a fourth overlapping code file. It auto-merged, as
did pmacs-protocol/src/lib.rs. The single code conflict was the
pmacs_protocol import list in pmacs-gpu/src/main.rs — TAB_STOP_COLUMNS
against the terminal types — resolved as a union.

The feared semantic collision did not occur, and this is verified rather
than assumed: terminal cell geometry still uses the monospace advance and
never TAB_STOP_COLUMNS. pmacs-gpu/src/terminal.rs references neither the
constant nor display_width, and terminal_cell_viewport / terminal_run_rect
/ hit_test_cell derive from mono_advance() and code_line_height() alone.
That separation is correct by construction: a terminal's columns come
from the child, while tab expansion is a document projection concern.

Doc conflicts resolved toward landed state: the tab-width lane moves to
"Closed since the last snapshot", the #135/#137 coordination section is
kept as a resolved worked example, and the Arc 5 lines in the roadmap and
handoff now read "implemented and in review". While resolving, restored a
clause main had dropped from the handoff's injection-follow-ups list
("literals, doc-comment code);"), keeping main's strikethrough-and-SHIPPED
convention for the modeline entry.

Post-integration gates, from a clean tree: cargo fmt --check; strict
workspace clippy; pmacs-protocol 17; cargo test --lib 1,768; --features
crdt 1,944 (3 ignored each); vterm Stage 1 9/10, Stage 2 4/4, Stage 3
5/7, statusline 7/8, tab-width 2/2 (default/CRDT); M4 121 passed (3
ignored, 1 filtered); required GPU 139; workspace sweep 2,946 passed
across 84 suites (19 ignored), one invocation; git diff --check clean.
2026-07-22 17:39:58 -04:00
Levi Neuwirth 3618289633 docs(vterm): record the #135/#137 rebase-and-regate constraint
PR #137 (tab-width-parity) is approved and frozen at 5b23e11. Neither
lane copies from or merges the other; whichever lands second rebases
onto the canonical resulting main and reruns the complete gate suite.

The overlap is pmacs-gpu/src/main.rs, pmacs-protocol/src/lib.rs,
Cargo.lock, and the two ledger docs. The lock and docs are mechanical;
the two source files are not — both PRs edit the GPU renderer's
measurement path and widen the protocol crate's export surface in the
same region, so a conflict-free apply is not evidence of a correct
merge.
2026-07-22 15:36:51 -04:00
Levi Neuwirth 9ff6a62623 fix(vterm): address stage 3 review round 2
One real defect, three cleanups, and a named deferral.

A daemon disconnect in terminal mode hid the disconnect notice. The
Disconnected arm set the placeholder text but never left terminal mode,
where the document code layer is not prepared at all and the terminal glyph
layer keeps painting its last frame — so the user was left looking at a
frozen, live-looking terminal that silently ignored input. GPU auto-reconnect
is a named deferral, so that state persisted until relaunch. State::
on_daemon_disconnected now leaves terminal mode, forces a repaint even when
the notice text is byte-identical, and requests a redraw.

The fix and its test share a file, so scripts/bite's file granularity cannot
bite it; the equivalent was done by hand. Neutralizing only the
exit_terminal_mode() call makes the test fail on the "must leave terminal
mode" assertion; restoring it makes it pass.

sync_semantic_terminal_layout no longer clones the whole visible cell grid to
read one size. It ran every dispatcher tick for any semantic frontend with a
declared terminal; TerminalManager::screen_size reads the value from the
borrowed projection instead.

Inbound terminal events now require a negotiated v19 session. The outbound
TerminalFrame was gated twice while TerminalResize/TerminalPointer relied on
the frontend's send gate alone. A pre-v19 peer cannot construct those
variants, so this only refuses a hand-rolled client — and the a32 forgery
tests already prove such an event reaches nothing but the sender's own
authenticated active view — but the asymmetry was not deliberate.

A terminal-mode press that misses the grid no longer arms a drag, so a later
in-grid motion cannot send a Drag with no preceding Down. Daemon-side impact
was nil; the state is now honest. A release still always ends the drag.

The roadmap and handoff Arc 5 lines still said Stage 3 was framed and
awaiting approval, contradicting this PR's own ledger. Both corrected.

Named deferral: terminal wheel gestures discard scroll magnitude. One winit
wheel event becomes one gesture regardless of the lines it accumulated, while
the document path scrolls by lines. Closing it means either N gestures
(chattier) or a magnitude field on the pointer event — a protocol change.
Neither belongs in this stage.

Gates: fmt; strict workspace clippy; 1,758 default + 1,934 CRDT library
tests; Stage 1 9/10, Stage 2 4/4, Stage 3 5/7, statusline 7/8
(default/CRDT); M4 120; required GPU 129; workspace sweep 2,923 across 83
suites; diff check clean.
2026-07-22 15:33:26 -04:00
Levi Neuwirth 5b23e11f71 docs: link tab-width parity PR
Record PR #137 in the framing, durable handoff, active-work recovery ledger, and side-quest backlog.
2026-07-22 15:06:10 -04:00
Levi Neuwirth 3d28a31573 docs: record tab-width implementation lane
Record the proven implementation head, full local gate results, recovery commands, concurrent vterm overlap, and the advanced side-quest backlog.
2026-07-22 15:04:52 -04:00
Levi Neuwirth 9f7bc77f44 feat(render): unify tab-width projection
Share one fixed eight-column tab-stop contract across core and GPU renderers. Consolidate byte-to-display-column accounting, expand GPU code tabs with source provenance, align caret/hit/decoration geometry, and refresh minimap projection on edits.
2026-07-22 15:03:30 -04:00
Levi Neuwirth 50fd9a08e4 fix(vterm): address stage 3 review round 1
Five findings, all addressed. One was a real defect; one prediction did not
reproduce and is documented as such rather than papered over.

Hover no longer claims durable terminal control (finding 2, the real one).
apply_terminal_gesture claimed the controller before dispatching, including
for Move, which does nothing. A semantic frontend reports motion at pixel
rate, so sweeping the mouse across a passive split's terminal took durable
control, and the next layout sync resized the shared PTY to that background
view's geometry — precisely the theft the controller rule exists to prevent.
Bare motion no longer claims; every deliberate gesture still does.
scripts/bite HEAD src/editor.rs on the new test is a clean behavioral bite.

The terminal-mode presence-sweep skip is removed (finding 1), but the
predicted failure did NOT reproduce. The review reasoned that skipping the
sweep freezes last_broadcast at the abandoned document position. It does
not: the buffer-follow clears the terminal declaration when it ships the
snapshot, so terminal_active is false on the tick a window first shows a
terminal, and the declaration cannot arrive until a later tick — the
frontend learns the buffer id from that very snapshot. One truthful sweep
always lands first. The real-daemon two-frontend test written to catch the
freeze passes against the pre-fix tree; the bite is vacuous and the test is
labelled a regression guard, not fix evidence. The skip goes anyway: it was
load-bearing on tick ordering and bought nothing, and removing it makes
"presence follows the frontend" structural.

Terminal motion is deduplicated by cell (finding 3). Sub-cell motion
resolved to the same coordinate and still crossed the wire, where every
event is a daemon-side gesture. Press and release re-arm the memo so the
first drag after a press still reports. Its unit test cannot bite — the
seam did not exist pre-fix — and says so.

Declarations record only once sent (finding 4).
terminal_declaration_if_changed is now a pure query;
note_terminal_declaration_sent records. A failed write is retried instead of
suppressed as already-declared. The existing a35 test caught the contract
change and now pins both halves.

Unchanged frames skip revalidation (finding 5). The complete-payload
comparison runs before validate; only validated frames are ever stored, so a
frame equal to the baseline has already passed. The chrome tail is factored
into terminal_chrome so both exits emit it identically.

Gates: fmt; strict workspace clippy; 1,757 default + 1,933 CRDT library
tests; Stage 1 9/10, Stage 2 4/4, Stage 3 5/7, statusline 7/8
(default/CRDT); M4 120; required GPU 128; workspace sweep 2,921 across 83
suites; diff check clean.
2026-07-22 14:49:23 -04:00
Levi Neuwirth 9f2f0d5ccd docs: incorporate tab-width framing review
Make protocol-version constraints merge-order independent, require wrapped-tab decoration coverage, and explicitly exclude hover panel sizing.
2026-07-22 14:36:30 -04:00
Levi Neuwirth a8f1283581 docs: frame tab-width rendering parity
Define the fixed cross-frontend tab-stop contract, GPU source projection and mapping rules, core display-width consolidation, minimap behavior, and acceptance gates.
2026-07-22 14:25:19 -04:00
Levi Neuwirth 6ad3b88854 docs: record landed locals-query processing
Mark PR #134 as shipped in the durable handoff, framing, and side-quest
backlog. Remove the completed volatile lane and advance the canonical recovery
anchor to the merge commit.
2026-07-22 13:30:07 -04:00
Levi Neuwirth 1d0b46f023 docs(vterm): record the stage 3 pull request 2026-07-22 13:29:29 -04:00
Levi Neuwirth bdf2b6e4b4 feat(vterm): protocol v19 terminal frames and a native GPU terminal
Vterm Stage 3 — the final vterm stage. A semantic frontend can now host a
terminal: the daemon ships complete validated cell grids, and pmacs-gpu
renders them with fixed-cell geometry, its own input path, and no document
projection at all.

Protocol v19 appends three variants after their enums' final v18 members:
InstanceMessage::TerminalFrame (daemon-gated), and FrontendEvent::
TerminalResize / TerminalPointer (frontend-gated). It is the first bump to
gate in both directions, so criterion 28 pins each filter independently and
byte pins on StatuslineSegments and MenuPointer guard the placements.

pmacs-protocol gains src/terminal.rs: the shared row/column/visible-cell/
grapheme/metadata bounds, TerminalProcessState, TerminalSelectionSpan, and
TerminalFrame::validate — the ONE structural policy the daemon runs before
emission and the frontend runs after decode. src/terminal/* re-exports them
so no duplicate type exists, and unicode-width becomes a workspace dependency
so the screen and the validator measure glyph columns with one table. A new
8 MiB aggregate glyph bound keeps the largest legal frame (measured:
13,437,863 bytes) under the unchanged 16 MiB transport cap rather than
widening every connection's allocation ceiling.

The semantic producer suppresses the whole document family for a terminal
buffer while keeping the status band, theme, font, statusline, menu, and
minibuffer, and compares the complete ordered payload rather than
screen_generation — scroll, selection, and process state all change without
advancing it.

Two things the framing did not spell out, both found by the real-daemon
acceptance:

The Viewport gate keys on the authenticated source's ACTIVE buffer, not the
buffer the message names. Viewport also aligns the window to what it
declares, so a stale document viewport in flight when a command opened a
terminal dragged the frontend straight back off it: the window oscillated,
every terminal declaration was refused, and no frame ever arrived, with
nothing logged anywhere.

The producer clears terminal mode on every exit path. The daemon uses that
flag to suppress CursorByte and the presence sweep, so an early return that
left it set kept both suppressed after the frontend returned to a document.

pmacs-gpu/src/terminal.rs is a pure cell-space paint planner, unit-testable
without a GPU. The renderer builds one shaped buffer per text run, so a wide
or cluster glyph's advance can never choose the next column's origin.

Criterion 37 needed a seam rather than a fixture: pmacs-gpu depends only on
pmacs-protocol, so attach::connect's reader sink was generalized and a
--headless-probe mode added. The acceptance drives a real daemon, a real
/bin/sh child, the real attach client, and real composited pixels in one
path — which is how both defects above were found.

Gates: fmt; strict workspace clippy; 1,757 default + 1,933 CRDT library
tests; vterm Stage 1 9/10, Stage 2 4/4, Stage 3 4/5 acceptance
(default/CRDT); statusline 7/8; M4 120; required GPU 127; workspace sweep
2,919 across 83 suites; diff check clean.
2026-07-22 13:28:35 -04:00
Levi Neuwirth e5db4a98f8 test: enforce locals-query coverage
Assert that every bundled local-sensitive highlight query has a non-empty,
compilable locals query. Clarify the upstream-parity worst-case complexity of
lexical reference resolution in the framing document.
2026-07-22 13:05:33 -04:00
Levi Neuwirth 08ea6a3e12 docs: record locals-query pull request
Link PR #134 from the durable handoff and active-work lane now that the
implementation is published for review.
2026-07-22 12:31:18 -04:00
Levi Neuwirth cdeb5fb7cd docs: record locals-query implementation lane
Replace the obsolete fail-closed locals note with the settled lexical-facts
contract and record the feature branch, verification, and recovery commands in
the active-work ledger.
2026-07-22 12:29:39 -04:00
Levi Neuwirth 42a28b90c7 docs: frame locals-query processing
Define grammar locals metadata, lexical resolution semantics, shared local
predicate filtering, settle-time caching, producer coverage, and acceptance
criteria for shadowed versus non-shadowed builtins.
2026-07-22 12:03:37 -04:00
Levi Neuwirth 3adac8c4cb docs(vterm): carry approved stage 3 framing onto the implementation branch
Revision 8 of docs/vterm-framing.md was reviewed and approved on the
documentation branch vterm-stage3-framing. Stage 3 is implemented on this
branch, cut from canonical main, rather than stacked on that branch.

The framing locks additive protocol v19 (TerminalFrame, TerminalResize,
TerminalPointer), an 8 MiB aggregate glyph-byte bound under the unchanged
16 MiB transport cap, dual viewport declaration after every semantic
snapshot, authenticated per-view routing, and a fixed-cell native GPU
renderer. Criteria 28-37 are the scope of this branch.
2026-07-22 11:46:45 -04:00
Levi Neuwirth 9b8b312848 docs: record landed modeline detection
Advance the durable baseline to PR #132, remove the completed volatile lane,
and record the shared language pin, bounded modeline contract, Vterm Stage 2
landing, remaining deferrals, and current roadmap state.
2026-07-22 11:30:45 -04:00
Levi Neuwirth b45e5ee5ec Merge canonical main into modeline detection
Integrate landed Vterm Stage 2 before the approved modeline merge. Preserve the
active modeline lane in the volatile ledger and record the full integrated gate
results.
2026-07-22 10:56:35 -04:00
Levi Neuwirth 506912a069 docs(vterm): record current-main integration gates
Record the resolved mode-system integration head, exact post-integration
verification, and isolated M4 timeout reruns before the authorized merge.
2026-07-22 10:29:54 -04:00
Levi Neuwirth 3f0252fb97 Merge canonical main into vterm-tui
Integrate mode-system wiring and handoff updates before PR #130 lands.
Preserve per-frontend terminal dispatch while resolving major-mode keymaps,
and expose mode, terminal, and LSP statusline providers together.
2026-07-22 10:28:56 -04:00
Levi Neuwirth 88a371efdb docs: checkpoint modeline implementation
Record the implementation head, completed acceptance contract, full gate
results, and pull-request handoff for modeline detection.
2026-07-22 10:02:54 -04:00
Levi Neuwirth f8d05d2134 feat: detect language from modelines
Parse bounded Emacs and Vim modelines, normalize common aliases, and give
explicit file metadata precedence over inferred language. Pin one fresh-load
language decision for syntax, LSP, pairing, comments, and initial major mode,
while preserving the LSP path guard and explicit mode overrides.

Cover supported forms, rejection boundaries, precedence, unknown modes,
shebang and modeline pinning, reopen behavior, and pathless buffers.
2026-07-22 10:02:20 -04:00
Levi Neuwirth d5e59a9dcf docs: approve modeline detection framing
Record user approval of Revision 2 and mark implementation active in the
isolated modeline lane.
2026-07-22 09:44:35 -04:00
Levi Neuwirth f521413bce docs: checkpoint revised modeline framing
Record the review-complete Revision 2 framing head and approval boundary in
the active-work ledger.
2026-07-22 09:41:25 -04:00
Levi Neuwirth 6b4f3c3b38 docs: correct Vim modeline framing
Match Vim's real direct and set-form tokenization, reject nonexistent colon
assignments, clarify suffix scanning and trust, extend aliases, and pin the
shebang-edit regression in acceptance.
2026-07-22 09:41:06 -04:00
Levi Neuwirth 49efa805b5 docs(vterm): record PR 130 review round 2
Update the durable handoff and active-work ledger with the second-review
fix checkpoint and exact final gate evidence.

Co-authored-by: OpenAI Codex <codex@openai.com>
2026-07-22 09:10:30 -04:00
Levi Neuwirth b9a7e40855 fix(vterm): harden view anchors and interactive authority
Clamp anchors into partially evicted wrapped lines, require authenticated
interactive origins, and avoid per-mouse cell snapshots. Restore dispatcher
rationale, named context errors, and focused regressions for the corrected
contracts.

Co-authored-by: OpenAI Codex <codex@openai.com>
2026-07-22 09:09:44 -04:00
Levi Neuwirth 5a39ac4a9c docs: record modeline framing lane
Advance the canonical base after the mode-system handoff merge and preserve
the draft modeline framing branch, checkpoint, scope, and recovery command.
2026-07-22 09:05:49 -04:00
Levi Neuwirth 47a7f4cefd docs: frame modeline language detection
Define bounded Emacs and Vim modeline parsing, alias normalization,
explicit precedence, one pinned language decision shared by syntax and LSP,
and the acceptance contract for load-time mode detection.
2026-07-22 09:05:02 -04:00
Levi Neuwirth aafa47514c docs: record landed mode system
Move mode-system wiring from the active ledger into the durable handoff,
refresh the side-quest priorities, and preserve the macOS acceptance lessons
from the final CI review round.
2026-07-22 08:40:35 -04:00
Levi Neuwirth 2e332b579c docs(vterm): record PR 130 review round 1
Align the durable handoff with the approved escape-prefix contract, record the performance and lifecycle hardening, update the Stage 2 verification map, and publish exact final gate evidence in the active-work ledger.
2026-07-22 08:29:33 -04:00
Levi Neuwirth 4c382ae797 fix: harden mode acceptance startup
Give the daemon its normal five-second handshake window before switching
the mode-system acceptance client to short frame polling. Document reload
and session-persistence boundaries and correct stale describe-key guidance.
2026-07-22 08:18:18 -04:00
Levi Neuwirth 6725e9a598 docs(active-work): record Vterm Stage 2 PR
Record the published branch checkpoint and PR #130 as the active review lane. Preserve the explicit no-merge-without-authorization boundary.
2026-07-21 21:40:48 -04:00
Levi Neuwirth d2fca0c3ad docs(active-work): record gated Vterm Stage 2 lane
Replace the obsolete framing-only recovery entry with the integrated branch head, exact verification evidence, and portable worktree command.
2026-07-21 21:39:17 -04:00
Levi Neuwirth da8f6aeae4 fix(vterm): harden integrated Stage 2 behavior
Resolve post-main integration drift in authenticated routing, terminal view projection, Lua installation, and inherited acceptance callers. Preserve the terminal statusline provider alongside the landed Themes provider and record the final Stage 2 gate evidence.

Co-authored-by: OpenAI Codex <codex@openai.com>
2026-07-21 21:38:08 -04:00
Levi Neuwirth 692c3c5fdc docs: record mode system review lane
Record the portable branch, pull request, implementation checkpoint,
verification, and cross-machine recovery command for mode-system wiring.
2026-07-21 20:27:03 -04:00
Levi Neuwirth 0ddff24589 Merge canonical main into vterm-tui
Integrate config-registry and handoff updates landed after the Stage 2
framing branch was cut.
2026-07-21 20:18:53 -04:00
Levi Neuwirth dc9225778a test(vterm): prove Stage 2 TUI integration
Add cross-surface Lua, shared-view, clipboard, authenticated routing,
BEL, resize, and real-host PTY acceptance. Ensure terminal-local keymaps
run before raw child transport and document the criterion-to-test map.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 20:16:23 -04:00
Levi Neuwirth a548850423 docs: require truthful authorship attribution
Remove the standing instruction to claim Claude co-authorship and clarify
that commit trailers and PR attribution must reflect actual contributions.
2026-07-21 19:49:05 -04:00
Levi Neuwirth 424f82be5f docs: frame mode system wiring
Record approved decisions and acceptance criteria for major-mode storage,
dispatch, introspection, initialization, and statusline integration.
2026-07-21 19:49:05 -04:00
Levi Neuwirth 30464bcffd docs: absorb the config registry (#127) into the handoff
Merges canonical main up to 2e37c04 and records the second of the two
arcs that landed while this lane was open. Vterm Stage 1 (#126) was
already recorded; this adds the config registry and reconciles every
claim the two merges falsified.

Handoff §1: main pointer moved to 2e37c04, and a config-registry entry
covering the parts a future agent cannot re-derive from the code --- the
always-store rule and why the "equal-value set is a no-op" reading
silently voids a buffer-local pin; the two-scope model and the
no-ambient-buffer contract on get(name); explicit-dispose-only listener
lifetime and the absence of any MetaMethod::Gc; the InitCompleteFlag
freeze that kept editor.rs untouched; and the strict-registry /
lenient-wrapper split that preserves trim_on_save("yes") and
interval_ms(1500.7).

Handoff §5 gains two lessons. Tab width is a rendering-parity bug, not
a config gap: five sites across two crates with two different values,
and no tab expansion at all on the GPU main text path, so
editor.tab-width is the obvious-looking first adopter and is not one.
And "a test that never runs passes" --- pmacs.editor.save() is the raw
save while buffer.before-save fires inside the buffer.save COMMAND, and
save() no-ops on an unmodified buffer, which made two review-round tests
vacuous until the buffer was dirtied and the command invoked.

Handoff §6: the three config-registry-blocked deferrals are resolved
(the per-buffer auto-pair toggle shipped as editing.auto-pair), replaced
by the registry's own named deferrals --- persistence, list-settings, a
settings completion source, table-valued settings, the unmigrated scalar
setters, and a scope = "global" flag, since set_local is currently
accepted for autosave.interval-ms where a per-buffer value is
meaningless.

active-work.md: base pointer and recovery assertion moved to 2e37c04;
the Vterm Stage 2 lane is told to cut from current main rather than
643d1e1; a closed-since-last-snapshot section records the merged lane
and the parallel-lane result --- two arcs in sibling worktrees with the
shared files assigned one lane each in advance rebased with zero
conflicts, which is worth repeating and states its precondition.

side-quest-backlog.md: both original north-star items have now shipped,
so the board is re-ranked to locals-query processing, mode-system wiring
(promoted --- every editor resolve still passes &[], making it the
largest remaining scoping gap), and tab-width parity. The config-registry
entry is struck and tab width is split out of it, since listing tab
width as a config consequence is what made it look like a cheap adopter.

Documentation only: the diff against main touches no runtime code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 19:16:27 -04:00
Levi Neuwirth 1aa19c3bb5 Merge remote-tracking branch 'githubsucks/main' into handoff-2026-07-20 2026-07-21 19:11:36 -04:00
Levi Neuwirth 9dafdd4c89 docs(vterm): approve Stage 2 TUI contract
Carry the reviewed Revision 7 framing onto the Stage 2 implementation branch
as its first commit. The contract defines durable per-view state, authenticated
input authority, TUI composition, strict Lua operations, and acceptance 15-27.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 18:47:02 -04:00
Levi Neuwirth 11a719c059 docs(active-work): record approved Vterm framing lane
Add the portable Revision 7 branch, exact approved checkpoint, current state,
next implementation lane, and cross-machine recovery command. Preserve the
separate documentation-lane ownership boundary.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 18:40:10 -04:00
Levi Neuwirth f86c966090 fix(config): reject wrongly-typed spec fields; make trim-on-save buffer-aware
Review round 1, findings 2-4 plus doc notes. Finding 1 landed in fd80bcb.

Finding 3 --- spec fields meaningless for the declared type are now
rejected. DEFINE_SPEC_FIELDS whitelists all nine keys for every type and
the kind parser only reads its own arm's fields, so
`{ type = "string", choices = {...} }` silently defined a string that
accepts anything (the author meant enum) and `min` on a boolean was
dropped. These are typo-shaped bugs the R50 whitelist structurally
cannot see: the key is spelled correctly, it is on the wrong type.
`check_fields_relevant_to_kind` closes it with a pointed error naming
the misplaced field, and a companion test pins that each field is still
accepted where it belongs, including `min`/`max` on number as well as
integer.

Finding 4 --- the after_buffer_removed purge had no end-to-end test.
Every existing test called ConfigRegistry::remove_buffer directly, so
deleting the three lines wired into mod.rs would have left the whole
suite green. The new acceptance test kills a buffer through
pmacs.buffer.remove (the real remove_buffer_and_fire route) and asserts
the locals are gone; bite-verified by removing the hunk and watching it
fail.

Finding 2 (the half with a natural buffer) --- editing.trim-on-save is
now resolved against the buffer being saved rather than the global
chain. Reading globally meant set_local was accepted, stored, and
reported by describe, then never consulted: a pin the user believes in
that does nothing, which is the shape F1 exists to prevent. Two tests,
one for the override and one for the global fallback the change could
have broken; the override test fails against the old global read.

Both new save tests initially passed VACUOUSLY and were rewritten:
pmacs.editor.save() is the raw save, while buffer.before-save fires
inside the buffer.save COMMAND (default.lua:224), and save() no-ops on
an unmodified buffer --- so the original form asserted on a file that
was never rewritten. They now insert content to dirty the buffer and go
through pmacs.command.invoke("buffer.save").

The other half of finding 2 --- a per-buffer autosave.interval-ms is
semantically meaningless yet still accepted --- is recorded as a named
deferral proposing a define-time `scope = "global"` flag, alongside
deferrals for bound-parse field naming and StartupOnly reset symmetry.
Also recorded: interval_ms(1e30) now raises instead of storing a
nonsense float, an improvement but a real divergence from "the wrapper's
shape stays exactly as it was".

Doc: the module header cited framing revision 2; the shipped doc is
revision 3, whose corrections are what the code implements.

Gates: fmt, clippy -D warnings, --lib (1691), --lib --features crdt
(1865), lua54 backend, config_registry_acceptance (16), editops (72),
autosave (29), PMACS_REQUIRE_GPU=1 pmacs-gpu (109), and the full
workspace sweep (2806 tests, exit 0). git diff --check clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 18:29:18 -04:00
Levi Neuwirth 6844262495 feat(config): typed configuration registry with buffer-local scope
A third registry beside CommandRegistry and HookRegistry, per
docs/config-registry-framing.md. Unblocks the per-buffer auto-pair
toggle, the first of the five backlog items the missing config surface
was gating.

Substrate (src/config_registry.rs):

  * ConfigRegistry keyed by name with definition order preserved, R42
    mandatory descriptions, R50 typo detection, duplicate rejection,
    and SourceLocation provenance -- the command/hook vocabulary.
  * Closed scalar kinds: boolean, integer, number, string, enum. Owned
    Rust values; Lua tables, functions and userdata are never stored.
    Integer exactness is checked by value, never math.type, so the
    luajit and lua54 builds agree.
  * Two scopes. get(name, buf) resolves buffer-local -> global ->
    default; get(name) with no buffer resolves the global chain only
    and never consults an ambient buffer. Buffer-locals live in a
    registry-owned side table purged at after_buffer_removed, beside
    the keymap purge already there.
  * An override is ALWAYS stored, even when equal to the value it
    shadows; only value_epoch and listener dispatch key on effective
    change. Without this a buffer pinned to the current value stores
    nothing and a later global set flips it -- the pin silently never
    existed. equal_valued_local_override_is_still_stored_and_shields_buffer
    fails against the naive reading.

Bindings (src/lua_bindings/config.rs):

  * define/get/set/set_local/reset/is_set/describe/list/on_change.
    Spec tables are read raw, so neither an unknown key nor a
    metatable-provided value can smuggle a field in.
  * Listeners commit inside the borrow, snapshot, drop the borrow, and
    only then re-enter Lua -- verified by holding the borrow and
    watching the test panic with "RefCell already borrowed". A raising
    listener is logged without blocking later ones or rolling back, and
    a depth bound turns an accidental cycle into a pointed error.
    Listeners persist until explicitly disposed; there is no Gc path,
    matching the rest of the codebase.
  * StartupOnly freezes off the existing InitCompleteFlag at write
    time, so this arc adds no editor.rs call at all.

Adopters, each defining its own key so SourceLocation names the owning
module: editing.auto-pair (pair.lua, read per-buffer against the typed
edit's SOURCE buffer), editing.trim-on-save (editops.lua),
autosave.interval-ms (autosave.lua). No public function is removed or
deprecated, and both migration wrappers keep their legacy coercion --
trim_on_save("yes") still enables, interval_ms(1500.7) still floors to
1500 -- coercing before handing the strict registry a conforming value.

M-x describe-setting renders into *help*, modeled on describe-command.

Framing revision 3 records four defects implementation found in the
document itself: acceptance 30 and 31 contradicted each other; the
planned builtin/runtime/config.lua had nothing to hold and would have
broken the source-location contract had it held the one helper it might
have; F5 asked define to police a call it cannot see, moved to
set_local; and list() ordering was underspecified.

No protocol change; SUPPORTED stays [6..18]. No wire surface. Zero
changes to src/editor.rs.

Gates: fmt, clippy -D warnings, --lib (1683), --lib --features crdt
(1857), the new config_registry_acceptance (13) plus auto_pair (45),
editops (72), autosave (29) and m9_6 (25), m4 --skip basedpyright
(114), PMACS_REQUIRE_GPU=1 pmacs-gpu (109), the lua54 backend build,
and the full workspace sweep (2795 tests, exit 0). git diff --check
clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 18:29:18 -04:00
Levi Neuwirth 3bde76126a docs(config): framing for the config registry (revision 2)
The cross-cutting substrate ranked first on the side-quest north star.
A third registry beside CommandRegistry and HookRegistry, with two
scopes (global and buffer-local), a closed scalar value vocabulary,
post-commit listeners, and no wire surface.

Ground truth established by scout at 7bc0c61, including three findings
that shaped the design:

  * Tab width is five constants across two crates with two different
    values -- four TAB_WIDTH = 8 in the daemon, 4 in the GPU minimap,
    and no tab expansion at all on the GPU main text path. It is a
    rendering-parity bug, not a config gap, so it is deferred to
    stage 2 rather than made the proving adopter.
  * The mode system is unwired: every editor KeymapStack::resolve
    passes an empty active-modes slice. A mode scope would ship a knob
    that silently never fires.
  * load_user_config and set_init_complete both run inside
    EditorState::new under one cfg(not(test)) block, so the
    StartupOnly freeze point covers the daemon and local entry points
    uniformly -- and never runs in --lib test builds.

Revision 2 records review round 1 (F1-F11). The load-bearing fix is
F1: an override is now always stored, with only value_epoch and
listener dispatch keyed on effective-value change. The prior
"equal-value set is a true no-op" reading meant an equal-valued
buffer-local override stored nothing, so a later global set would flip
the very buffer the user had pinned -- silently voiding the per-buffer
toggle this arc exists to deliver.

Also carried by revision 2: listener dispatch semantics pinned across
scopes, GC-collected listeners dropped (no MetaMethod::Gc precedent
exists), migration wrappers keep their legacy coercion, StartupOnly x
set_local rejected at define time, string-list dropped, describe's
`local` field renamed buffer_local (Lua keyword), and the direct-remove
leak corrected to permanent-but-non-aliasing since BufferIds are never
reused.

No implementation. Framing only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 18:29:18 -04:00
Levi Neuwirth 4e93596e8a Merge canonical main after Vterm Stage 1
Synchronize the documentation continuity lane with #126, preserve the parked
work inventory, and record the landed terminal-core state and next sequential
TUI/GPU stages.
2026-07-21 16:59:57 -04:00
Levi Neuwirth 87369ed5db docs(handoff): record Vterm Stage 1 merge
Advance canonical main to the #126 merge, retire the completed active lane, and
record the landed headless terminal core plus the remaining TUI/GPU stages.
2026-07-21 16:56:42 -04:00
Levi Neuwirth ff6eb9a5ee docs(active-work): record green Vterm review-two CI
Record the fully green cross-platform PR matrix for the second-review head.
2026-07-21 16:41:27 -04:00
Levi Neuwirth 57a9304aa4 docs(active-work): record Vterm review round 2
Record the control-cell and mouse hardening commit, Revision 5, clean
behavioral bite, final gate counts, and pending updated PR CI.
2026-07-21 16:32:40 -04:00
Levi Neuwirth fc4e0ce77d docs(vterm): record Stage 1 review round 2
Record the control-free cell and SGR mouse hardening, accepted cleanup changes,
remaining DECSTBM/allocation/limit deferrals, behavioral bite, and final gate
counts in framing Revision 5 and project continuity docs.
2026-07-21 16:31:10 -04:00
Levi Neuwirth 2e97d60023 docs(active-work): record green Vterm review CI
Record the fully green Linux/macOS, Lua, GPU, format, lint, and acceptance
matrix for PR #126 after review round 1.
2026-07-21 15:48:03 -04:00
Levi Neuwirth 8dfb918082 docs(active-work): record Vterm review round 1
Record the addressed Stage 1 review, final branch head, full gate counts, and
clean behavioral bite while preserving the unmerged three-stage boundary.
2026-07-21 15:37:45 -04:00
Levi Neuwirth 5d5055871f docs(vterm): record Stage 1 review round 1
Record the IND, NEL, RI, TERM, portable-liveness, and tab-stop fixes; make the
line-oriented EOF contract explicit; and list the accepted fidelity,
performance, and lifecycle deferrals.

Update final from-start gates and the clean behavioral bite proof.
2026-07-21 15:37:11 -04:00
Levi Neuwirth 2a037dc14c docs(active-work): record Vterm CI portability fix
Update the Vterm Stage 1 lane with the Darwin PTY signal normalization,
post-fix branch head, and final from-start verification counts.
2026-07-21 14:39:19 -04:00
Levi Neuwirth 4d74d64b6f docs(vterm): record macOS portability fix
Record the Darwin PTY signal-name mismatch found by PR CI, the normalization
commit, and the final from-start green gate sequence with updated test counts.
2026-07-21 14:38:52 -04:00
Levi Neuwirth b3220b165e docs(active-work): record Vterm Stage 1 delivery
Record the published Stage 1 implementation and documentation heads, open PR
#126, final verification, and the sequencing boundary for the later TUI and
protocol/GPU stages.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-21 14:26:04 -04:00
Levi Neuwirth 5d7f0078f1 docs(vterm): refresh merged statusline baseline
Record canonical protocol v18 main after #125, mark Arc 4 complete, and pin
the Vterm Stage 1 feature commit and open PR #126 in the delivery records.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-21 14:24:46 -04:00
Levi Neuwirth bbc1f33a7c feat(vterm): add Stage 1 terminal core
Add compatibility-preserving full-screen ANSI operations, the bounded terminal
screen and input encoders, and a transactional TerminalManager owning one
read-only identity buffer, PTY process, and screen per session.

Drain terminal-owned process events before process.after-tick, retain exact
final output and PID/outcome annotations, reap killed buffers and shutdown
children safely, and enforce buffer-owned read-only checks across ordinary,
host, undo/redo, and CRDT mutation paths.

Cover split parser and grapheme boundaries, screen/reflow/history invariants,
device responses, lifecycle cleanup, and a real adversarial alternate-screen
PTY. Record the fully gated Stage 1 delivery and downstream TUI/GPU contracts.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-21 14:20:28 -04:00
Levi Neuwirth f26aa0b38b docs(vterm): fold architecture decisions
Record the chosen C-c escape, resize and exit behavior, additive v19
compatibility, complete-frame wire, unchanged Style, and shared-session
ownership. Specify the Emacs-style PID/outcome line retained after exit.
2026-07-21 13:26:36 -04:00
Levi Neuwirth 2ff67e7236 docs(vterm): frame staged terminal implementation
Define the terminal screen ownership boundary, three-PR delivery,
protocol v19 surface, fixed four-agent roster, and 33 acceptance cases.

No implementation is included; the framing remains pending user review.
2026-07-21 13:21:21 -04:00
Levi Neuwirth b65c927ac4 docs: record Themes Arc 4 completion
Advance canonical main and protocol state after PR #125, remove the
completed statusline lane from the active-work ledger, and mark the
first four roadmap arcs complete. Record Arc 5 stage 2 as the next
formal roadmap stage.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 12:56:17 -04:00
Levi Neuwirth 4ae888dda3 docs(active-work): record statusline review round two
Record the manually folded hardening changes, current feature head,
second review resolution, and final sequential verification counts.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 12:44:35 -04:00
Levi Neuwirth 1be7a30468 fix(statusline): harden narrow-band review edges
Document and pin the GPU built-in-only narrow-band clipping policy,
including the intentional ability of a wide right group to hide the
left identity. Guard the fixed UI face ordering used by binary search,
preserve flattened provider tracebacks in *errors*, and rename the
phase-one unavailable reason to cover missing layout contexts.

Refresh the implementation verification record after the full gate
suite.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-21 12:43:22 -04:00
Levi Neuwirth dd92c241b2 docs(handoff): record statusline first-review resolution
Update the volatile ledger with the rebased feature head, real TUI PTY
smoke evidence, post-rebase gates, review comment, and recovery state.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-21 12:17:48 -04:00
Levi Neuwirth 66765b3cbc docs(statusline): record rebased review baseline
Update the feature handoff and framing to current main bb17ec9 and the
post-rebase full-gate counts.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-21 12:15:19 -04:00
Levi Neuwirth 4b65b9e1e5 feat(statusline): add composable modeline segments at protocol v18
Add the strict pmacs.statusline provider registry, deterministic
borrow-released per-window evaluation, context-scoped failure latches,
and a pure built-in LSP provider.

Preserve the legacy TUI modeline while composing faced custom runs,
and append authoritative complete StatuslineSegments replacements for
semantic frontends. Expand dynamic ThemeFacts, reset producer/frontend
baselines symmetrically, and gate all provider work off protocol v18.

Teach the GPU to atomically validate, resolve, shape, clip, and cache
custom modeline runs without displacing the protected status suffix.
Document the public Lua lifecycle, wire ownership, snapshot semantics,
and the fully gated Arc 4 stage-3 delivery state.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-21 12:01:25 -04:00
Levi Neuwirth ac7f776c3a docs(statusline): close revision 3 review findings
Retain authoritative-empty payloads as emission baselines and pin the
legacy TUI behavior when the protected suffix itself cannot fit.
2026-07-21 12:01:25 -04:00
Levi Neuwirth fe1dc7ad94 docs(statusline): close review contracts in revision 2
Specify authoritative invalidation, safe grapheme runs, separator faces,
detach-aware latches, and the unknown LSP label.
2026-07-21 12:01:25 -04:00
Levi Neuwirth f16c98b56b docs(statusline): preserve stage-3 framing for review
Checkpoint revision 1 of the Arc 4 stage-3 statusline-segments framing
on its own portable branch. The framing remains awaiting user review;
there is no implementation or PR.
2026-07-21 12:01:25 -04:00
Levi Neuwirth 738506b06b docs(handoff): record statusline stage-3 delivery
Record the exact feature head, PR #125, complete sequential gate results,
and clean recovery state for the statusline-segments review lane.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-21 11:26:41 -04:00
Levi Neuwirth a9732d9fb1 docs(handoff): record statusline framing revision 3
Advance the active lane and durable handoff to the framing-only Revision
3 checkpoint without changing its awaiting-review status.
2026-07-21 10:25:56 -04:00
Levi Neuwirth c488cbb9d4 docs(handoff): record statusline framing revision 2
Advance the active review lane after its contract-tightening revision.
2026-07-21 10:04:05 -04:00
Levi Neuwirth 753689955d docs(handoff): record JSON and YAML merge
Mark PR #123 landed at bb17ec9 and remove its completed recovery lane.
2026-07-21 09:48:46 -04:00
Levi Neuwirth 5ba9c526b4 docs(handoff): record JSON/YAML review cleanup
Advance the PR #123 recovery heads and verification record after its
documentation-only pre-merge cleanup.
2026-07-21 09:35:29 -04:00
Levi Neuwirth ffcb903fc1 docs(json-yaml): refresh final review state
Remove stale transfer-task wording and record the rebased, fully gated
JSON/YAML provider validation in the framing and handoff.
2026-07-21 09:34:54 -04:00
Levi Neuwirth 03ef1801d2 docs: record green JSON/YAML CI
Mark CI run 29778967156 successful across all 12 jobs for exact PR head
5c202c5. Leave user review as the only remaining action and retain the
standing prohibition on unprompted merge.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-07-20 17:23:36 -04:00
Levi Neuwirth f870bc4ca9 docs: mark JSON/YAML locally gated and public
Record the green logged workspace sweep, final diff audit, and matching
public/checkpoint head 5c202c5. Pin PR #123's full head OID and fresh CI
run so any machine can resume at CI or review without reconstructing
local state.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-07-20 17:22:51 -04:00
Levi Neuwirth b489780781 docs: checkpoint JSON/YAML gate progress
Record the green formatting, standalone Clippy, default and CRDT library,
M4 acceptance, live JSON/YAML provider, and required-GPU results for
checkpoint 5c202c5. Leave only the logged workspace sweep, final diff
check, and public PR-branch update outstanding.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-07-20 17:05:14 -04:00
Levi Neuwirth 6db8a4b166 docs: advance amended JSON/YAML checkpoint
Record checkpoint 5c202c5 after the one-line doc-markdown correction was
amended into the live YAML test commit. Preserve the first Clippy result
and its rerun state for cross-machine continuation.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-07-20 17:01:50 -04:00
Levi Neuwirth 5c202c54c1 test(json-yaml): verify real YAML provider through pmacs
Drive Red Hat yaml-language-server 1.24.0 through the default YAML
auto-attach path. Disable SchemaStore and the Kubernetes CRD catalog for
network-free determinism, require language-specific initialization and a
real syntax diagnostic, and prove the server remains alive afterward.

Update the framing and runtime commentary with the completed live-provider
evidence. The test passes against the pinned provider and fails against the
pre-JSON/YAML runtime under scripts/bite.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-07-20 17:00:20 -04:00
Levi Neuwirth af7e010381 docs: record rebased JSON/YAML checkpoint
Advance the portable JSON/YAML head to 3ef5e2e and record its clean rebase
onto canonical main f8096ff. Leave the full gates and public PR-branch
update as the only remaining work.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-07-20 16:56:11 -04:00
Levi Neuwirth 19ad5cc8ac fix(json-yaml): checkpoint reviewed LSP configuration fixes
Preserve PR #123's unpushed review fixes on a transfer branch: initial
didChangeConfiguration delivery, explicit JSON validation, the pinned
JSON server provider, corrected YAML configuration sections, and
deterministic plus real-provider acceptance coverage. Record the
observed yaml-language-server 1.24.0 standalone smoke and leave the
real YAML-through-pmacs test, rebase, and full gates explicitly pending
for the destination machine.
2026-07-20 16:49:37 -04:00
Levi Neuwirth 9ce6f1abf3 feat(json-yaml): JSON + YAML grammars and language servers
Add tree-sitter-json (0.24) and tree-sitter-yaml (0.7) to
BUILTIN_LANGUAGES (both ABI-current via tree-sitter-language, verified
compiling under tree-sitter 0.26), each self-contained highlights, no
injections of their own. Extensions json=.json, yaml=.yaml/.yml; root
kinds json `document`, yaml `stream`.

The payoff from the #122 injection engine is free: the markdown block
injection query already sets injection.language "yaml" for `---`
frontmatter (minus_metadata) and "toml" for `+++` (plus_metadata), so
registering yaml lights up YAML frontmatter highlighting with no extra
wiring, and ```json / ```yaml / ```yml fences resolve through the engine
(yml->yaml alias already present). Two acceptance tests pin this synergy.

LSP (builtin/runtime/lsp.lua): pmacs.lsp.config.json uses the maintained
extracted-bundle binary `vscode-json-language-server --stdio` (NOT the
stale standalone vscode-json-languageserver); MIT, no telemetry, remote
$schema fetch left enabled (no handledSchemaProtocols). pmacs.lsp.config
.yaml uses `yaml-language-server --stdio` with Red Hat telemetry
disabled by default. Both ship the exact workspace/configuration sections
each server pulls (json+http; yaml+http+redhat.telemetry) present-not-null
so the servers get defaults rather than erroring — the CMake #117 lesson.
Sections derived from server source/docs (neither binary installed on
this build machine to observe live; verify where present). Filetype
fallback entries added. JSON is the standing prerequisite for the Jupyter
.ipynb arc; handoff §6 updated.

Nine acceptance tests (grammar ABI, highlights compile, detection,
grammar<->LSP-key alignment, the two frontmatter/fence synergy proofs,
and the pinned LSP-config sections).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJ9FQ832QwftJXCD9LeFan
2026-07-20 16:49:37 -04:00
Levi Neuwirth f233765f74 docs(json-yaml): framing for JSON + YAML grammars
Frame the JSON/YAML grammar-gap addition (tree-sitter-json 0.24 +
tree-sitter-yaml 0.7, both ABI-current) plus their language servers, and
the free frontmatter/fence highlighting that falls out of the #122
injection engine (the markdown block query already injects yaml for `---`
frontmatter and toml for `+++`). Four decisions (Q#JY1-JY4), nine
acceptance tests. JSON is also the standing prerequisite for the Jupyter
.ipynb arc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJ9FQ832QwftJXCD9LeFan
2026-07-20 16:49:37 -04:00
Levi Neuwirth eb779cfcd1 docs: make active recovery machine-agnostic
Define the canonical repository by URL and bootstrap a stable local
`githubsucks` alias instead of assigning authority to machine-specific
remote names. Record JSON/YAML checkpoint f99870e and the completed live
YAML provider plus bite evidence, leaving only rebase and full gates.

Keep AGENTS.md and CLAUDE.md synchronized so a fresh agent receives the
same recovery rule on any machine.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-07-20 16:47:02 -04:00
Levi Neuwirth ad05498545 docs: pin portable branch heads in active-work ledger
Record the pushed JSON/YAML checkpoint and framing heads so a clean
machine can verify it recovered the intended state, and document the
existing-local-branch worktree variant.
2026-07-20 10:57:48 -04:00
Levi Neuwirth 968e01ae6a docs: add cross-machine active-work handoff
Add synchronized agent bootstraps and a volatile active-work ledger so
another machine can distinguish durable project state from open
branches, local checkpoints, machine-only providers, and incomplete
verification. Record githubsucks/main as the canonical development
line, refresh the #124/protocol-v17 handoff, correct the current
keybinding reference for compile mode, and mark the July roadmap as a
historical snapshot.
2026-07-20 10:51:34 -04:00
Levi Neuwirth b3d326d937 fix(font): close stage-2 GPU behavioral findings
Normalize source bytes to representable shaped-cluster cursors and
reflow the code buffer whenever gutter or minimap geometry changes.

Measure alternate monospace advances across complete shaped runs and
load hermetic fixture faces before FontSystem construction. Complete
the rendered geometry, popup, caret, snapshot, and fixture acceptance
coverage, and record the review fixes in framing revision 5.
2026-07-18 15:29:25 +01:00
Levi Neuwirth 6cd78f0870 test(font): wire acceptance suite + protocol/design docs (items 2-8, 15)
tests/gpu_font_acceptance.rs (items 2-7; the header manifest routes
item 1 to src/protocol.rs pins, item 8 to the src/frontend.rs TUI
drop unit, items 9-14/16-19 to pmacs-gpu's headless suite, and item
15 to the docs):

- 2: a fresh attachment's first frame carries the REAL (None, None)
     default; unchanged ticks are silent; a late joiner receives the
     current preference without post-attach mutation
- 3: a mid-session set_font emits exactly one FontFacts on the next
     frame; an identical re-set advances the epoch without emitting
- 4 (producer half): on_buffer_snapshot_sent re-ships buffer facts
     but never the bufferless FontFacts
- 5: real-daemon probe -- a v17 semantic session receives FontFacts,
     a v16 peer never does (crdt feature)
- 6: the strict Lua contract -- 5.999/72.01/0/-16/NaN/inf/non-number
     sizes error naming `size`; empty/non-string family errors
     naming `family`; unknown keys rejected by name; hostile
     __index/__pairs metatables never invoked and never inject
     values; quantization pins 15.994->1599 / 15.996->1600 and both
     boundaries; set_font {} resets both axes; the getter returns a
     fresh quantized plain table; every rejected shape leaves the
     preference and the wire untouched
- 7: a load_user_config_at fixture's init.lua set_font lands in the
     handle installed before user config, and a pre-attach
     preference ships on the first frame

Bites (mutate, observe the acceptance test fail, restore): the
Option-seeded first-frame send, the payload compare, the snapshot
survival of the font baselines, the v17 gate (BOTH halves widened --
producer for_peer alone leaks nothing because the daemon skip arm
still filters; the wire test only fails when belt AND braces are
cut), the unknown-key rejection, the range-check-original ordering,
and the raw_get metatable isolation.

Docs (item 15): docs/semantic-frontend-protocol.md gains the
FontFacts variant entry (v17 gate, authoritative default, no-pixels
preference relay, fail-closed receiver) and folds FontFacts into the
BufferSnapshot reset-contract paragraph (bufferless facts survive;
the frontend's caret-follow scroll residual is the buffer-scoped
part). docs/pmacs-gpu-design.md's "future customization needs no
wire-protocol changes" claim is corrected in place and points at the
framing as design of record; the Lua-override bullet now names the
landed set_font shape. The framing status bumps to implemented.

Also re-homes the ProcessSupervisor doc comment that the make_font_pref
insertion had orphaned onto the wrong function.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VoiEyuPjoBhvwACf8HAnLB
2026-07-18 11:46:44 +01:00
Levi Neuwirth 2521169350 docs: gpu-set-font framing (Arc 4 stage 2) at revision 4
pmacs.gpu.set_font { family?, size? }: one global daemon-side font
preference relayed to GPU peers as the bufferless FontFacts fact at
protocol v17 (size in integer hundredths of a logical pixel -- the
InstanceMessage Eq derive forbids f32), applied mid-session as one
fail-closed GPU transaction: sanitized current-order fontdb
assembly with four-style monospace queries, derived metric fields
scaled from one knob (band height included), atomic
set_metrics_and_size on all seven buffers with real drawable
dimensions, Wrap::None on row-oriented popups, a measured
advance-ratio probe, and visual-run-aware caret preservation (a
normalized code-buffer Scroll residual + shape_until_cursor,
shared with the CursorByte and optimistic-edit paths, gutter
continuation blanks keeping line numbers aligned). Revisions 2-3
fold framing rounds 1-2 (Eq-safe wire size, wire validation
failing closed, caret repair ordered before the final reshape,
vertical-containment acceptance, sanitized default query,
quantization pins); revision 4 is the user's round 3 (visual runs,
horizontal-scroll deferral, atomicity, popup row invariance,
strict Lua raw-data contract). Acceptance items 1-19.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VoiEyuPjoBhvwACf8HAnLB
2026-07-18 11:45:51 +01:00
Levi Neuwirth afe2690158 docs: sync handoff for injections (#122); prune backlog
Post-merge handoff sync for multi-language injections (#122), folded
into the side-quest-backlog PR (rebased onto current main, which now
carries #120 themes stage 1 and #122 injections).

agent-handoff.md:
- §1: main head → 5e73966; add the #122 injection-engine entry (layered
  ParseTreeBundle, worker-side layer building off the static grammar
  table, settle-time query resolution, the new substrate — injections_query,
  the alias snapshot, injection_capped, compute_highlight_spans_for, the
  flatten event-sweep, the GPU fold — and the two hard-won findings).
- §6: the "multi-language injections" deferral is retired; replaced with
  the real follow-ups (injection.combined, child-tree incrementality,
  injectable Lua-registered languages, HTML/CSS/GraphQL/SQL consumer
  grammars). Jupyter is now gated on JSON only.

side-quest-backlog.md: injections marked SHIPPED with its remaining
follow-ups; Jupyter gate and north star revised (JSON grammar and
locals-query processing rise to the top now that injections landed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJ9FQ832QwftJXCD9LeFan
2026-07-15 16:21:43 +01:00
Levi Neuwirth c51c88cac0 docs: side-quest-backlog — non-themes deferral inventory
Consolidate the non-themes backlog into docs/side-quest-backlog.md: an
exhaustive, deduplicated index compiled from every framing doc's
"Deferred (named)" section, the handoff §6 list, the roadmap arcs, and a
code-level marker sweep. Organized as side quests (one-shot-ish, led by
the highlighting/detection/LSP/editing families that continue the
#114–#118 stack), raid bosses (vterm, folding, DAP, GPU splits, Jupyter),
cross-cutting substrate blockers, and a prioritization north star.
Themes/faces/color items are excluded (they're the Arc 4 main quest) and
listed once so they're visibly accounted for. Handoff §6 gains a pointer
to it.

Docs only. git diff --check clean.
2026-07-15 16:10:19 +01:00
Levi Neuwirth 325dcd553f fix(injections): PR #122 round 2 — sibling precedence, observable cap, docs
Two follow-ups + doc cleanup.

[P2] Same-depth sibling precedence was reversed. The wire priority was
(depth, capture_order), omitting the layer ordinal, so two overlapping
spans from different sibling layers tied — and the active-set insert
then applied the later one first, making the earlier sibling win, the
opposite of the grid's layer-by-layer paint. Priority is now
(layer_index, capture_order): layer_index is the depth-ascending
position in bundle.layers, so a deeper layer AND a later same-depth
sibling both override, matching the grid exactly. New
flatten_same_depth_sibling_later_layer_wins pins it.

[P2] Cap surfacing had no end-to-end test. Added
injection_cap_surfaced_once_and_rearms_via_lua, which drives the real
Lua settle path (syntax.lua tick -> _injection_capped -> pmacs.error)
and asserts surfaced-once, suppressed-on-unchanged-reparse, and
re-armed-after-dropping-below-then-exceeding-the-cap.

Docs:
- Q#IJ6 now states the accurate bound O(n log n + Sum active) for the
  event sweep, not O(boundaries).
- The full-buffer perf test is renamed/narrowed to guard the FLATTENER
  regression; the summary's per-line dominant-style tally is a separate
  pre-existing O(lines x spans) loop, not claimed linear.
- Framing #9 now matches the test: it drives spans_from_segments (the
  extracted replace_style_spans transform) + source_color_at, not a live
  State render.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJ9FQ832QwftJXCD9LeFan
2026-07-15 12:07:21 +01:00
Levi Neuwirth 79d75a29e0 fix(injections): PR #122 round 1 — sweep flatten, sync aliases, real multi-range, surfaced cap
Four review findings + a cleanup bundle.

[P1] Wire flattener was O(spans²) and ran over the WHOLE buffer (the
file-style summary uses a whole-buffer viewport, not the visible one).
Replaced the per-interval full scan with an ordered active-set event
sweep (activate on start, expire on end, fold the active set) — linear
in practice. Added full_buffer_summary_scales_on_large_grammar_file
(1500-line rust) as the perf gate.

[P2] _parse_now used the empty alias map from make_request while
_dispatch snapshotted the registry map, so a `py` fence injected async
but not sync. Snapshot aliases on both paths; pinned by
sync_parse_now_resolves_alias.

[P2] The multi-range inline test used a one-line paragraph, whose block
inline node has no named children (link/emphasis are child-grammar
structures) — one range, so it couldn't falsify multi-range. Replaced
with a multi-line blockquote whose inline node carries a named
block_continuation: content_node_ranges now asserts >1 collected range
and emphasis parses on both lines.

[P2] The layer backstop dropped regions silently; the framing requires
a surfaced warning. run_parse now sets ParseTreeBundle::injection_capped;
syntax.lua's settle tick raises it once per buffer via pmacs.error
(_injection_capped). Added injection_layer_cap_surfaces_and_preserves_root
(drives >4096 fences, asserts the flag + bounded count + intact root).

Cleanup:
- The GPU acceptance test now drives the real StyleSpans full-frame
  transform (spans_from_segments, extracted from replace_style_spans)
  instead of a hand-rolled sort.
- content_node_ranges excludes NAMED children (documented as a round-1
  refinement); framing mechanic #3 / Q#IJ5 updated to match.
- parse_duration doc now says root parse; the markdown entry no longer
  describes inline as unhighlighted/future.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJ9FQ832QwftJXCD9LeFan
2026-07-15 12:07:21 +01:00