@timurproko/a1 0.2.5 → 0.2.6-dev.727

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 (148) hide show
  1. package/bin/cli.js +13 -2
  2. package/bin/ui.js +13 -0
  3. package/dist/app/session-shell/prompt-suggestion-controller.d.ts +5 -4
  4. package/dist/app/session-shell/prompt-suggestion-controller.js +148 -58
  5. package/dist/app/session-shell/session-shell-root.d.ts +5 -1
  6. package/dist/app/session-shell/session-shell-root.js +13 -6
  7. package/dist/app/session-shell/session-shell.js +132 -51
  8. package/dist/app/session-shell/session-viewport-controller.js +33 -21
  9. package/dist/cli/dispatch.js +5 -3
  10. package/dist/cli/session-context.d.ts +5 -1
  11. package/dist/cli/session-context.js +25 -8
  12. package/dist/composition/owned-ui.d.ts +3 -0
  13. package/dist/composition/owned-ui.js +66 -6
  14. package/dist/composition/settings-route-host.js +4 -3
  15. package/dist/contracts/owned-ui/index.d.ts +4 -2
  16. package/dist/contracts/owned-ui/index.js +1 -1
  17. package/dist/contracts/owned-ui/model.d.ts +4 -0
  18. package/dist/contracts/owned-ui/suggestion-diagnostics.d.ts +5 -1
  19. package/dist/contracts/owned-ui/suggestion-diagnostics.js +3 -1
  20. package/dist/contracts/owned-ui/validation.js +7 -0
  21. package/dist/features/launch/index.d.ts +1 -1
  22. package/dist/features/launch/session-context.d.ts +17 -2
  23. package/dist/features/launch/session-context.js +9 -5
  24. package/dist/features/owned-ui/reference-routes.d.ts +1 -1
  25. package/dist/features/owned-ui/reference-routes.js +1 -1
  26. package/dist/features/owned-ui/settings-app.js +21 -39
  27. package/dist/features/prompt-suggestions/diagnostics.js +4 -1
  28. package/dist/foundation/lifecycle/index.d.ts +2 -2
  29. package/dist/foundation/lifecycle/index.js +1 -1
  30. package/dist/foundation/lifecycle/session-repository-context.d.ts +19 -2
  31. package/dist/foundation/lifecycle/session-repository-context.js +434 -66
  32. package/dist/foundation/process-containment/index.d.ts +1 -0
  33. package/dist/foundation/process-containment/index.js +1 -0
  34. package/dist/foundation/process-containment/native-process-inspector.d.ts +3 -0
  35. package/dist/foundation/process-containment/native-process-inspector.js +21 -0
  36. package/dist/foundation/release/progress-palette.generated.d.ts +2 -2
  37. package/dist/foundation/release/progress-palette.generated.js +2 -2
  38. package/dist/foundation/startup/startup-descriptor.js +2 -2
  39. package/dist/integrations/pi/components/components.js +2 -2
  40. package/dist/integrations/pi/components/index.d.ts +2 -2
  41. package/dist/integrations/pi/components/index.js +1 -1
  42. package/dist/integrations/pi/components/lazy-selectors.d.ts +42 -0
  43. package/dist/integrations/pi/components/lazy-selectors.js +32 -0
  44. package/dist/integrations/pi/components/modal-frame.js +3 -4
  45. package/dist/integrations/pi/components/models-dialog.js +5 -5
  46. package/dist/integrations/pi/components/prompt-input-port.d.ts +1 -0
  47. package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -2
  48. package/dist/integrations/pi/components/resources/builtin-themes.js +2 -2
  49. package/dist/integrations/pi/components/share-operation-dialog.js +3 -3
  50. package/dist/integrations/pi/components/shell-editor-autocomplete.js +8 -7
  51. package/dist/integrations/pi/components/shell-extension-ui.d.ts +2 -0
  52. package/dist/integrations/pi/components/shell-extension-ui.js +20 -10
  53. package/dist/integrations/pi/components/shell-hotkey-sections.js +2 -2
  54. package/dist/integrations/pi/components/shell-presenters-info.js +10 -10
  55. package/dist/integrations/pi/components/shell-presenters-transcript.js +10 -10
  56. package/dist/integrations/pi/components/shell-selectors-dialogs.js +5 -6
  57. package/dist/integrations/pi/components/shell-shared-facade.js +1 -1
  58. package/dist/integrations/pi/components/skills-dialog.js +3 -3
  59. package/dist/integrations/pi/components/submitted-prompt-adapter.js +2 -3
  60. package/dist/integrations/pi/components/theme.d.ts +9 -0
  61. package/dist/integrations/pi/components/theme.js +30 -0
  62. package/dist/integrations/pi/components/tool-result-adapter.js +6 -1
  63. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
  64. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +1 -1
  65. package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
  66. package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
  67. package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
  68. package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
  69. package/dist/integrations/pi/components/upstream/components/extension-editor.js +6 -6
  70. package/dist/integrations/pi/components/upstream/components/extension-input.js +4 -4
  71. package/dist/integrations/pi/components/upstream/components/extension-selector.js +4 -4
  72. package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
  73. package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +5 -5
  74. package/dist/integrations/pi/components/upstream/components/owned-editor.js +8 -5
  75. package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
  76. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +1 -1
  77. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +3 -3
  78. package/dist/integrations/pi/components/upstream/components/session-footer.js +1 -1
  79. package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
  80. package/dist/integrations/pi/components/upstream/components/session-selector.js +14 -20
  81. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +3 -2
  82. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +6 -3
  83. package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +1 -1
  84. package/dist/integrations/pi/components/upstream/components/status-indicator.js +1 -1
  85. package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
  86. package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
  87. package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +1 -1
  88. package/dist/integrations/pi/components/upstream/components/thinking-selector.js +2 -2
  89. package/dist/integrations/pi/components/upstream/components/tool-execution.d.ts +4 -0
  90. package/dist/integrations/pi/components/upstream/components/tool-execution.js +11 -1
  91. package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +2 -2
  92. package/dist/integrations/pi/components/upstream/components/tree-selector.js +27 -18
  93. package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
  94. package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
  95. package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +4 -4
  96. package/dist/integrations/pi/components/upstream/history/editor-core.js +11 -7
  97. package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
  98. package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
  99. package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
  100. package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
  101. package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
  102. package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
  103. package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
  104. package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
  105. package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +31 -0
  106. package/dist/integrations/pi/components/upstream/program-status-reporter.js +89 -0
  107. package/dist/integrations/pi/components/upstream/theme/system-theme.d.ts +1 -1
  108. package/dist/integrations/pi/components/upstream/theme/system-theme.js +1 -1
  109. package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
  110. package/dist/integrations/pi/components/upstream/theme/theme.d.ts +18 -1
  111. package/dist/integrations/pi/components/upstream/theme/theme.js +207 -10
  112. package/dist/integrations/pi/engine/pi-settings-metadata.json +1 -1
  113. package/dist/integrations/pi/engine/resources/changelog.json +4 -4
  114. package/dist/integrations/pi/engine/session-events.js +10 -2
  115. package/dist/integrations/pi/engine/transcript-projection.js +2 -1
  116. package/dist/integrations/pi/startup-public.js +306 -290
  117. package/dist/integrations/pi/startup-public.manifest.json +289 -265
  118. package/dist/integrations/pi/tui-runtime/adapter.d.ts +8 -1
  119. package/dist/integrations/pi/tui-runtime/adapter.js +31 -1
  120. package/dist/integrations/pi/tui-runtime/contracts.d.ts +3 -1
  121. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
  122. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +1 -1
  123. package/dist/native/darwin-arm64/manifest.json +1 -1
  124. package/dist/native/linux-x64/manifest.json +1 -1
  125. package/dist/native/win32-x64/manifest.json +2 -2
  126. package/dist/native/win32-x64/process-guardian.exe +0 -0
  127. package/dist/product-identity.d.ts +2 -2
  128. package/dist/product-identity.js +2 -2
  129. package/dist/product-identity.json +3 -1
  130. package/dist/runtime-payload-inventory.json +3092 -2878
  131. package/dist/ui/components/prompt-input.d.ts +2 -0
  132. package/dist/ui/components/prompt-input.js +5 -1
  133. package/dist/ui/components/text-selection.d.ts +1 -1
  134. package/dist/ui/components/text-selection.js +3 -1
  135. package/dist/ui/components/theme.d.ts +2 -0
  136. package/dist/ui/components/transcript-viewport.d.ts +6 -4
  137. package/dist/ui/components/transcript-viewport.js +94 -16
  138. package/dist/ui/components/value-menu.d.ts +2 -0
  139. package/dist/ui/components/value-menu.js +13 -8
  140. package/dist/ui/settings/declarations.d.ts +26 -14
  141. package/dist/ui/settings/declarations.js +24 -11
  142. package/dist/ui/settings/migrations.js +16 -0
  143. package/docs/architecture/project-structure.md +4 -3
  144. package/docs/architecture/prompt-suggestions.md +14 -10
  145. package/docs/local-worktree-cleanup.md +23 -9
  146. package/docs/manual-owned-ui-checkpoint.md +1 -1
  147. package/docs/openspec-archive-automation.md +20 -19
  148. package/package.json +3 -3
@@ -1,12 +1,14 @@
1
1
  # Prompt suggestion reliability
2
2
 
3
- Bare A1 predicts a short next user input with one isolated request using the selected model. A clear offered action consistent with recent user intent, such as `archive it` after accepted merged work, is preferred over abstaining merely because optional testing was also offered. Required validation, conflicting intent, and unresolved choices still allow no suggestion. There is no quoted-text extraction fallback.
3
+ Bare A1 predicts a short next user input with an isolated request using the selected model. A successful eligible response normally starts one pre-settlement request. If that prefetch was missed, settlement starts it; if the first current attempt produces no candidate, one sequential recovery request is allowed. A clear offered action consistent with recent user intent, such as `archive it` after accepted merged work, is preferred over abstaining merely because optional testing was also offered. Required validation, conflicting intent, unresolved choices, and exhausted recovery still allow no suggestion. There is no quoted-text extraction fallback.
4
4
 
5
5
  ## Request and editor boundaries
6
6
 
7
- The adapter resolves the lowest supported effort from the selected session model's available thinking levels, without changing the main thinking setting. Non-reasoning models omit reasoning controls; supported `off` also omits the optional reasoning argument, matching the model runtime's ordinary completion contract. Other supported efforts are supplied explicitly. Missing capabilities produce `unavailable`, not a guessed provider option. Provider mapping/clamping remains owned by the pinned model runtime; the diagnostic policy describes the applied request option, not inferred server-side computation.
7
+ The adapter preserves the selected session model's current reasoning level and request options without changing the main thinking setting. Non-reasoning models omit reasoning controls; supported `off` also omits the optional reasoning argument, matching the model runtime's ordinary completion contract. Missing capabilities produce `unavailable`, not a guessed provider option. Provider mapping/clamping remains owned by the pinned model runtime; the diagnostic policy describes the applied request option, not inferred server-side computation.
8
8
 
9
- The controller retains the 15-second deadline, does not retry or switch models, and retires a timeout before aborting. A provider that ignores abort cannot revive retired text. A timely candidate remains private until matching settlement. Ghost text is not editor content, approval, or a submission: Tab accepts it into the editor, and Enter must be pressed separately to submit it. Typing aborts pending generation but keeps a delivered suggestion: the ghost text is hidden while the editor holds a draft and reappears when the draft is cleared. Submission, session/model replacement, continuation, interruption, or disabling suggestions invalidates unaccepted work. `a1 pi` does not install this feature.
9
+ Each attempt retains the 15-second deadline and uses the same transformed conversation, tools, model, reasoning, budgets, session identity, transport, and payload hook. The controller never overlaps attempts or switches models. `empty`, `rejected`, `provider-failure`, `unavailable`, or timeout can start one retry after settlement; cancellation and stale identity cannot. A provider that ignores abort cannot revive its retired attempt.
10
+
11
+ A timely candidate remains private until matching settlement. A candidate blocked only by temporary readiness, focus, autocomplete, or prompt mode is retained and presented when the same editor becomes eligible. Ghost text is not editor content, approval, or a submission: Tab accepts it into the editor, and Enter must be pressed separately to submit it. Typing aborts pending generation but keeps a delivered suggestion: the ghost text is hidden while the editor holds a draft and reappears when the draft is cleared. Submission, session/model replacement, continuation, interruption, or disabling suggestions invalidates unaccepted work. `a1 pi` does not install this feature.
10
12
 
11
13
  ## Opt-in local diagnostics
12
14
 
@@ -26,12 +28,12 @@ While that session is running, inspect the selected JSON file using a local edit
26
28
  node -e 'const fs=require("node:fs"); console.table(JSON.parse(fs.readFileSync(process.argv[1],"utf8")).records)' .artifacts/suggestion-diagnostics.json
27
29
  ```
28
30
 
29
- The `prompt-suggestion-diagnostics-v1` snapshot contains at most 128 metadata records and 64 KiB. Capture is off by default. Records include process-local session/run/response/request numbers, bounded provider/model identifiers, applied reasoning policy, elapsed milliseconds, event, and optional reason. They exclude conversation/candidate text, tool data, raw errors, credentials, and session/worktree paths. There is no upload. Older records are evicted, so a retained terminal event can outlive its evicted start event. `request: 0` means no request was started for that decision.
31
+ The `prompt-suggestion-diagnostics-v1` snapshot contains at most 128 metadata records and 64 KiB. Capture is off by default. Records include process-local session/run/response/request numbers, bounded attempt number and trigger (`prefetch`, `settlement`, or `retry`), provider/model identifiers, applied reasoning policy, elapsed milliseconds, event, and optional reason. They exclude conversation/candidate text, tool data, raw errors, credentials, and session/worktree paths. There is no upload. Older records are evicted, so a retained terminal event can outlive its evicted start event. `request: 0` means no request was started for that decision.
30
32
 
31
33
  | Event | Meaning |
32
34
  | --- | --- |
33
35
  | `skipped` | No request started; inspect `reason`. |
34
- | `started` | One generator request was initiated; reasoning may be `unavailable` for an injected generator without policy metadata. |
36
+ | `started` | One generator request was initiated; inspect `attempt` and `trigger`. Reasoning may be `unavailable` for an injected generator without policy metadata. |
35
37
  | `displayed` | A current candidate was shown after settlement. |
36
38
  | `empty` | The provider returned no text; this does not reveal the model's private reason for abstaining. |
37
39
  | `rejected` | Returned content violated the candidate contract, contained tool calls, was truncated, or had invalid formatting/voice. |
@@ -40,7 +42,9 @@ The `prompt-suggestion-diagnostics-v1` snapshot contains at most 128 metadata re
40
42
  | `timeout` | The controller's 15-second deadline expired. |
41
43
  | `cancelled` | Work was invalidated or aborted, including typing or continuation. |
42
44
  | `stale-result` | A result or settlement identity did not match its request. |
43
- | `presentation-blocked` | A valid candidate could not be shown; inspect `reason`. |
45
+ | `presentation-blocked` | A valid candidate met a permanent presentation blocker; inspect `reason`. |
46
+ | `presentation-deferred` | A valid candidate is retained behind temporary readiness, focus, autocomplete, or prompt-mode state. |
47
+ | `retry-exhausted` | Both bounded attempts ended without a candidate. |
44
48
  | `late-result-discarded` | A retired request eventually resolved/rejected; this is not a second terminal outcome or request. |
45
49
 
46
50
  Eligibility/presentation reasons include `disabled`, `disposed`, `early-conversation`, `no-model`, `failed-response`, `incomplete-response`, `tool-continuation`, `replacement-input`, `modal`, `draft`, `not-ready`, `not-focused`, `autocomplete`, `prompt-mode`, and `stale-identity`. `ineligible` and `presentation-unavailable` cover injected ports without finer metadata. A missing suggestion alone is never evidence of timeout or intentional model abstention.
@@ -51,10 +55,10 @@ To disable capture, omit/unset `A1_SUGGESTION_DIAGNOSTICS` before the next launc
51
55
 
52
56
  ## Verification and evidence limits
53
57
 
54
- The focused tests cover the synthetic archive offer and required-testing/unresolved-choice counterexamples, unchanged primary thinking, typed outcomes, timeout/cancellation races, editor acceptance, and local privacy/bounds:
58
+ The focused tests cover settlement fallback, one-request success, bounded retry/exhaustion, timeout and late-result races, deferred presentation, request parity, editor acceptance, and local privacy/bounds:
55
59
 
56
60
  ```sh
57
- npx vitest run test/app/session-shell/prompt-suggestion-controller.test.ts test/integrations/pi/engine/adapter.test.ts test/features/prompt-suggestions/diagnostics.test.ts test/contracts/owned-ui/contracts.test.ts test/app/session-shell/session-shell.test.ts
61
+ npx vitest run test/app/session-shell/prompt-suggestion-controller.test.ts test/app/session-shell/session-shell-suggestions.test.ts test/integrations/pi/engine/adapter.test.ts test/integrations/pi/engine/session-events.test.ts test/features/prompt-suggestions/diagnostics.test.ts test/contracts/owned-ui/contracts.test.ts test/app/session-shell/session-shell.test.ts
58
62
  ```
59
63
 
60
64
  A separate opt-in probe uses the profile's saved model/authentication with a scratch cwd, in-memory sessions/settings, disabled extensions/skills/prompts, and no tools. It performs five original-policy predictions, five revised-policy predictions, and one required-testing counterexample. This makes **11 provider requests** and can consume quota. Run only with explicit authorization:
@@ -63,6 +67,6 @@ A separate opt-in probe uses the profile's saved model/authentication with a scr
63
67
  RUN_PROMPT_SUGGESTION_PROVIDER_TEST=1 PROMPT_SUGGESTION_AGENT_DIR="C:/path/to/agent-profile" npx vitest run test/integrations/pi/engine/prompt-suggestion-provider.integration.test.ts
64
68
  ```
65
69
 
66
- The probe reports outcome/latency summaries and archival-candidate counts, not raw text. It requires at least one revised archival continuation and rejects an archival continuation in the required-testing case. Five samples are a smoke comparison, not a statistical reliability guarantee. Missing credentials, model availability, or a successful real archival prediction leave provider acceptance pending; fake tests do not prove model quality.
70
+ The probe reports outcome/latency summaries and archival-candidate counts, not raw text. It requires at least one revised archival continuation and rejects an archival continuation in the required-testing case. Five samples are a smoke comparison, not a statistical reliability guarantee. It tests prompt quality, not settlement/retry lifecycle correctness; deterministic fault injection owns recovery acceptance. Missing credentials or model availability therefore do not block lifecycle evidence.
67
71
 
68
- For manual review, use a harmless synthetic conversation with two assistant responses: establish that an imaginary change was tested, accepted, and merged, then ask for a closeout offer containing `Say archive it` with optional extra testing. Do not ask the agent to perform real archival to test ghost text. Keep main thinking high and the editor untouched while waiting, inspect the outcome snapshot, check Tab/Enter separately, and repeat with typing cancellation and suggestions disabled. Verify required testing is not treated as optional. Real latency, model abstention, and existing context-reconstruction limitations can still leave the editor empty.
72
+ For manual review, repeat ordinary completed-work conversations with the editor untouched and diagnostics enabled. A normal candidate should show one `prefetch` request. A recovered miss should show either a first `settlement` request or a second `retry` request, followed by `displayed`; two failed attempts should end with `retry-exhausted`. Check that temporary focus/autocomplete blocking records `presentation-deferred` and reveals the same candidate after eligibility returns. Check Tab/Enter separately, then repeat with typing cancellation and suggestions disabled. Real latency, model abstention, and existing context-reconstruction limitations can still exhaust both attempts and leave the editor empty.
@@ -22,11 +22,25 @@ Every delivery session then starts, before it creates a worktree, with one bound
22
22
  node scripts/governance/local-worktree-cleanup.mjs sweep --repo D:/Git/a1
23
23
  ```
24
24
 
25
- `sweep` evaluates every released registration in one pass under the queue limits (100 registrations, 500 remote requests, a durable round-robin cursor) with a 180-second elapsed budget, since each merged candidate costs three evidence loads, and completes each candidate whose PR is verified merged using exactly the `complete` safeguards. It needs no `enable` and starts no process: its authority is each candidate's release. A candidate whose PR is open, draft, or not yet finalized reports `pending`; a candidate whose PR closed without merge reports `awaiting-discard` and is never touched; blockers report their exact reason. An old stop sentinel does not prevent a sweep, but `disable` run while a sweep is executing stops it before its next destructive step. If another session holds the mutation lock the sweep reports `mutation-busy` and the agent relays it as deferred rather than waiting. The JSON report carries a `lines` array with one relayable line per candidate and pruned branch, for example `#458 close-absent-and-skewed-cleanup: removed [worktree-removed, local-ref-removed]`. Pending or blocked results never delay the new delivery.
25
+ `sweep` evaluates every released registration in one pass under the queue limits (100 registrations, 500 remote requests, a durable round-robin cursor) with a 180-second elapsed budget, since each merged candidate costs three evidence loads, and completes each candidate whose PR is verified merged using exactly the `complete` safeguards. It needs no `enable` and starts no process: its authority is each candidate's release. A candidate whose PR is open, draft, or not yet finalized reports `pending`; a candidate whose PR closed without merge reports `awaiting-discard` and is never touched; blockers report their exact reason. An old stop sentinel does not prevent a sweep, but `disable` run while a sweep is executing stops it before its next destructive step. If another session is cleaning the same path or ref, sweep reports that candidate `deferred (resource-busy)` and continues with disjoint registrations. The JSON report carries a `lines` array with one relayable line per candidate and pruned branch, for example `#458 close-absent-and-skewed-cleanup: removed [worktree-removed, local-ref-removed]`. Pending, deferred, or blocked results never delay another candidate or the new delivery.
26
+
27
+ ### Concurrent cleanup scopes
28
+
29
+ Independent `complete`, `discard`, `retire-redundant`, sweep, and enabled queue operations may run at the same time when their canonical worktree paths and topic refs are disjoint. Long remote evidence reads, content traversal, Windows retry waits, generated-content purge, and non-force removal hold only the exact path/ref resource locks. The same candidate remains exclusive across ownership, hand-off, cleanup, empty-directory recovery, and branch pruning; a competing command receives `resource-busy` rather than racing the journal.
30
+
31
+ The existing `mutation.lock` now protects only brief atomic `state.json` transactions and remains at the same path so an older cleanup process already running during an upgrade is still honored. State-lock overlap is retried for a bounded interval. Fetches that update `refs/remotes/origin/develop` and exact local-ref changes coordinate only that shared ref operation; they do not serialize the surrounding candidate work. Every destructive boundary still repeats its existing evidence, identity, content, and compare-and-delete checks.
32
+
33
+ ### Standalone documentation evidence
34
+
35
+ A PR without an `openspec-implementation` fence does not require corrective implementation association when its complete changed-file list is standalone documentation under the repository's existing documentation lifecycle policy. This includes ordinary documentation, the root `README.md`, canonical specification revisions, and revisions to existing active-change or archived-change documentation. Cleanup reuses the same path allowlist and immutable lifecycle checks as documentation auto-merge rather than maintaining a broader cleanup-only definition.
36
+
37
+ The PR must be non-draft, same-repository, merged into `develop`, and bound to the registered PR, head, and branch. Cleanup additionally requires successful required CI for that exact head, the merge commit to remain an ancestor of current `develop`, and the remote topic ref to be absent. Introduced active changes, implementation/code or mixed paths, release notes, acceptance records, malformed lifecycle metadata, incomplete changed-file evidence, and invalid rename shapes do not qualify. Those cases remain on their existing implementation-association or fail-closed paths.
38
+
39
+ Qualifying documentation uses the ordinary cleanup path without weakening it: exact worktree and local-ref identity, ownership, clean content, generated-content inspection, journaling, non-force Git removal, residue handling, and compare-and-delete local-ref behavior remain required. A blocker at any gate retains the worktree; agents never substitute manual deletion.
26
40
 
27
41
  ### Nothing left to remove
28
42
 
29
- A released entry whose evidence can never verify (for example `delivery-content-drift` after a stale-base merge, or `source-association` for a PR without an `openspec-implementation` fence) would otherwise be re-verified and reported `blocked` on every sweep. One narrow exception repairs an integrated unassociated delivery without rewriting its merged body: current `develop` must contain exactly one archived `association-repair.json` for the registered change, naming the exact original PR/head/merge and successful validation run, and its named corrective version-3 PR must itself have authorized manual merge, current exact-head CI, synchronized specs, a valid archive, and absent original/corrective remote refs. Only then does cleanup continue through all ordinary worktree identity, ownership, cleanliness, disposable-content, non-force removal, journaling, and local-ref safeguards. A mismatch remains blocked and generic merge/archive evidence never substitutes.
43
+ A released entry whose evidence can never verify (for example `delivery-content-drift` after a stale-base merge, or `source-association` for an unassociated implementation PR) would otherwise be re-verified and reported `blocked` on every sweep. One narrow exception repairs an integrated unassociated delivery without rewriting its merged body: current `develop` must contain exactly one archived `association-repair.json` for the registered change, naming the exact original PR/head/merge and successful validation run, and its named corrective version-3 PR must itself have authorized manual merge, current exact-head CI, synchronized specs, a valid archive, and absent original/corrective remote refs. Only then does cleanup continue through all ordinary worktree identity, ownership, cleanliness, disposable-content, non-force removal, journaling, and local-ref safeguards. A mismatch remains blocked and generic merge/archive evidence never substitutes.
30
44
 
31
45
  When no valid corrective association exists and such an entry's worktree path is gone, Git holds no live row for it (its own dangling row is retired), and its local topic ref is absent, the sweep and `complete` ask GitHub only whether the pull request merged into `develop` in this repository and then mark the journal `done` with `retired-nothing-left` and the original evidence reason. Nothing is deleted; a present path, row, or ref keeps the entry blocked, an unmerged PR keeps it `pending` or `awaiting-discard`, a deferred failure such as `remote-budget` is never treated as unverifiable, and preview retires nothing. For an all-absent entry whose PR is not merged, the maintainer runs the explicit form, which reads nothing from GitHub and deletes nothing:
32
46
 
@@ -64,7 +78,7 @@ node scripts/governance/local-worktree-cleanup.mjs complete \
64
78
 
65
79
  The central disposable policy is `node_modules`, `dist`, `.builds`, `.artifacts`, `native/process-guardian/target`, `native/terminal-host/target`, and the exact generated file `src/integrations/pi/engine/pi-settings-metadata.json`. 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; Vitest writes the metadata file for source-side settings tests and leaves it shared for overlapping test processes until worktree cleanup. Agents select the owning worktree's `.artifacts/` root for their own transient delivery files rather than OS temp or another checkout, but its disposable status never makes scratch authoritative or permits secrets to be stored there. Registrations that still name `.artifacts/openspec-archive` or `.artifacts/validation` stay valid and are widened to the current policy on the next `complete`.
66
80
 
67
- Each root itself must be an ignored non-link regular file or directory inside the exact worktree. A descendant symbolic link or Windows junction is accepted only when its canonical target stays inside that same exact disposable root. Inspection records the link's path, filesystem identity, and target; purge revalidates them and removes the link entry without traversing it before removing the root. Root-level links, escapes, drift, unresolved/cyclic targets, special files, and nested repository boundaries remain blocking. Authority is component-exact: near matches such as `.artifacts-user`, `artifacts`, or `pi-settings-metadata-user.json`, 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 paths 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 or files 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 disposable path that stays locked after the retry budget reports `blocked` with `disposable-path-locked` and the path; the worktree, its `.git` pointer, and its journal are untouched, so stop the process holding the handle and rerun the same command.
81
+ Each approved root must be an ignored regular file, directory, symbolic link, or Windows junction at that exact path inside the exact worktree. An exact-root link may target an external generated-content directory; cleanup records its link classification, filesystem identity, and canonical target, revalidates all three immediately before deletion, and removes only the link entry through a non-recursive primitive. It never traverses, removes, or mutates the external target. A descendant link remains stricter: its canonical target must stay inside that same exact disposable root. Escapes by descendant links, drift, replacements, unresolved/cyclic targets, special files, and nested repository boundaries remain blocking. Authority is component-exact: near matches such as `.artifacts-user`, `artifacts`, or `pi-settings-metadata-user.json`, 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 paths 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 or files 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 disposable path that stays locked after the retry budget reports `blocked` with `disposable-path-locked` (or `disposable-link-locked` for a link entry) and the path; the worktree, its `.git` pointer, and its journal are untouched, so stop the process holding the handle and rerun the same command.
68
82
 
69
83
  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. A handed-off entry whose worktree was deleted by hand completes through its journal, and its branch is deleted under the accepted-ancestry rule. Legacy roles can supply separate `--source-pr`, `--candidate-pr`, and `--role` values.
70
84
 
@@ -96,7 +110,7 @@ node scripts/governance/local-worktree-cleanup.mjs retire-redundant \
96
110
  --confirm-redundant
97
111
  ```
98
112
 
99
- The command requires an exact canonical, unlocked, non-current Git worktree on a normal topic branch; no cleanup registration; no pull request in any state for that branch; no remote topic ref; no unique commit beyond freshly fetched `origin/develop`; and no staged, unstaged, untracked, hidden-index, unknown ignored, nested-repository, submodule, or other protected content. Central-policy generated content is inspected and purged normally. Under the mutation lock the command revalidates every gate, journals the captured filesystem/HEAD/ref identity, removes the checkout non-forcibly, and compare-and-deletes only the unchanged local ref. It never removes a remote ref or enables broad cleanup authority.
113
+ The command requires an exact canonical, unlocked, non-current Git worktree on a normal topic branch; no cleanup registration; no pull request in any state for that branch; no remote topic ref; no unique commit beyond freshly fetched `origin/develop`; and no staged, unstaged, untracked, hidden-index, unknown ignored, nested-repository, submodule, or other protected content. Central-policy generated content is inspected and purged normally. Under its exact path/ref resource locks, with brief atomic state transactions, the command revalidates every gate, journals the captured filesystem/HEAD/ref identity, removes the checkout non-forcibly, and compare-and-deletes only the unchanged local ref. It never removes a remote ref or enables broad cleanup authority.
100
114
 
101
115
  A repeated exact confirmed invocation resumes a partial journal or reports `already-retired`. A branch with any pull request remains owned by `complete`/sweep or explicit closed-unmerged `discard`; an open, dirty, remote-backed, locally advanced, registered, locked, detached, protected, replaced, or ambiguous checkout remains retained. Agents never substitute manual deletion when this command blocks.
102
116
 
@@ -150,13 +164,13 @@ node scripts/governance/local-worktree-cleanup.mjs register --repo D:/Git/a1 --p
150
164
 
151
165
  Registration binds the repository, exact directory/filesystem identity, candidate PR, HEAD/ref, role, and generation. It returns an ID and generation, not the owner token. The worktree stays `owned`: registration alone never authorizes removal. Supported roles:
152
166
 
153
- - `implementation`: exact merged implementation PR head; candidate PR equals source PR. This is the only version-3 role because the same PR contains implementation, acceptance manifest, synchronized specs, and archive.
167
+ - `implementation`: exact merged implementation PR head, or exact merged standalone-documentation PR head under the policy above; candidate PR equals source PR. This is the only version-3 role because the same PR contains implementation, acceptance manifest, synchronized specs, and archive.
154
168
  - `acceptance`: legacy exact verified implementation merge commit; candidate PR equals source PR.
155
169
  - `archive`: legacy exact merged generated archive PR head; candidate PR is the archive PR and source PR is the implementation PR.
156
170
 
157
171
  A CI/base/older-ancestor checkout does not qualify automatically. Version 3 has no local acceptance/archive checkout to register. No local archive checkout is required when a legacy archive was generated entirely on GitHub. Legacy version-1/version-2 linkage remains supported, but individually reviewing and registering a legacy checkout is explicit adoption, not a bulk sweep.
158
172
 
159
- Low-level `register` keeps an explicit disposable allowlist for legacy and diagnostic use. The standard `complete` command supplies the central repository policy automatically; agents do not choose flags for normal completed-delivery cleanup. Neither route permits discarding tracked, staged, unstaged, untracked, unknown ignored, linked, special, or actual nested repository/submodule content. Declaring or centrally recognizing a generated directory does not bypass ignored-path, identity, type, or traversal checks.
173
+ Low-level `register` keeps an explicit disposable allowlist for legacy and diagnostic use. The standard `complete` command supplies the central repository policy automatically; agents do not choose flags for normal completed-delivery cleanup. Neither route permits discarding tracked, staged, unstaged, untracked, unknown ignored, unapproved linked, special, or actual nested repository/submodule content. The sole link exception is the guarded exact-root or contained descendant behavior above. Declaring or centrally recognizing a generated directory does not bypass ignored-path, identity, type, or traversal checks.
160
174
 
161
175
  Before handing a completed checkout to cleanup, stop its development processes, leave its directory, and release it using the returned ID and current generation:
162
176
 
@@ -176,7 +190,7 @@ Before resuming a released worktree, acquire it:
176
190
  node scripts/governance/local-worktree-cleanup.mjs claim --repo D:/Git/a1 --id REGISTRATION_ID --generation CURRENT_GENERATION
177
191
  ```
178
192
 
179
- Use a private token for the new session. Claim, release, and cleanup share a per-repository lock. A successful claim prevents deletion until the new owner releases it. A deleting or completed candidate cannot be claimed. A path reused after completed cleanup requires a new explicit `register` operation.
193
+ Use a private token for the new session. Claim, release, hand-off, and cleanup share the candidate's exact path/ref resource locks and commit their state changes through brief repository-state transactions. A successful claim prevents deletion until the new owner releases it. A deleting or completed candidate cannot be claimed. A path reused after completed cleanup requires a new explicit `register` operation.
180
194
 
181
195
  A session crash does not release ownership. After separately confirming that the owner and all related processes have stopped, an explicit recovery claims it for review:
182
196
 
@@ -184,7 +198,7 @@ A session crash does not release ownership. After separately confirming that the
184
198
  node scripts/governance/local-worktree-cleanup.mjs recover --repo D:/Git/a1 --id REGISTRATION_ID --generation CURRENT_GENERATION --confirm-stopped
185
199
  ```
186
200
 
187
- Recovery never releases or deletes. The generation must still match. A Git worktree lock remains a veto. A leftover `mutation.lock` from a killed cleanup process is evicted only on proof: the holder writes its PID and refreshes a heartbeat in the lock every five seconds, and a later `handoff`, `sweep`, `complete`, `discard`, claim, or queue pass evicts the lock only when that heartbeat (or, for an old lock without one, the file's modification time) is more than two minutes old and the PID no longer exists. A live, unprobeable, or own PID keeps the lock, as does a fresh or unreadable-but-fresh file, and the operation reports `mutation-busy`. Each eviction is journaled as `lock-evicted-<time>-<id>.json` beside `state.json` with the evicted record; it releases no ownership and advances no journal step. A lock that stays `mutation-busy` therefore has a live holder: wait for it or stop that process first.
201
+ Recovery never releases or deletes. The generation must still match. A Git worktree lock remains a veto. A leftover repository-state or scoped resource lock from a killed cleanup process is evicted only on proof: the holder writes its PID and refreshes a heartbeat in the lock every five seconds, and a later operation needing that scope evicts the lock only when that heartbeat (or, for an old lock without one, the file's modification time) is more than two minutes old and the PID no longer exists. A live, unprobeable, or own PID keeps the lock, as does a fresh or unreadable-but-fresh file, and the affected operation reports `mutation-busy` for legacy/state contention or `resource-busy` for a candidate/ref scope. Each eviction is journaled as `lock-evicted-<time>-<id>.json` beside `state.json` with the evicted record; it releases no ownership and advances no journal step. A live scoped holder delays only commands needing that same path or ref.
188
202
 
189
203
  ## Outcomes and interruption handling
190
204
 
@@ -222,7 +236,7 @@ Stop watch with Ctrl+C, or request immediate stop authority from another termina
222
236
  node scripts/governance/local-worktree-cleanup.mjs disable --repo D:/Git/a1
223
237
  ```
224
238
 
225
- Disable writes a stop sentinel without waiting for a busy mutation lock. The worker checks it before each destructive step; an already executing Git operation cannot be undone. No later deletion starts while disabled. State and partial journals remain available for review and future explicit enablement.
239
+ Disable writes a stop sentinel without waiting for a busy state or resource lock. The worker checks it before each destructive step; an already executing Git operation cannot be undone. No later deletion starts while disabled. State and partial journals remain available for review and future explicit enablement.
226
240
 
227
241
  Dependency-free focused fixtures (temporary repositories only, no live PR mutation or watcher activation):
228
242
 
@@ -55,7 +55,7 @@ Use equivalent values in bare A1 and the Pi comparison profile. Exercise both a
55
55
  - [ ] `/settings`: selected cursor, label and value accent; unselected values muted; descriptions and hints dim; search uses `> ` with inverse cursor; scalar menus, numeric controls, warning-parts dialog, deferred notice, failed write, section spacing, clipping, and hidden-entry absence match their pinned semantic roles.
56
56
  - [ ] Transcript: toggle images and image width, thinking level/visibility, Mermaid mode, output padding, cache notices, warnings, auto-compaction, queue modes, command autocomplete, provider timeout/retry/error, and changelog collapse. Existing and streaming blocks must re-render without focus, selection, scroll, or queued-work loss.
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
- - [ ] Stable release note: with a built matching stable fixture from an explicitly approved draft GitHub Release snapshot and a fresh A1 profile, verify that exact note opens once after trust/other startup modals, fills the existing `What's New` screen, renders the Pi-style `## [version] - YYYY-MM-DD` heading and categorized `###` sections, scrolls by keys/wheel/rail, resizes, and closes with Escape. Relaunch to verify it stays closed, then use `/changelog` to verify version-labeled packaged history puts the latest A1 release at the top and the oldest at the bottom. A preview fixture must not auto-open or write acknowledgement state; `a1 pi` must retain Pi's oldest-first in-feed changelog so its latest release remains nearest the bottom.
58
+ - [ ] Stable release note: with a built matching stable fixture from an explicitly approved draft GitHub Release snapshot and a fresh A1 profile, verify that exact note opens once after trust/other startup modals, fills the existing `What's New` screen, renders the Pi-style `## [version] - YYYY-MM-DD` heading and categorized `###` sections, scrolls by keys/wheel/rail, resizes, and closes with Escape. Relaunch to verify it stays closed, then use `/changelog` to verify the distinct `Changelog` screen's version-labeled packaged history puts the latest A1 release at the top and the oldest at the bottom. A preview fixture must not auto-open or write acknowledgement state; `a1 pi` must retain Pi's oldest-first in-feed changelog so its latest release remains nearest the bottom.
59
59
  - [ ] 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.
60
60
  - [ ] 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`.
61
61
  - [ ] 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.
@@ -1,8 +1,8 @@
1
1
  # Atomic OpenSpec delivery and legacy archival
2
2
 
3
- New OpenSpec deliveries use one ordinary development pull request from draft planning through implementation, validation, acceptance, specification synchronization, and archival. The only integration action is an authorized maintainer's manual merge. Automation never auto-merges implementation-bound work and never creates a version-3 acceptance or archive follow-up PR.
3
+ New OpenSpec deliveries use one ordinary development pull request from draft planning through implementation, validation, acceptance, specification synchronization, and archival. An authorized maintainer chooses integration by manually merging the exact validated head or personally enabling GitHub native auto-merge for that unchanged head. Agents, Apps, bots, merge queue, and repository automation never arm or invoke implementation integration and never create a version-3 acceptance or archive follow-up PR.
4
4
 
5
- Unrelated standalone documentation remains separate: a non-draft unassociated PR changing only `openspec/**`, `docs/**`, and/or root `README.md` retains the existing CI-gated automatic route. A new active change, implementation association, malformed lifecycle data, or mixed path keeps the manual hold.
5
+ Unrelated standalone documentation remains separate: a non-draft unassociated PR changing only `openspec/**`, `docs/**`, and/or root `README.md` retains the existing CI-gated automatic route. A new active change, implementation association, malformed lifecycle data, or mixed path remains outside documentation-owned integration. Before finalization or without valid human provenance, any arm is disabled; a finalized version-3 human arm remains a separate maintainer-owned route.
6
6
 
7
7
  Version-1 and version-2 deliveries and their existing comments, acceptance PRs, archive PRs, receipts, retries, and bounded catch-up remain supported under [Legacy delivery](#legacy-delivery). Do not silently convert an in-flight legacy delivery.
8
8
 
@@ -14,7 +14,7 @@ Version-1 and version-2 deliveries and their existing comments, acceptance PRs,
14
14
  4. **Plain acceptance list:** keep the body phase-free and add final `## Acceptance` with one to ten concise implementation-specific behavior-and-result bullets. Do not use checkboxes, generic review/CI/approval/archive statements, URLs, mentions, or automated-test inventory.
15
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
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
- 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.
17
+ 7. **Maintainer integration accepts:** after reviewing the finalized candidate, an authorized human either manually merges the exact validated head after the stable protected aggregate succeeds or personally enables GitHub native auto-merge for that unchanged head so protected integration waits for the aggregate. That human action means the listed scenarios are accepted. Agents, Apps, bots, merge queue, automation-owned implementation arms, and documentation integration remain forbidden. A changed head, acceptance list, or finalization invalidates the earlier arm and requires the maintainer to choose again.
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: the agent parks the worktree with `handoff` at step 7, and the next session's `sweep` removes it once the merge, archive, and remote-ref evidence verify (see [local cleanup](local-worktree-cleanup.md)).
19
19
 
20
20
  ### Complete-regression evidence ordering
@@ -38,7 +38,7 @@ Replace the multi-PR OpenSpec handoff with one manually merged development PR wh
38
38
 
39
39
  - Keep planning and implementation in the same draft PR.
40
40
  - Integrate implementation, synchronized specs, acceptance, and archive atomically.
41
- - Preserve standalone documentation auto-merge while forbidding implementation auto-merge.
41
+ - Preserve standalone documentation auto-merge while forbidding automation-owned implementation auto-merge.
42
42
 
43
43
  ## Automation
44
44
 
@@ -75,7 +75,7 @@ Do not add a quoted phase line or a routine `Validation` section listing command
75
75
  </details>
76
76
  ```
77
77
 
78
- 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.
78
+ 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 integration. 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 integration, trusted verification derives `Archived`; do not rewrite the accepted body.
79
79
 
80
80
  ## Agent scratch files
81
81
 
@@ -118,14 +118,15 @@ After finalization, replace it with the exact emitted paths:
118
118
  "version": 3,
119
119
  "change": "example-change",
120
120
  "archive": "openspec/changes/archive/2026-09-15-example-change/",
121
- "acceptanceManifest": "openspec/changes/archive/2026-09-15-example-change/acceptance.md"
121
+ "acceptanceManifest": "openspec/changes/archive/2026-09-15-example-change/acceptance.md",
122
+ "finalizedHead": "0123456789abcdef0123456789abcdef01234567"
122
123
  }
123
124
  ```
124
125
 
125
126
  </details>
126
127
  ````
127
128
 
128
- Version 3 forbids `specificationPr` and `archivePreparationTasks`. Both final paths must be absent for a draft or present and mutually consistent for a finalized candidate. Unknown fields, duplicate fences/JSON keys, unsafe paths, mismatched dates/change identities, and partial finalization fail closed.
129
+ Version 3 forbids `specificationPr` and `archivePreparationTasks`. The archive path, acceptance-manifest path, and exact `finalizedHead` binding must be absent for a draft or mutually consistent for a finalized candidate. Existing finalized records without the head binding are readable only for trusted normalization and cannot satisfy current-head validation. Unknown fields, duplicate fences/JSON keys, unsafe paths, mismatched dates/change identities, malformed SHAs, and partial finalization fail closed.
129
130
 
130
131
  ## Acceptance list
131
132
 
@@ -139,7 +140,7 @@ Use plain bullets:
139
140
  - Finalized specs and archive match the implementation.
140
141
  ```
141
142
 
142
- The committed conditional manifest contains the same ordered text. Trusted policy validates membership but never checks or edits it and never claims that the scenarios passed. Manual merge is the acceptance decision; no acceptance comment, checkbox edit, review-approval requirement, JSON edit, acceptance PR, archive PR, or later command is needed.
143
+ The committed conditional manifest contains the same ordered text. Trusted policy validates membership but never checks or edits it and never claims that the scenarios passed. The authorized maintainer's manual merge or personal native auto-merge arm for the unchanged exact head is the acceptance decision; no acceptance comment, checkbox edit, review-approval requirement, JSON edit, acceptance PR, archive PR, or later command is needed.
143
144
 
144
145
  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.
145
146
 
@@ -152,13 +153,13 @@ The `OpenSpec finalization` workflow (`.github/workflows/openspec-finalization.y
152
153
  - **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.
153
154
  - **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.
154
155
 
155
- 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.
156
+ 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 with `finalizedHead` equal to that exact commit, and only when both the body and PR head still match the operation's expected values. The guaranteed head-binding change triggers native `pull_request: edited` validation even when a re-finalization reuses the same archive paths. The workflow's own body edit triggers further runs that report `already-finalized`; an intermediate run with a missing or stale binding defers before product suites and emits no protected aggregate. 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.
156
157
 
157
158
  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.
158
159
 
159
160
  A missing fence is not an ordinary ready PR when immutable base/head evidence shows that the candidate introduces or restores an active change, or mixes active-change edits with code or operational paths. Base-controlled readiness and finalization both fail with `missing-implementation-association`; deleting editable body metadata cannot bypass finalization. Existing active-change documentation-only revisions and ordinary code PRs without active delivery paths retain their established routes.
160
161
 
161
- If an unassociated implementation has already integrated, do not edit its merged body or publish an archive-only follow-up. A corrective implementation-bound PR for the same still-active change must add the prevention fix and an exact `association-repair.json` record naming the original PR/head/merge/validation and the corrective PR. Normal version-3 finalization then synchronizes and archives the change; the corrective PR's authorized manual merge accepts that repair without pretending the original PR was finalized retroactively.
162
+ If an unassociated implementation has already integrated, do not edit its merged body or publish an archive-only follow-up. A corrective implementation-bound PR for the same still-active change must add the prevention fix and an exact `association-repair.json` record naming the original PR/head/merge/validation and the corrective PR. Normal version-3 finalization then synchronizes and archives the change; the corrective PR's authorized maintainer integration accepts that repair without pretending the original PR was finalized retroactively.
162
163
 
163
164
  ## Finalization command
164
165
 
@@ -194,13 +195,13 @@ gh pr edit <pr> --body-file .artifacts/agent/openspec-pr-body.md
194
195
 
195
196
  Use repeated `--known-gap "exact disposition"` only for an actually reviewed explicit gap. Gaps remain visible in the committed manifest and do not become test results. Missing or ambiguous disposition blocks finalization.
196
197
 
197
- 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.
198
+ 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. Local preparation cannot know the eventual commit SHA, so trusted finalization normalizes the body with `finalizedHead` after the commit is present on the branch. Repeating the trusted operation against identical finalized inputs and a matching head binding is verification-only and byte-stable.
198
199
 
199
200
  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.
200
201
 
201
202
  ## Conditional acceptance and derived receipt
202
203
 
203
- `acceptance.md` truthfully says its verdict activates only when the containing exact head is manually merged by an authorized human after required current-head checks. Its `openspec-delivery` block records stable pre-merge facts:
204
+ `acceptance.md` truthfully says its verdict activates only when an authorized human manually merges the containing exact head after required current-head checks or personally arms native auto-merge for that unchanged head and GitHub integrates it after those checks. Its `openspec-delivery` block records stable pre-merge facts:
204
205
 
205
206
  - schema version, repository, change, and source PR;
206
207
  - archive and manifest paths and finalization date;
@@ -209,7 +210,7 @@ Before a first finalization, canonical specs must still equal the selected targe
209
210
  - archive, canonical-spec, task, and evidence digests; and
210
211
  - explicit known-gap dispositions.
211
212
 
212
- It does not predict source head, merge commit, merger, or merge time. The PR head contains the manifest, so required CI binds those bytes without a recursive self-hash. After merge, the shared reader combines the manifest with immutable GitHub source head, successful required run, authorized human actor, absence of automatic/queue/App provenance, merge commit/time, and `develop` ancestry. That derived result is the durable version-3 receipt used by audit and cleanup.
213
+ It does not predict source head, merge commit, merger, or merge time. The PR head contains the manifest, so required CI binds those bytes without a recursive self-hash. After merge, the shared reader combines the manifest with immutable GitHub source head, successful required run, authorized human actor and permission, integration route, merge commit/time, and `develop` ancestry. Direct manual integration requires no active automatic authority. Human-enabled native auto-merge additionally requires a matching final-head enable event and `auto_merge.enabled_by`, with no later candidate commit or disable event. Queue, App/Bot, automation-owned, stale, malformed, or differently authored authority remains invalid. A human enable followed by disable before a valid manual merge is an abandoned attempt, not contradictory provenance. That shared result is the durable version-3 receipt used by audit and cleanup.
213
214
 
214
215
  Unavailable, stale, automatic, unauthorized, conflicting, or contradictory provenance produces `invalid-provenance`/`blocked`, not acceptance. Post-merge code does not repair it by pushing `develop` or publishing another PR.
215
216
 
@@ -217,7 +218,7 @@ Unavailable, stale, automatic, unauthorized, conflicting, or contradictory prove
217
218
 
218
219
  Normal Development CI remains complete for the implementation once its reviewable candidate exists. An archive-shaped final diff does not select documentation-only validation because the authoritative version-3 association remains implementation-bound. Base-controlled readiness defers a ready head that still holds the active change without running test suites or emitting `Development validation required`. The finalization workflow pushes the finalized head and updates its implementation fence; that update starts one complete selected validation, while PR-level concurrency cancels any superseded eligible run.
219
220
 
220
- `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.
221
+ The trusted post-push `finalizedHead` body edit reruns required CI as a native pull-request event. The ordinary finalized phase-free run exposes every selected lane and the stable protected aggregate on the PR checks page. Manual `workflow_dispatch` remains branch diagnostic evidence: it lacks authoritative PR payload and cannot replace finalized-delivery, acceptance, selection, visibility, or protected aggregate evidence. Documentation auto-merge's trusted owner also reevaluates lifecycle association. It preserves only an authorized human arm for the exact finalized version-3 head, never creates or exercises that arm, and disables stale, automated, malformed, draft, edited, or otherwise ineligible arms. Every publication entry point explicitly refuses version 3.
221
222
 
222
223
  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.
223
224
 
@@ -229,7 +230,7 @@ Read-only inspection remains:
229
230
  GH_TOKEN="$(gh auth token)" node scripts/governance/reconcile-openspec-archive.mjs --dry-run --pr <implementation-pr>
230
231
  ```
231
232
 
232
- For version 3, status distinguishes `needs-finalization`, `ready-for-manual-merge`, `accepted-and-archived`, `closed`, `blocked`, and `invalid-provenance`. A successful workflow invocation does not imply acceptance while the PR is open. Dry run never mutates refs, PRs, body text, tasks, evidence, specs, or acceptance.
233
+ For version 3, status distinguishes `needs-finalization`, `ready-for-maintainer-integration`, `accepted-and-archived`, `closed`, `blocked`, and `invalid-provenance`. A successful workflow invocation does not imply acceptance while the PR is open. Dry run never mutates refs, PRs, body text, tasks, evidence, specs, or acceptance.
233
234
 
234
235
  Scheduled scans continue to serve legacy catch-up. Version-3 candidates are verification-only and do not consume publication slots or block the legacy queue.
235
236
 
@@ -237,7 +238,7 @@ Scheduled scans continue to serve legacy catch-up. Version-3 candidates are veri
237
238
 
238
239
  After version-3 merge, verify:
239
240
 
240
- - the source PR is merged with the exact reviewed head by an authorized human;
241
+ - the source PR is merged with the exact reviewed head through a verified authorized-human integration route;
241
242
  - required exact-head CI succeeded;
242
243
  - current `develop` descends from the merge;
243
244
  - the active change is absent;
@@ -263,16 +264,16 @@ This bootstrap policy itself finishes under deployed version-2 authority. The fi
263
264
  - draft planning remaining unmerged;
264
265
  - explicit plan approval and same-PR implementation;
265
266
  - automated current-target finalization and exact-head CI;
266
- - authorized human manual merge with plain acceptance scenarios;
267
+ - authorized human integration, including manual merge and personally enabled exact-head native auto-merge, with plain acceptance scenarios;
267
268
  - integrated canonical specs/archive and no generated acceptance/archive PR;
268
269
  - read-only `accepted-and-archived` verification and exact-head branch cleanup;
269
- - stale head/body/base, incomplete tasks/evidence, malformed manifest, and automatic-merge refusal fixtures; and
270
+ - stale head/body/base/arm, incomplete tasks/evidence, malformed manifest, and automated or unauthorized auto-merge refusal fixtures; and
270
271
  - an unrelated standalone spec/docs PR retaining auto-merge.
271
272
 
272
273
  Unit tests or API success alone are not live acceptance. Until this evidence exists, version 3 is deployable but documented as awaiting its operational canary.
273
274
 
274
275
  ## Disable or roll back
275
276
 
276
- Before a version-3 merge, disable new version-3 authoring and continue using legacy version 2. After a version-3 merge, preserve its integrated archive and provenance and use an ordinary explicit corrective PR. Never direct-push a rewritten receipt, delete historical evidence, relax branch protection, or reinterpret an automatic merge as human acceptance.
277
+ Before a version-3 merge, disable new version-3 authoring and continue using legacy version 2. After a version-3 merge, preserve its integrated archive and provenance and use an ordinary explicit corrective PR. Never direct-push a rewritten receipt, delete historical evidence, relax branch protection, or reinterpret automation-owned, stale, App/Bot, or queue-backed integration as human acceptance.
277
278
 
278
279
  Disabling the OpenSpec archive workflow stops legacy publication and version-3 post-merge reporting, but does not change existing acceptance records, documentation auto-merge, remote branch cleanup, or release authority.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timurproko/a1",
3
- "version": "0.2.5",
3
+ "version": "0.2.6-dev.727",
4
4
  "description": "Standalone terminal workspace for supervised native and managed agents",
5
5
  "type": "module",
6
6
  "privateLaunchContract": "neutral-launch-v1",
@@ -65,8 +65,8 @@
65
65
  "typecheck:bin": "tsgo -p tsconfig.bin.json"
66
66
  },
67
67
  "dependencies": {
68
- "@earendil-works/pi-coding-agent": "1.0.4",
69
- "@earendil-works/pi-tui": "1.0.4",
68
+ "@earendil-works/pi-coding-agent": "1.1.0",
69
+ "@earendil-works/pi-tui": "1.1.0",
70
70
  "@silvia-odwyer/photon-node": "0.3.4",
71
71
  "chalk": "5.6.2",
72
72
  "cross-spawn": "7.0.6",