@msn-control/liftoff 0.11.2 → 0.12.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 (339) hide show
  1. package/DEVELOPER.md +26 -24
  2. package/README.md +18 -18
  3. package/assets/governance/single-maintainer-gitflow/activation-v2-graph.json +1583 -0
  4. package/dist/adapters/credentials/github-enrollment.d.ts +51 -0
  5. package/dist/adapters/credentials/github-enrollment.js +226 -0
  6. package/dist/adapters/credentials/github-enrollment.js.map +1 -0
  7. package/dist/adapters/credentials/protected-input.d.ts +7 -0
  8. package/dist/adapters/credentials/protected-input.js +68 -0
  9. package/dist/adapters/credentials/protected-input.js.map +1 -0
  10. package/dist/adapters/filesystem/executables.d.ts +2 -0
  11. package/dist/adapters/filesystem/executables.js +70 -0
  12. package/dist/adapters/filesystem/executables.js.map +1 -0
  13. package/dist/adapters/filesystem/update-previews.d.ts +9 -0
  14. package/dist/adapters/filesystem/update-previews.js +45 -2
  15. package/dist/adapters/filesystem/update-previews.js.map +1 -1
  16. package/dist/adapters/filesystem/workstation-attempts.d.ts +13 -0
  17. package/dist/adapters/filesystem/workstation-attempts.js +78 -0
  18. package/dist/adapters/filesystem/workstation-attempts.js.map +1 -0
  19. package/dist/adapters/github/activation-rest.d.ts +40 -0
  20. package/dist/adapters/github/activation-rest.js +272 -0
  21. package/dist/adapters/github/activation-rest.js.map +1 -0
  22. package/dist/adapters/process/shell-command.d.ts +1 -0
  23. package/dist/adapters/process/shell-command.js +5 -2
  24. package/dist/adapters/process/shell-command.js.map +1 -1
  25. package/dist/adapters/state/azure-blob.d.ts +43 -0
  26. package/dist/adapters/state/azure-blob.js +335 -0
  27. package/dist/adapters/state/azure-blob.js.map +1 -0
  28. package/dist/adapters/state/darwin-capabilities.d.ts +33 -0
  29. package/dist/adapters/state/darwin-capabilities.js +146 -0
  30. package/dist/adapters/state/darwin-capabilities.js.map +1 -0
  31. package/dist/adapters/state/darwin-native-host.d.ts +32 -0
  32. package/dist/adapters/state/darwin-native-host.js +294 -0
  33. package/dist/adapters/state/darwin-native-host.js.map +1 -0
  34. package/dist/adapters/state/darwin-profile.d.ts +6 -0
  35. package/dist/adapters/state/darwin-profile.js +56 -0
  36. package/dist/adapters/state/darwin-profile.js.map +1 -0
  37. package/dist/adapters/state/darwin-system-program.d.ts +1 -0
  38. package/dist/adapters/state/darwin-system-program.js +94 -0
  39. package/dist/adapters/state/darwin-system-program.js.map +1 -0
  40. package/dist/adapters/state/local-qualification.d.ts +16 -0
  41. package/dist/adapters/state/local-qualification.js +299 -0
  42. package/dist/adapters/state/local-qualification.js.map +1 -0
  43. package/dist/adapters/state/local.d.ts +25 -0
  44. package/dist/adapters/state/local.js +145 -0
  45. package/dist/adapters/state/local.js.map +1 -0
  46. package/dist/adapters/state/native-command.d.ts +21 -0
  47. package/dist/adapters/state/native-command.js +82 -0
  48. package/dist/adapters/state/native-command.js.map +1 -0
  49. package/dist/adapters/state/native-files.d.ts +2 -0
  50. package/dist/adapters/state/native-files.js +47 -0
  51. package/dist/adapters/state/native-files.js.map +1 -0
  52. package/dist/adapters/state/native-system.d.ts +38 -0
  53. package/dist/adapters/state/native-system.js +86 -0
  54. package/dist/adapters/state/native-system.js.map +1 -0
  55. package/dist/adapters/state/opentofu.d.ts +35 -0
  56. package/dist/adapters/state/opentofu.js +350 -0
  57. package/dist/adapters/state/opentofu.js.map +1 -0
  58. package/dist/adapters/state/owned-process.d.ts +43 -0
  59. package/dist/adapters/state/owned-process.js +252 -0
  60. package/dist/adapters/state/owned-process.js.map +1 -0
  61. package/dist/adapters/state/posix-lock-program.d.ts +1 -0
  62. package/dist/adapters/state/posix-lock-program.js +185 -0
  63. package/dist/adapters/state/posix-lock-program.js.map +1 -0
  64. package/dist/adapters/state/posix-native-lock.d.ts +15 -0
  65. package/dist/adapters/state/posix-native-lock.js +145 -0
  66. package/dist/adapters/state/posix-native-lock.js.map +1 -0
  67. package/dist/adapters/state/protected-workspace.d.ts +57 -0
  68. package/dist/adapters/state/protected-workspace.js +412 -0
  69. package/dist/adapters/state/protected-workspace.js.map +1 -0
  70. package/dist/application/context.d.ts +3 -0
  71. package/dist/application/diagnose/doctor.d.ts +5 -0
  72. package/dist/application/diagnose/doctor.js +21 -5
  73. package/dist/application/diagnose/doctor.js.map +1 -1
  74. package/dist/application/diagnose/generated-project.js +2 -7
  75. package/dist/application/diagnose/generated-project.js.map +1 -1
  76. package/dist/application/initialize/fixture.js +8 -1
  77. package/dist/application/initialize/fixture.js.map +1 -1
  78. package/dist/application/initialize/use-case.js +70 -36
  79. package/dist/application/initialize/use-case.js.map +1 -1
  80. package/dist/application/project/manifest.js +5 -4
  81. package/dist/application/project/manifest.js.map +1 -1
  82. package/dist/application/state-migration/execution.d.ts +32 -0
  83. package/dist/application/state-migration/execution.js +440 -0
  84. package/dist/application/state-migration/execution.js.map +1 -0
  85. package/dist/application/state-migration/index.d.ts +22 -0
  86. package/dist/application/state-migration/index.js +17 -0
  87. package/dist/application/state-migration/index.js.map +1 -0
  88. package/dist/application/state-migration/lifecycle.d.ts +3 -0
  89. package/dist/application/state-migration/lifecycle.js +149 -0
  90. package/dist/application/state-migration/lifecycle.js.map +1 -0
  91. package/dist/application/state-migration/planning.d.ts +7 -0
  92. package/dist/application/state-migration/planning.js +150 -0
  93. package/dist/application/state-migration/planning.js.map +1 -0
  94. package/dist/application/state-migration/recovery.d.ts +5 -0
  95. package/dist/application/state-migration/recovery.js +145 -0
  96. package/dist/application/state-migration/recovery.js.map +1 -0
  97. package/dist/application/state-migration/runtime.d.ts +32 -0
  98. package/dist/application/state-migration/runtime.js +188 -0
  99. package/dist/application/state-migration/runtime.js.map +1 -0
  100. package/dist/application/state-migration/service.d.ts +2 -0
  101. package/dist/application/state-migration/service.js +20 -0
  102. package/dist/application/state-migration/service.js.map +1 -0
  103. package/dist/application/update/command-guidance.d.ts +19 -2
  104. package/dist/application/update/command-guidance.js +20 -6
  105. package/dist/application/update/command-guidance.js.map +1 -1
  106. package/dist/application/update/guidance-context.d.ts +2 -0
  107. package/dist/application/update/guidance-context.js +35 -0
  108. package/dist/application/update/guidance-context.js.map +1 -0
  109. package/dist/application/update/inspection.d.ts +21 -4
  110. package/dist/application/update/inspection.js +88 -29
  111. package/dist/application/update/inspection.js.map +1 -1
  112. package/dist/application/update/migration-runtime.js +25 -13
  113. package/dist/application/update/migration-runtime.js.map +1 -1
  114. package/dist/application/update/output.d.ts +4 -1
  115. package/dist/application/update/output.js +14 -4
  116. package/dist/application/update/output.js.map +1 -1
  117. package/dist/application/update/preview.d.ts +10 -1
  118. package/dist/application/update/preview.js +26 -4
  119. package/dist/application/update/preview.js.map +1 -1
  120. package/dist/application/update/revalidation-plan.d.ts +1 -0
  121. package/dist/application/update/revalidation-plan.js +27 -15
  122. package/dist/application/update/revalidation-plan.js.map +1 -1
  123. package/dist/application/update/revalidation.d.ts +4 -1
  124. package/dist/application/update/revalidation.js +64 -23
  125. package/dist/application/update/revalidation.js.map +1 -1
  126. package/dist/application/update/use-case.js +50 -29
  127. package/dist/application/update/use-case.js.map +1 -1
  128. package/dist/cli/args/definitions.js +11 -3
  129. package/dist/cli/args/definitions.js.map +1 -1
  130. package/dist/cli/args/parser.js +29 -3
  131. package/dist/cli/args/parser.js.map +1 -1
  132. package/dist/domain/governance/activation/approvals.d.ts +264 -7
  133. package/dist/domain/governance/activation/approvals.js +166 -23
  134. package/dist/domain/governance/activation/approvals.js.map +1 -1
  135. package/dist/domain/governance/activation/capabilities.js +5 -2
  136. package/dist/domain/governance/activation/capabilities.js.map +1 -1
  137. package/dist/domain/governance/activation/evidence.d.ts +2 -1
  138. package/dist/domain/governance/activation/evidence.js +64 -11
  139. package/dist/domain/governance/activation/evidence.js.map +1 -1
  140. package/dist/domain/governance/activation/graph.d.ts +11 -384
  141. package/dist/domain/governance/activation/graph.js +424 -379
  142. package/dist/domain/governance/activation/graph.js.map +1 -1
  143. package/dist/domain/governance/activation/inputs.d.ts +3 -1
  144. package/dist/domain/governance/activation/inputs.js +47 -6
  145. package/dist/domain/governance/activation/inputs.js.map +1 -1
  146. package/dist/domain/governance/activation/operations.d.ts +4 -1
  147. package/dist/domain/governance/activation/operations.js +110 -22
  148. package/dist/domain/governance/activation/operations.js.map +1 -1
  149. package/dist/domain/governance/activation/readiness.d.ts +10 -0
  150. package/dist/domain/governance/activation/readiness.js +77 -38
  151. package/dist/domain/governance/activation/readiness.js.map +1 -1
  152. package/dist/domain/governance/activation/types.d.ts +151 -9
  153. package/dist/domain/governance/activation/types.js +23 -1
  154. package/dist/domain/governance/activation/types.js.map +1 -1
  155. package/dist/domain/governance/activation/validators.d.ts +4 -1
  156. package/dist/domain/governance/activation/validators.js +419 -26
  157. package/dist/domain/governance/activation/validators.js.map +1 -1
  158. package/dist/domain/governance/policy/identity.d.ts +55 -13
  159. package/dist/domain/governance/policy/identity.js +28 -8
  160. package/dist/domain/governance/policy/identity.js.map +1 -1
  161. package/dist/domain/project/artifact-lifecycle.d.ts +2 -1
  162. package/dist/domain/project/artifact-lifecycle.js +7 -1
  163. package/dist/domain/project/artifact-lifecycle.js.map +1 -1
  164. package/dist/domain/project/catalog.d.ts +50 -1
  165. package/dist/domain/project/catalog.js +104 -4
  166. package/dist/domain/project/catalog.js.map +1 -1
  167. package/dist/domain/project/contracts.d.ts +9 -1
  168. package/dist/domain/project/infrastructure-layout.d.ts +1 -1
  169. package/dist/domain/project/infrastructure-layout.js +3 -1
  170. package/dist/domain/project/infrastructure-layout.js.map +1 -1
  171. package/dist/domain/project/manifest/governance.d.ts +1 -1
  172. package/dist/domain/project/manifest/governance.js +9 -10
  173. package/dist/domain/project/manifest/governance.js.map +1 -1
  174. package/dist/domain/project/planning.js +4 -5
  175. package/dist/domain/project/planning.js.map +1 -1
  176. package/dist/domain/repair/stateful-bounded.d.ts +1 -0
  177. package/dist/domain/repair/stateful-bounded.js +37 -0
  178. package/dist/domain/repair/stateful-bounded.js.map +1 -0
  179. package/dist/domain/repair/stateful-invariants.d.ts +28 -0
  180. package/dist/domain/repair/stateful-invariants.js +278 -0
  181. package/dist/domain/repair/stateful-invariants.js.map +1 -0
  182. package/dist/domain/repair/stateful.d.ts +690 -0
  183. package/dist/domain/repair/stateful.js +26 -0
  184. package/dist/domain/repair/stateful.js.map +1 -0
  185. package/dist/domain/workstation/constraints.d.ts +1 -0
  186. package/dist/domain/workstation/constraints.js.map +1 -1
  187. package/dist/domain/workstation/contracts.d.ts +42 -0
  188. package/dist/domain/workstation/contracts.js +2 -0
  189. package/dist/domain/workstation/contracts.js.map +1 -0
  190. package/dist/domain/workstation/executables.d.ts +19 -0
  191. package/dist/domain/workstation/executables.js +68 -0
  192. package/dist/domain/workstation/executables.js.map +1 -0
  193. package/dist/domain/workstation/versions.d.ts +8 -0
  194. package/dist/domain/workstation/versions.js +145 -0
  195. package/dist/domain/workstation/versions.js.map +1 -0
  196. package/dist/framework-adapters.d.ts +2 -0
  197. package/dist/framework-adapters.js +148 -22
  198. package/dist/framework-adapters.js.map +1 -1
  199. package/dist/framework-validation.d.ts +6 -0
  200. package/dist/framework-validation.js +89 -24
  201. package/dist/framework-validation.js.map +1 -1
  202. package/dist/generators/common/base.js +57 -17
  203. package/dist/generators/common/base.js.map +1 -1
  204. package/dist/governance-activation/activation-state.js +39 -7
  205. package/dist/governance-activation/activation-state.js.map +1 -1
  206. package/dist/governance-activation/authority-records.d.ts +4 -0
  207. package/dist/governance-activation/authority-records.js +24 -0
  208. package/dist/governance-activation/authority-records.js.map +1 -0
  209. package/dist/governance-activation/commands.d.ts +9 -1
  210. package/dist/governance-activation/commands.js +392 -97
  211. package/dist/governance-activation/commands.js.map +1 -1
  212. package/dist/governance-activation/compatibility.d.ts +11 -8
  213. package/dist/governance-activation/compatibility.js +37 -23
  214. package/dist/governance-activation/compatibility.js.map +1 -1
  215. package/dist/governance-activation/doctor.js +40 -16
  216. package/dist/governance-activation/doctor.js.map +1 -1
  217. package/dist/governance-activation/github-config.d.ts +17 -0
  218. package/dist/governance-activation/github-config.js +88 -0
  219. package/dist/governance-activation/github-config.js.map +1 -0
  220. package/dist/governance-activation/github-discovery.d.ts +18 -0
  221. package/dist/governance-activation/github-discovery.js +229 -0
  222. package/dist/governance-activation/github-discovery.js.map +1 -0
  223. package/dist/governance-activation/github-ports.d.ts +12 -0
  224. package/dist/governance-activation/github-ports.js +4 -0
  225. package/dist/governance-activation/github-ports.js.map +1 -0
  226. package/dist/governance-activation/github-publication.d.ts +3 -0
  227. package/dist/governance-activation/github-publication.js +190 -0
  228. package/dist/governance-activation/github-publication.js.map +1 -0
  229. package/dist/governance-activation/historical-common.d.ts +98 -0
  230. package/dist/governance-activation/historical-common.js +269 -0
  231. package/dist/governance-activation/historical-common.js.map +1 -0
  232. package/dist/governance-activation/historical-credential-policy.d.ts +3 -0
  233. package/dist/governance-activation/historical-credential-policy.js +91 -0
  234. package/dist/governance-activation/historical-credential-policy.js.map +1 -0
  235. package/dist/governance-activation/historical-inputs.d.ts +6 -0
  236. package/dist/governance-activation/historical-inputs.js +57 -0
  237. package/dist/governance-activation/historical-inputs.js.map +1 -0
  238. package/dist/governance-activation/historical-safety.d.ts +9 -0
  239. package/dist/governance-activation/historical-safety.js +102 -0
  240. package/dist/governance-activation/historical-safety.js.map +1 -0
  241. package/dist/governance-activation/historical-source-metadata.d.ts +31 -0
  242. package/dist/governance-activation/historical-source-metadata.js +55 -0
  243. package/dist/governance-activation/historical-source-metadata.js.map +1 -0
  244. package/dist/governance-activation/historical-state.d.ts +12 -50
  245. package/dist/governance-activation/historical-state.js +195 -308
  246. package/dist/governance-activation/historical-state.js.map +1 -1
  247. package/dist/governance-activation/historical-v1-auxiliary.d.ts +1 -0
  248. package/dist/governance-activation/historical-v1-auxiliary.js +43 -0
  249. package/dist/governance-activation/historical-v1-auxiliary.js.map +1 -0
  250. package/dist/governance-activation/historical-v1-phase-contracts.d.ts +31 -0
  251. package/dist/governance-activation/historical-v1-phase-contracts.js +46 -0
  252. package/dist/governance-activation/historical-v1-phase-contracts.js.map +1 -0
  253. package/dist/governance-activation/historical-v2.d.ts +53 -0
  254. package/dist/governance-activation/historical-v2.js +313 -0
  255. package/dist/governance-activation/historical-v2.js.map +1 -0
  256. package/dist/governance-activation/history-contracts.d.ts +21 -12
  257. package/dist/governance-activation/history-contracts.js +99 -27
  258. package/dist/governance-activation/history-contracts.js.map +1 -1
  259. package/dist/governance-activation/inputs.d.ts +8 -2
  260. package/dist/governance-activation/inputs.js +41 -6
  261. package/dist/governance-activation/inputs.js.map +1 -1
  262. package/dist/governance-activation/migration-history.d.ts +43 -5
  263. package/dist/governance-activation/migration-history.js +231 -50
  264. package/dist/governance-activation/migration-history.js.map +1 -1
  265. package/dist/governance-activation/migration.d.ts +7 -4
  266. package/dist/governance-activation/migration.js +53 -252
  267. package/dist/governance-activation/migration.js.map +1 -1
  268. package/dist/governance-activation/phase-azure.d.ts +3 -0
  269. package/dist/governance-activation/phase-azure.js +205 -0
  270. package/dist/governance-activation/phase-azure.js.map +1 -0
  271. package/dist/governance-activation/phase-bootstrap-state.js +3 -0
  272. package/dist/governance-activation/phase-bootstrap-state.js.map +1 -1
  273. package/dist/governance-activation/phase-github.d.ts +3 -0
  274. package/dist/governance-activation/phase-github.js +192 -0
  275. package/dist/governance-activation/phase-github.js.map +1 -0
  276. package/dist/governance-activation/phase-governance.js +8 -2
  277. package/dist/governance-activation/phase-governance.js.map +1 -1
  278. package/dist/governance-activation/public-plans.d.ts +36 -0
  279. package/dist/governance-activation/public-plans.js +100 -0
  280. package/dist/governance-activation/public-plans.js.map +1 -0
  281. package/dist/governance-activation/read-only.d.ts +3 -1
  282. package/dist/governance-activation/read-only.js +7 -3
  283. package/dist/governance-activation/read-only.js.map +1 -1
  284. package/dist/governance-activation/reconciliation.js +10 -0
  285. package/dist/governance-activation/reconciliation.js.map +1 -1
  286. package/dist/governance-activation/seed-lifecycle.js +14 -25
  287. package/dist/governance-activation/seed-lifecycle.js.map +1 -1
  288. package/dist/governance-activation/source-of-truth.d.ts +21 -5
  289. package/dist/governance-activation/source-of-truth.js +102 -13
  290. package/dist/governance-activation/source-of-truth.js.map +1 -1
  291. package/dist/governance-activation/task-projection.d.ts +4 -1
  292. package/dist/governance-activation/task-projection.js +32 -3
  293. package/dist/governance-activation/task-projection.js.map +1 -1
  294. package/dist/governance-activation/task-writes.d.ts +42 -0
  295. package/dist/governance-activation/task-writes.js +250 -0
  296. package/dist/governance-activation/task-writes.js.map +1 -0
  297. package/dist/governance-activation/transition-files.d.ts +12 -0
  298. package/dist/governance-activation/transition-files.js +109 -0
  299. package/dist/governance-activation/transition-files.js.map +1 -0
  300. package/dist/governance-activation/transition-planning.d.ts +3 -1
  301. package/dist/governance-activation/transition-planning.js +158 -20
  302. package/dist/governance-activation/transition-planning.js.map +1 -1
  303. package/dist/governance-activation/transition-ports.d.ts +31 -3
  304. package/dist/governance-activation/transition-records.d.ts +11 -1
  305. package/dist/governance-activation/transition-records.js +52 -6
  306. package/dist/governance-activation/transition-records.js.map +1 -1
  307. package/dist/governance-activation/transitions.d.ts +5 -0
  308. package/dist/governance-activation/transitions.js +271 -37
  309. package/dist/governance-activation/transitions.js.map +1 -1
  310. package/dist/governance-assessment/engine.js +22 -15
  311. package/dist/governance-assessment/engine.js.map +1 -1
  312. package/dist/governance-assessment/project.d.ts +2 -0
  313. package/dist/governance-assessment/project.js +2 -1
  314. package/dist/governance-assessment/project.js.map +1 -1
  315. package/dist/interactive.d.ts +0 -1
  316. package/dist/interactive.js +3 -22
  317. package/dist/interactive.js.map +1 -1
  318. package/dist/openspec-profile.d.ts +2 -1
  319. package/dist/openspec-profile.js +11 -41
  320. package/dist/openspec-profile.js.map +1 -1
  321. package/dist/repository-governance.d.ts +10 -5
  322. package/dist/repository-governance.js +178 -92
  323. package/dist/repository-governance.js.map +1 -1
  324. package/dist/telemetry/contract.d.ts +1 -1
  325. package/dist/telemetry/contract.js +3 -0
  326. package/dist/telemetry/contract.js.map +1 -1
  327. package/dist/workstation-catalog.d.ts +13 -1
  328. package/dist/workstation-catalog.js +122 -0
  329. package/dist/workstation-catalog.js.map +1 -1
  330. package/dist/workstation.d.ts +69 -14
  331. package/dist/workstation.js +600 -215
  332. package/dist/workstation.js.map +1 -1
  333. package/docs/cli-reference.md +94 -23
  334. package/docs/configuration-and-manifests.md +11 -10
  335. package/docs/prerequisites.md +93 -18
  336. package/docs/repository-governance.md +68 -40
  337. package/docs/spec-workflows-and-agents.md +132 -13
  338. package/docs/troubleshooting.md +28 -0
  339. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { canonicalJson, canonicalSha256, sha256Hex } from './canonical-json.js';
2
2
  import { activationContractVersion, approvalEnvelopeSchemaVersion, buildActivationCompatibilityMap, createActivationIdentity, evidenceHeaderSchemaVersion, governanceActivationPolicyVersion, liftoffActivationPackageVersion, phaseGraphSchemaVersion } from '../policy/identity.js';
3
+ import { activationPhaseIds, lifecyclePhaseIds, localSetupPhaseIds } from './types.js';
3
4
  const terminalVerified = ['verified', 'failed'];
4
5
  const terminalApproved = ['approved', 'failed'];
5
6
  const terminalConditional = ['verified', 'failed', 'inapplicable'];
@@ -12,7 +13,7 @@ function mutations(local, remote = ['none']) {
12
13
  !normalizedLocal.includes('write-activation-state')) {
13
14
  normalizedLocal.push('write-activation-state');
14
15
  }
15
- return { local: normalizedLocal, remote };
16
+ return { local: normalizedLocal.filter((mutation) => mutation !== 'none'), remote };
16
17
  }
17
18
  function evidence(schema, required = true, liveReadbackProviders = []) {
18
19
  return { schema, required, headerSchemaVersion: evidenceHeaderSchemaVersion, liveReadbackProviders };
@@ -23,394 +24,438 @@ function approval(kind, required) {
23
24
  function rollback(kind, target, description) {
24
25
  return { kind, target, description };
25
26
  }
26
- export const canonicalPhaseGraph = {
27
- schemaVersion: phaseGraphSchemaVersion,
28
- versions: {
29
- liftoffVersion: liftoffActivationPackageVersion,
30
- policyVersion: governanceActivationPolicyVersion,
31
- activationContractVersion,
32
- phaseGraphSchemaVersion
27
+ const nonGovernanceTaskPhases = new Set([
28
+ 'seed-valid',
29
+ 'seed-verified',
30
+ 'seed-archived',
31
+ 'committed',
32
+ 'pushed',
33
+ 'phase-0-complete'
34
+ ]);
35
+ const rawPhases = [
36
+ {
37
+ id: 'seed-valid',
38
+ label: 'Generated bootstrap seed is strict-valid',
39
+ dependencies: [],
40
+ applicability: { kind: 'always' },
41
+ allowedMutations: mutations(['read-worktree', 'write-evidence']),
42
+ evidence: evidence('seed-valid.v1'),
43
+ approvalGate: approval('none', false),
44
+ invalidationInputs: ['project-files', 'policy', 'activation-identity'],
45
+ rollback: rollback('none', null, 'No mutation is authorized by seed validation.'),
46
+ terminalStates: terminalVerified
33
47
  },
34
- phases: [
35
- {
36
- id: 'seed-valid',
37
- label: 'Generated bootstrap seed is strict-valid',
38
- dependencies: [],
39
- applicability: { kind: 'always' },
40
- allowedMutations: mutations(['read-worktree', 'write-evidence']),
41
- evidence: evidence('seed-valid.v1'),
42
- approvalGate: approval('none', false),
43
- invalidationInputs: ['project-files', 'policy', 'activation-identity'],
44
- rollback: rollback('none', null, 'No mutation is authorized by seed validation.'),
45
- terminalStates: terminalVerified
46
- },
47
- {
48
- id: 'seed-verified',
49
- label: 'Generated bootstrap baseline checks are verified',
50
- dependencies: [dep(['seed-valid'], 'Seed strict validation must pass first.')],
51
- applicability: { kind: 'always' },
52
- allowedMutations: mutations(['read-worktree', 'write-seed-tasks', 'write-evidence']),
53
- evidence: evidence('seed-verified.v1'),
54
- approvalGate: approval('none', false),
55
- invalidationInputs: ['project-files', 'activation-identity'],
56
- rollback: rollback('none', null, 'A failed baseline leaves the seed active.'),
57
- terminalStates: terminalVerified
58
- },
59
- {
60
- id: 'seed-archived',
61
- label: 'Generated bootstrap seed is synced and archived',
62
- dependencies: [dep(['seed-verified'], 'Only a verified seed may be archived.')],
63
- applicability: { kind: 'always' },
64
- allowedMutations: mutations(['read-worktree', 'write-openspec-seed', 'write-evidence']),
65
- evidence: evidence('seed-archived.v1'),
66
- approvalGate: approval('none', false),
67
- invalidationInputs: ['project-files', 'activation-identity'],
68
- rollback: rollback('none', null, 'Archive failures keep the seed active.'),
69
- terminalStates: terminalVerified
70
- },
71
- {
72
- id: 'committed',
73
- label: 'Initial repository baseline is committed',
74
- dependencies: [dep(['seed-archived'], 'Generated seed must be complete before commit guidance.')],
75
- applicability: { kind: 'always' },
76
- allowedMutations: mutations(['read-worktree', 'git-commit', 'write-evidence']),
77
- evidence: evidence('committed.v1'),
78
- approvalGate: approval('repository-publish', true),
79
- invalidationInputs: ['baseline-sha', 'project-files', 'approval-envelope'],
80
- rollback: rollback('none', null, 'Never rewrite a committed user history automatically.'),
81
- terminalStates: terminalVerified
82
- },
83
- {
84
- id: 'pushed',
85
- label: 'Initial repository baseline is pushed',
86
- dependencies: [dep(['committed'], 'Commit evidence precedes initial push.')],
87
- applicability: { kind: 'always' },
88
- allowedMutations: mutations(['read-worktree', 'write-evidence'], ['git-push', 'github-read']),
89
- evidence: evidence('pushed.v1', true, ['github']),
90
- approvalGate: approval('repository-publish', true),
91
- invalidationInputs: ['baseline-sha', 'approval-envelope'],
92
- rollback: rollback('none', null, 'Never force-push, delete, or rewrite refs.'),
93
- terminalStates: terminalVerified
94
- },
95
- {
96
- id: 'phase-0-complete',
97
- label: 'Read-only Phase 0 discovery is complete',
98
- dependencies: [dep(['pushed'], 'Remote repository identity must be resolvable.')],
99
- applicability: { kind: 'always' },
100
- allowedMutations: mutations(['write-evidence'], ['github-read', 'azure-read']),
101
- evidence: evidence('phase-0-complete.v1', true, ['github']),
102
- approvalGate: approval('none', false),
103
- invalidationInputs: ['baseline-sha', 'policy', 'live-readback'],
104
- rollback: rollback('none', null, 'Discovery is read-only and can be refreshed.'),
105
- terminalStates: terminalVerified
106
- },
107
- {
108
- id: 'activation-approved',
109
- label: 'Governance activation plan is approved',
110
- dependencies: [dep(['phase-0-complete'], 'Approval reviews Phase 0 evidence.')],
111
- applicability: { kind: 'always' },
112
- allowedMutations: mutations(['write-openspec-governance', 'write-activation-state', 'write-evidence']),
113
- evidence: evidence('activation-approved.v1', false),
114
- approvalGate: approval('activation-plan', true),
115
- invalidationInputs: ['baseline-sha', 'approval-envelope', 'policy'],
116
- rollback: rollback('none', null, 'Approval expiry returns descendants to blocked.'),
117
- terminalStates: terminalApproved
118
- },
119
- {
120
- id: 'credential-ready',
121
- label: 'Runner preflight credential policy is ready when required',
122
- dependencies: [dep(['activation-approved'], 'Credential enrollment follows approved activation scope.')],
123
- applicability: {
124
- kind: 'conditional',
125
- discriminator: 'credential-required',
126
- when: 'credentialRequired=true',
127
- inapplicableWhen: 'credentialRequired=false',
128
- exclusiveWith: []
129
- },
130
- allowedMutations: mutations(['write-evidence'], ['github-secret-write', 'github-read']),
131
- evidence: evidence('credential-ready.v1', true, ['github']),
132
- approvalGate: approval('credential-enrollment', true),
133
- invalidationInputs: ['credentials', 'approval-envelope', 'activation-identity'],
134
- rollback: rollback('none', null, 'Leaked or expired credentials block use and require rotation.'),
135
- terminalStates: terminalConditional
136
- },
137
- {
138
- id: 'provider-ready',
139
- label: 'Azure provider namespaces are terminal ready',
140
- dependencies: [
141
- dep(['activation-approved'], 'Provider readiness belongs to approved infrastructure scope.'),
142
- dep(['credential-ready'], 'Runner preflight credential readiness or inapplicability precedes provider work.')
143
- ],
144
- applicability: {
145
- kind: 'conditional',
146
- discriminator: 'private-staging-dast',
147
- when: 'privateStagingDast=true',
148
- inapplicableWhen: 'privateStagingDast=false',
149
- exclusiveWith: []
150
- },
151
- allowedMutations: mutations(['write-evidence'], ['azure-read', 'azure-provider-register']),
152
- evidence: evidence('provider-ready.v1', true, ['azure']),
153
- approvalGate: approval('infrastructure-cost', true),
154
- invalidationInputs: ['provider-inventory', 'approval-envelope', 'policy'],
155
- rollback: rollback('retain', null, 'Provider registrations are retained subscription capabilities.'),
156
- terminalStates: ['verified', 'failed', 'inapplicable', 'retained']
157
- },
158
- {
159
- id: 'state-path-selected',
160
- label: 'Private state path is selected',
161
- dependencies: [dep(['provider-ready'], 'Provider readiness precedes private state path selection.')],
162
- applicability: {
163
- kind: 'conditional',
164
- discriminator: 'private-staging-dast',
165
- when: 'privateStagingDast=true',
166
- inapplicableWhen: 'privateStagingDast=false',
167
- exclusiveWith: []
168
- },
169
- allowedMutations: mutations(['write-activation-state', 'write-evidence'], ['azure-read']),
170
- evidence: evidence('state-path-selected.v1', true, ['azure']),
171
- approvalGate: approval('infrastructure-cost', true),
172
- invalidationInputs: ['remote-state', 'provider-inventory', 'approval-envelope'],
173
- rollback: rollback('none', null, 'A changed path selection invalidates mutually exclusive descendants.'),
174
- terminalStates: terminalConditional
175
- },
176
- {
177
- id: 'existing-private-path',
178
- label: 'Existing private backend management path is verified',
179
- dependencies: [dep(['state-path-selected'], 'State path selection chooses this branch.')],
180
- applicability: {
181
- kind: 'conditional',
182
- discriminator: 'state-path',
183
- when: 'statePath=existing-private',
184
- inapplicableWhen: 'statePath!=existing-private',
185
- exclusiveWith: ['bootstrap-local']
186
- },
187
- allowedMutations: mutations(['write-evidence'], ['azure-read']),
188
- evidence: evidence('existing-private-path.v1', true, ['azure']),
189
- approvalGate: approval('none', false),
190
- invalidationInputs: ['remote-state', 'live-readback'],
191
- rollback: rollback('none', null, 'Existing path verification is read-only.'),
192
- terminalStates: terminalConditional
193
- },
194
- {
195
- id: 'bootstrap-local',
196
- label: 'Bounded local bootstrap creates access-establishing resources',
197
- dependencies: [
198
- dep(['provider-ready'], 'Provider readiness precedes local bootstrap.'),
199
- dep(['state-path-selected'], 'State path selection precedes local bootstrap.')
200
- ],
201
- applicability: {
202
- kind: 'conditional',
203
- discriminator: 'state-path',
204
- when: 'statePath=bootstrap-local',
205
- inapplicableWhen: 'statePath!=bootstrap-local',
206
- exclusiveWith: ['existing-private-path']
207
- },
208
- allowedMutations: mutations(['write-local-state', 'write-evidence'], ['azure-network-provision', 'github-write']),
209
- evidence: evidence('bootstrap-local.v1', true, ['github', 'azure']),
210
- approvalGate: approval('infrastructure-cost', true),
211
- invalidationInputs: ['approval-envelope', 'provider-inventory', 'remote-state'],
212
- rollback: rollback('reverse-to', 'provider-ready', 'Remove only repository-owned bootstrap resources in dependency order.'),
213
- terminalStates: terminalConditional
214
- },
215
- {
216
- id: 'runner-ready',
217
- label: 'Restricted larger runner is assigned and ready',
218
- dependencies: [dep(['bootstrap-local'], 'Local bootstrap must establish runner networking before runner proof.')],
219
- applicability: {
220
- kind: 'conditional',
221
- discriminator: 'state-path',
222
- when: 'statePath=bootstrap-local',
223
- inapplicableWhen: 'statePath!=bootstrap-local',
224
- exclusiveWith: []
225
- },
226
- allowedMutations: mutations(['write-evidence'], ['github-read', 'github-write']),
227
- evidence: evidence('runner-ready.v1', true, ['github']),
228
- approvalGate: approval('infrastructure-cost', true),
229
- invalidationInputs: ['runner-inventory', 'approval-envelope'],
230
- rollback: rollback('reverse-to', 'bootstrap-local', 'Remove repository runner assignment before network resources.'),
231
- terminalStates: terminalConditional
232
- },
233
- {
234
- id: 'private-backend-proof',
235
- label: 'Private backend is reachable from runner',
236
- dependencies: [dep(['runner-ready'], 'Runner readiness precedes private backend proof.')],
237
- applicability: {
238
- kind: 'conditional',
239
- discriminator: 'state-path',
240
- when: 'statePath=bootstrap-local',
241
- inapplicableWhen: 'statePath!=bootstrap-local',
242
- exclusiveWith: []
243
- },
244
- allowedMutations: mutations(['write-evidence'], ['github-read', 'azure-read']),
245
- evidence: evidence('private-backend-proof.v1', true, ['github', 'azure']),
246
- approvalGate: approval('none', false),
247
- invalidationInputs: ['runner-inventory', 'remote-state', 'live-readback'],
248
- rollback: rollback('reverse-to', 'runner-ready', 'Failed proof keeps remote import blocked.'),
249
- terminalStates: terminalConditional
250
- },
251
- {
252
- id: 'remote-import-verified',
253
- label: 'Declarative remote import and no-change plan are verified',
254
- dependencies: [dep(['private-backend-proof'], 'Private backend proof precedes remote import.')],
255
- applicability: {
256
- kind: 'conditional',
257
- discriminator: 'state-path',
258
- when: 'statePath=bootstrap-local',
259
- inapplicableWhen: 'statePath!=bootstrap-local',
260
- exclusiveWith: []
261
- },
262
- allowedMutations: mutations(['write-evidence'], ['azure-state-import']),
263
- evidence: evidence('remote-import-verified.v1', true, ['azure']),
264
- approvalGate: approval('infrastructure-cost', true),
265
- invalidationInputs: ['remote-state', 'approval-envelope'],
266
- rollback: rollback('reverse-to', 'private-backend-proof', 'Failed import leaves local state retained for remediation.'),
267
- terminalStates: terminalConditional
268
- },
269
- {
270
- id: 'remote-ready',
271
- label: 'Remote state is ready and local bootstrap state is frozen',
272
- dependencies: [dep(['existing-private-path', 'remote-import-verified'], 'Remote readiness follows either existing private path or verified remote import.')],
273
- applicability: {
274
- kind: 'conditional',
275
- discriminator: 'private-staging-dast',
276
- when: 'privateStagingDast=true',
277
- inapplicableWhen: 'privateStagingDast=false',
278
- exclusiveWith: []
279
- },
280
- allowedMutations: mutations(['write-evidence'], ['azure-read']),
281
- evidence: evidence('remote-ready.v1'),
282
- approvalGate: approval('none', false),
283
- invalidationInputs: ['remote-state', 'live-readback'],
284
- rollback: rollback('retain', null, 'Retain local bootstrap state read-only for exactly 30 days when used.'),
285
- terminalStates: ['verified', 'failed', 'inapplicable', 'retained']
286
- },
287
- {
288
- id: 'application-foundation',
289
- label: 'Application infrastructure foundation is reconciled',
290
- dependencies: [dep(['remote-ready'], 'Application resources wait for remote state readiness or inapplicability.')],
291
- applicability: { kind: 'always' },
292
- allowedMutations: mutations(['write-evidence', 'write-openspec-governance'], ['azure-resource-provision']),
293
- evidence: evidence('application-foundation.v1', true, ['azure']),
294
- approvalGate: approval('infrastructure-cost', true),
295
- invalidationInputs: ['project-files', 'remote-state', 'approval-envelope'],
296
- rollback: rollback('reverse-to', 'remote-ready', 'Application resources are removed without unregistering providers.'),
297
- terminalStates: terminalVerified
48
+ {
49
+ id: 'seed-verified',
50
+ label: 'Generated bootstrap baseline checks are verified',
51
+ dependencies: [dep(['seed-valid'], 'Seed strict validation must pass first.')],
52
+ applicability: { kind: 'always' },
53
+ allowedMutations: mutations(['read-worktree', 'write-seed-tasks', 'write-evidence']),
54
+ evidence: evidence('seed-verified.v1'),
55
+ approvalGate: approval('none', false),
56
+ invalidationInputs: ['project-files', 'activation-identity'],
57
+ rollback: rollback('none', null, 'A failed baseline leaves the seed active.'),
58
+ terminalStates: terminalVerified
59
+ },
60
+ {
61
+ id: 'seed-archived',
62
+ label: 'Generated bootstrap seed is synced and archived',
63
+ dependencies: [dep(['seed-verified'], 'Only a verified seed may be archived.')],
64
+ applicability: { kind: 'always' },
65
+ allowedMutations: mutations(['read-worktree', 'write-openspec-seed', 'write-evidence']),
66
+ evidence: evidence('seed-archived.v1'),
67
+ approvalGate: approval('none', false),
68
+ invalidationInputs: ['project-files', 'activation-identity'],
69
+ rollback: rollback('none', null, 'Archive failures keep the seed active.'),
70
+ terminalStates: terminalVerified
71
+ },
72
+ {
73
+ id: 'committed',
74
+ label: 'Initial repository baseline is committed',
75
+ dependencies: [dep(['seed-archived'], 'Generated seed must be complete before commit guidance.')],
76
+ applicability: { kind: 'always' },
77
+ allowedMutations: mutations(['read-worktree', 'git-commit', 'write-evidence']),
78
+ evidence: evidence('committed.v1'),
79
+ approvalGate: approval('repository-publish', true),
80
+ invalidationInputs: ['baseline-sha', 'project-files', 'approval-envelope'],
81
+ rollback: rollback('none', null, 'Never rewrite a committed user history automatically.'),
82
+ terminalStates: terminalVerified
83
+ },
84
+ {
85
+ id: 'pushed',
86
+ label: 'Initial repository baseline is pushed',
87
+ dependencies: [dep(['committed'], 'Commit evidence precedes initial push.')],
88
+ applicability: { kind: 'always' },
89
+ allowedMutations: mutations(['read-worktree', 'git-remote-bind', 'write-evidence'], ['git-push', 'github-read', 'github-repository-create', 'github-write']),
90
+ evidence: evidence('pushed.v1', true, ['github']),
91
+ approvalGate: approval('repository-publish', true),
92
+ invalidationInputs: ['baseline-sha', 'approval-envelope'],
93
+ rollback: rollback('none', null, 'Never force-push, delete, or rewrite refs.'),
94
+ terminalStates: terminalVerified
95
+ },
96
+ {
97
+ id: 'phase-0-complete',
98
+ label: 'Read-only Phase 0 discovery is complete',
99
+ dependencies: [dep(['pushed'], 'Remote repository identity must be resolvable.')],
100
+ applicability: { kind: 'always' },
101
+ allowedMutations: mutations(['write-evidence'], ['github-read', 'azure-read']),
102
+ evidence: evidence('phase-0-complete.v1', true, ['github']),
103
+ approvalGate: approval('none', false),
104
+ invalidationInputs: ['baseline-sha', 'policy', 'live-readback'],
105
+ rollback: rollback('none', null, 'Discovery is read-only and can be refreshed.'),
106
+ terminalStates: terminalVerified
107
+ },
108
+ {
109
+ id: 'activation-approved',
110
+ label: 'Governance activation plan is approved',
111
+ dependencies: [dep(['phase-0-complete'], 'Approval reviews Phase 0 evidence.')],
112
+ applicability: { kind: 'always' },
113
+ allowedMutations: mutations(['write-openspec-governance', 'write-activation-state', 'write-evidence']),
114
+ evidence: evidence('activation-approved.v1', false),
115
+ approvalGate: approval('activation-plan', true),
116
+ invalidationInputs: ['baseline-sha', 'approval-envelope', 'policy'],
117
+ rollback: rollback('none', null, 'Approval expiry returns descendants to blocked.'),
118
+ terminalStates: terminalApproved
119
+ },
120
+ {
121
+ id: 'bootstrap-workflow-source-ready',
122
+ label: 'Scoped bootstrap verification workflows are published',
123
+ dependencies: [dep(['activation-approved'], 'Bootstrap workflow publication requires the reviewed activation scope.')],
124
+ applicability: { kind: 'always' },
125
+ allowedMutations: mutations(['read-worktree', 'write-workflows', 'git-commit', 'write-evidence'], ['git-push', 'github-read', 'github-write']),
126
+ evidence: evidence('bootstrap-workflow-source-ready.v1', true, ['github']),
127
+ approvalGate: approval('repository-publish', true),
128
+ invalidationInputs: ['workflow-source', 'approval-envelope', 'baseline-sha'],
129
+ rollback: rollback('none', null, 'Preserve published history; repair only the approved workflow scope.'),
130
+ terminalStates: terminalVerified
131
+ },
132
+ {
133
+ id: 'credential-ready',
134
+ label: 'Runner preflight credential policy is ready when required',
135
+ dependencies: [dep(['bootstrap-workflow-source-ready'], 'Credential use is verified through the published approved bootstrap workflow.')],
136
+ applicability: {
137
+ kind: 'conditional',
138
+ discriminator: 'credential-required',
139
+ when: 'credentialRequired=true',
140
+ inapplicableWhen: 'credentialRequired=false',
141
+ exclusiveWith: []
298
142
  },
299
- {
300
- id: 'workflow-source-ready',
301
- label: 'Workflow source and ruleset payloads are ready',
302
- dependencies: [dep(['application-foundation'], 'Workflow source targets the reconciled application foundation.')],
303
- applicability: { kind: 'always' },
304
- allowedMutations: mutations(['write-workflows', 'write-ruleset-source', 'write-evidence']),
305
- evidence: evidence('workflow-source-ready.v1'),
306
- approvalGate: approval('none', false),
307
- invalidationInputs: ['project-files', 'policy'],
308
- rollback: rollback('reverse-to', 'application-foundation', 'Remove or repair only workflow/ruleset source changes.'),
309
- terminalStates: terminalVerified
143
+ allowedMutations: mutations(['write-credential-policy', 'write-evidence'], ['github-secret-write', 'github-read', 'github-workflow-dispatch']),
144
+ evidence: evidence('credential-ready.v1', true, ['github']),
145
+ approvalGate: approval('credential-enrollment', true),
146
+ invalidationInputs: ['credentials', 'approval-envelope', 'activation-identity'],
147
+ rollback: rollback('none', null, 'Leaked or expired credentials block use and require rotation.'),
148
+ terminalStates: terminalConditional
149
+ },
150
+ {
151
+ id: 'provider-ready',
152
+ label: 'Azure provider namespaces are terminal ready',
153
+ dependencies: [
154
+ dep(['activation-approved'], 'Provider readiness belongs to approved infrastructure scope.'),
155
+ dep(['credential-ready'], 'Runner preflight credential readiness or inapplicability precedes provider work.')
156
+ ],
157
+ applicability: { kind: 'always' },
158
+ allowedMutations: mutations(['write-evidence'], ['azure-read', 'azure-provider-register']),
159
+ evidence: evidence('provider-ready.v1', true, ['azure']),
160
+ approvalGate: approval('infrastructure-cost', true),
161
+ invalidationInputs: ['provider-inventory', 'approval-envelope', 'policy'],
162
+ rollback: rollback('retain', null, 'Provider registrations are retained subscription capabilities.'),
163
+ terminalStates: ['verified', 'failed', 'inapplicable', 'retained']
164
+ },
165
+ {
166
+ id: 'state-path-selected',
167
+ label: 'Private state path is selected',
168
+ dependencies: [dep(['provider-ready'], 'Provider readiness precedes private state path selection.')],
169
+ applicability: {
170
+ kind: 'conditional',
171
+ discriminator: 'cloud-state-required',
172
+ when: 'cloudStateRequired=true',
173
+ inapplicableWhen: 'cloudStateRequired=false',
174
+ exclusiveWith: []
310
175
  },
311
- {
312
- id: 'dev-proof',
313
- label: 'Development proof is green',
314
- dependencies: [dep(['workflow-source-ready'], 'Workflow source must exist before proving checks.')],
315
- applicability: { kind: 'always' },
316
- allowedMutations: mutations(['write-evidence'], ['github-read']),
317
- evidence: evidence('dev-proof.v1', true, ['github']),
318
- approvalGate: approval('none', false),
319
- invalidationInputs: ['workflow-source', 'project-files'],
320
- rollback: rollback('none', null, 'A failed check blocks descendants until fixed.'),
321
- terminalStates: terminalVerified
176
+ allowedMutations: mutations(['write-activation-state', 'write-evidence'], ['azure-read']),
177
+ evidence: evidence('state-path-selected.v1', true, ['azure']),
178
+ approvalGate: approval('infrastructure-cost', true),
179
+ invalidationInputs: ['remote-state', 'provider-inventory', 'approval-envelope'],
180
+ rollback: rollback('none', null, 'A changed path selection invalidates mutually exclusive descendants.'),
181
+ terminalStates: terminalConditional
182
+ },
183
+ {
184
+ id: 'existing-private-path',
185
+ label: 'Existing private backend management path is verified',
186
+ dependencies: [dep(['state-path-selected'], 'State path selection chooses this branch.')],
187
+ applicability: {
188
+ kind: 'conditional',
189
+ discriminator: 'state-path',
190
+ when: 'statePath=existing-private',
191
+ inapplicableWhen: 'statePath!=existing-private',
192
+ exclusiveWith: ['bootstrap-local']
322
193
  },
323
- {
324
- id: 'staging-qualified',
325
- label: 'Staging release qualification is complete',
326
- dependencies: [dep(['dev-proof'], 'Development proof precedes staging qualification.')],
327
- applicability: { kind: 'always' },
328
- allowedMutations: mutations(['write-evidence'], ['github-read', 'azure-read']),
329
- evidence: evidence('staging-qualified.v1', true, ['github', 'azure']),
330
- approvalGate: approval('none', false),
331
- invalidationInputs: ['workflow-source', 'security-evidence', 'live-readback'],
332
- rollback: rollback('none', null, 'Qualification failures keep production blocked.'),
333
- terminalStates: terminalVerified
194
+ allowedMutations: mutations(['write-evidence'], ['azure-read', 'github-read', 'backend-state-read']),
195
+ evidence: evidence('existing-private-path.v1', true, ['azure']),
196
+ approvalGate: approval('none', false),
197
+ invalidationInputs: ['remote-state', 'live-readback'],
198
+ rollback: rollback('none', null, 'Existing path verification is read-only.'),
199
+ terminalStates: terminalConditional
200
+ },
201
+ {
202
+ id: 'bootstrap-local',
203
+ label: 'Bounded local bootstrap creates access-establishing resources',
204
+ dependencies: [
205
+ dep(['provider-ready'], 'Provider readiness precedes local bootstrap.'),
206
+ dep(['state-path-selected'], 'State path selection precedes local bootstrap.')
207
+ ],
208
+ applicability: {
209
+ kind: 'conditional',
210
+ discriminator: 'state-path',
211
+ when: 'statePath=bootstrap-local',
212
+ inapplicableWhen: 'statePath!=bootstrap-local',
213
+ exclusiveWith: ['existing-private-path']
334
214
  },
335
- {
336
- id: 'production-rehearsed',
337
- label: 'Production promotion and rollback are rehearsed',
338
- dependencies: [dep(['staging-qualified'], 'Only a staging-qualified candidate may be rehearsed.')],
339
- applicability: { kind: 'always' },
340
- allowedMutations: mutations(['write-evidence'], ['github-read', 'azure-read']),
341
- evidence: evidence('production-rehearsed.v1', true, ['github', 'azure']),
342
- approvalGate: approval('none', false),
343
- invalidationInputs: ['live-readback', 'workflow-source'],
344
- rollback: rollback('none', null, 'Rollback remains ungated and documented.'),
345
- terminalStates: terminalVerified
215
+ allowedMutations: mutations(['read-worktree', 'write-local-state', 'write-evidence'], ['azure-network-provision', 'azure-read']),
216
+ evidence: evidence('bootstrap-local.v1', true, ['azure']),
217
+ approvalGate: approval('infrastructure-cost', true),
218
+ invalidationInputs: ['approval-envelope', 'provider-inventory', 'remote-state'],
219
+ rollback: rollback('reverse-to', 'provider-ready', 'Remove only repository-owned bootstrap resources in dependency order.'),
220
+ terminalStates: terminalConditional
221
+ },
222
+ {
223
+ id: 'runner-ready',
224
+ label: 'Restricted larger runner is assigned and ready',
225
+ dependencies: [dep(['bootstrap-local'], 'Local bootstrap must establish runner networking before runner proof.')],
226
+ applicability: {
227
+ kind: 'conditional',
228
+ discriminator: 'state-path',
229
+ when: 'statePath=bootstrap-local',
230
+ inapplicableWhen: 'statePath!=bootstrap-local',
231
+ exclusiveWith: []
346
232
  },
347
- {
348
- id: 'green-red-proof',
349
- label: 'Required checks are proven green and deliberately red',
350
- dependencies: [dep(['production-rehearsed'], 'Promotion rehearsal precedes final context proof.')],
351
- applicability: { kind: 'always' },
352
- allowedMutations: mutations(['write-evidence'], ['github-read']),
353
- evidence: evidence('green-red-proof.v1', true, ['github']),
354
- approvalGate: approval('none', false),
355
- invalidationInputs: ['security-evidence', 'workflow-source'],
356
- rollback: rollback('none', null, 'Missing red proof prevents enforcement.'),
357
- terminalStates: terminalVerified
233
+ allowedMutations: mutations(['write-evidence'], ['github-read', 'github-write', 'github-workflow-dispatch']),
234
+ evidence: evidence('runner-ready.v1', true, ['github']),
235
+ approvalGate: approval('infrastructure-cost', true),
236
+ invalidationInputs: ['runner-inventory', 'approval-envelope'],
237
+ rollback: rollback('reverse-to', 'bootstrap-local', 'Remove repository runner assignment before network resources.'),
238
+ terminalStates: terminalConditional
239
+ },
240
+ {
241
+ id: 'private-backend-proof',
242
+ label: 'Private backend is reachable from runner',
243
+ dependencies: [dep(['runner-ready'], 'Runner readiness precedes private backend proof.')],
244
+ applicability: {
245
+ kind: 'conditional',
246
+ discriminator: 'state-path',
247
+ when: 'statePath=bootstrap-local',
248
+ inapplicableWhen: 'statePath!=bootstrap-local',
249
+ exclusiveWith: []
358
250
  },
359
- {
360
- id: 'enforcement-approved',
361
- label: 'Final ruleset enforcement is approved',
362
- dependencies: [dep(['green-red-proof'], 'Only exact green/red evidence may request enforcement.')],
363
- applicability: { kind: 'always' },
364
- allowedMutations: mutations(['write-activation-state', 'write-evidence']),
365
- evidence: evidence('enforcement-approved.v1', false),
366
- approvalGate: approval('enforcement', true),
367
- invalidationInputs: ['approval-envelope', 'ruleset-readback'],
368
- rollback: rollback('none', null, 'Approval expiry blocks ruleset application.'),
369
- terminalStates: terminalApproved
251
+ allowedMutations: mutations(['write-evidence'], ['github-read', 'github-workflow-dispatch', 'azure-read', 'backend-state-read']),
252
+ evidence: evidence('private-backend-proof.v1', true, ['github', 'azure']),
253
+ approvalGate: approval('activation-plan', true),
254
+ invalidationInputs: ['runner-inventory', 'remote-state', 'live-readback'],
255
+ rollback: rollback('reverse-to', 'runner-ready', 'Failed proof keeps remote import blocked.'),
256
+ terminalStates: terminalConditional
257
+ },
258
+ {
259
+ id: 'remote-import-verified',
260
+ label: 'Declarative remote import and no-change plan are verified',
261
+ dependencies: [dep(['private-backend-proof'], 'Private backend proof precedes remote import.')],
262
+ applicability: {
263
+ kind: 'conditional',
264
+ discriminator: 'state-path',
265
+ when: 'statePath=bootstrap-local',
266
+ inapplicableWhen: 'statePath!=bootstrap-local',
267
+ exclusiveWith: []
370
268
  },
371
- {
372
- id: 'rulesets-applied',
373
- label: 'Repository rulesets are applied idempotently last',
374
- dependencies: [dep(['enforcement-approved'], 'Final enforcement approval precedes ruleset mutation.')],
375
- applicability: { kind: 'always' },
376
- allowedMutations: mutations(['write-evidence'], ['github-ruleset-write', 'github-read']),
377
- evidence: evidence('rulesets-applied.v1', true, ['github']),
378
- approvalGate: approval('enforcement', true),
379
- invalidationInputs: ['approval-envelope', 'ruleset-readback'],
380
- rollback: rollback('reverse-to', 'green-red-proof', 'Rulesets can be disabled or repaired without approval-gating rollback.'),
381
- terminalStates: terminalVerified
269
+ allowedMutations: mutations(['write-evidence'], ['azure-state-import', 'azure-read', 'backend-state-read', 'backend-state-write']),
270
+ evidence: evidence('remote-import-verified.v1', true, ['azure']),
271
+ approvalGate: approval('infrastructure-cost', true),
272
+ invalidationInputs: ['remote-state', 'approval-envelope'],
273
+ rollback: rollback('reverse-to', 'private-backend-proof', 'Failed import leaves local state retained for remediation.'),
274
+ terminalStates: terminalConditional
275
+ },
276
+ {
277
+ id: 'remote-ready',
278
+ label: 'Remote state is ready and local bootstrap state is frozen',
279
+ dependencies: [dep(['existing-private-path', 'remote-import-verified'], 'Remote readiness follows either existing private path or verified remote import.')],
280
+ applicability: {
281
+ kind: 'conditional',
282
+ discriminator: 'cloud-state-required',
283
+ when: 'cloudStateRequired=true',
284
+ inapplicableWhen: 'cloudStateRequired=false',
285
+ exclusiveWith: []
382
286
  },
383
- {
384
- id: 'live-readback',
385
- label: 'Live enforcement readback matches source',
386
- dependencies: [dep(['rulesets-applied'], 'Live readback follows ruleset application.')],
387
- applicability: { kind: 'always' },
388
- allowedMutations: mutations(['write-evidence'], ['github-read']),
389
- evidence: evidence('live-readback.v1', true, ['github']),
390
- approvalGate: approval('none', false),
391
- invalidationInputs: ['ruleset-readback', 'live-readback'],
392
- rollback: rollback('reverse-to', 'rulesets-applied', 'Mismatched live readback blocks completion.'),
393
- terminalStates: terminalVerified
287
+ allowedMutations: mutations(['write-evidence'], ['azure-read', 'backend-state-read']),
288
+ evidence: evidence('remote-ready.v1'),
289
+ approvalGate: approval('none', false),
290
+ invalidationInputs: ['remote-state', 'live-readback'],
291
+ rollback: rollback('retain', null, 'Retain local bootstrap state read-only for exactly 30 days when used.'),
292
+ terminalStates: ['verified', 'failed', 'inapplicable', 'retained']
293
+ },
294
+ {
295
+ id: 'application-prerequisites-ready',
296
+ label: 'Application registry and workload identity prerequisites are ready',
297
+ dependencies: [dep(['remote-ready'], 'Registry and identity prerequisites require verified backend readiness.')],
298
+ applicability: { kind: 'always' },
299
+ allowedMutations: mutations(['read-worktree', 'write-evidence', 'write-openspec-governance'], ['azure-resource-provision', 'azure-read', 'backend-state-read', 'backend-state-write']),
300
+ evidence: evidence('application-prerequisites-ready.v1', true, ['azure']),
301
+ approvalGate: approval('infrastructure-cost', true),
302
+ invalidationInputs: ['project-files', 'remote-state', 'approval-envelope'],
303
+ rollback: rollback('reverse-to', 'remote-ready', 'Compensate only owned prerequisites within the approved recovery scope.'),
304
+ terminalStates: terminalVerified
305
+ },
306
+ {
307
+ id: 'workflow-source-ready',
308
+ label: 'Workflow source and ruleset payloads are ready',
309
+ dependencies: [dep(['application-prerequisites-ready'], 'Workflow source binds the verified registry and workload identities.')],
310
+ applicability: { kind: 'always' },
311
+ allowedMutations: mutations(['read-worktree', 'write-workflows', 'write-ruleset-source', 'write-evidence']),
312
+ evidence: evidence('workflow-source-ready.v1'),
313
+ approvalGate: approval('none', false),
314
+ invalidationInputs: ['project-files', 'policy'],
315
+ rollback: rollback('reverse-to', 'application-prerequisites-ready', 'Repair only approved workflow/ruleset changes without rewriting Git history.'),
316
+ terminalStates: terminalVerified
317
+ },
318
+ {
319
+ id: 'application-artifact-ready',
320
+ label: 'Immutable application artifacts are built and published from approved source',
321
+ dependencies: [dep(['workflow-source-ready'], 'The reviewed build workflow must be published before artifact production.')],
322
+ applicability: { kind: 'always' },
323
+ allowedMutations: mutations(['read-worktree', 'write-evidence'], ['github-read', 'github-workflow-dispatch', 'registry-publish', 'azure-read']),
324
+ evidence: evidence('application-artifact-ready.v1', true, ['github', 'azure']),
325
+ approvalGate: approval('infrastructure-cost', true),
326
+ invalidationInputs: ['project-files', 'workflow-source', 'approval-envelope'],
327
+ rollback: rollback('retain', null, 'Keep immutable published artifacts; never replace an existing digest.'),
328
+ terminalStates: terminalVerified
329
+ },
330
+ {
331
+ id: 'application-foundation',
332
+ label: 'Application infrastructure is deployed with the verified immutable artifact',
333
+ dependencies: [dep(['application-artifact-ready'], 'Deployment requires real source-bound immutable application artifacts.')],
334
+ applicability: { kind: 'always' },
335
+ allowedMutations: mutations(['read-worktree', 'write-evidence', 'write-openspec-governance'], ['azure-resource-provision', 'azure-read', 'backend-state-read', 'backend-state-write']),
336
+ evidence: evidence('application-foundation.v1', true, ['azure']),
337
+ approvalGate: approval('infrastructure-cost', true),
338
+ invalidationInputs: ['project-files', 'remote-state', 'approval-envelope'],
339
+ rollback: rollback('reverse-to', 'application-artifact-ready', 'Recover only approved owned resources; never unregister shared providers.'),
340
+ terminalStates: terminalVerified
341
+ },
342
+ {
343
+ id: 'dev-proof',
344
+ label: 'Development proof is green',
345
+ dependencies: [dep(['application-foundation'], 'The real application deployment precedes development proof.')],
346
+ applicability: { kind: 'always' },
347
+ allowedMutations: mutations(['write-evidence'], ['github-read', 'github-workflow-dispatch']),
348
+ evidence: evidence('dev-proof.v1', true, ['github']),
349
+ approvalGate: approval('activation-plan', true),
350
+ invalidationInputs: ['workflow-source', 'project-files'],
351
+ rollback: rollback('none', null, 'A failed check blocks descendants until fixed.'),
352
+ terminalStates: terminalVerified
353
+ },
354
+ {
355
+ id: 'staging-qualified',
356
+ label: 'Staging release qualification is complete',
357
+ dependencies: [dep(['dev-proof'], 'Development proof precedes staging qualification.')],
358
+ applicability: { kind: 'always' },
359
+ allowedMutations: mutations(['write-evidence'], ['github-read', 'github-workflow-dispatch', 'azure-read', 'azure-resource-provision', 'backend-state-write']),
360
+ evidence: evidence('staging-qualified.v1', true, ['github', 'azure']),
361
+ approvalGate: approval('infrastructure-cost', true),
362
+ invalidationInputs: ['workflow-source', 'security-evidence', 'live-readback'],
363
+ rollback: rollback('none', null, 'Qualification failures keep production blocked.'),
364
+ terminalStates: terminalVerified
365
+ },
366
+ {
367
+ id: 'production-rehearsed',
368
+ label: 'Production promotion and rollback are rehearsed',
369
+ dependencies: [dep(['staging-qualified'], 'Only a staging-qualified candidate may be rehearsed.')],
370
+ applicability: { kind: 'always' },
371
+ allowedMutations: mutations(['write-evidence'], ['github-read', 'github-workflow-dispatch', 'azure-read', 'azure-resource-provision', 'backend-state-write']),
372
+ evidence: evidence('production-rehearsed.v1', true, ['github', 'azure']),
373
+ approvalGate: approval('infrastructure-cost', true),
374
+ invalidationInputs: ['live-readback', 'workflow-source'],
375
+ rollback: rollback('none', null, 'Rollback remains ungated and documented.'),
376
+ terminalStates: terminalVerified
377
+ },
378
+ {
379
+ id: 'green-red-proof',
380
+ label: 'Required checks are proven green and deliberately red',
381
+ dependencies: [dep(['production-rehearsed'], 'Promotion rehearsal precedes final context proof.')],
382
+ applicability: { kind: 'always' },
383
+ allowedMutations: mutations(['write-evidence'], ['github-read', 'github-workflow-dispatch']),
384
+ evidence: evidence('green-red-proof.v1', true, ['github']),
385
+ approvalGate: approval('activation-plan', true),
386
+ invalidationInputs: ['security-evidence', 'workflow-source'],
387
+ rollback: rollback('none', null, 'Missing red proof prevents enforcement.'),
388
+ terminalStates: terminalVerified
389
+ },
390
+ {
391
+ id: 'enforcement-approved',
392
+ label: 'Final ruleset enforcement is approved',
393
+ dependencies: [dep(['green-red-proof'], 'Only exact green/red evidence may request enforcement.')],
394
+ applicability: { kind: 'always' },
395
+ allowedMutations: mutations(['write-activation-state', 'write-evidence']),
396
+ evidence: evidence('enforcement-approved.v1', false),
397
+ approvalGate: approval('enforcement', true),
398
+ invalidationInputs: ['approval-envelope', 'ruleset-readback'],
399
+ rollback: rollback('none', null, 'Approval expiry blocks ruleset application.'),
400
+ terminalStates: terminalApproved
401
+ },
402
+ {
403
+ id: 'rulesets-applied',
404
+ label: 'Repository rulesets are applied idempotently last',
405
+ dependencies: [dep(['enforcement-approved'], 'Final enforcement approval precedes ruleset mutation.')],
406
+ applicability: { kind: 'always' },
407
+ allowedMutations: mutations(['write-evidence'], ['github-ruleset-write', 'github-read']),
408
+ evidence: evidence('rulesets-applied.v1', true, ['github']),
409
+ approvalGate: approval('enforcement', true),
410
+ invalidationInputs: ['approval-envelope', 'ruleset-readback'],
411
+ rollback: rollback('reverse-to', 'green-red-proof', 'Rulesets can be disabled or repaired without approval-gating rollback.'),
412
+ terminalStates: terminalVerified
413
+ },
414
+ {
415
+ id: 'live-readback',
416
+ label: 'Live enforcement readback matches source',
417
+ dependencies: [dep(['rulesets-applied'], 'Live readback follows ruleset application.')],
418
+ applicability: { kind: 'always' },
419
+ allowedMutations: mutations(['write-evidence'], ['github-read']),
420
+ evidence: evidence('live-readback.v1', true, ['github']),
421
+ approvalGate: approval('none', false),
422
+ invalidationInputs: ['ruleset-readback', 'live-readback'],
423
+ rollback: rollback('reverse-to', 'rulesets-applied', 'Mismatched live readback blocks completion.'),
424
+ terminalStates: terminalVerified
425
+ },
426
+ {
427
+ id: 'bootstrap-state-disposed',
428
+ label: 'Retained local bootstrap state is disposed after day 30',
429
+ dependencies: [dep(['live-readback'], 'Disposal is scheduled only after live enforcement readback.')],
430
+ applicability: {
431
+ kind: 'conditional',
432
+ discriminator: 'state-path',
433
+ when: 'statePath=bootstrap-local',
434
+ inapplicableWhen: 'statePath!=bootstrap-local',
435
+ exclusiveWith: []
394
436
  },
395
- {
396
- id: 'bootstrap-state-disposed',
397
- label: 'Retained local bootstrap state is disposed after day 30',
398
- dependencies: [dep(['live-readback'], 'Disposal is scheduled only after live enforcement readback.')],
399
- applicability: {
400
- kind: 'conditional',
401
- discriminator: 'state-path',
402
- when: 'statePath=bootstrap-local',
403
- inapplicableWhen: 'statePath!=bootstrap-local',
404
- exclusiveWith: []
405
- },
406
- allowedMutations: mutations(['delete-local-state', 'write-evidence']),
407
- evidence: evidence('bootstrap-state-disposed.v1'),
408
- approvalGate: approval('destructive-disposal', true),
409
- invalidationInputs: ['remote-state', 'approval-envelope'],
410
- rollback: rollback('dispose', null, 'Deletion destroys only the local encryption key and records no payload.'),
411
- terminalStates: ['disposed', 'failed', 'inapplicable']
412
- }
413
- ]
437
+ allowedMutations: mutations(['delete-local-state', 'write-evidence']),
438
+ evidence: evidence('bootstrap-state-disposed.v1'),
439
+ approvalGate: approval('destructive-disposal', true),
440
+ invalidationInputs: ['remote-state', 'approval-envelope'],
441
+ rollback: rollback('dispose', null, 'Deletion destroys only the local encryption key and records no payload.'),
442
+ terminalStates: ['disposed', 'failed', 'inapplicable']
443
+ }
444
+ ];
445
+ export const canonicalPhaseGraph = {
446
+ schemaVersion: phaseGraphSchemaVersion,
447
+ versions: {
448
+ liftoffVersion: liftoffActivationPackageVersion,
449
+ policyVersion: governanceActivationPolicyVersion,
450
+ activationContractVersion,
451
+ phaseGraphSchemaVersion
452
+ },
453
+ completionGroups: {
454
+ local: localSetupPhaseIds,
455
+ activation: activationPhaseIds,
456
+ lifecycle: lifecyclePhaseIds
457
+ },
458
+ phases: rawPhases
414
459
  };
415
460
  function phaseBehavior(node) {
416
461
  return {