@timurproko/a1 0.2.7-dev.831 → 0.2.7-dev.834

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -102,10 +102,13 @@ export class OwnedUiTerminalHost {
102
102
  },
103
103
  }),
104
104
  } : { layoutRoot: pinnedLayoutRoot(this.#delegatingLayoutParts()) }),
105
- ...(input?.onEvent === undefined ? {} : {
105
+ ...(input?.onEvent === undefined && progressObserver === null ? {} : {
106
106
  inputDiagnostics: {
107
- onEvent: input.onEvent,
108
- ...(input.now === undefined ? {} : { now: input.now }),
107
+ onEvent: event => {
108
+ input?.onEvent?.(event);
109
+ progressObserver?.inputPhase?.(event.phase, event.revision);
110
+ },
111
+ ...(input?.now === undefined ? {} : { now: input.now }),
109
112
  },
110
113
  }),
111
114
  ...(options.terminal === undefined ? {} : { terminal: options.terminal }),
@@ -0,0 +1,34 @@
1
+ /** Payload-free fixture schema; type-only imports keep it outside the evaluated startup graph. */
2
+ export type ResidentInputPhase = "receipt" | "semantic-start" | "semantic-end" | "composition-start" | "composition-end" | "write-start" | "write-end";
3
+ export interface ProgressFields {
4
+ readonly eventSequence?: number;
5
+ readonly revision?: number;
6
+ readonly geometryGeneration?: number;
7
+ readonly bytes?: number;
8
+ readonly count?: number;
9
+ readonly eventKind?: string;
10
+ readonly frameId?: number;
11
+ readonly renderCause?: string;
12
+ readonly fragmentCount?: number;
13
+ readonly transactionKind?: "synchronized-output" | "ordinary";
14
+ }
15
+ export interface ProgressRecord extends ProgressFields {
16
+ readonly schema: "a1-resident-progress-observation-v1";
17
+ readonly runId: string;
18
+ readonly role: "child";
19
+ readonly stage: "engine-delivery" | "child-render-write" | "child-input-phase";
20
+ readonly pid: number;
21
+ readonly processInstance: string;
22
+ readonly timestampUnixUs: number;
23
+ readonly clockErrorUs: number;
24
+ readonly sequence: number;
25
+ readonly tabId: string;
26
+ readonly incarnation: number;
27
+ readonly lostBefore: number;
28
+ }
29
+ export interface ResidentProgressObserverPort {
30
+ readonly tabId: string;
31
+ engineDelivery(event: unknown): void;
32
+ inputPhase?(phase: ResidentInputPhase, revision: number): void;
33
+ childRenderWrite(bytes: number, fragments: number, transaction: "synchronized-output" | "ordinary", frameId?: number, renderCause?: string): void;
34
+ }
@@ -1,7 +1,4 @@
1
- export interface ResidentProgressObserverPort {
2
- readonly tabId: string;
3
- engineDelivery(event: unknown): void;
4
- childRenderWrite(bytes: number, fragments: number, transaction: "synchronized-output" | "ordinary", frameId?: number, renderCause?: string): void;
5
- }
6
- /** Returns the opt-in payload-free observer for a resident child, or null on ordinary launches. */
1
+ import type { ResidentProgressObserverPort } from "./progress-observation-schema.js";
2
+ export type { ResidentProgressObserverPort } from "./progress-observation-schema.js";
3
+ /** Opt-in payload-free child observer; ordinary launches return null. */
7
4
  export declare function residentProgressObserver(environment?: NodeJS.ProcessEnv): ResidentProgressObserverPort | null;
@@ -17,7 +17,10 @@ class ResidentProgressObserver {
17
17
  #engineSequence = 0;
18
18
  #pendingBytes = 0;
19
19
  #lost = 0;
20
- #writing = Promise.resolve();
20
+ #writing = false;
21
+ #pending = [];
22
+ #scheduled = false;
23
+ #directoryReady = false;
21
24
  #failed = false;
22
25
  get tabId() { return this.#tabId; }
23
26
  constructor(directory, runId, tabId, incarnation) {
@@ -36,6 +39,9 @@ class ResidentProgressObserver {
36
39
  count: 1,
37
40
  });
38
41
  }
42
+ inputPhase(phase, revision) {
43
+ this.#observe("child-input-phase", { eventKind: phase, revision, count: 1 });
44
+ }
39
45
  childRenderWrite(bytes, fragments, transaction, frameId, renderCause) {
40
46
  this.#observe("child-render-write", {
41
47
  eventSequence: this.#engineSequence,
@@ -59,7 +65,7 @@ class ResidentProgressObserver {
59
65
  pid: process.pid,
60
66
  processInstance: this.#processInstance,
61
67
  timestampUnixUs: Math.round((performance.timeOrigin + performance.now()) * 1_000),
62
- // Rationale: timeOrigin is calibrated to the Unix epoch; retain a conservative cross-process error.
68
+ // Rationale: epoch-calibrated timeOrigin retains conservative cross-process clock error.
63
69
  clockErrorUs: 1_000,
64
70
  sequence: ++this.#sequence,
65
71
  tabId: this.#tabId,
@@ -75,18 +81,43 @@ class ResidentProgressObserver {
75
81
  }
76
82
  this.#lost = 0;
77
83
  this.#pendingBytes += length;
78
- this.#writing = this.#writing.then(async () => {
79
- await mkdir(this.#directory, { recursive: true });
80
- await appendFile(this.#path, line, "utf8");
81
- }).catch(() => {
84
+ this.#pending.push(line);
85
+ this.#schedule();
86
+ }
87
+ #schedule() {
88
+ if (this.#scheduled || this.#writing || this.#failed)
89
+ return;
90
+ this.#scheduled = true;
91
+ // Performance: check-phase batches yield to input and amortize file opens and promises.
92
+ setImmediate(() => { this.#scheduled = false; void this.#flush(); });
93
+ }
94
+ async #flush() {
95
+ if (this.#failed || this.#pending.length === 0)
96
+ return;
97
+ this.#writing = true;
98
+ const batch = this.#pending.join("");
99
+ this.#pending = [];
100
+ try {
101
+ if (!this.#directoryReady) {
102
+ await mkdir(this.#directory, { recursive: true });
103
+ this.#directoryReady = true;
104
+ }
105
+ await appendFile(this.#path, batch, "utf8");
106
+ }
107
+ catch {
82
108
  this.#failed = true;
83
- }).finally(() => {
84
- this.#pendingBytes -= length;
85
- });
109
+ this.#pending = [];
110
+ }
111
+ finally {
112
+ this.#pendingBytes -= Buffer.byteLength(batch);
113
+ this.#writing = false;
114
+ if (this.#pending.length > 0)
115
+ this.#schedule();
116
+ }
86
117
  }
87
118
  }
88
119
  let observer;
89
- /** Returns the opt-in payload-free observer for a resident child, or null on ordinary launches. */
120
+ /** Opt-in payload-free child observer; ordinary launches return null. */
90
121
  export function residentProgressObserver(environment = process.env) {
91
122
  if (environment === process.env && observer !== undefined)
92
123
  return observer;
@@ -99,8 +130,7 @@ export function residentProgressObserver(environment = process.env) {
99
130
  : null;
100
131
  if (environment === process.env) {
101
132
  observer = value;
102
- // Security: test evidence paths and tab identity are not child/tool configuration. Retain them only in
103
- // this observer instance so extensions and spawned tools cannot append to the fixture trace.
133
+ // Security: keep evidence paths and identity private; erase them before extensions/tools inherit env.
104
134
  for (const name of [
105
135
  OBSERVATION_DIRECTORY_ENV,
106
136
  OBSERVATION_RUN_ENV,
@@ -7,7 +7,7 @@
7
7
  "platform": "darwin",
8
8
  "architecture": "arm64",
9
9
  "capability": "supported",
10
- "builtAt": "2026-10-24T19:42:42.626Z",
10
+ "builtAt": "2026-10-26T04:56:17.941Z",
11
11
  "artifact": {
12
12
  "filename": "process-guardian.node",
13
13
  "sha256": "a87eaaffcd986b624c8b044b756446cc1bdaf4334a1775b97820542fe34f9fb7",
@@ -9,11 +9,11 @@
9
9
  "architecture": "arm64",
10
10
  "target": "aarch64-apple-darwin",
11
11
  "capability": "supported",
12
- "builtAt": "2026-10-24T19:46:17.340Z",
12
+ "builtAt": "2026-10-26T04:59:18.364Z",
13
13
  "artifact": {
14
14
  "filename": "terminal-host.node",
15
- "sha256": "e4de01b7bec86cbced1c52a6d81be5978a0de558a92bbfed9537c5dfc1af4605",
16
- "size": 5925216
15
+ "sha256": "54bdccc28f03d9e974efb691f99ec2645c528748b1ea9832c9c1e059e111ce92",
16
+ "size": 5941872
17
17
  },
18
18
  "entry": {
19
19
  "filename": "dist/foundation/resident-tabs/host-entry.js",
@@ -7,7 +7,7 @@
7
7
  "platform": "darwin",
8
8
  "architecture": "x64",
9
9
  "capability": "supported",
10
- "builtAt": "2026-10-24T19:42:48.347Z",
10
+ "builtAt": "2026-10-26T04:56:23.732Z",
11
11
  "artifact": {
12
12
  "filename": "process-guardian.node",
13
13
  "sha256": "783a65f0de287a1c02cd5429dbe97bc8633f4cc8a7b92e3e961180b9bdcff814",
@@ -9,11 +9,11 @@
9
9
  "architecture": "x64",
10
10
  "target": "x86_64-apple-darwin",
11
11
  "capability": "supported",
12
- "builtAt": "2026-10-24T19:48:24.843Z",
12
+ "builtAt": "2026-10-26T05:01:25.953Z",
13
13
  "artifact": {
14
14
  "filename": "terminal-host.node",
15
- "sha256": "a0eb75eb03c62a5bab59db0fd60e43a79b91767dfb0661af0b00a6a8c23cb3c4",
16
- "size": 6476744
15
+ "sha256": "048fb157fd7f98770d7256ef66638ef5ed225ae42225af8f3095413f95d4957b",
16
+ "size": 6476992
17
17
  },
18
18
  "entry": {
19
19
  "filename": "dist/foundation/resident-tabs/host-entry.js",
@@ -7,7 +7,7 @@
7
7
  "platform": "linux",
8
8
  "architecture": "x64",
9
9
  "capability": "supported",
10
- "builtAt": "2026-10-24T19:42:38.190Z",
10
+ "builtAt": "2026-10-26T04:56:11.560Z",
11
11
  "artifact": {
12
12
  "filename": "process-guardian.node",
13
13
  "sha256": "118e5954e3864672bd8482ab7edf419cb27dcdf2533720316979b7f5cc5a53a5",
@@ -9,11 +9,11 @@
9
9
  "architecture": "x64",
10
10
  "target": "x86_64-unknown-linux-gnu",
11
11
  "capability": "supported",
12
- "builtAt": "2026-10-24T19:46:11.090Z",
12
+ "builtAt": "2026-10-26T04:59:27.220Z",
13
13
  "artifact": {
14
14
  "filename": "terminal-host.node",
15
- "sha256": "fd28a219164f83256eba84c61ba55b662a01a9af77292ff8f5106970a5cd0dc4",
16
- "size": 7210032
15
+ "sha256": "9e59caca78d8e966e1a1d468e47ebba59fb242e43b86e4ee8893a8dd20cb9ab8",
16
+ "size": 7212552
17
17
  },
18
18
  "entry": {
19
19
  "filename": "dist/foundation/resident-tabs/host-entry.js",
@@ -7,10 +7,10 @@
7
7
  "platform": "win32",
8
8
  "architecture": "x64",
9
9
  "capability": "supported",
10
- "builtAt": "2026-10-24T19:43:33.634Z",
10
+ "builtAt": "2026-10-26T04:57:24.731Z",
11
11
  "artifact": {
12
12
  "filename": "process-guardian.node",
13
- "sha256": "eec176bb7bc151266c5097b6f78e3ea95d11780aa13d045c7940f0d397e3d8e6",
13
+ "sha256": "a51e98cbd97f0abfcd99b00101133bfe45509f4a620f275a696985a16f4e2312",
14
14
  "size": 402432
15
15
  },
16
16
  "provenance": {
@@ -9,11 +9,11 @@
9
9
  "architecture": "x64",
10
10
  "target": "x86_64-pc-windows-msvc",
11
11
  "capability": "supported",
12
- "builtAt": "2026-10-24T19:46:43.778Z",
12
+ "builtAt": "2026-10-26T05:00:51.094Z",
13
13
  "artifact": {
14
14
  "filename": "terminal-host.node",
15
- "sha256": "7eb4d836b8d9a4c13593921f329065bd3b706c0593d8d4e992b56ee461006ac5",
16
- "size": 6288896
15
+ "sha256": "2be0eb9858bbfde8dd6dddb8bfc5881918f6c7804f74cd51cc97b56112b1adad",
16
+ "size": 6294016
17
17
  },
18
18
  "entry": {
19
19
  "filename": "dist/foundation/resident-tabs/host-entry.js",
@@ -1,4 +1,4 @@
1
- import { displayWidth } from "./text.js";
1
+ import { displayWidth, graphemeWidth } from "./text.js";
2
2
  /**
3
3
  * Ported from the A1 UI reference implementation (`core/presentation/spans.ts`).
4
4
  * Writing over part of a rendered row is not string slicing: the row carries
@@ -53,7 +53,7 @@ export function overlaySpan(line, from, to, span, options = {}) {
53
53
  continue;
54
54
  }
55
55
  for (const { segment } of GRAPHEMES.segment(token)) {
56
- const width = displayWidth(segment);
56
+ const width = graphemeWidth(segment);
57
57
  if (column + width <= from)
58
58
  head += segment;
59
59
  else if (column >= to)
@@ -1,11 +1,8 @@
1
- /**
2
- * Display-width text handling. Terminals lay out by column, not by code unit,
3
- * so measuring with `String.length` mis-sizes CJK, emoji, and combining marks,
4
- * and counting styling escapes as visible width breaks every layout that uses
5
- * colour.
6
- */
1
+ /** Terminal-column geometry: preserve graphemes, Unicode cell widths and ANSI styling. */
7
2
  /** Removes styling sequences so only visible characters remain. */
8
3
  export declare function stripAnsi(text: string): string;
4
+ /** Width of one grapheme cluster: two for emoji, else the widest code point it contains. */
5
+ export declare function graphemeWidth(grapheme: string): number;
9
6
  export interface DisplayColumnRange {
10
7
  readonly from: number;
11
8
  readonly to: number;
@@ -1,9 +1,4 @@
1
- /**
2
- * Display-width text handling. Terminals lay out by column, not by code unit,
3
- * so measuring with `String.length` mis-sizes CJK, emoji, and combining marks,
4
- * and counting styling escapes as visible width breaks every layout that uses
5
- * colour.
6
- */
1
+ /** Terminal-column geometry: preserve graphemes, Unicode cell widths and ANSI styling. */
7
2
  const ANSI_PATTERN = /\[[0-9;:?]*[ -/]*[@-~]|[\]_][^]*(?:|\\)|[@-Z\\-_]/g;
8
3
  const SEGMENTER = new Intl.Segmenter(undefined, { granularity: "grapheme" });
9
4
  const WORD_SEGMENTER = new Intl.Segmenter(undefined, { granularity: "word" });
@@ -76,7 +71,7 @@ function couldBeEmoji(grapheme) {
76
71
  grapheme.length > 1);
77
72
  }
78
73
  /** Width of one grapheme cluster: two for emoji, else the widest code point it contains. */
79
- function graphemeWidth(grapheme) {
74
+ export function graphemeWidth(grapheme) {
80
75
  if (couldBeEmoji(grapheme) && RGI_EMOJI_PATTERN.test(grapheme))
81
76
  return 2;
82
77
  let width = 0;
@@ -126,8 +121,11 @@ export function displayColumnSlice(text, requestedFrom, requestedTo) {
126
121
  }
127
122
  /** Columns this text occupies once styling is removed. */
128
123
  export function displayWidth(text) {
124
+ const plain = stripAnsi(text);
125
+ if (!/[^\x20-\x7e]/u.test(plain))
126
+ return plain.length;
129
127
  let width = 0;
130
- for (const { segment } of SEGMENTER.segment(stripAnsi(text)))
128
+ for (const { segment } of SEGMENTER.segment(plain))
131
129
  width += graphemeWidth(segment);
132
130
  return width;
133
131
  }
@@ -239,7 +239,7 @@ The channels carry bounded generation-1 frames: a u32 little-endian length follo
239
239
 
240
240
  ### 6. Rendering, input, and outer-terminal fidelity
241
241
 
242
- - **Composition.** The attach client composes row 0 (the strip) and rows `1..N` (the viewed tab's surface). The tab PTY is sized `cols × (rows − 1)`. Ghostty remains the sole child-terminal parser. Its stream parser reports synchronized-output begin/end/reset boundaries to the holder, which keeps mutable parser state separate from an immutable committed surface and never publishes an open transaction. A non-renewable 250 ms deadline publishes one typed recovery commit for a malformed transaction. On Windows, ConPTY re-renders the child's cells on its own schedule and relays the DEC 2026 markers when it parses them, so a render pass can land between a frame's markers and the rest of its cells can arrive after the end marker; the holder therefore treats a relayed end marker as "frame parsed", keeps the state private until the following render pass has arrived and settled for 2 ms, and publishes anyway after a 40 ms bound. A begin marker that arrives while that pass is still pending does not publish the torn state. Unix PTYs relay bytes verbatim, so their markers still delimit frames exactly. The outer composer owns the only synchronized envelope and falls back to a full repaint only when identity, geometry generation, dimensions, or the structured base changes.
242
+ - **Composition.** The attach client composes row 0 (the strip) and rows `1..N` (the viewed tab's surface). The tab PTY is sized `cols × (rows − 1)`. Ghostty remains the sole child-terminal parser. Its stream parser reports synchronized-output begin/end/reset boundaries to the holder, which keeps mutable parser state separate from an immutable committed surface and never publishes an open transaction. A non-renewable 250 ms deadline publishes one typed recovery commit for a malformed transaction. On Windows, ConPTY re-renders the child's cells on its own schedule and relays the DEC 2026 markers when it parses them, so a render pass can land between a frame's markers and the rest of its cells can arrive after the end marker; the holder therefore treats a relayed end marker as "frame parsed", keeps the state private until the following render pass has arrived and settled for 2 ms, with a non-renewable 16 ms fallback for the oldest unpublished pass. New end markers and continuous settling fragments cannot postpone that bound; consuming a complete or recovery publication clears it for the next update. The fallback never authorizes ordinary publication inside an open transaction. A begin marker that arrives while that pass is still pending does not publish the torn state. Unix PTYs relay bytes verbatim, so their markers still delimit frames exactly. The outer composer owns the only synchronized envelope and falls back to a full repaint only when identity, geometry generation, dimensions, or the structured base changes. Decoded child grids move into shared immutable attach/outer-offer/completed-baseline custody, so chrome-only work neither deep-clones nor revalidates an unchanged body. Overlay restoration and new grids still take the damage/validation path, and resize fading uses copy-on-write. Each attach round admits one queued input before its bounded server-render round; neither input nor rendering can starve the other. Attach and holder wait on coalesced wake notifications only after a round receives no work, so an already-ready backlog never waits for another producer pulse; all per-lane round limits and quiescent idle waits remain intact.
243
243
  - **Outer modes.** The client negotiates the outer terminal's modes: raw mode, alternate screen, bracketed paste, focus events, SGR mouse, kitty keyboard protocol where available, and synchronized output.
244
244
  - Child-requested modes are tracked in the holder's model. Input is re-encoded per child mode by libghostty-vt, which the proof already does.
245
245
  - Mouse rows are offset by the strip. Row 0 belongs to the client.
@@ -260,7 +260,7 @@ Direct `a1 solo` is the behavioural oracle for every viewed resident child. Only
260
260
  - **Modes and cursor.** Each surface carries the child's cursor cell and modes. Attach mirrors a cursor shape the child chose and resets it on detach or failure; a default block cursor is left to the outer terminal, as direct A1 leaves it.
261
261
  - **Shortcut projection.** The owned child projects the effective A1 keybindings plus `keybindings.json` into one assignment per tab action: a key an A1 action holds never becomes a tab shortcut, and the earlier declaration keeps a duplicated key. It publishes the projection as `bridge.shortcuts`; the server relays it as `tabs.shortcuts`, and attach dispatches and labels exactly that projection. `/hotkeys` renders the same projection. A shared case file is replayed by both resolvers.
262
262
  - **Committed presentation.** A requested view commits only with a topology that lists it and a complete target surface. Retained rows, palette/default colors, modes, and cursor are captured atomically; equal captures do not invent a revision. Surfaces of the committed view apply in revision order, and revisions rise across holder incarnations. A retained re-offer is marked stale from the request start and parks for at most 120 ms while the fresh frame arrives. One compositor writes strip, body, overlay, modes, and the viewport-clipped final cursor inside a single synchronized update. It erases suffix cells when a complete replacement row becomes shorter and restores the newest underlying surface when an overlay leaves. Clock, hover, and title-animation damage repaints only the strip and restores the child's cursor.
263
- - **Evidence.** One interaction matrix drives three layers: an owned-shell oracle that records content-free observations, role fixtures that drive real server, holder, and attach processes with a certified parity child, and exact-artifact harnesses. `verify-interaction-parity.mjs` compares the bytes the same child observes directly and through the built host. `verify-resident-parallel-progress.mjs` configures the real engine against a bounded loopback streaming provider and crosses all six first-response orders with all three initial views while every turn remains unfinished behind a completion barrier. At matching 100×29 child geometry, the same real-A1 prompt also runs through isolated direct-solo and resident profiles; the native Ghostty oracle compares a content-free digest of the intermediate fixture cells and their resolved styles together with normalized cursor and mode state. It advances only at parser-reported synchronized-output boundaries, rejects unbalanced transactions or disappearing intermediate cells, and excludes only the resident strip row rather than normalizing terminal semantics. Opt-in per-process JSONL observations identify engine delivery, completed child writes, PTY ingestion, distinct holder commits, attach receipt, and completed outer paint by run/tab/incarnation/process-instance/sequence without recording terminal or conversation content; queue loss, clock faults, duplicates, stale order, and missing stages fail the report. Named pressure variants keep all turns unfinished while exercising hidden progress, repeated switching, navigation input, rename overlays, tab-local resize, a bounded 35 ms attach-receipt delay, and a 900 ms paused outer sink; every tab must retain partial animation/progress before settlement and then present its final output. A detached/reconnect variant releases all three unfinished turns after terminating the authenticated attach and exact self-reported server identity; child writes, PTY ingestion, and holder commits must continue before a replacement server and attach present every retained final output. Separate isolated exact-artifact control markers stop one target tab at engine delivery, physical child rendering, holder commit, or outer paint; each control requires its upstream stages and the other tabs to advance, then removes the stop and requires final output from all three tabs. The outer-paint control waits for a payload-free `fixture-stop-ack` from the sole writer before starting its scenario; that acknowledgement follows all earlier writes, and same-writer sequence ordering excludes only pre-acknowledgement paints from the zero-progress check. Any later paint still fails. A fifth control fragments a real owned-shell synchronized write into at most 64 physical writes without changing its bytes, records the DEC private mode 2026 transaction classification, and requires ordinary complete holder commits without deadline recovery before final output. This characterizes the built PTY/ConPTY coherence path; a passing fragmented run does not by itself assign the historical stall to that path without a failing live reproduction. The marker path is absent in ordinary sessions and is scrubbed before extensions or tools inherit the child environment, while observation callbacks remain passive and cannot select a control. CI runs the vendored Ghostty VT tests and both exact-artifact harnesses on Windows x64, Linux x64, and macOS arm64. Each platform's verdict stands alone.
263
+ - **Evidence.** One interaction matrix drives three layers: an owned-shell oracle that records content-free observations, role fixtures that drive real server, holder, and attach processes with a certified parity child, and exact-artifact harnesses. `verify-interaction-parity.mjs` compares the bytes the same child observes directly and through the built host. `verify-resident-parallel-progress.mjs` configures the real engine against a bounded loopback streaming provider and crosses all six first-response orders with all three initial views while every turn remains unfinished behind a completion barrier. At matching 100×29 child geometry, the same real-A1 prompt also runs through isolated direct-solo and resident profiles; the native Ghostty oracle compares a content-free digest of the intermediate fixture cells and their resolved styles together with normalized cursor and mode state. It advances only at parser-reported synchronized-output boundaries, rejects unbalanced transactions or disappearing intermediate cells, and excludes only the resident strip row rather than normalizing terminal semantics. Opt-in per-process JSONL observations identify engine delivery, completed child writes, PTY ingestion, distinct holder commits, attach receipt, and completed outer paint by run/tab/incarnation/process-instance/sequence without recording terminal or conversation content; queue loss, clock faults, duplicates, stale order, and missing stages fail the report. The child observer batches check-phase appends with one directory initialization while retaining its pending-byte and loss limits. Auxiliary PTY-input completion and child input/semantic/composition/write phases narrow input-side delays without recording key or terminal content. Healthy viewed windows require at least forty matched live commit-to-first-paint samples per tab and enforce p95 at most 33 ms; activation/stale re-offers, later chrome paints of the same revision, and deliberately stopped or paused-sink windows cannot masquerade as live delivery samples. An additional real-A1 fixture compares forty synthetic typing, Models navigation, and transcript wheel responses per path at equal child geometry. Timing requires the shipping Rust optimization profile with all fixture controls retained; debug unit/role/probe coverage and feature-free shipping-artifact checks remain separate. Both paths retain matching complete 60-marker transcript baselines before sampling. Untimed provider setup acknowledges a complete literal editor echo before sending a separate Enter; the measured inputs keep their ordinary 30 ms cadence. Its incremental native Ghostty oracle matches completed semantic states, permits coalesced intermediate states, and rejects missing responses, one-second stalls, or resident p95 beyond direct solo plus the existing 16+33 ms input/presentation envelope. Direct target hashes come from the final semantic state in each ordinary inter-input interval, while timing uses its first observed occurrence, not a later settling delay or an early torn ConPTY hash. A fixed fixture role entry pins the exact addon for all detached roles, including Windows WMI launches that do not inherit the invoking shell's development override; production launch behavior is unchanged. Named pressure variants keep all turns unfinished while exercising hidden progress, repeated switching, navigation input, rename overlays, tab-local resize, a bounded 35 ms attach-receipt delay, and a 900 ms paused outer sink; every tab must retain partial animation/progress before settlement and then present its final output. A detached/reconnect variant releases all three unfinished turns after terminating the authenticated attach and exact self-reported server identity; child writes, PTY ingestion, and holder commits must continue before a replacement server and attach present every retained final output. Separate isolated exact-artifact control markers stop one target tab at engine delivery, physical child rendering, holder commit, or outer paint; each control requires its upstream stages and the other tabs to advance, then removes the stop and requires final output from all three tabs. The outer-paint control waits for a payload-free `fixture-stop-ack` from the sole writer before starting its scenario; that acknowledgement follows all earlier writes, and same-writer sequence ordering excludes only pre-acknowledgement paints from the zero-progress check. Any later paint still fails. A fifth control fragments a real owned-shell synchronized write into at most 64 physical writes without changing its bytes, records the DEC private mode 2026 transaction classification, and requires ordinary complete holder commits without deadline recovery before final output. This characterizes the built PTY/ConPTY coherence path; a passing fragmented run does not by itself assign the historical stall to that path without a failing live reproduction. The marker path is absent in ordinary sessions and is scrubbed before extensions or tools inherit the child environment, while observation callbacks remain passive and cannot select a control. CI runs the vendored Ghostty VT tests and both exact-artifact harnesses on Windows x64, Linux x64, and macOS arm64. Each platform's verdict stands alone.
264
264
 
265
265
  ### 7. Status and attention come from the tab bridge
266
266
 
@@ -6,11 +6,13 @@ Development validation computes one exact base/head selection with:
6
6
  npm run select:validation-impact -- --base <full-base-sha> --head <full-head-sha> --output .artifacts/validation/impact.json
7
7
  ```
8
8
 
9
- The versioned `config/validation-ownership.json` registry maps stable product and test path groups to a mandatory PR core, affected unit tests, resource-sensitive tests, and integration owners. The initial coarse owners are UI/rendering, launch/startup, release/package/update, Pi, native containment, image/history, governance, and shared product inputs. Each integration owner in `config/integration-owners.json` declares `pull-request` or `exhaustive` cadence. A changed pull-request test selects its owner; a changed exhaustive test selects focused deterministic contracts and records the exhaustive owner as cadence-deferred. Shared support selects every declared PR consumer and records affected exhaustive consumers; copies, renames, and deletions inspect both identities. Reasons and changed paths are recorded in `impact.json`.
9
+ The versioned `config/validation-ownership.json` registry maps stable product and test path groups to a mandatory PR core, an explicit critical floor per owner, changed and bounded transitive consumers, resource-sensitive tests, and integration owners. The coarse owners are UI/rendering, launch/startup, release/package/update, Pi, native containment, image/history, governance, and shared product inputs. Each integration owner in `config/integration-owners.json` declares `pull-request`, `direct-impact`, or `exhaustive` cadence. A changed pull-request test selects its owner; a changed exhaustive test selects focused deterministic contracts and records the exhaustive owner as cadence-deferred. Shared support selects every declared PR consumer and records affected exhaustive consumers; copies, renames, and deletions inspect both identities. Reasons and changed paths are recorded in `impact.json`.
10
10
 
11
- Unknown operational inputs, unavailable comparison history, workflow/selector/suite/aggregate changes, and manual Development dispatch select every pull-request owner. Missing, malformed, or unknown cadence blocks instead of guessing. Documentation-only and version-only changes retain explicit exemptions. An implementation-bound association (an `openspec-implementation` link in the PR body) only disables those two exemptions: the PR core still runs, and owners are still selected by impact rather than forced to conservative coverage. Selection does not require whole-repository source parsing.
11
+ Reviewed `refinements` can narrow a coarse owner's tests and integration links for known subareas: scrollbar/settings, clipboard/editor/repository commands, documentation/cleanup/delivery governance, and development-environment tooling. Each rule keeps an explicit minimum test set; a bounded relative-import graph across `test/`, `src/`, `scripts/`, and `bin/` adds at most 24 sorted transitive consumers per changed path, including consumers outside the coarse owner, and integration owners of those retained consumers. The graph is supplemental, not sole coverage authority. Unreviewed or absent source identities and an unavailable graph retain the coarse owner. Changed tests, shared support, and mixed source/support changes retain their coarse contracts; rename and deletion classification still includes both identities. Some UI changes deliberately select more tests than before because the graph exposes formerly missed shell consumers.
12
12
 
13
- The `changes` job then derives the modular job matrix from that same selection through `scripts/release/validation-matrix.mjs`, which declares every Development modular job and returns only the entries the selection activates; GitHub never schedules an inactive entry, so an ordinary PR does not spend runner minutes on jobs that would resolve to nothing. Each scheduled job still resolves its own owners from the uploaded impact artifact, and the aggregate still requires evidence for every selected owner, so an entry that should have run and did not fails the run.
13
+ Unknown operational inputs, unavailable comparison history, workflow/selector/suite/aggregate changes, and manual Development dispatch select every coarse owner's critical floor and only integration owners with `pull-request` cadence. Direct-impact owners require a changed declared test, support, or production surface; exhaustive owners remain deferred. Missing, malformed, or unknown cadence blocks instead of guessing. Documentation-only and version-only changes retain explicit exemptions. An implementation-bound association (an `openspec-implementation` link in the PR body) only disables those two exemptions: the PR core still runs, and owners are still selected by impact rather than forced to conservative coverage. Selection does not require whole-repository source parsing.
14
+
15
+ The `changes` job then derives the modular job matrix from that same selection through `scripts/release/validation-matrix.mjs`, which declares every Development modular job and returns only the entries the selection activates; GitHub never schedules an inactive entry, so an ordinary PR does not spend runner minutes on jobs that would resolve to nothing. The matrix uses fail-fast cancellation, so a decisive failure stops remaining cells while missing or cancelled selected evidence still blocks the aggregate. Each scheduled job still resolves its own owners from the uploaded impact artifact, and the aggregate still requires evidence for every selected owner, so an entry that should have run and did not fails the run.
14
16
 
15
17
  ## Commands and coverage levels
16
18
 
@@ -42,7 +44,7 @@ Preflight selects the committed merge-base diff with `origin/develop` exactly as
42
44
 
43
45
  `test:pr-core` is not a replacement for `test:fast`: CI combines it with directly changed and coarse-owner tests from the exact impact selection. Selected resource-sensitive tests run independently on an isolated Windows runner. Selected package, startup, rendering, Pi, compatibility, and platform owners also run independently after their actual prerequisites.
44
46
 
45
- Conservative Development retains every pull-request owner but does not schedule exhaustive owners. The complete regression implementation runs inside a PR only when base policy verifies an `openspec-ci` App-created repair, its generated candidate identity, and a failed Full regression source in `regression-provenance.json`. Publishing/prerequisite/validation-authority impact, shared inputs, unknown paths, labels, Publish-only repairs, and successful-run persistent-overrun candidates retain bounded ordinary validation. Planning-only generated repair drafts stay exempt; eligible implementation drafts get feedback without integration authority. The selected exact-head evidence must include Windows Node 22/24, Linux Node 24, and macOS Node 24. Full regression and nightly/stable release retain both cadence classes and the same coverage through the shared implementation. The real three-release `update-predecessor` exact-package oracle is exhaustive; deterministic predecessor command, fixture, materialization, warmup, package, and update contracts remain PR-eligible. Preview and release continue to consume exact candidate bytes under their channel-specific contracts. A standalone manual Full regression remains useful for diagnosis or an unselected candidate, but never replaces automatically selected current-PR evidence. The generated ownership ledger command is:
47
+ Conservative Development retains every critical owner floor and the small set of `pull-request` integration owners, while scheduling only directly affected `direct-impact` owners and deferring all exhaustive owners. The complete regression implementation runs inside a PR only when base policy verifies an `openspec-ci` App-created repair, its generated candidate identity, and a failed Full regression source in `regression-provenance.json`. Publishing/prerequisite/validation-authority impact, shared inputs, unknown paths, labels, Publish-only repairs, and successful-run persistent-overrun candidates retain bounded ordinary validation. Planning-only generated repair drafts stay exempt; eligible implementation drafts get feedback without integration authority. The selected exact-head evidence must include Windows Node 22/24, Linux Node 24, and macOS Node 24. Full regression and nightly/stable release retain both cadence classes and the same coverage through the shared implementation. The real three-release `update-predecessor` exact-package oracle is exhaustive; deterministic predecessor command, fixture, materialization, warmup, package, and update contracts remain PR-eligible. Preview and release continue to consume exact candidate bytes under their channel-specific contracts. A standalone manual Full regression remains useful for diagnosis or an unselected candidate, but never replaces automatically selected current-PR evidence. The generated ownership ledger command is:
46
48
 
47
49
  ```bash
48
50
  node scripts/release/generate-validation-ownership-ledger.mjs --output .artifacts/validation/ownership-ledger.json
@@ -54,6 +56,24 @@ The `terminal-host` owner is CI-only. A change under `native/terminal-host/` or
54
56
 
55
57
  The protected aggregate requires every partition of every selected platform, keyed by `partition` in the outcome authority and job envelope. Because the role suite no longer warms the resident launch paths in the build-and-probe job, its certification step runs one unmeasured `measure-resident-tabs.mjs` pass before the measured pass whose budgets are unchanged. Fidelity, latency, chaos, and certification start roles as `process.execPath dist/foundation/resident-tabs/host-entry.js` with `A1_TERMINAL_HOST_PATH` naming the addon. Windows cleanup identifies those Node-hosted residents by command line; it never kills every `node.exe` by image name. Locally, `npm run test:terminal-host` without a partition is unchanged and runs everything in one process. Local Windows builds fail in `build.rs` unless `TERMINAL_HOST_LOCAL_BUILD=1` is set, because Zig's package fetch unpacks test data that workstation antivirus quarantines. Native lanes also publish the terminal library they linked; a local build can link it instead of running Zig (see Local native iteration in [`architecture/resident-tabs.md`](architecture/resident-tabs.md)), which is development evidence only and never replaces selected CI. `TERMINAL_HOST_CONTRACTS_ONLY=1` is a library-only diagnostic and cannot substitute for selected CI. See [`native/terminal-host/README.md`](../native/terminal-host/README.md).
56
58
 
59
+ ## Coverage-preserving efficiency
60
+
61
+ Complete regression selects the full rendering scope instead of also executing its superseded smoke files. Full captures call the same smoke assertions, including independent producer identity, readiness, semantic parity, synchronization, and bounded paint checks. Smoke-only corrupted-evidence controls live in an ordinary deterministic test. Scheduled content runs once in each gate through the same owned-versus-pinned helper. The retained full matrix has 11 streaming workloads across three producers and two modes, two scheduled-content workloads across two producers, and six input workloads batched across three producers: 73 matrix launches plus 10 protocol-failure launches. Standalone smoke retains 19 launches. Full regression avoids the additional 19 smoke launches; it does not remove a workload or platform lane.
62
+
63
+ The coverage ledger test reconstructs every full-plan invocation and requires each retained file exactly once, except the two smoke files whose executed replacement contracts it names explicitly. Unit, shell integration, source/emitted entries, independent pinned parity, security/race controls, and runtime-specific tests are not interchangeable merely because they touch the same module.
64
+
65
+ The package-command transcript fixture uses four file-owned producer processes (owned/pinned times color 0/1), rather than starting 22 equivalent loaders. Every request still runs the real command with its independent home/settings and fresh transcript; failed producers are never restarted. Fresh-home isolation and process disposal are tested. Cold-entry contracts elsewhere retain their cold process boundary. Git cleanup scenarios still initialize their own real repository/worktree, but write private Git configuration once instead of launching four config/remote commands. Release fixtures create baseline refs in one real atomic ref transaction. Setup remains inside the owning scenario and no mutable fixture repository is shared.
66
+
67
+ Exact-package identity walks hash each payload as it is read, retain only file digests, and parse the manifest from that same walk. They keep the original digest contract, all pre/post consumer verifications, fresh prefixes, and separate shard installations. This removes duplicate manifest reads and full-payload buffering; it does not cache verification results or promise a material improvement to npm installation time.
68
+
69
+ Generate a content-free per-file inventory and optional observed timing report from an existing Actions run and log:
70
+
71
+ ```bash
72
+ node scripts/release/validation-cost-report.mjs --run .artifacts/agent/completed-run.json --log .artifacts/agent/job.log --output .artifacts/validation/cost-report.json
73
+ ```
74
+
75
+ The run JSON is the output of `gh run view RUN --json jobs,headSha,createdAt,updatedAt`; the log is from that same run's chosen job. Omit both inputs for inventory only. Reports are observational, never validation receipts. They identify source drift, each retained file's coarse owner/execution class, job and step duration, total runner time, longest job, workflow elapsed time, and runner span. Queue and DAG critical-path timing remain unavailable rather than guessed. File timings preserve repeated observations; never add concurrent job/file durations and call the result elapsed savings. Compare comparable completed runs before claiming a hosted speedup. No passing outcomes, installed trees, or mutable fixture state may be cached by these optimizations.
76
+
57
77
  ## Windows Full regression shards
58
78
 
59
79
  Standalone and PR-attached Full regression run each Windows runtime (Node 22 and Node 24) as five hosted-runner shards derived from the one canonical `full-release` plan: `core` (command gates and the bounded-parallel ordinary remainder), `resource` (the serial resource-sensitive invocation with its unchanged explicit bound), `rendering` (the serial isolated rendering invocation), `package` (packing, its own exact-package installation, Defender-backed first-attempt startup before package contracts, package smoke, and update timing), and `predecessor` (packing, its own exact-package installation, and the exhaustive published-predecessor invocation, which took 11 to 12 minutes of the former package shard on Windows). Each shard checks out, installs, builds, and records its own build receipt; the package and predecessor shards each pack and install their own candidate, and no installed state crosses shards. Linux, macOS, local `npm run test:full`, and the sequential publication lanes keep one complete plan with one shared installation.
@@ -132,4 +152,4 @@ Draft pull requests run no Development test suites. A ready version-3 PR whose b
132
152
 
133
153
  To disable selective execution without reducing PR coverage, use manual Development dispatch or force conservative ownership selection. To restore the historical predecessor oracle to every applicable PR, change its cadence from `exhaustive` to `pull-request`; do not delete it from Full/nightly/release. To disable prior-attempt reuse, require all accepted attempts to equal the aggregate attempt; this must not remove attempt-qualified artifacts or failure visibility. To disable prerequisite reuse, unset readiness/tarball variables and receipt paths so tier orchestration rebuilds and repacks.
134
154
 
135
- Rollback must retain every test, startup budget, zero automatic retry policy, platform/runtime lane, exact-package identity, resource isolation, complete fast/full/release compositions, and the single stable protected-branch aggregate.
155
+ Rollback must retain complete Full/nightly/release test coverage, startup budgets, zero automatic retry policy, required release platform/runtime lanes, exact-package identity, resource isolation, and the single stable protected-branch aggregate. It must not restore owner-wide or unrelated exhaustive execution to ordinary pull requests.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timurproko/a1",
3
- "version": "0.2.7-dev.831",
3
+ "version": "0.2.7-dev.834",
4
4
  "description": "Standalone terminal workspace for supervised native and managed agents",
5
5
  "type": "module",
6
6
  "privateLaunchContract": "neutral-launch-v1",