@timurproko/a1 0.1.8-dev.444 → 0.1.8-dev.457

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.
Files changed (37) hide show
  1. package/README.md +9 -0
  2. package/dist/composition/owned-ui.js +11 -0
  3. package/dist/contracts/owned-ui/model.d.ts +10 -0
  4. package/dist/foundation/release/update.js +1 -1
  5. package/dist/foundation/startup/startup-descriptor.js +2 -2
  6. package/dist/integrations/pi/components/shell-editor-autocomplete.js +1 -0
  7. package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +2 -0
  8. package/dist/integrations/pi/components/upstream/components/owned-editor.js +17 -0
  9. package/dist/integrations/pi/engine/adapter.d.ts +2 -0
  10. package/dist/integrations/pi/engine/adapter.js +25 -6
  11. package/dist/integrations/pi/engine/settings-effects.d.ts +1 -1
  12. package/dist/integrations/pi/engine/settings-effects.js +1 -1
  13. package/dist/integrations/pi/session-ui/quit-outro-effects.d.ts +29 -0
  14. package/dist/integrations/pi/session-ui/quit-outro-effects.js +242 -0
  15. package/dist/integrations/pi/session-ui/quit-outro.d.ts +38 -0
  16. package/dist/integrations/pi/session-ui/quit-outro.js +98 -0
  17. package/dist/integrations/pi/session-ui/session-shell-root.d.ts +12 -1
  18. package/dist/integrations/pi/session-ui/session-shell.js +57 -5
  19. package/dist/integrations/pi/startup-public.js +86 -13
  20. package/dist/integrations/pi/startup-public.manifest.json +121 -61
  21. package/dist/integrations/pi/tui-runtime/adapter.d.ts +10 -2
  22. package/dist/integrations/pi/tui-runtime/adapter.js +53 -4
  23. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +7 -0
  24. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +12 -0
  25. package/dist/native/darwin-arm64/manifest.json +1 -1
  26. package/dist/native/linux-x64/manifest.json +1 -1
  27. package/dist/native/win32-x64/manifest.json +2 -2
  28. package/dist/native/win32-x64/process-guardian.exe +0 -0
  29. package/dist/ui/settings/declarations.d.ts +3 -1
  30. package/dist/ui/settings/declarations.js +22 -1
  31. package/dist/ui/settings/migrations.js +7 -0
  32. package/docs/ci-release-runbook.md +10 -10
  33. package/docs/local-worktree-cleanup.md +8 -4
  34. package/docs/manual-owned-ui-checkpoint.md +3 -2
  35. package/docs/openspec-archive-automation.md +21 -8
  36. package/docs/validation.md +5 -3
  37. package/package.json +1 -1
@@ -120,15 +120,20 @@ export class PiTuiRuntimeAdapter {
120
120
  #stopPromise;
121
121
  #rootDisposed = false;
122
122
  #terminalProgress = false;
123
+ #presentationFrozen = false;
123
124
  constructor(options) {
124
125
  this.#root = options.root;
125
126
  this.#overlayGeometry = options.onOverlayGeometry === undefined ? undefined : new OverlayGeometryTracker(options.onOverlayGeometry);
126
127
  this.#terminal = options.terminal ?? new ProcessTerminal();
127
128
  this.#inputDiagnostics = options.inputDiagnostics;
128
129
  this.#diagnosticNow = options.inputDiagnostics?.now ?? (() => performance.now());
130
+ // Invariant: the pinned renderer's frames pass through this gate, while writeControl and
131
+ // the stop sequence reach the terminal directly. Freezing drops frames without touching
132
+ // the renderer, so a scheduled repaint cannot land on top of the quit outro.
133
+ const gatedTerminal = frozenGateTerminal(this.#terminal, () => this.#presentationFrozen);
129
134
  const tracedTerminal = options.inputDiagnostics === undefined
130
- ? this.#terminal
131
- : diagnosticTerminal(this.#terminal, phase => this.#traceRuntimePhase(phase));
135
+ ? gatedTerminal
136
+ : diagnosticTerminal(gatedTerminal, phase => this.#traceRuntimePhase(phase));
132
137
  const decoratedTerminal = options.decorateTerminal?.(tracedTerminal) ?? tracedTerminal;
133
138
  const coordination = options.inputCoordination ?? (options.inputDiagnostics === undefined
134
139
  ? undefined
@@ -297,13 +302,26 @@ export class PiTuiRuntimeAdapter {
297
302
  }
298
303
  /**
299
304
  * Writes a terminal control sequence. Used to enable and disable mouse
300
- * reporting while an A1-owned application is presented, and for nothing else:
301
- * the transparent and pinned paths never call it.
305
+ * reporting while an A1-owned application is presented and to paint the quit
306
+ * outro while presentation is frozen, and for nothing else: the transparent
307
+ * and pinned paths never call it.
302
308
  */
303
309
  writeControl(data) {
304
310
  this.#assertRunning("control sequence");
305
311
  this.#terminal.write(data);
306
312
  }
313
+ /**
314
+ * Drops every pinned frame write until the runtime stops. The quit outro owns
315
+ * the alternate screen between the last presented frame and the leave; the
316
+ * renderer keeps scheduling but nothing it paints reaches the terminal.
317
+ */
318
+ freezePresentation() {
319
+ this.#assertRunning("presentation freeze");
320
+ this.#presentationFrozen = true;
321
+ }
322
+ get presentationFrozen() {
323
+ return this.#presentationFrozen;
324
+ }
307
325
  addPreInputListener(listener) {
308
326
  if (this.#preInputListeners.has(listener))
309
327
  throw new TypeError("Pi TUI pre-input listener is already registered");
@@ -433,6 +451,9 @@ export class PiTuiRuntimeAdapter {
433
451
  }
434
452
  try {
435
453
  const stopOptions = options.preserveScreen === undefined ? undefined : { preserveScreen: options.preserveScreen };
454
+ // Invariant: the gate opens only for the synchronous stop sequence, so no render
455
+ // scheduled during the outro can slip in before the alternate screen is left.
456
+ this.#presentationFrozen = false;
436
457
  this.#tui.stop(stopOptions);
437
458
  }
438
459
  catch (error) {
@@ -566,6 +587,7 @@ export class PiTuiRuntimeAdapter {
566
587
  throw new Error(`Pi TUI ${operation} requires a running runtime`);
567
588
  }
568
589
  #restoreAfterFailedStart() {
590
+ this.#presentationFrozen = false;
569
591
  try {
570
592
  this.#tui.stop();
571
593
  }
@@ -581,6 +603,7 @@ export class PiTuiRuntimeAdapter {
581
603
  this.#terminalProgress = false;
582
604
  }
583
605
  #bestEffortTerminalRestore() {
606
+ this.#presentationFrozen = false;
584
607
  this.#clearTerminalProgress();
585
608
  try {
586
609
  if (this.mode === "fullscreen")
@@ -676,6 +699,32 @@ function diagnosticTerminal(terminal, trace) {
676
699
  setProgress: active => terminal.setProgress(active),
677
700
  };
678
701
  }
702
+ function frozenGateTerminal(terminal, frozen) {
703
+ return {
704
+ get columns() { return terminal.columns; },
705
+ get rows() { return terminal.rows; },
706
+ get kittyProtocolActive() { return terminal.kittyProtocolActive; },
707
+ start: (onInput, onResize) => terminal.start(onInput, onResize),
708
+ stop: () => terminal.stop(),
709
+ drainInput: (maxMs, idleMs) => terminal.drainInput(maxMs, idleMs),
710
+ write: data => { if (!frozen())
711
+ terminal.write(data); },
712
+ moveBy: lines => { if (!frozen())
713
+ terminal.moveBy(lines); },
714
+ hideCursor: () => { if (!frozen())
715
+ terminal.hideCursor(); },
716
+ showCursor: () => { if (!frozen())
717
+ terminal.showCursor(); },
718
+ clearLine: () => { if (!frozen())
719
+ terminal.clearLine(); },
720
+ clearFromCursor: () => { if (!frozen())
721
+ terminal.clearFromCursor(); },
722
+ clearScreen: () => { if (!frozen())
723
+ terminal.clearScreen(); },
724
+ setTitle: title => terminal.setTitle(title),
725
+ setProgress: active => terminal.setProgress(active),
726
+ };
727
+ }
679
728
  function preInputTerminal(terminal, route, frameMouse) {
680
729
  let mouse;
681
730
  return {
@@ -63,6 +63,13 @@ export declare class DamageAwareTerminalAdapter implements PiTuiTerminalPort {
63
63
  get kittyProtocolActive(): boolean;
64
64
  get lastDecision(): PiTuiDamageDecision;
65
65
  get hyperlinkCleanupPending(): boolean;
66
+ /**
67
+ * The rows as last forwarded to the terminal, top to bottom, with styling
68
+ * intact. A row the adapter has not seen since its last invalidation is empty.
69
+ * The quit outro animates over this snapshot because it is what the terminal
70
+ * shows, not what a fresh render would produce.
71
+ */
72
+ presentedRows(): readonly string[];
66
73
  /** Latches the former link rows, including rows whose replacement contains no link. */
67
74
  requestHyperlinkCleanup(rows?: readonly number[]): void;
68
75
  arm(descriptor: PiTuiDamageFrameDescriptor, safety: PiTuiDamageFrameSafety): void;
@@ -40,6 +40,18 @@ export class DamageAwareTerminalAdapter {
40
40
  get kittyProtocolActive() { return this.inner.kittyProtocolActive; }
41
41
  get lastDecision() { return this.#decision; }
42
42
  get hyperlinkCleanupPending() { return this.#cleanupRevision > this.#cleanedRevision; }
43
+ /**
44
+ * The rows as last forwarded to the terminal, top to bottom, with styling
45
+ * intact. A row the adapter has not seen since its last invalidation is empty.
46
+ * The quit outro animates over this snapshot because it is what the terminal
47
+ * shows, not what a fresh render would produce.
48
+ */
49
+ presentedRows() {
50
+ const presented = [];
51
+ for (let row = 1; row <= this.rows; row += 1)
52
+ presented.push(this.#rows.get(row) ?? "");
53
+ return presented;
54
+ }
43
55
  /** Latches the former link rows, including rows whose replacement contains no link. */
44
56
  requestHyperlinkCleanup(rows) {
45
57
  this.#cleanupRevision += 1;
@@ -5,7 +5,7 @@
5
5
  "platform": "darwin",
6
6
  "architecture": "arm64",
7
7
  "capability": "supported",
8
- "builtAt": "2026-09-17T06:08:17.369Z",
8
+ "builtAt": "2026-09-17T10:19:32.993Z",
9
9
  "artifact": {
10
10
  "filename": "process-guardian",
11
11
  "sha256": "9db1726bbe3fc2e8292f2ead1e7e9d0fd4d7d0dc9217b372582bf354b0f565dc",
@@ -5,7 +5,7 @@
5
5
  "platform": "linux",
6
6
  "architecture": "x64",
7
7
  "capability": "supported",
8
- "builtAt": "2026-09-17T06:07:57.909Z",
8
+ "builtAt": "2026-09-17T10:19:33.794Z",
9
9
  "artifact": {
10
10
  "filename": "process-guardian",
11
11
  "sha256": "d8cda6b0c7cb36c0cc41e90802aceebf6c02eaebbc08a83d7d963d2e918dbd7a",
@@ -5,10 +5,10 @@
5
5
  "platform": "win32",
6
6
  "architecture": "x64",
7
7
  "capability": "supported",
8
- "builtAt": "2026-09-17T06:08:28.019Z",
8
+ "builtAt": "2026-09-17T10:20:20.745Z",
9
9
  "artifact": {
10
10
  "filename": "process-guardian.exe",
11
- "sha256": "2b7d0783c9b89c4bd790a82cb43bd3905421f3109ae5d5a3a76fbffc2e205976",
11
+ "sha256": "049f0659bfe5d506a900d07e219c6a96480e8495dede8375c7ea5f9e5dc1990d",
12
12
  "size": 177664
13
13
  },
14
14
  "provenance": {
@@ -1,4 +1,4 @@
1
- export declare const OWNED_UI_SETTINGS_VERSION = 4;
1
+ export declare const OWNED_UI_SETTINGS_VERSION = 5;
2
2
  export type OwnedUiSettingValue = string | number | boolean;
3
3
  export type OwnedUiSettingApplication = "live" | "restart";
4
4
  export interface OwnedUiSettingDeclaration {
@@ -15,6 +15,8 @@ export interface OwnedUiSettingDeclaration {
15
15
  readonly defaultValue: OwnedUiSettingValue;
16
16
  readonly allowedValues: readonly OwnedUiSettingValue[];
17
17
  }
18
+ /** Playback lengths the quit outro offers, in milliseconds. */
19
+ export declare const QUIT_EFFECT_DURATIONS_MS: readonly number[];
18
20
  export declare const OWNED_UI_SETTING_DECLARATIONS: readonly OwnedUiSettingDeclaration[];
19
21
  export declare function assertOwnedUiSettingDeclarations(declarations: readonly OwnedUiSettingDeclaration[]): void;
20
22
  export declare function findOwnedUiSettingDeclaration(declarations: readonly OwnedUiSettingDeclaration[], id: string): OwnedUiSettingDeclaration | null;
@@ -1,7 +1,10 @@
1
- export const OWNED_UI_SETTINGS_VERSION = 4;
1
+ export const OWNED_UI_SETTINGS_VERSION = 5;
2
2
  const MAX_ID_LENGTH = 64;
3
3
  const ID_PATTERN = /^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$/;
4
4
  const SCROLL_SECTION = Object.freeze({ id: "scroll", title: "Scroll" });
5
+ const QUIT_SECTION = Object.freeze({ id: "quit", title: "Quit" });
6
+ /** Playback lengths the quit outro offers, in milliseconds. */
7
+ export const QUIT_EFFECT_DURATIONS_MS = Object.freeze(Array.from({ length: 18 }, (_, index) => 300 + index * 100));
5
8
  export const OWNED_UI_SETTING_DECLARATIONS = Object.freeze([
6
9
  Object.freeze({
7
10
  id: "scrollbarAppearance",
@@ -48,6 +51,24 @@ export const OWNED_UI_SETTING_DECLARATIONS = Object.freeze([
48
51
  defaultValue: 100,
49
52
  allowedValues: Object.freeze([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]),
50
53
  }),
54
+ Object.freeze({
55
+ id: "quitEffect",
56
+ label: "Effect",
57
+ section: QUIT_SECTION,
58
+ description: "Animation played over the last screen when the session quits.",
59
+ application: "live",
60
+ defaultValue: "fall",
61
+ allowedValues: Object.freeze(["fall", "dissolve", "starburst", "waves", "off"]),
62
+ }),
63
+ Object.freeze({
64
+ id: "quitEffectDurationMs",
65
+ label: "Duration",
66
+ section: QUIT_SECTION,
67
+ description: "Milliseconds the quit animation plays before the terminal is restored.",
68
+ application: "live",
69
+ defaultValue: 800,
70
+ allowedValues: QUIT_EFFECT_DURATIONS_MS,
71
+ }),
51
72
  Object.freeze({
52
73
  id: "promptSuggestions",
53
74
  label: "Prompt suggestions",
@@ -29,6 +29,13 @@ export const OWNED_UI_SETTINGS_MIGRATIONS = Object.freeze([
29
29
  return { ...values };
30
30
  },
31
31
  }),
32
+ Object.freeze({
33
+ to: 5,
34
+ description: "Introduce the quit outro effect and duration with prototype defaults.",
35
+ migrate(values) {
36
+ return { ...values };
37
+ },
38
+ }),
32
39
  ]);
33
40
  export function assertOwnedUiSettingsMigrations(migrations, currentVersion = OWNED_UI_SETTINGS_VERSION) {
34
41
  const firstProduced = currentVersion - migrations.length + 1;
@@ -58,9 +58,9 @@ effect of stable publication, not a trigger.
58
58
 
59
59
  Ordinary type, architecture, unit/contract, and dist checks always run for code changes. Changed-file documentation and rendering run as independent parallel jobs. Rendered shell/component changes select `smoke`; viewport, scheduler, terminal adapter, evidence harness, package identity, and selector changes select `full`; unrelated changes select `none`. The aggregate accepts a skipped modular job only when the current selector requested the skip.
60
60
 
61
- Integration owners declare one cadence in `config/integration-owners.json`. Impact mode selects affected `pull-request` owners; an invalidator, unknown operational path, or manual Development dispatch selects every `pull-request` owner. `exhaustive` owners are never silently skipped or reported as passed: impact and aggregate evidence list them as cadence-deferred, and malformed cadence blocks selection. Full regression and nightly/stable release still execute both cadence classes.
61
+ Integration owners declare one cadence in `config/integration-owners.json`. Impact mode selects affected `pull-request` owners: a changed production path selects its coarse owner, a changed test selects its owner, and a changed file under `test/support/` or `test/fixtures/` selects the owners of the retained tests that import it directly or through other support files (the selection lists those tests as its `shared-support` reason). A support file that no retained test imports, or a test tree the scanner cannot read, falls back to every owner the shared rule declares and records `shared-support-declared`; an invalidator, unknown operational path, or manual Development dispatch selects every `pull-request` owner. An implementation-bound PR body does not force conservative selection; it only removes the documentation-only and version-only shortcuts. The modular matrix itself is derived from the selection by `scripts/release/validation-matrix.mjs`, so inactive jobs are not scheduled at all rather than checking out and exiting early. `exhaustive` owners are never silently skipped or reported as passed: impact and aggregate evidence list them as cadence-deferred, and malformed cadence blocks selection. Full regression and nightly/stable release still execute both cadence classes.
62
62
 
63
- The real three-release `update-predecessor` scenario is exhaustive because four fresh npm installations dominated recent PR critical paths. PR validation retains deterministic predecessor command, lifecycle, fault, fixture, materialization, warmup, package, and update contracts. This permits a real published-history incompatibility to reach `develop` before nightly detects it; nightly failure still blocks publication. For a high-risk release/update change, explicitly dispatch `.github/workflows/full-regression.yml` before merge instead of adding the exhaustive owner back to ordinary Development.
63
+ The real three-release `update-predecessor` scenario is exhaustive because four fresh npm installations dominated recent PR critical paths, and `update-performance` is exhaustive because its assertion is wall-clock timing on a shared runner; the update path's deterministic contracts stay on pull requests through `pi-release-resume` and `package-contracts`. PR validation retains deterministic predecessor command, lifecycle, fault, fixture, materialization, warmup, package, and update contracts. This permits a real published-history incompatibility or update slowdown to reach `develop` before the next exhaustive run detects it. `.github/workflows/full-regression.yml` runs every night at `02:47 UTC` against the `develop` tip with every owner and enforced budgets, independent of publication, so such a regression shows as a failed Full regression run the next morning; nightly publication's own complete validation still blocks publication. For a high-risk release/update change, dispatch Full regression before merge instead of adding an exhaustive owner back to ordinary Development.
64
64
 
65
65
  Development outcomes report each owner/scope invocation separately while sharing authenticated build/package preparation. The aggregate reports setup, scope, job, aggregate-processing, total runner, and runner-critical-path durations. The acceptance targets are at most eight minutes of runner critical path and five minutes for one PR-required scope; an over-target result remains unmet without retries, timeout increases, workload reduction, or mutable installation caches. Hosted queue time is reported separately when available and is not counted as test execution.
66
66
 
@@ -86,9 +86,9 @@ Rendering evidence captures each selected producer/mode/workload matrix once and
86
86
 
87
87
  ## Resource-sensitive fast validation
88
88
 
89
- The authoritative fast-tier declaration identifies tests that repeatedly create temporary repositories, launch child processes, mutate storage, or coordinate release cohorts. The planner removes those files from the parallel remainder and runs each exactly once in its own `vitest-fast-resource-sensitive-*` process with file parallelism disabled. Per-file process isolation prevents one resource-heavy file from consuming another file's unchanged five-second test budget; no timeout override or retry is added. Pull-request, development-package, and complete release plans use the same partition on every platform.
89
+ The authoritative fast-tier declaration identifies tests that repeatedly create temporary repositories, launch child processes, mutate storage, or coordinate release cohorts. The planner removes those files from the parallel remainder and runs them exactly once in one serial `vitest-fast-resource-sensitive` process with file parallelism disabled, on an isolated runner that no other partition shares. One process instead of one per file removes about twenty cold starts from the partition; each file still gets a fresh module context. Pull-request, development-package, and complete release plans use the same partition on every platform.
90
90
 
91
- The partition retains Vitest's five-second default test timeout. It does not add a test, suite, platform, or workflow timeout, and a failure is not retried or converted to success. If a serialized test still approaches five seconds, use `scripts/release/report-resource-sensitive-validation.mjs` to record repeated per-file and test-body timing, then optimize repository setup, subprocess count, storage operations, or release fixtures. Do not increase a timeout to create margin.
91
+ The partition runs under an explicit `--testTimeout=30000`, the same hang bound the other explicit fast-tier invocations use. That bound is a hang detector, not a performance gate: shared Windows runners vary by a factor of two or more for identical work, and a fixed five-second wall-clock limit failed passing suites on runner noise. Per-test durations remain in the reporter evidence; `scripts/release/report-resource-sensitive-validation.mjs` records repeated executions and lists every test body above five seconds under `slowTests` so a real slowdown is visible without failing the pull request. A failure is still not retried or converted to success, and the bound is not raised to create margin.
92
92
 
93
93
  Inspect the partition without running tests:
94
94
 
@@ -106,12 +106,12 @@ node scripts/release/report-resource-sensitive-validation.mjs --repeats 3 --outp
106
106
 
107
107
  `Development validation required` remains the merge gate for every pull request. For applicable code changes, it requires the dedicated Defender-enabled exact-package startup lane on Windows Node 22. Development validation (including manual dispatch) does not schedule a Windows Node 24 startup lane. The Node 22 lane retains the complete package-install, image preparation/package, and durable-history checks plus startup evidence artifacts. A missing, cancelled, failed, or unexpectedly skipped required startup result still blocks the aggregate; documentation-only, version-only, and draft exemptions are unchanged.
108
108
 
109
- | Startup runtime | Development validation (PR or manual) | Nightly/release validation | Manual Full regression |
110
- | --- | --- | --- | --- |
111
- | Windows Node 22 | Required for applicable changes | Retained | Retained |
112
- | Windows Node 24 | Not scheduled | Retained | Retained |
109
+ | Startup runtime | Development validation (PR or manual) | Development preview (`npm run develop`) | Nightly and stable publication | Manual Full regression |
110
+ | --- | --- | --- | --- | --- |
111
+ | Windows Node 22 | Required for applicable changes | Not scheduled | Retained | Retained |
112
+ | Windows Node 24 | Not scheduled | Retained | Retained | Retained |
113
113
 
114
- Each selected startup lane runs the package-install scenarios once: a failed budget remains failed and is never retried to obtain a warmed result. Both post-update profiles must reach input-ready state within five seconds, and both warm profiles must remain within three seconds. Node 24 runtime support, other PR jobs, Defender, and publication gates are unchanged. Full validation retains every deferred startup, image, and history test through its existing suite owners.
114
+ Each selected startup lane runs the package-install scenarios once: a failed budget remains failed and is never retried to obtain a warmed result. The budgets are the ones the `a1-shell` capability declares (2 seconds after an update and on a warm launch, 2.5 seconds with no live supervisor); development validation and development previews record an overrun as a warning, while nightly, stable, and Full regression fail on it (see `STARTUP_BUDGET_ENFORCEMENT` in [validation](validation.md)). The publication lane set comes from `scripts/release/publication-validation-matrix.mjs`: a numbered preview validates on the Windows, Linux, and macOS Node 24 lanes, and nightly covers the same head on Windows Node 22 within a day. Node 24 runtime support, other PR jobs, Defender, and publication gates are unchanged. Full validation retains every deferred startup, image, and history test through its existing suite owners.
115
115
 
116
116
  The trade-off is delayed detection: a Node-24-specific regression can reach `develop` before nightly catches it, and the same is true for a real published-predecessor regression. A green bounded PR check does not certify Node 24 or real historical predecessor execution, and nightly failure still blocks its publication. When deferred feedback is needed before nightly, explicitly request the non-publishing Full regression workflow for the desired branch or tag:
117
117
 
@@ -147,7 +147,7 @@ validation; malformed, mixed, renamed, stale, or unavailable inputs fail closed.
147
147
  A legitimate generated baseline update remains outside the allowlist and follows the
148
148
  manually accepted mixed/code path.
149
149
 
150
- A new implementation-bound specification starts as OpenSpec-only artifacts in one normally named draft PR. Explicit approval to implement continues in that same worktree, branch, history, and PR; the plan does not merge first. Approved refinements reconcile planning before code. After implementation, the same branch conservatively synchronizes deltas and stages the dated archive plus conditional acceptance manifest. Add one to three plain implementation-specific bullets under `## Acceptance`, mark the finalized PR ready, and require exact-head CI. Auto-merge remains disabled: an authorized maintainer's manual merge accepts the listed scenarios and atomically integrates implementation, specs, and archive. No acceptance or archive follow-up PR is created. Closing an unmerged draft integrates nothing; cleanup still needs separate approval. See [delivery and archive handoff](openspec-archive-automation.md) for commands and legacy compatibility.
150
+ A new implementation-bound specification starts as OpenSpec-only artifacts in one normally named draft PR. Explicit approval to implement continues in that same worktree, branch, history, and PR; the plan does not merge first. Approved refinements reconcile planning before code. After implementation, add one to three plain implementation-specific bullets under `## Acceptance` and mark the PR ready; the trusted `OpenSpec finalization` workflow conservatively synchronizes deltas, stages the dated archive plus conditional acceptance manifest, and commits them to the same branch, and exact-head CI validates that head. Auto-merge remains disabled: an authorized maintainer's manual merge accepts the listed scenarios and atomically integrates implementation, specs, and archive. No acceptance or archive follow-up PR is created. Closing an unmerged draft integrates nothing; cleanup still needs separate approval. See [delivery and archive handoff](openspec-archive-automation.md) for commands and legacy compatibility.
151
151
 
152
152
  ## Numbered development previews
153
153
 
@@ -18,7 +18,7 @@ node scripts/governance/local-worktree-cleanup.mjs complete \
18
18
 
19
19
  `complete` is explicit cleanup authorization for that exact candidate. It creates and releases an exact registration when needed, applies the repository-owned generated-path policy, verifies live merge/archive/CI/ref evidence, evaluates only that candidate, uses journaled non-force Git removal, deletes only the unchanged local topic ref, and leaves persistent watcher authority unchanged. Repeating it reports the completed candidate as already absent. Existing conflicting ownership, identity drift, unavailable evidence, or unknown content remains blocking.
20
20
 
21
- The central disposable policy is `node_modules`, `dist`, `.builds`, `.artifacts/openspec-archive`, `.artifacts/validation`, `native/process-guardian/target`, and `native/terminal-host/target`. The artifact roots contain repository-generated finalization and validation reports; the two native roots contain repository-generated Cargo output. Each encountered path must be ignored and stay inside the exact worktree with no link, special file, or nested repository boundary. Authority is component-exact: `.artifacts`, sibling directories such as `.artifacts/other`, near matches such as `.artifacts/validation-user`, arbitrary `target` directories, and sibling native projects remain blocking. Tracked/staged/unstaged/untracked content and every unknown ignored path still block. A tracked regular `.gitmodules` file alone is ordinary content; actual nested `.git` metadata, gitlinks, configured submodules, and submodule changes block. Ordinary content and these approved generated roots are traversed under separate finite entry allowances, so a normal dependency installation does not consume the ordinary source-tree allowance; both allowances retain the same deadline and content-boundary checks.
21
+ The central disposable policy is `node_modules`, `dist`, `.builds`, `.artifacts`, `native/process-guardian/target`, and `native/terminal-host/target`. The `.artifacts` root is the repository's ignored generated-artifact root (finalization and validation reports, packed candidates, agent-written logs and diffs); the two native roots contain repository-generated Cargo output. Registrations that still name `.artifacts/openspec-archive` or `.artifacts/validation` stay valid and are widened to the root on the next `complete`. Each encountered path must be ignored and stay inside the exact worktree with no link, special file, or nested repository boundary. Authority is component-exact: near matches such as `.artifacts-user` or `artifacts`, arbitrary `target` directories, and sibling native projects remain blocking. Tracked/staged/unstaged/untracked content and every unknown ignored path still block. A tracked regular `.gitmodules` file alone is ordinary content; actual nested `.git` metadata, gitlinks, configured submodules, and submodule changes block. Ordinary content and these approved generated roots are traversed under separate finite entry allowances, so a normal dependency installation does not consume the ordinary source-tree allowance; both allowances retain the same deadline and content-boundary checks. Once those checks pass, cleanup deletes the declared disposable roots itself with a bounded retry for transient Windows sharing violations before handing the worktree to Git, so non-force Git removal only has to delete tracked content. A root that stays locked after the retry budget reports `blocked` with `disposable-path-locked` and the root's path; the worktree, its `.git` pointer, and its journal are untouched, so stop the process holding the handle and rerun the same command.
22
22
 
23
23
  Agents do not manually remove generated content, call `git worktree remove`, or delete the local branch after delivery. The JSON result is authoritative: report success only for `removed` or verified `already-absent`; otherwise retain the worktree and report the exact blocker. Legacy roles can supply separate `--source-pr`, `--candidate-pr`, and `--role` values.
24
24
 
@@ -135,12 +135,16 @@ State, journals, stop controls, and execution reports live in `<git-common-dir>/
135
135
  - `unmanaged`: no local registration; no automatic adoption.
136
136
  - `removed`: worktree and eligible local-ref operations were verified.
137
137
  - `already-absent`: a completed journal's path/ref are still absent.
138
- - `partial`: a destructive step began but all cleanup could not be verified.
138
+ - `partial`: a destructive step began but all cleanup could not be verified; the same command resumes it.
139
139
  - `deferred`: a bounded pass or concurrent mutation owner prevented evaluation.
140
140
 
141
- Non-force Git removal is the only worktree deletion operation. Local topic-ref deletion then compares the exact old SHA and refuses refs checked out elsewhere. `develop`, primary/current directories, changed heads, and active sessions are protected. Normal removal retires its own Git worktree registration; unrelated stale/missing registrations are never globally pruned.
141
+ Non-force Git removal is the only operation that deletes tracked content from an intact worktree. Local topic-ref deletion then compares the exact old SHA and refuses refs checked out elsewhere. `develop`, primary/current directories, changed heads, and active sessions are protected. Normal removal retires its own Git worktree registration; unrelated stale/missing registrations are never globally pruned.
142
142
 
143
- Windows file locks can leave a directory after Git removes part of a worktree. `partial` retains that residue and its journal; there is no `rm -rf`, force discard, or automatic directory-repair fallback. Stop the locking process and review the exact residual data before separately authorized manual repair. A recreated path is not the old checkout. If a prior run fully removed the worktree and only ref cleanup remains, a subsequent enabled pass rechecks evidence and safely resumes the branch-only step.
143
+ A released worktree whose directory was deleted by hand before cleanup ran is finished through its journal rather than failing on the missing directory: the same merge/archive evidence is verified, Git may hold no registration for the path or only this candidate's own dangling one, that registration is retired, the step is recorded as `worktree-already-absent`, and the unchanged local topic ref is deleted under the usual compare-and-delete rule. A `complete` invocation for an absent path that was never registered blocks with `worktree-absent-unregistered`, because there is no journaled head to compare the ref against.
144
+
145
+ Post-merge provenance accepts a `merged` timeline event whose time is within five seconds of the pull request's `merged_at`; GitHub stamps the two from different services and has reported them one second apart. The single-event, human-actor, no-App, and same-commit checks are unchanged.
146
+
147
+ Windows file locks can interrupt Git after it has already unlinked the `.git` pointer and part of the tree. That pass reports `partial` with `git-operation-failed` and keeps the journal at `remove-intent`; rerunning the same command resumes it. If the exact registered worktree is still intact, the retry re-inspects it and repeats non-force Git removal. Otherwise the retry verifies the residue: Git must no longer list the path as a valid worktree, the residue may contain no `.git` entry, link, special file, or nested repository, and every remaining regular file must either sit below a declared disposable root or match the exact tracked path and blob hash of the journaled head (`git hash-object` with the repository's filters). Only residue verified that way is removed, with the same bounded retry, after which this candidate's own dangling Git registration is retired and ref cleanup continues. A residue with any unknown, changed, or boundary-violating path reports `residual-content` and lists the offending paths for manual review; a residue that is still locked reports `residual-locked` and is retried on a later pass. `git worktree prune` is never run. A recreated or foreign worktree at the path reports `residual-or-reused-path` and needs a new registration. If a prior run fully removed the worktree and only ref cleanup remains, a subsequent pass rechecks evidence and safely resumes the branch-only step.
144
148
 
145
149
  Ownership is cooperative: managed sessions must claim before use. It cannot police arbitrary external editors. Remote ref checks and local deletion also are not one distributed transaction; refs are read immediately before destructive steps, and uncertain identities always block.
146
150
 
@@ -57,8 +57,9 @@ Use equivalent values in bare A1 and the Pi comparison profile. Exercise both a
57
57
  - [ ] Trust startup: from an undecided project, compare selected Trust/Do not trust rows, arrow navigation, Enter, Escape/Ctrl+C, clearing, cursor state, and restoration. No project extension/theme/prompt/skill may run before selection, and a fail-closed diagnostic must appear once on the restored parent rather than above a blank fullscreen frame.
58
58
  - [ ] Terminal lifecycle: toggle hardware cursor, clear-on-shrink, and terminal progress; resize smaller/larger; open/close selectors; select and copy transcript text; verify no duplicate rows, stale OSC progress, leaked mouse mode, misplaced cursor, or broken parent input.
59
59
  - [ ] Images: in Kitty or iTerm2 verify inline width and clipping; in Windows Terminal verify the textual fallback and absence of image protocol bytes without hiding `showImages`.
60
- - [ ] Fullscreen exit `transcript`: verify the parent is restored before styled user, assistant Markdown, thinking, tool, notice, warning, error, and spacing rows are printed. No overlay, draft, animation, scrollbar, or inline-image payload may appear.
61
- - [ ] Fullscreen exit `resume-hint`: verify only dim `To resume this session:` plus `a1 --session <compact-id>` is printed for the default directory. A custom directory must place quoted `--session-dir <dir>` before `--session`; the raw default `.jsonl` path must never print.
60
+ - [ ] Bare A1 quit (`/quit` and the second `Ctrl+C`): the configured quit effect plays over the last frame on the alternate screen, the terminal is restored once, and the parent shows only its earlier scrollback plus the dim `To resume this session:` hint. No frame rows, transcript rows, editor box, or footer may remain. With `/settings` → Quit → Effect set to `off`, the leave is immediate and the parent output is identical.
61
+ - [ ] Fullscreen exit `transcript` (`a1 pi` only): verify the parent is restored before styled user, assistant Markdown, thinking, tool, notice, warning, error, and spacing rows are printed. No overlay, draft, animation, scrollbar, or inline-image payload may appear.
62
+ - [ ] Fullscreen exit `resume-hint` (`a1 pi`) and bare A1: verify only dim `To resume this session:` plus `a1 --session <compact-id>` is printed for the default directory. A custom directory must place quoted `--session-dir <dir>` before `--session`; the raw default `.jsonl` path must never print.
62
63
 
63
64
  Record acceptance with:
64
65
 
@@ -12,8 +12,8 @@ Version-1 and version-2 deliveries and their existing comments, acceptance PRs,
12
12
  2. **Same-PR implementation:** continue after explicit approval in the same worktree, branch, history, draft PR, and phase-free body. Reconcile approved refinements in proposal, design, deltas, and tasks before corresponding code edits.
13
13
  3. **Complete evidence:** finish implementation, required tests/evidence, substantive tasks, and explicit known-gap disposition. CI success is objective evidence, not acceptance.
14
14
  4. **Plain acceptance list:** keep the body phase-free and add final `## Acceptance` with one to three concise implementation-specific behavior-and-result bullets. Do not use checkboxes, generic review/CI/approval/archive statements, URLs, mentions, or automated-test inventory.
15
- 5. **In-branch finalization:** reconcile current `origin/develop`, conservatively synchronize all deltas, move the active change into its dated archive, and stage the conditional acceptance manifest in the same branch.
16
- 6. **Ready and validate:** mark the finalized PR ready without changing its body lifecycle marker because none exists. One normal exact-head workflow validates the implementation, synchronized specs, archive, manifest, tasks/evidence, exact PR-body list, and every selected product/governance scope before emitting the stable protected aggregate. A new commit, acceptance-list change, or advanced target requires full renewed validation; no lifecycle body edit or second workflow run is required.
15
+ 5. **Ready and automated finalization:** mark the PR ready. The trusted `OpenSpec finalization` workflow reconciles current `develop`, conservatively synchronizes all deltas, moves the active change into its dated archive, stages the conditional acceptance manifest, commits that to the same branch with the archive App identity, and writes the emitted paths into the body's implementation fence. Running the [finalization command](#finalization-command) locally first is optional and yields the same bytes.
16
+ 6. **Validate:** one normal exact-head workflow validates the finalized head: implementation, synchronized specs, archive, manifest, tasks/evidence, exact PR-body list, and every selected product/governance scope before emitting the stable protected aggregate. A new commit or acceptance-list change re-finalizes automatically when needed and requires full renewed validation; no lifecycle body edit or second workflow run is required.
17
17
  7. **Manual merge accepts:** after the stable protected aggregate succeeds, an authorized human reviews and manually merges the exact validated head. That single action means the listed scenarios are accepted and explicitly authorizes integration. Auto-merge, merge queue, Apps, bots, and documentation reconciliation are forbidden.
18
18
  8. **Verify and clean:** trusted post-merge policy derives `Archived` and reports `accepted-and-archived` from committed bytes and immutable GitHub provenance without editing the accepted PR body. It publishes no lifecycle branch or PR. Shared exact-head remote cleanup may delete the unchanged topic ref; local cleanup remains separately ownership-controlled.
19
19
 
@@ -69,7 +69,7 @@ Do not add a quoted phase line or a routine `Validation` section listing command
69
69
  </details>
70
70
  ```
71
71
 
72
- Keep acceptance absent during proposal review so unfinished intent is not mistaken for final acceptance criteria. Keep the finalized phase-free body unchanged through exact-head validation, maintainer review, and authorized manual merge. The same workflow run validates its finalized delivery record and applicable product/governance scopes before the stable protected aggregate succeeds. Do not add a lifecycle body edit or start a second validation run. After manual merge, trusted verification derives `Archived`; do not rewrite the accepted body.
72
+ Keep acceptance absent during proposal review so unfinished intent is not mistaken for final acceptance criteria. The finalization workflow rewrites only the implementation fence; keep the rest of the phase-free body unchanged through exact-head validation, maintainer review, and authorized manual merge. The same workflow run validates its finalized delivery record and applicable product/governance scopes before the stable protected aggregate succeeds. Do not add a lifecycle body edit or start a second validation run. After manual merge, trusted verification derives `Archived`; do not rewrite the accepted body.
73
73
 
74
74
  ## Version-3 implementation metadata
75
75
 
@@ -129,9 +129,22 @@ The committed conditional manifest contains the same ordered text. Trusted polic
129
129
 
130
130
  If the body list changes, candidate validation reruns and compares it with the committed manifest. If the head changes, all prior exact-head CI is stale. If only the body changes to disagree with the manifest, integration remains blocked until the list and committed candidate agree again. No lifecycle body edit is needed after green CI.
131
131
 
132
+ ## Automated finalization
133
+
134
+ The `OpenSpec finalization` workflow (`.github/workflows/openspec-finalization.yml`) runs on `pull_request_target` for `synchronize`, `ready_for_review`, `reopened`, and `edited` events of every non-draft PR targeting `develop`, one event at a time per PR. It checks out default-branch policy, installs the pinned tooling without hooks, and runs `scripts/governance/publish-openspec-finalization.mjs --pr <n>`; the PR head enters that process only as the `openspec/` tree the pinned OpenSpec engine reads. Drafts, closed, legacy, and unassociated PRs are skipped. For a version-3 candidate it reconciles the head to its finalized form:
135
+
136
+ - **Active and current:** ordinary finalization with today's UTC date; one `docs(openspec): finalize <change>` commit.
137
+ - **Finalized, valid, and current:** nothing is pushed; the run reports `already-finalized`.
138
+ - **Finalized but drifted:** a later commit edited the archived tasks, evidence, design, or deltas, or the acceptance list changed. Finalization reruns from the archived form under the same archive date; one `docs(openspec): refinalize <change>` commit replaces the manifest and resynchronized specs.
139
+ - **Behind `develop`:** a restore commit returns the archive to its active form with the merge-base's spec bytes, a merge of `develop` follows, and finalization runs against the new tip. A merge conflict outside `openspec/` stops the run with `finalization-merge-conflict`; rebase or merge `develop` yourself and push.
140
+
141
+ The commit is pushed with a lease on the head the run read, so a developer push in between makes the run report `retry` and the next event finishes the work. Only after the push does the workflow `PATCH` the body fence, and only when the body is unchanged since it was read. The workflow's own push and body edit trigger further runs that report `already-finalized`. Every pushed commit is either a merge of the exact `develop` tip or confined to the change's active path, its archive path, and its declared canonical specs.
142
+
143
+ Because the branch gains commits from the archive App, pull before pushing. A rebase that drops them is harmless: the next push is reconciled from whatever the head contains. Do not revert a finalization commit to make a fix; push the fix and let the workflow re-finalize. When the workflow fails, its summary names the finalization code (`tasks-incomplete`, `acceptance-*`, `delivery-known-gaps`, `openspec-operation`, `finalization-merge-conflict`, ...), nothing is pushed, and `Finalized delivery validation` on the unfinalized head reports that automated finalization is pending.
144
+
132
145
  ## Finalization command
133
146
 
134
- Finalization has inspection mode by default and an explicit `--write` mode. It never commits, pushes, edits GitHub, marks a PR ready, or merges. Use a temporary body file so the operation can update exact version-3 paths without mutating remote PR state:
147
+ The local command remains available for inspection or when a developer prefers to finalize before marking the PR ready; the workflow then verifies the head and pushes nothing. It has inspection mode by default and an explicit `--write` mode. It never commits, pushes, edits GitHub, marks a PR ready, or merges. Use a temporary body file so the operation can update exact version-3 paths without mutating remote PR state:
135
148
 
136
149
  ```bash
137
150
  git fetch origin develop
@@ -164,7 +177,7 @@ Use repeated `--known-gap "exact disposition"` only for an actually reviewed exp
164
177
 
165
178
  The operation validates the active change strictly, requires complete substantive tasks, runs the pinned OpenSpec archive/synchronization engine in isolation, verifies the resulting canonical specs, retains every archive artifact, computes deterministic content digests, writes `acceptance.md`, and applies only the allowed OpenSpec diff. Repeating it against identical finalized inputs is verification-only and byte-stable.
166
179
 
167
- Before finalization, canonical specs must still equal the selected target. If `develop` advances, rebase/reconcile and regenerate. To refine a finalized but unmerged change, restore the active artifacts with ordinary branch history, update plan/code coherently, and rerun finalization; never hand-edit only the synchronized spec or archive copy.
180
+ Before a first finalization, canonical specs must still equal the selected target. On an already finalized head the command re-finalizes from the archived form: it resets the synchronized specs to the target's bytes, reapplies the deltas, and rewrites the manifest under the same archive path, reporting `refinalized` (or `would-refinalize` without `--write`). If `develop` advances, merge or rebase onto it and rerun; the archive engine, not a hand edit, must produce the synchronized spec and archive copy.
168
181
 
169
182
  ## Conditional acceptance and derived receipt
170
183
 
@@ -183,11 +196,11 @@ Unavailable, stale, automatic, unauthorized, conflicting, or contradictory prove
183
196
 
184
197
  ## CI and automation ownership
185
198
 
186
- Normal Development CI remains complete for the implementation. An archive-shaped final diff does not select documentation-only validation because the authoritative version-3 association remains implementation-bound. The trusted acceptance-policy job validates finalization from base-controlled policy while ordinary impact selection retains all applicable product and governance owners.
199
+ Normal Development CI remains complete for the implementation. An archive-shaped final diff does not select documentation-only validation because the authoritative version-3 association remains implementation-bound. The trusted acceptance-policy job validates finalization from base-controlled policy while ordinary impact selection retains all applicable product and governance owners. A ready head that still holds the active change fails that job with an `Awaiting automated finalization` notice pointing at the finalization workflow; the head the workflow pushes receives its own complete validation, and `Development validation` cancels the superseded run.
187
200
 
188
201
  `pull_request` body edits rerun required CI. The ordinary finalized phase-free run exposes the stable protected aggregate directly; it does not wait for a lifecycle body edit. Documentation auto-merge's trusted owner also reevaluates lifecycle association and disables any armed merge. Every publication entry point explicitly refuses version 3.
189
202
 
190
- The OpenSpec archive workflow remains default-branch trusted. For version 3 it uses read-only contents, PR, and Actions access to report the integrated result; App credentials are unnecessary and are not minted. For legacy candidates it retains its existing scoped App publication behavior.
203
+ The OpenSpec archive workflow remains default-branch trusted. For version 3 it uses read-only contents, PR, and Actions access to report the integrated result; App credentials are unnecessary and are not minted for post-merge verification. For legacy candidates it retains its existing scoped App publication behavior. The OpenSpec finalization workflow is the one version-3 user of the archive App: it mints a short-lived installation token with `contents: write` and `pull_requests: write`, pushes only to the candidate's own branch under a lease, edits only the body fence, and revokes the token when the run ends.
191
204
 
192
205
  ## Status and audit
193
206
 
@@ -230,7 +243,7 @@ This bootstrap policy itself finishes under deployed version-2 authority. The fi
230
243
 
231
244
  - draft planning remaining unmerged;
232
245
  - explicit plan approval and same-PR implementation;
233
- - current-target finalization and exact-head CI;
246
+ - automated current-target finalization and exact-head CI;
234
247
  - authorized human manual merge with plain acceptance scenarios;
235
248
  - integrated canonical specs/archive and no generated acceptance/archive PR;
236
249
  - read-only `accepted-and-archived` verification and exact-head branch cleanup;
@@ -8,7 +8,9 @@ npm run select:validation-impact -- --base <full-base-sha> --head <full-head-sha
8
8
 
9
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`.
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. Selection does not require whole-repository source parsing.
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.
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.
12
14
 
13
15
  ## Commands and coverage levels
14
16
 
@@ -53,7 +55,7 @@ node scripts/release/run-validation-tier.mjs --prepare-exact-package --handoff <
53
55
  node scripts/release/run-validation-tier.mjs --exact-package-handoff <path> --result <path>
54
56
  ```
55
57
 
56
- The preparing command verifies the existing build receipt and the package receipt for the exact candidate, installs once, and writes an `a1-exact-package-handoff-v1` document with its consumers, prepared paths, measured duration, and verified receipt. It runs no other planned command, so Full regression's real work is not executed twice.
58
+ The preparing command verifies the existing build receipt and the package receipt for the exact candidate, installs once, and writes an `a1-exact-package-handoff-v1` document with its consumers, prepared paths, measured duration, and verified receipt. The receipt's `preparation.phases` splits that duration into `installMs` (the npm global install), `proxySynchronizationMs` (the pi-tui proxy repair), and `installedIdentityMs` (the installed-package identity walk); on hosted Windows runners the install phase is the cost, because npm writes roughly 13,000 dependency files there. It runs no other planned command, so Full regression's real work is not executed twice.
57
59
 
58
60
  The consuming command re-verifies that handoff against the lane, candidate digest, installation policy, declared consumers, and installed bytes before any owner runs, and records the result as `verified-shared-preparation`. A malformed handoff, one that contradicts the plan, or one that fails verification produces a single failed `exact-package-preparation` outcome and stops the run; it never falls back to a second installation. Removing the prepared installation stays with the consuming command either way.
59
61
 
@@ -87,7 +89,7 @@ Download these artifacts from the exact workflow run:
87
89
  - `development-validation-aggregate-<head>-<run>-<attempt>`: selected/deferred owners, accepted/reused attempts, evidence count, runner critical path, total runner time, aggregate processing, setup/gate/scope time, cache state, and invocation count. It reports the eight-minute critical-path and five-minute individual-scope targets as met or unmet; hosted queue delay is not test execution and remains separate.
88
90
  - startup/resume phase JSONL and performance JSON: first-attempt launch evidence and retained failed setup/readiness records.
89
91
 
90
- A finalized version-3 PR keeps its phase-free body unchanged. Its ordinary exact-head workflow runs selected product/governance lanes and `Finalized delivery validation` in parallel, then emits the stable protected `Development validation required` aggregate only when both authorities succeed. Green CI enables maintainer review and manual merge but does not claim human acceptance or merge automatically. No lifecycle body edit or second workflow run is required. Any implementation commit changes the head and reruns applicable validation; any body change reruns finalized-record validation and must continue to match the committed manifest. Legacy acceptance-record-only PRs retain their separate trusted `Acceptance record validation` route. Queue availability remains explicitly unavailable inside a runner and is calculated from the Actions API during final run analysis rather than guessed.
92
+ A finalized version-3 PR keeps its phase-free body unchanged. Its ordinary exact-head workflow runs selected product/governance lanes and `Finalized delivery validation` in parallel, then emits the stable protected `Development validation required` aggregate only when both authorities succeed. Green CI enables maintainer review and manual merge but does not claim human acceptance or merge automatically. No lifecycle body edit or second workflow run is required. Any implementation commit changes the head and reruns applicable validation; any body change reruns finalized-record validation and must continue to match the committed manifest. A ready head that still holds the active change fails `Finalized delivery validation` with an `Awaiting automated finalization` notice; the `OpenSpec finalization` workflow pushes the finalized head, which receives its own run. Legacy acceptance-record-only PRs retain their separate trusted `Acceptance record validation` route. Queue availability remains explicitly unavailable inside a runner and is calculated from the Actions API during final run analysis rather than guessed.
91
93
 
92
94
  ## Rollback
93
95
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timurproko/a1",
3
- "version": "0.1.8-dev.444",
3
+ "version": "0.1.8-dev.457",
4
4
  "description": "Standalone terminal workspace for supervised native and managed agents",
5
5
  "type": "module",
6
6
  "privateLaunchContract": "neutral-launch-v1",