Skip to content

v0.19.0 physical-QA stabilization: input ownership, exact copy, queue and Setup clarity - #395

Draft
raiseCatError wants to merge 18 commits into
release/v0.19.0from
stabilize/v0.19.0
Draft

raiseCatError wants to merge 18 commits into
release/v0.19.0from
stabilize/v0.19.0

Conversation

@raiseCatError

Copy link
Copy Markdown
Owner

Physical-QA stabilization for v0.19.0. Draft: do not merge. It targets release/v0.19.0 (9e85a910), whose head and evidence are unchanged; merging needs the maintainer's physical retest and approval.

Required (P0/P1, fix/v019-input-ownership)

  • Input ownership. Replies to read reply, read -k 1, read -n 1 and hidden reads were queued, left in the composer or lost (QA 1.3, 1.4, 1.5, 1.7). The shell holding its own terminal is now evidence of a builtin read; keys that decide routing wait for an on-demand look (input-look, negotiated); held keys follow a program that takes the terminal; an answer clears the stale request. Real-PTY tests cover zsh, Bash and Fish at 0 and 300 ms.
  • Waiting state in its own color, with the program's question and one instruction.
  • Exact /copy: tabs and the final newline as printed (QA 1.11, 1.12). Diagnostics B and C are byte-exact through the real clipboard.

Recommended (P2)

  • fix/v019-queue-ux: queue preview (up to three commands in run order), inline review before resuming or approving (nothing runs from one key; a typed y never approves), the pause said once, and a paste note for NMSh commands among other lines.
  • fix/v019-setup-ux: real screen-saver previews (Random's real choices), the Chroma preview follows the setting and says what hides it, and a legible activity-wording example.

Details, diagnostics and the remaining physical QA are in the release ledger (docs/release-train-v019-v020).

Verification on bcc8e760

  • Local canonical npm run verify:release (macOS arm64, Node 26.10.0): pass, 2457/2457, 0 skipped; bench typecheck and timing smoke pass. An earlier run on 1179936b failed 4/2456; it found a real Ctrl+C race (fixed in fb395506) and three stale expectations. Both receipts are kept.
  • CI: this PR's checks.
  • Physical QA: not performed on this build; required before any merge.

…yped

Physical QA found replies to `read reply`, `read -k 1` and `read -n 1` queued
or left in the composer, and hidden replies typed quickly lost. On macOS the
only evidence of a line or key read was a question-shaped prompt left open,
so reads without a prompt were never seen; and a key typed before the first
look (or after the schedule backed off) was routed on no evidence at all.

- InputWatch: the shell itself holding its terminal while a command runs is a
  builtin's read. Line input off there is a confirmed key read; ordinary line
  settings idle across two samples (the second 100 ms later) are a likely
  line read. A loop's shell between commands is not.
- lookNow and the negotiated input-look/input-looked messages: the frontend
  holds the first key of a draft, and an Enter that would queue, until the
  session has looked (at most 800 ms, after the shell's exec), then routes
  them on that evidence. Older services are never asked.
- Held keys reach a program that took the terminal meanwhile (Fish's reader)
  in order, and a draft typed for the command is handed to that reader.
- An answer sent clears the frontend's copy of the request, so the next
  command typed at speed is never sent to a program that stopped reading.
- Typing right after Ctrl+C/Ctrl+Z stays type-ahead for the prompt.

Real-PTY tests through the session service cover zsh, Bash and Fish line,
hidden and key reads at 0 and 300 ms, Ctrl+Q while a read waits, Enter
during sleep and a loop, and commands typed right after a read and Ctrl+C.
The waiting state shared the running shimmer's lavender family and put its
instructions in the subtle tier, said twice in different words, so physical
QA found it too easy to miss.

- A semantic attention color (cyan) for the headline, the composer's mark
  and waiting rows in /sessions, apart from running, paused, failed and done.
- The second activity row is the program's own question, or what it reads
  when it left none ("zsh is probably reading a line").
- The composer carries the one instruction at secondary contrast: "Type your
  answer · Enter sends it to zsh · Ctrl+Q queues a command", "Hidden input ·
  nothing you type is shown · ...", "Press a key · it goes straight to ...".
Physical QA counted 399 lines after copying `seq 1 400`; checklist item 1.11
expects `printf 'a\tb\n  indented\nüñí\n'` to copy as
6109620a2020696e64656e7465640ac3bcc3b1c3ad0a. Both failed in the stored
output, before the clipboard: command output is kept through the screen
model, which draws a tab as spaces and records lines without saying whether
the last one was ended, so `x\ny` and `x\ny\n` were stored alike.

- The parser marks the cells a tab advanced over; exactLine writes the tab
  back while its whole span is intact (an overwritten span stays as shown).
  Drawing, selection, search, compare and reports keep the drawn text.
- A record keeps copyText (only when it differs) and outputNewline, set
  from program output only: escapes after the newline still count, NMSh's
  own notices and carriage returns do not. Both survive restore.
- serializeCopyPayload is the one exact copy; /copy, /cp, the picker, block
  Copy and clips use it. Records join with one line break, never two.

Tests that pinned the dropped newline or tab expansion now expect the
printed bytes. A live test runs each command and /copy separately through
the real composer and checks both diagnostics byte for byte.
…king regex

The trailing-escape pattern used to find a write's last text was anchored
with a repeated group, so a large write of escape sequences ending in text
was scanned quadratically, on every output chunk. The parser now records
whether the last text it wrote ended a line, in its single pass; an escape
split across writes is still not text.
Physical QA found the queue hard to follow without reopening /queue, the
pause said twice, and approval only through /queue then a.

- The expanded queue near the composer: a header and up to three commands
  in run order with their conditions, then "+N more". It takes its rows from
  the transcript's view through the screen plan (withQueueRows, a new queue
  region after the activity region); the shell's PTY never resizes. From 24
  rows three commands, from 18 two, below that the one-line row. Hidden while
  a program waits for input. Safe glyphs and NO_COLOR keep it aligned.
- An empty Enter at idle, with nothing else owning input, arms an inline
  review of a paused queue or of the entry that asks first, showing exactly
  what will run (the whole command for an approval). Only then do Enter or y
  confirm; n or Esc leave it, e edits. A review owns the keys while armed, so
  a typed "y" at the composer is always a command, never an approval; any
  change to what it shows dismisses it; an empty Enter right after a confirm
  never reaches the command it started. "n" on an approval pauses the queue
  so typed commands run directly instead of waiting behind it.
- A pause is said once in the transcript, with its reason; the queue's row is
  the state and what to do.
A submission is NMSh's only when the whole of it is one NMSh command, so a
pasted /copy, /queue or /compare among other lines went to zsh as a path
(physical QA's contaminated clipboard test). The compact preview and the
full review now classify those lines as NMSh commands and say, before
anything is inserted or queued, that here they reach the shell as text and
must be submitted alone. Nothing is reinterpreted or run differently; an
absolute path and unknown slash words stay the shell's.
Among other lines the shell receives a pasted /copy, so what it contains
runs there: /copy $(curl … | sh) must still say it runs downloaded code.
The NMSh tag is now added beside the line's ordinary classification, and
every risk outranks it in the label and in whether the paste is previewed.
Physical QA found Setup's appearance choices hard to judge: screen savers
previewed as an empty or unrelated star field, choosing a Chroma changed
nothing visible, and the activity wording was a muted, truncated note.

- One screen saver preview for Setup, the color editor and /screensaver
  (idlePreviewRows): Black Hole, Fireworks, Circletastic and raiseCatError
  animate a fixed sample NMSh screen where no screen is captured (never the
  Setup panel or anything private), and Random shows each saver it can
  actually choose, from the registry, in turn, naming it.
- The Chroma preview follows the setting: choosing one shows it at once; P
  compares with the base theme until the choice changes. The Chroma row says
  what will show and what hides or stills it: Off by default, NO_COLOR, an
  external prompt or Prompt None, Decorative effects Off, Reduced Motion,
  identity modules only.
- Selecting an activity row previews the real running, finished and failed
  lines (Expressive by default: Cooking… then Cooked for 18s; failures stay
  factual), at secondary contrast.
…s for the prompt

The canonical run found it: after Ctrl+C on a read with a question open,
the frontend still held that question, so the next command's first key
started a draft marked as a reply. When the prompt came back mid-typing,
the reply rule discarded it ("finished before your reply was sent") and
the rest ran as a broken fragment. An interrupt or suspend now ends the
question here as an answer does, and a draft started in the stop window
is never a reply.

Also two tests that pinned the dropped final newline (block Copy output,
welcome copy) now expect the bytes printed.
…ing answers

Linux CI (dispatch run 38803613336, ubuntu shard 1/2) showed the answer on
screen while the journal record was not yet written, so the exactly-once
check read no record. The test now counts the command's records before it
runs and waits for one more; the product behavior is unchanged.
raiseCatError added a commit that referenced this pull request Oct 15, 2026
…tion and the workspace UI proposal

Records the maintainer's first physical QA: triage, diagnostics A-C before and
after (exact bytes), root causes, the branches and backport map, every
canonical and CI run on the stabilization heads (failed runs kept with their
causes), draft PRs #395/#396, and what still needs a person. Adds the final
sidebar/Git decision proposal (recommendation: delegate, then retire) and the
Setup navigation proposal. No release branch, tag or PR target changed.
raiseCatError added a commit that referenced this pull request Oct 16, 2026
…a20, qa19r, qa20r)

Physical QA must test the stabilized candidates (#395, #396), but the launcher only knew
wt/v019 and wt/v020, which hold the original candidates. The new nmsh_qa_stable commands
run a read-only build of one pinned commit, verified before every launch (commit, tracked
sources, dist digest, the build's own identity), in a QA directory that records that build;
reopening uses the same build and refuses a service of any other. Original QA directories
and their running services are untouched; cleanup is explicit and asks first.

zsh docs/development/nmsh-qa.test.zsh: 78 checks (selection, wrong commit, wrong session
identity, reopening, isolation, cleanup).
Physical QA found theme settings scattered across Prompt and Appearance, with Chroma
offered in both and the rows that depend on a theme shown before it. The approved order
(workspace-ui-decision.md):

- Look (formerly Appearance) follows Terminal: theme family, variant, accent, theme text,
  UI chrome, then Chroma with its dependent rows under it. It is the only place Setup
  chooses Chroma.
- Prompt shows Chroma as a read-only line; Enter goes to Look's Chroma row.
- Motion starts with Reduced Motion, Decorative effects, Shimmer and Milestone effects,
  above the motion rows they govern; the Shimmer sample preview moved with its row.
- Cursor follows Motion; the remaining steps are unchanged.

/setup look and /setup motion are listed; /setup appearance and /setup chroma still work.
/setup chroma now selects the Chroma row itself: its index was counted over hidden theme
rows and landed on Theme Studio. Saved values and every setting's reachability are
unchanged (tests/setupOrder.test.ts).
@raiseCatError

Copy link
Copy Markdown
Owner Author

Update 2026-10-16: new head 1aeb05c0

Head: 1aeb05c0d569c06562e8fa9219eae3069686e0cd = adfce9c1 + merge of fix/v019-setup-order (e2ab71da).

Change: Setup order Look → Prompt → Motion (approved in workspace-ui-decision.md).

  • Look (formerly Appearance) follows Terminal: theme family, variant, accent, theme text and UI chrome, then Chroma with its dependent rows. It is the only place Setup chooses Chroma.
  • Prompt shows Chroma as a read-only line; Enter goes to Look's Chroma row.
  • Motion starts with Reduced Motion, Decorative effects, Shimmer and Milestone effects.
  • /setup look and /setup motion are new; /setup appearance and /setup chroma still work.
  • Fixed: /setup chroma selected Theme Studio instead of Chroma. The bug is also present on 9e85a910.
  • Tests: tests/setupOrder.test.ts covers order, reachability, persistence, previews, narrow widths, Safe glyphs and NO_COLOR.

Gates on 1aeb05c0:

  • Local canonical verify:release: pass, 2466/2466, 0 skipped.
  • PR CI 38846487932: pass.
  • Dispatch CI 38846491065, attempt 1: fail, kept as evidence. Ubuntu Fish 3.7.0, typingAfterRead "live fish: keys typed the moment a read finishes are never lost".
  • Same run, attempt 2 (failed jobs only): pass.
  • This Fish failure is open, not waived. It also appeared on v0.20.0 physical-QA stabilization: v0.19 fixes forward, task bar, managed-Claude deferral #396's dispatch run. See the release-train ledger.

Physical QA: test this head with qa19 / qa19r from docs/development/nmsh-qa.zsh on docs/release-train-v019-v020. That launcher verifies this exact commit and isolates the session. Not ready, not merged.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant