@6reduk/workspace-pipeline 0.1.0

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 (157) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +78 -0
  3. package/docs/collaboration.md +59 -0
  4. package/docs/config-fields.md +65 -0
  5. package/docs/contracts.md +149 -0
  6. package/docs/doctor.md +165 -0
  7. package/docs/launch.md +50 -0
  8. package/docs/lifecycle-cli.md +141 -0
  9. package/docs/lifecycle.md +42 -0
  10. package/docs/migrations/unity.md +288 -0
  11. package/docs/native-provider-format.md +149 -0
  12. package/docs/provider-bundles.md +81 -0
  13. package/docs/provider-resources.md +37 -0
  14. package/docs/release.md +25 -0
  15. package/docs/remove.md +70 -0
  16. package/docs/repair.md +80 -0
  17. package/docs/repositories.md +209 -0
  18. package/docs/repository-manual-recovery.md +102 -0
  19. package/docs/repository-observations.md +29 -0
  20. package/docs/repository-recovery.md +204 -0
  21. package/docs/repository-retention.md +46 -0
  22. package/docs/repository-transport-budgets.md +26 -0
  23. package/docs/retention.md +237 -0
  24. package/docs/source.md +50 -0
  25. package/docs/switch.md +412 -0
  26. package/package.json +39 -0
  27. package/schemas/common.schema.json +251 -0
  28. package/schemas/inventory.schema.json +15 -0
  29. package/schemas/operation.schema.json +286 -0
  30. package/schemas/pipeline.schema.json +317 -0
  31. package/schemas/state.schema.json +302 -0
  32. package/schemas/workspace.schema.json +67 -0
  33. package/src/cli.js +7 -0
  34. package/src/commands/adopt.js +2 -0
  35. package/src/commands/bootstrap-recovery.js +90 -0
  36. package/src/commands/dispatch.js +394 -0
  37. package/src/commands/init.js +84 -0
  38. package/src/commands/launch.js +69 -0
  39. package/src/commands/migration-apply.js +53 -0
  40. package/src/commands/migration.js +50 -0
  41. package/src/commands/repositories.js +61 -0
  42. package/src/commands/repository-abandon.js +16 -0
  43. package/src/commands/repository-ancestors.js +21 -0
  44. package/src/commands/repository-locks.js +77 -0
  45. package/src/contracts/parse.js +57 -0
  46. package/src/contracts/semantic.js +240 -0
  47. package/src/contracts/validate.js +21 -0
  48. package/src/launch/grok.js +20 -0
  49. package/src/migrations/legacy-unity-begin.js +35 -0
  50. package/src/migrations/legacy-unity-compensate.js +82 -0
  51. package/src/migrations/legacy-unity-deactivate.js +60 -0
  52. package/src/migrations/legacy-unity-deactivation-resume-apply.js +62 -0
  53. package/src/migrations/legacy-unity-deactivation-resume.js +81 -0
  54. package/src/migrations/legacy-unity-finalize.js +88 -0
  55. package/src/migrations/legacy-unity-install-recovery.js +76 -0
  56. package/src/migrations/legacy-unity-install-resume.js +60 -0
  57. package/src/migrations/legacy-unity-install.js +88 -0
  58. package/src/migrations/legacy-unity-lease.js +136 -0
  59. package/src/migrations/legacy-unity-preflight.js +67 -0
  60. package/src/migrations/legacy-unity-preview.js +91 -0
  61. package/src/migrations/legacy-unity-resume-apply.js +39 -0
  62. package/src/migrations/legacy-unity-resume.js +41 -0
  63. package/src/migrations/legacy-unity-resumed-evidence.js +88 -0
  64. package/src/migrations/legacy-unity.js +99 -0
  65. package/src/operations/apply.js +576 -0
  66. package/src/operations/backup.js +94 -0
  67. package/src/operations/bootstrap-lock.js +87 -0
  68. package/src/operations/bootstrap-owner-retirement.js +121 -0
  69. package/src/operations/bundle-update.js +54 -0
  70. package/src/operations/config-fields.js +24 -0
  71. package/src/operations/continuation-lifecycle.js +77 -0
  72. package/src/operations/doctor.js +214 -0
  73. package/src/operations/history.js +170 -0
  74. package/src/operations/installer-identity.js +49 -0
  75. package/src/operations/journal.js +142 -0
  76. package/src/operations/lifecycle.js +133 -0
  77. package/src/operations/lineage-guard.js +20 -0
  78. package/src/operations/lock.js +109 -0
  79. package/src/operations/maintenance.js +62 -0
  80. package/src/operations/migration-pending.js +22 -0
  81. package/src/operations/ownership.js +122 -0
  82. package/src/operations/plan.js +278 -0
  83. package/src/operations/reconciliation.js +112 -0
  84. package/src/operations/recovery-lease.js +66 -0
  85. package/src/operations/remove.js +140 -0
  86. package/src/operations/repair.js +188 -0
  87. package/src/operations/repository-abandon.js +192 -0
  88. package/src/operations/repository-ancestors.js +158 -0
  89. package/src/operations/repository-apply.js +122 -0
  90. package/src/operations/repository-authorization.js +48 -0
  91. package/src/operations/repository-bootstrap-continuation.js +190 -0
  92. package/src/operations/repository-bootstrap-reconcile.js +106 -0
  93. package/src/operations/repository-bootstrap-recover.js +114 -0
  94. package/src/operations/repository-bootstrap.js +82 -0
  95. package/src/operations/repository-clone.js +63 -0
  96. package/src/operations/repository-history.js +108 -0
  97. package/src/operations/repository-inputs.js +41 -0
  98. package/src/operations/repository-journal.js +127 -0
  99. package/src/operations/repository-lock-reconcile.js +401 -0
  100. package/src/operations/repository-pending.js +29 -0
  101. package/src/operations/repository-reconcile.js +182 -0
  102. package/src/operations/repository-resumption-approvals.js +77 -0
  103. package/src/operations/repository-retention-apply.js +75 -0
  104. package/src/operations/repository-retention.js +137 -0
  105. package/src/operations/repository-workspace.js +78 -0
  106. package/src/operations/retention-apply.js +133 -0
  107. package/src/operations/retention-combined-scan.js +30 -0
  108. package/src/operations/retention-combined.js +41 -0
  109. package/src/operations/retention-policy.js +65 -0
  110. package/src/operations/retention-receipts.js +126 -0
  111. package/src/operations/retention-scan.js +86 -0
  112. package/src/operations/retention.js +56 -0
  113. package/src/operations/state.js +210 -0
  114. package/src/operations/switch-activate.js +64 -0
  115. package/src/operations/switch-backups.js +29 -0
  116. package/src/operations/switch-continuation-journal.js +94 -0
  117. package/src/operations/switch-continuation-pending.js +60 -0
  118. package/src/operations/switch-continuation-records.js +109 -0
  119. package/src/operations/switch-continuation-recovery.js +91 -0
  120. package/src/operations/switch-continuation-runtime.js +135 -0
  121. package/src/operations/switch-continuation-store.js +120 -0
  122. package/src/operations/switch-continuation.js +76 -0
  123. package/src/operations/switch-execute.js +68 -0
  124. package/src/operations/switch-inspect.js +45 -0
  125. package/src/operations/switch-journal-store.js +109 -0
  126. package/src/operations/switch-journal.js +71 -0
  127. package/src/operations/switch-lifecycle.js +72 -0
  128. package/src/operations/switch-pending.js +43 -0
  129. package/src/operations/switch-preflight.js +73 -0
  130. package/src/operations/switch-prepare.js +75 -0
  131. package/src/operations/switch-records.js +60 -0
  132. package/src/operations/switch-recovery-store.js +74 -0
  133. package/src/operations/switch.js +52 -0
  134. package/src/operations/toml-fields.js +133 -0
  135. package/src/providers/bundles.js +42 -0
  136. package/src/providers/common-entry.js +16 -0
  137. package/src/providers/grok.js +26 -0
  138. package/src/providers/interface.js +25 -0
  139. package/src/providers/kimi.js +26 -0
  140. package/src/providers/native.js +155 -0
  141. package/src/providers/registry.js +10 -0
  142. package/src/providers/shared.js +51 -0
  143. package/src/providers/source.js +30 -0
  144. package/src/source/git.js +303 -0
  145. package/src/source/inventory.js +87 -0
  146. package/src/source/repository-budget.js +18 -0
  147. package/src/source/snapshot.js +37 -0
  148. package/src/workspace/paths.js +54 -0
  149. package/src/workspace/profiles.js +8 -0
  150. package/src/workspace/repositories.js +57 -0
  151. package/src/workspace/repository-inventory.js +77 -0
  152. package/src/workspace/repository-observation.js +38 -0
  153. package/src/workspace/repository-preflight.js +129 -0
  154. package/src/workspace/repository-preview.js +196 -0
  155. package/src/workspace/repository-tree.js +57 -0
  156. package/src/workspace/reserved.js +11 -0
  157. package/src/workspace/resolve.js +53 -0
package/docs/switch.md ADDED
@@ -0,0 +1,412 @@
1
+ # Switch lifecycle (internal APIs and CLI)
2
+
3
+ Current implementation includes phase execution, repeated uncertain continuation,
4
+ final activation and doctor/history integration. CLI preview/apply routing is
5
+ available with the packaged Codex/Claude registry. This does not authorize a live
6
+ project migration. See [CLI contract](lifecycle-cli.md).
7
+ The CLI routes uncertain-target and clean-boundary continuation, including a
8
+ completed journal whose activation is still pending. See boundary rules below.
9
+ Older prerequisite sections describe their historical implementation boundaries;
10
+ the CLI contract and boundary section describe the current combined behavior.
11
+ Prerequisite sections describe their own limited scope, not execution authority.
12
+
13
+ `composeSwitchPreview({previous, removal, replacement})` is pure, non-executable
14
+ composition. `removal` is a full-removal native preview against actual previous
15
+ state. `replacement` is a setup candidate against the projected post-removal
16
+ configuration, not a setup request executed against an active workspace.
17
+
18
+ The function checks both envelopes, enforces the same workspace/layout, different
19
+ pipeline identity and snapshot digest, and binds incoming before bytes to removal
20
+ results wherever paths overlap. It retains separate remove-old/install-new phases,
21
+ initial observations and projected final results. Foreign observations survive.
22
+ No mutation of input, filesystem, Git, configs or approvals occurs.
23
+
24
+ The returned envelope has applySupported=false and sourceVerification=not-verified.
25
+ Pure schema/hash consistency is not proof of installed ownership, trusted adapter
26
+ replay or staged source bytes. The future coordinator must stage and validate the
27
+ new Git source before any removal and obtain fresh approval under a live lock.
28
+ Source manifests cannot inject executable adapters.
29
+
30
+ ## Git-backed preparation (internal, no apply)
31
+
32
+ `prepareSwitch({wrapper, manifestPath, network?, tempRoot?}, registry)` in
33
+ `operations/switch-prepare.js` stages an explicitly selected Git source outside
34
+ the wrapper. It replays the installed package to prepare full removal, verifies
35
+ the incoming package, invokes trusted CLI adapters, and composes incoming requests
36
+ against projected post-removal bytes. Existing foreign files/JSON fields remain
37
+ subject to normal ownership checks; switch grants no takeover authority.
38
+
39
+ The old removal/state, incoming manifest, staged snapshot and observed destination
40
+ bytes are rechecked after adapter work. The outer private envelope reports
41
+ `sourceVerification: verified-at-preparation`, not ongoing source freshness; its
42
+ embedded pure phase preview deliberately retains `not-verified`. Preparation can
43
+ write disposable Git staging directories outside the workspace (also on failure),
44
+ but never applies removal, installs provider files, creates a journal, or modifies
45
+ workspace state. No temporary-directory deletion or cleanup policy is added here.
46
+
47
+ `applySupported` remains false. There is no lock, atomic snapshot, approval or
48
+ crash-recovery guarantee for this preview. A future executor must replay/approve
49
+ the exact two-phase operation under a live workspace lock and use one phased
50
+ journal. Public source switches remain unavailable.
51
+
52
+ Public switch routing remains unimplemented. Existing native
53
+ single-phase journals cannot simply concatenate targets when the same path is
54
+ deleted/restored and later recreated. The phased journal keeps those two
55
+ steps and their readbacks distinct under one operation, with non-ready state on
56
+ interruption. No remove-plus-unrelated-setup workaround is enabled.
57
+
58
+ ## Two-phase event model
59
+
60
+ `inspectSwitchEvents(preview, previous, events)` verifies a single ordered chain
61
+ bound to the reconstructed two-phase preview. Events have exact keys, sequence,
62
+ previous canonical event digest and preview digest. A start is followed by
63
+ phase-qualified intent/outcome pairs in target order. An unfinished intent is
64
+ uncertain; failed/uncertain outcomes stop progress. A `phase-checked` event binds
65
+ the expected whole projected path/hash map after every target in that phase.
66
+ Only then may the next phase begin, even when a phase has no targets. Both phase
67
+ checks are necessary for event-chain completion; completion is not activation.
68
+
69
+ The same path can occur once in each phase, without flattening targets or losing
70
+ which write an outcome describes. The future executor must obtain actual target
71
+ readback evidence, enforce approval and bind transaction recovery to this model.
72
+ This pure helper neither reads nor creates journal files. Its chain
73
+ uses canonical event digests, not hashes of serialized file bytes. It does not
74
+ validate source provenance or attest that asserted filesystem observations occurred.
75
+
76
+ This is a full, bounded in-memory inspection. Do not call it over all accumulated
77
+ events before every persisted append: that would repeat work quadratically.
78
+ The internal cursor advances one event at a time; durable writer/head checks are
79
+ described below. No retention guarantee is claimed by this helper.
80
+
81
+ ## Internal journal storage
82
+
83
+ `createSwitchJournal` / `readSwitchJournal` in `switch-journal-store.js` persist
84
+ and inspect these events under `.pipeline/journals/<uuid>/`. The writer requires
85
+ a live workspace lock, reports the exact directory through `onLocation`, creates
86
+ each event exclusively, syncs its file and checks the recorded bytes. A failed
87
+ append poisons the writer; neither automatic append-resume nor repair is offered.
88
+ Existing evidence is retained. A read-only reader reconstructs incomplete intents
89
+ as uncertain and rejects malformed, reordered or incorrectly bound events.
90
+
91
+ Each append checks the last file's byte hash, while the event chain uses canonical
92
+ digests. Full audits occur at initialization, both phase checks and failed/uncertain
93
+ outcomes. Older prefix corruption may only be found at these audits, not the next
94
+ append. Tests count head reads and audits; there is no complete performance benchmark
95
+ or guarantee against concurrent hostile filesystem access/power loss.
96
+
97
+ This storage is internal and not connected to the public CLI. Storage primitives
98
+ alone grant no activation or write authority. The lifecycle and history readers
99
+ described below bind the exact prepared switch, approval, snapshots and recovery
100
+ envelope. Do not bypass those checks or create real workspace switch journals
101
+ through these low-level APIs.
102
+
103
+ ## Recovery envelope (structural binding)
104
+
105
+ `switch-records.js` validates a prepared switch against an exact approval digest
106
+ and previous state, then builds a `switch-recovery` envelope bound to one journal.
107
+ It reconstructs the two-phase preview, checks the full-removal record and required
108
+ backup inventory, and retains both snapshot descriptors. The envelope is detached
109
+ and digest-bound; a wrong approval, replaced phase, missing backup descriptor or
110
+ modified recovery snapshot is rejected. No synthetic nested approval is created.
111
+
112
+ These helpers perform no I/O. `sourceVerification` is a claim from preparation,
113
+ not proof re-established by record validation. The envelope does not demonstrate
114
+ that its journal exists or that snapshots/backups have been durably installed.
115
+ `activationSupported` stays false. Locked adapter/source replay, persistence and
116
+ generic recovery/history integration remain required before execution is enabled.
117
+
118
+ ## Locked preflight
119
+
120
+ `verifySwitchApproval(lock, prepared, approval, registry, previous)` in
121
+ `switch-preflight.js` detaches and validates the exact record before awaiting,
122
+ requires a live lock, and verifies actual state bytes, full old-package removal
123
+ replay (including backups), incoming origin and staged package bytes. Staging
124
+ directories must exist outside and not contain the workspace. It reconstructs
125
+ the incoming adapter plan against the approved projected post-removal observations
126
+ and compares the exact result and observation scope.
127
+
128
+ State, source, removal and target observations are repeated after asynchronous
129
+ adapter execution. This preflight does not fetch Git, write recovery records,
130
+ modify provider files, or activate anything. It returns `applySupported: false`.
131
+ Passing it is not a reusable capability: the executor must recheck relevant
132
+ dependencies at persistence/write boundaries and handle intervening external edits.
133
+
134
+ ## Prerequisite persistence (internal, no target writes)
135
+
136
+ `persistSwitchRecovery` in `switch-recovery-store.js` performs locked preflight,
137
+ bounds the recovery record, copies/verifies the new snapshot, initializes one
138
+ phased journal and exclusively writes/syncs/readbacks the associated recovery file
139
+ at `.pipeline/transactions/<same-uuid>/recovery.json`. Preflight and durable
140
+ evidence inspection are repeated before returning exact recovery hash and paths.
141
+ No journal writer capability, pending/active transition or target write is returned.
142
+
143
+ `readSwitchRecovery` checks record/journal identity, both persisted snapshot trees,
144
+ old backup hashes and the event chain without requiring the temporary source
145
+ directory. It does not inspect current provider-target state or authorize resumption.
146
+ Partial/orphan metadata is retained on errors, including an unusable recovery file.
147
+ There is no automatic retry, deletion or generic-history bypass. Executor and
148
+ activation helpers perform their own current-state checks.
149
+
150
+ Incoming ownership backups are derived by `incomingSwitchBackups` from approved
151
+ post-removal observation bytes. Whole-file hashes and owned JSON-field before
152
+ values are verified separately; backups retain the entire observed file. All
153
+ existing backup collisions are checked before creating new backups. An identical
154
+ backup is reused; different bytes at the same path cause failure, not overwrite.
155
+ Backups are saved before journal/recovery creation and checked by recovery reads.
156
+ Descriptor derivation is deterministic from the frozen preview, so no additional
157
+ recovery-record field or historical record rewrite is introduced. Legacy field
158
+ backup collisions with changed foreign siblings fail closed and are not resolved
159
+ automatically by this step.
160
+
161
+ ## Pending transition (internal)
162
+
163
+ `markSwitchPending` in `switch-pending.js` requires the exact persisted recovery
164
+ path/hash, a live lock and current explicit approval. It verifies the untouched
165
+ start-only journal, replays preflight, stages state bytes, repeats checks before
166
+ rename and verifies the resulting state file. Old active deployment and activation
167
+ history remain unchanged; status becomes `needs-reconciliation`.
168
+
169
+ For switch, `pending` binds the canonical recovery-record digest (including the
170
+ unique journal identity), not merely equal desired bytes or a repeatable preview.
171
+ Generic readers must learn this switch-specific binding before public routing.
172
+ Interruption after rename leaves pending state; no rollback or false ready result
173
+ is attempted. Scratch/evidence files may remain on failure. The helper does not
174
+ write provider targets or authorize their execution. Advisory locking does not
175
+ exclude hostile same-user OS races.
176
+
177
+ ## Pending inspection
178
+
179
+ `inspectPendingSwitch(workspace, recoveryPath)` verifies exact pending-state binding
180
+ to this transaction, durable evidence and actual target bytes. It reconstructs the
181
+ expected intermediate state from completed events in phase order. For interrupted
182
+ intent/uncertain outcome it distinguishes `uncertain-before`, `uncertain-desired`
183
+ and `conflict`; seeing desired bytes never manufactures a completed outcome.
184
+ Other observed paths must match the intermediate projection, including unchanged
185
+ dependencies. It repeats state/evidence/target checks to reject observed drift.
186
+
187
+ The result always remains `needs-reconciliation` with `executionAllowed: false`.
188
+ Journal completion, if present, is reported separately and is not activation.
189
+ It neither writes nor resumes an operation, and is not yet wired into generic
190
+ doctor/history. No atomic snapshot or hostile-concurrency guarantee is implied.
191
+
192
+ ## Explicit phase execution (internal)
193
+
194
+ `executeSwitchPhase` accepts one phase name, exact recovery path/hash and current
195
+ approval. It verifies the pending transaction and intact intermediate files,
196
+ reopens only an intact `open` journal at its verified head and executes that phase.
197
+ Installation cannot be selected while removal is current. Uncertain or stopped
198
+ chains cannot be reopened through this entry point.
199
+
200
+ Each target gets a durable intent before mutation and a completed outcome only
201
+ after readback. Existing checked file-write/delete primitives are reused with
202
+ unchanged bodies. State/recovery hashes and all projected observed paths are
203
+ checked around writes; journal head checks remain incremental. Full evidence and
204
+ snapshot audits occur at phase entry/exit, not before each append. Prefix/snapshot
205
+ drift may therefore be detected at the boundary rather than at the next target.
206
+ This is not an overall linear-time claim: target dependency scans still cover the
207
+ whole observed scope at each write.
208
+
209
+ Both phases share one journal. Phase completion verifies the intermediate state
210
+ and records its projection check. Even after both phases, state stays pending;
211
+ no active-deployment promotion or user-ready claim is made. An error after intent
212
+ retains uncertainty and blocks ordinary rerun; no outcome is invented or history
213
+ rewritten. History/doctor integration and explicit continuation are described
214
+ below; nothing is exposed as a public CLI command.
215
+
216
+ ## Final activation (internal)
217
+
218
+ `activateSwitch` requires exact recovery hash, current approval, live lock, both
219
+ completed phase checks, matching pending identity and conflict-free final files.
220
+ It stages and rechecks the transition before rename. The new deployment becomes
221
+ active with an anchor containing recovery path/byte hash and terminal journal
222
+ sequence/byte hash; pending is cleared. Snapshots, backups, approvals and journal
223
+ history are not rewritten. Runtime remains `not-run`.
224
+
225
+ `inspectActivatedSwitch` confirms the exact active deployment and anchor, completed
226
+ journal and final file hashes with repeated dependency/target checks. It can establish
227
+ that activation was written after an interruption at rename, without reapplying.
228
+ A returned `applied` is local configuration evidence, not live-provider readiness.
229
+ Generic doctor/history recognize these records as described below. Public write
230
+ routing is still absent. Uncertain phases require the separate continuation path.
231
+
232
+ ## History and doctor integration
233
+
234
+ History dispatches exact `switch-recovery` records to the phased evidence reader,
235
+ retaining unfinished/orphan/corrupt diagnostics and normal predecessor-anchor
236
+ checks. Historical switch verification uses stored evidence, not today's target
237
+ bytes. Completed journal status alone still does not prove activation.
238
+
239
+ Doctor selects the exact active anchor, or identifies a pending switch by its
240
+ unique recovery digest. Switch readiness uses exact activation/final-projection
241
+ inspection; pending switches always remain non-ready. A stale explicit selection
242
+ or invalid historical predecessor cannot be hidden by a valid current switch.
243
+ Native setup/update/repair/removal dispatch and field projections remain unchanged.
244
+ Switch-specific comparison is conservative and exact; it does not yet extend native
245
+ foreign-field projection allowances to completed switch results. Public switch
246
+ execution and release qualification remain pending; internal continuation follows.
247
+
248
+ ## Continuation preview (read-only)
249
+
250
+ `prepareSwitchContinuation` binds a proposed new continuation to the exact pending
251
+ recovery, journal sequence/canonical head/byte head, state bytes and observations.
252
+ For a conflict-free uncertain operation, before bytes select
253
+ `retry-approved-target`; desired bytes select `verify-desired` without a duplicate
254
+ write. Remaining approved targets and phase checks are listed in original order.
255
+ Equal before/desired hashes also select verification only.
256
+
257
+ The preview is digest-bound, `applySupported: false`, and requires fresh approval.
258
+ It rechecks dependencies before returning and never rewrites the predecessor or
259
+ marks its uncertain outcome completed. Foreign changes and failed journals are
260
+ rejected. Verified clean boundaries use the rules below. Recovery/journal lineage, execution and resolution of
261
+ historical unfinished diagnostics are separate helpers described below.
262
+
263
+ ## Continuation approval verification (internal, read-only)
264
+
265
+ `verifySwitchContinuationApproval` accepts only an exact `decision: approve` and
266
+ `previewDigest` binding. It detaches caller inputs before awaiting, validates the
267
+ preview digest, checks the live workspace lock, and reconstructs the preview from
268
+ current recovery, journal, state and target observations. Any changed dependency
269
+ or observation invalidates the old approval. The lock is checked again at return.
270
+
271
+ This is a point-in-time read-only check, not a durable authorization receipt or
272
+ permission to append to the old uncertain journal. `applySupported` stays false.
273
+ Future execution must recheck its dependencies at mutation boundaries; advisory
274
+ locking does not prevent unrelated programs from editing files.
275
+
276
+ ## Continuation event model (internal, pure)
277
+
278
+ `createSwitchContinuationCursor` interprets a new chain for an already verified
279
+ continuation preview. The start event binds the exact predecessor descriptor;
280
+ later events bind the preview digest and previous event digest. It never appends
281
+ to the predecessor. Retry operations require intent and outcome. A first target
282
+ marked `verify-desired` instead accepts readback without a write intent. Both
283
+ paths require the desired hash for completion and ordered phase projection checks.
284
+
285
+ An unfinished intent remains uncertain; failed/uncertain outcomes stop the chain.
286
+ An invalid append poisons the cursor. A completed chain is not activation or
287
+ runtime evidence. Validation here is structural and sequencing only, not proof
288
+ that predecessor files, approval or observed bytes exist. Event storage is
289
+ described below, as are locked execution and history resolution. This model does not
290
+ make continuation available through the CLI.
291
+
292
+ ## Continuation journal storage (internal)
293
+
294
+ `createSwitchContinuationJournal` verifies exact approval under the workspace
295
+ lock before creating a fresh UUID journal. Location callbacks report planned,
296
+ created and initialized paths. Approval/dependency checks are repeated around
297
+ initialization callbacks. The predecessor journal is never a valid destination.
298
+
299
+ Events use exclusive creation, sync and byte-hash readback. Appends check the live
300
+ lock and previous file hash; full replay runs at initialization, phase boundaries
301
+ and stopped outcomes, not on every event. Prefix corruption may therefore be
302
+ detected at a boundary rather than at the next append. IO/validation failure
303
+ poisons the writer and preserves partial files. `openSwitchContinuationJournal`
304
+ can reopen only an audited open chain with the expected byte head; uncertain or
305
+ failed chains cannot reopen. No cleanup is provided here.
306
+ `readSwitchContinuationJournal` performs a bounded read-only event audit against
307
+ the supplied preview. It does not prove approval, live target state or resolution
308
+ of the predecessor's uncertainty.
309
+
310
+ This is internal evidence storage only. It does not write provider targets or
311
+ change pending/active state. The recovery wrapper below persists the binding;
312
+ execution-boundary checks and generic history integration are separate helpers
313
+ before continuation can be exposed through the CLI. Separate chains created
314
+ here are not treated as automatic permission to execute or as resolved history.
315
+
316
+ ## Continuation recovery binding (internal)
317
+
318
+ `persistSwitchContinuationRecovery` stores a strict `switch-continuation-recovery`
319
+ record beside the new chain, using the same UUID for transaction and journal.
320
+ The envelope includes the exact preview, approval and new journal path. The full
321
+ record is size-bounded before writing; exclusive creation, sync and hash readback
322
+ are followed by repeated locked approval and evidence checks. Partial records
323
+ remain on failure. No mutable writer or execution permission is returned.
324
+
325
+ `readSwitchContinuationRecovery` checks the envelope, UUID binding, predecessor
326
+ recovery byte hash, original snapshots/backups and exact old journal position.
327
+ It reconstructs the interrupted target, remaining approved operations and
328
+ historical observations from the immediate predecessor's plan and journal, with
329
+ the original switch verified through the ancestry chain. Both old dependencies
330
+ and the new journal are rechecked for drift. Stored hashes are integrity bindings,
331
+ not signatures or authentication of a human decision.
332
+
333
+ This reader checks historical evidence independently of current target files.
334
+ An intact record can remain readable after a user edit, without authorizing that
335
+ edit or continuation. Selection, target execution guards, final activation and
336
+ generic history resolution are described below. The
337
+ old uncertainty is not relabelled successful by record creation or validation.
338
+
339
+ ## Selecting the pending continuation (internal)
340
+
341
+ `markSwitchContinuationPending` requires the exact recovery byte hash, matching
342
+ stored/current approval and an initialized one-event continuation journal. It
343
+ revalidates the preview against the old pending state, stages a new state file,
344
+ then repeats evidence, approval, staged-byte and current-state checks before
345
+ rename. Only `pending` changes: its new digest identifies the exact continuation
346
+ record (including its unique journal), not just the same desired configuration.
347
+ The active deployment and previous activation anchor are retained.
348
+
349
+ `inspectSelectedSwitchContinuation` verifies that exact pending identity and
350
+ historical evidence, including after interruption following rename. It does not
351
+ claim current target readiness: `executionAllowed` remains false. Errors preserve
352
+ staged or renamed state rather than rolling back. An ordinary rerun against the
353
+ old pending state fails after selection; the original switch executor also cannot
354
+ continue under the new identity. No public command is added here.
355
+
356
+ ## Continuation execution, activation and history
357
+
358
+ `executeSwitchContinuationPhase` executes exactly one selected remaining phase.
359
+ It checks the recovery byte hash, stored approval, exact pending state, journal
360
+ head and projected target bytes. A verified desired first target gets readback
361
+ only; retries and later targets receive intent/write/readback/outcome. It reuses
362
+ checked file primitives. State, recovery and observed targets are guarded around
363
+ writes; full evidence audits run at phase boundaries. This is not an OS-wide lock
364
+ or an overall linear-time claim. Failed writes preserve uncertainty.
365
+
366
+ `activateSwitchContinuation` requires a completed chain, conflict-free final
367
+ projection and matching selected state. It stores the new desired deployment
368
+ with an exact continuation recovery/head anchor, repeating checks before rename.
369
+ `inspectSwitchContinuation` checks pending projection or exact completed active
370
+ state, including activation readback after a crash. Runtime remains not-run.
371
+
372
+ History retains the original uncertain status and adds `resolvedBy` only after
373
+ verifying a completed continuation against that exact predecessor. This removes
374
+ only its unfinished diagnostic, not corrupt/orphan diagnostics. Doctor recognizes
375
+ pending continuation digests and exact activation anchors; stale selections and
376
+ invalid dependencies cannot claim ready.
377
+
378
+ An interrupted continuation may now be the predecessor of a fresh, explicitly
379
+ approved continuation. `readSwitchLineage` performs two iterative ancestry passes,
380
+ rejects cycles and allows at most 32 continuation links plus the original switch.
381
+ Preparation rejects exceeding that budget before creating the next journal.
382
+ Every link binds exact parent bytes and journal position; the original switch
383
+ supplies snapshots, backups and desired installation. Each immediate predecessor
384
+ supplies its remaining operations and verified progress. Completed operations
385
+ are not replayed, and readback-only authority cannot expand into write authority.
386
+ Final activation selects the new record, not a timestamp or equal desired hash.
387
+ History resolves the verified ancestors without rewriting them.
388
+
389
+ ## Clean-boundary continuation
390
+
391
+ A pending original switch or continuation may have an `open` journal with no
392
+ uncertain target, or a `completed` journal not yet activated. Fresh continuation
393
+ uses `uncertain: null` and binds the exact predecessor head, pending selection,
394
+ observed projection and remaining suffix. Completed outcomes are skipped; a
395
+ missing phase check is retained even when that phase has no operations left.
396
+ Existing readback-only authority stays readback-only, never becomes a write retry.
397
+
398
+ Both recorded phase checks allow an empty remaining list. Its new start-only
399
+ journal is completed structurally; pending selection and activation still repeat
400
+ source/ancestry/current-target validation. Neither record creation nor completion
401
+ alone declares the installation active. A crash of this new continuation can be
402
+ continued again with a new exact approval, within the existing ancestry bound.
403
+
404
+ History accepts verified open/completed predecessors as well as uncertain ones
405
+ only through validated lineage. It preserves their original records and statuses.
406
+ No timestamp selection, inferred outcomes, replay of completed writes, or reopening
407
+ of the predecessor journal is permitted. Failed or corrupt chains stay rejected.
408
+ This bounds one ancestry read; scanning all history is not claimed to be linear.
409
+
410
+ Repository moves, documentation relocation, changing layout, same-pipeline updates
411
+ and partial provider removal are not this switch preview's scope. Caller-defined
412
+ payloads are private and may contain config secrets; do not publish them as logs.
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@6reduk/workspace-pipeline",
3
+ "version": "0.1.0",
4
+ "description": "Workspace-local Git pipeline configuration dispatcher",
5
+ "type": "module",
6
+ "bin": {
7
+ "workspace-pipeline": "src/cli.js"
8
+ },
9
+ "files": [
10
+ "src/",
11
+ "schemas/",
12
+ "docs/"
13
+ ],
14
+ "engines": {
15
+ "node": ">=22"
16
+ },
17
+ "license": "MIT",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/6reduk/workspace-pipeline-cli.git"
21
+ },
22
+ "scripts": {
23
+ "check": "node --check src/cli.js",
24
+ "test": "node --test test/*.test.js",
25
+ "pack:check": "npm pack --dry-run --ignore-scripts",
26
+ "test:packed": "node scripts/verify-packed-cli.mjs",
27
+ "test:packed:identity": "node scripts/verify-packed-identity.mjs",
28
+ "test:packed:providers": "node scripts/verify-packed-providers.mjs",
29
+ "test:packed:pilot": "node scripts/verify-packed-pilot.mjs"
30
+ },
31
+ "dependencies": {
32
+ "ajv": "8.20.0",
33
+ "yaml": "2.9.1",
34
+ "toml-eslint-parser": "0.10.1"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ }
39
+ }