@msn-control/liftoff 0.9.9 → 0.10.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 (106) hide show
  1. package/DEVELOPER.md +142 -0
  2. package/README.md +26 -18
  3. package/assets/governance/single-maintainer-gitflow/policy.md +13 -11
  4. package/dist/args.js +21 -0
  5. package/dist/args.js.map +1 -1
  6. package/dist/artifact-lifecycle.d.ts +1 -1
  7. package/dist/artifact-lifecycle.js +5 -0
  8. package/dist/artifact-lifecycle.js.map +1 -1
  9. package/dist/commands.js +355 -13
  10. package/dist/commands.js.map +1 -1
  11. package/dist/file-system.js +100 -13
  12. package/dist/file-system.js.map +1 -1
  13. package/dist/governance-activation/activation-state.d.ts +32 -0
  14. package/dist/governance-activation/activation-state.js +165 -0
  15. package/dist/governance-activation/activation-state.js.map +1 -0
  16. package/dist/governance-activation/approvals.d.ts +188 -0
  17. package/dist/governance-activation/approvals.js +508 -0
  18. package/dist/governance-activation/approvals.js.map +1 -0
  19. package/dist/governance-activation/canonical-json.d.ts +3 -0
  20. package/dist/governance-activation/canonical-json.js +36 -0
  21. package/dist/governance-activation/canonical-json.js.map +1 -0
  22. package/dist/governance-activation/commands.d.ts +10 -0
  23. package/dist/governance-activation/commands.js +1023 -0
  24. package/dist/governance-activation/commands.js.map +1 -0
  25. package/dist/governance-activation/compatibility.d.ts +68 -0
  26. package/dist/governance-activation/compatibility.js +447 -0
  27. package/dist/governance-activation/compatibility.js.map +1 -0
  28. package/dist/governance-activation/credentials.d.ts +160 -0
  29. package/dist/governance-activation/credentials.js +403 -0
  30. package/dist/governance-activation/credentials.js.map +1 -0
  31. package/dist/governance-activation/doctor.d.ts +10 -0
  32. package/dist/governance-activation/doctor.js +379 -0
  33. package/dist/governance-activation/doctor.js.map +1 -0
  34. package/dist/governance-activation/evidence.d.ts +49 -0
  35. package/dist/governance-activation/evidence.js +246 -0
  36. package/dist/governance-activation/evidence.js.map +1 -0
  37. package/dist/governance-activation/graph.d.ts +397 -0
  38. package/dist/governance-activation/graph.js +441 -0
  39. package/dist/governance-activation/graph.js.map +1 -0
  40. package/dist/governance-activation/identity.d.ts +35 -0
  41. package/dist/governance-activation/identity.js +89 -0
  42. package/dist/governance-activation/identity.js.map +1 -0
  43. package/dist/governance-activation/index.d.ts +18 -0
  44. package/dist/governance-activation/index.js +19 -0
  45. package/dist/governance-activation/index.js.map +1 -0
  46. package/dist/governance-activation/migration.d.ts +44 -0
  47. package/dist/governance-activation/migration.js +268 -0
  48. package/dist/governance-activation/migration.js.map +1 -0
  49. package/dist/governance-activation/readiness.d.ts +23 -0
  50. package/dist/governance-activation/readiness.js +158 -0
  51. package/dist/governance-activation/readiness.js.map +1 -0
  52. package/dist/governance-activation/reconciliation.d.ts +11 -0
  53. package/dist/governance-activation/reconciliation.js +58 -0
  54. package/dist/governance-activation/reconciliation.js.map +1 -0
  55. package/dist/governance-activation/release-integrity.d.ts +11 -0
  56. package/dist/governance-activation/release-integrity.js +49 -0
  57. package/dist/governance-activation/release-integrity.js.map +1 -0
  58. package/dist/governance-activation/seed-lifecycle.d.ts +116 -0
  59. package/dist/governance-activation/seed-lifecycle.js +609 -0
  60. package/dist/governance-activation/seed-lifecycle.js.map +1 -0
  61. package/dist/governance-activation/source-of-truth.d.ts +164 -0
  62. package/dist/governance-activation/source-of-truth.js +986 -0
  63. package/dist/governance-activation/source-of-truth.js.map +1 -0
  64. package/dist/governance-activation/task-projection.d.ts +21 -0
  65. package/dist/governance-activation/task-projection.js +75 -0
  66. package/dist/governance-activation/task-projection.js.map +1 -0
  67. package/dist/governance-activation/transitions.d.ts +163 -0
  68. package/dist/governance-activation/transitions.js +2128 -0
  69. package/dist/governance-activation/transitions.js.map +1 -0
  70. package/dist/governance-activation/type-contract.d.ts +1 -0
  71. package/dist/governance-activation/type-contract.js +27 -0
  72. package/dist/governance-activation/type-contract.js.map +1 -0
  73. package/dist/governance-activation/types.d.ts +390 -0
  74. package/dist/governance-activation/types.js +108 -0
  75. package/dist/governance-activation/types.js.map +1 -0
  76. package/dist/governance-activation/validators.d.ts +17 -0
  77. package/dist/governance-activation/validators.js +1305 -0
  78. package/dist/governance-activation/validators.js.map +1 -0
  79. package/dist/init-filesystem.js +5 -1
  80. package/dist/init-filesystem.js.map +1 -1
  81. package/dist/planner.js +3 -3
  82. package/dist/planner.js.map +1 -1
  83. package/dist/power-apps-templates.js +14 -1
  84. package/dist/power-apps-templates.js.map +1 -1
  85. package/dist/process-runner.d.ts +3 -0
  86. package/dist/process-runner.js +68 -10
  87. package/dist/process-runner.js.map +1 -1
  88. package/dist/repository-governance.d.ts +13 -3
  89. package/dist/repository-governance.js +357 -51
  90. package/dist/repository-governance.js.map +1 -1
  91. package/dist/telemetry/contract.d.ts +1 -1
  92. package/dist/telemetry/contract.js +6 -0
  93. package/dist/telemetry/contract.js.map +1 -1
  94. package/dist/templates.js +320 -25
  95. package/dist/templates.js.map +1 -1
  96. package/dist/types.d.ts +14 -6
  97. package/docs/cli-reference.md +60 -12
  98. package/docs/configuration-and-manifests.md +40 -16
  99. package/docs/existing-repositories.md +22 -11
  100. package/docs/getting-started.md +46 -10
  101. package/docs/project-structure.md +34 -5
  102. package/docs/repository-governance.md +200 -245
  103. package/docs/safety-and-consent.md +24 -2
  104. package/docs/troubleshooting.md +55 -4
  105. package/docs/workloads.md +1 -1
  106. package/package.json +2 -1
@@ -38,12 +38,14 @@ a reviewed project change.
38
38
 
39
39
  See [prerequisites](prerequisites.md) for the complete plan-derived tool model.
40
40
 
41
- ## 2. Start interactive initialization
41
+ ## 2. Start the primary path
42
42
 
43
43
  From the directory that should contain the project, run:
44
44
 
45
- ```bash
46
- liftoff init
45
+ ```text
46
+ liftoff init my-project
47
+ cd my-project
48
+ /liftoff-setup
47
49
  ```
48
50
 
49
51
  The guided flow asks for:
@@ -69,8 +71,15 @@ there, validates the complete result, and only then merges it into the target.
69
71
  OpenSpec projects use all 12 OpenSpec 1.11 workflows as both skills and commands.
70
72
  If the global OpenSpec profile differs, Liftoff displays the exact global change
71
73
  and asks separately before staging.
72
- Governance activation is a later selected-agent action after commit and push;
73
- see [repository governance](repository-governance.md).
74
+
75
+ When governance is enabled, `/liftoff-setup` is the next selected-agent action.
76
+ It has no model-selection requirement: safety comes from the Liftoff CLI phase
77
+ graph, local evidence, approval envelopes, and readback. Setup first completes,
78
+ syncs, and archives the generated `bootstrap-<project>` seed. Only then does it
79
+ reach explicit authority gates for repository commit/push, credentials, billed
80
+ infrastructure or policy exceptions, final enforcement, destructive cleanup, and
81
+ external blockers. Commit and push are never implicit in `liftoff init`, `--yes`,
82
+ or read-only checks.
74
83
 
75
84
  For deterministic generic generation, use `--type genai --pattern generic`.
76
85
 
@@ -86,26 +95,53 @@ a project name creates a named child directory.
86
95
  Read [existing repositories](existing-repositories.md) before initializing a
87
96
  non-empty target.
88
97
 
89
- ## 4. Validate the result
98
+ ## 4. Local baseline setup verifies
99
+
100
+ `/liftoff-setup` runs only local, project-applicable baseline checks before it
101
+ archives the seed:
102
+
103
+ ```bash
104
+ liftoff validate
105
+ # backend tests from the generated README when a backend exists
106
+ # frontend build from the generated README when a frontend exists
107
+ docker compose config -q
108
+ tofu fmt -check -recursive
109
+ tofu init -backend=false
110
+ tofu validate
111
+ openspec validate --strict
112
+ ```
113
+
114
+ Absent components are inapplicable: a Power Apps project does not fabricate
115
+ backend, Docker, or OpenTofu success, and an API project without a frontend skips
116
+ frontend build evidence. The baseline does not run `tofu plan`, `tofu apply`,
117
+ start containers, deploy, mutate GitHub, or require cloud credentials. If a check
118
+ fails, the seed remains active and `/liftoff-setup` resumes idempotently after
119
+ you fix the blocker; verified phases are not repeated.
90
120
 
91
- Run maintenance commands from the generated project root:
121
+ You can run read-only maintenance at any time:
92
122
 
93
123
  ```bash
94
124
  liftoff validate
95
125
  liftoff doctor
126
+ liftoff governance status --json
127
+ liftoff governance plan --json
128
+ liftoff governance verify --json
96
129
  ```
97
130
 
98
131
  `validate` checks durable generated artifacts and framework markers. `doctor`
99
- adds read-only workstation, runtime, authentication, dependency, and
100
- workload-specific diagnostics.
132
+ adds read-only workstation, runtime, authentication, dependency,
133
+ workload-specific, and governance-state diagnostics.
101
134
 
102
- Next steps depend on the selected workload:
135
+ After setup archives the seed and you explicitly approve repository publication,
136
+ normal development follows your selected workflow:
103
137
 
104
138
  - GenAI and API projects: copy `.env.example` to `.env`, install the generated
105
139
  stack dependencies, then use `liftoff dev` and `liftoff infra` to print local
106
140
  development and infrastructure commands.
107
141
  - Power Apps projects: run `npm ci`, then `npm run dev`. Environment binding,
108
142
  connector addition, and `power-apps push` are deliberately deferred.
143
+ - OpenSpec or Spec Kit changes drive normal feature work; release and hotfix
144
+ flows follow the governed GitFlow plan after activation evidence is green.
109
145
 
110
146
  See [workloads](workloads.md) for exact generated outputs and deferred actions.
111
147
 
@@ -23,7 +23,15 @@ project/
23
23
  | `-- governance/ # managed-core local handoff when enabled
24
24
  | |-- policy.md
25
25
  | |-- context.json
26
- | `-- README.md
26
+ | |-- README.md
27
+ | |-- phase-graph.json
28
+ | |-- compatibility.json
29
+ | `-- credential-policy.schema.json
30
+ |-- governance/ # user-owned activation state after setup starts
31
+ | |-- activation-state.json
32
+ | |-- approvals/
33
+ | |-- evidence/
34
+ | `-- credentials/
27
35
  |-- backend/
28
36
  | `-- uv.lock # Python stacks only
29
37
  |-- database/
@@ -43,8 +51,10 @@ project/
43
51
  |-- .claude/skills/openspec-*/ and .claude/commands/opsx/ # OpenSpec + Claude
44
52
  |-- .github/workflows/copilot-setup-steps.yml # optional hosted agent
45
53
  |-- .github/agents/openspec.agent.md # optional hosted agent
46
- |-- .github/prompts/liftoff-repository-governance.prompt.md
47
- | or .claude/commands/liftoff-repository-governance.md
54
+ |-- .github/prompts/liftoff-setup.prompt.md
55
+ |-- .github/prompts/liftoff-repository-governance.prompt.md # compatibility alias
56
+ | or .claude/commands/liftoff-setup.md
57
+ | and .claude/commands/liftoff-repository-governance.md
48
58
  |-- frontend/ # only when selected
49
59
  |-- functions/<worker-name>/ # only for worker-enabled GenAI patterns
50
60
  `-- migration/legacy/ # only after liftoff migrate
@@ -77,6 +87,10 @@ project/
77
87
  - OpenSpec projects receive all 12 pinned workflows as both skills and commands
78
88
  for supported selected-agent surfaces. The two hosted Copilot agent files are
79
89
  generated only after explicit opt-in.
90
+ - `/liftoff-setup` is generated when repository governance is enabled. It calls
91
+ `liftoff governance status|plan|apply-next|resume|verify` and has no model
92
+ selection or separate setup-skill version. `/liftoff-repository-governance` is
93
+ a compatibility alias for the same state.
80
94
 
81
95
  ### Conditional areas
82
96
 
@@ -111,14 +125,16 @@ project/
111
125
  | |-- hooks/
112
126
  | |-- pages/
113
127
  | `-- providers/
128
+ |-- .liftoff/governance/ # managed-core setup files when enabled
129
+ |-- governance/ # user-owned activation state after setup starts
114
130
  `-- openspec/ or .specify/
115
131
  ```
116
132
 
117
133
  The exact selected-agent governance launcher is generated only when the
118
134
  repository-governance profile is enabled. It is Liftoff-owned; neighboring
119
135
  framework files remain framework-owned. Agent-created governance changes and
120
- `governance/activation-baseline.json` remain user-owned and are not listed in
121
- the manifest.
136
+ `governance/activation-state.json`, approvals, evidence, credentials, and
137
+ supersession records remain user-owned and are not listed as managed artifacts.
122
138
 
123
139
  This root follows the pinned official Microsoft starter. It includes the
124
140
  Power Apps SDK, Vite plugin, and project-local CLI through locked npm
@@ -128,6 +144,19 @@ Liftoff intentionally does not generate `backend/`, `database/`,
128
144
  `docker-compose.yml`, `environments/`, `infrastructure/`, or
129
145
  `power.config.json` for this workload.
130
146
 
147
+ ## Managed versus user-owned governance artifacts
148
+
149
+ `liftoff.manifest.json` v7 records managed-core hashes for the governance policy,
150
+ context, guide, phase graph, compatibility metadata, credential-policy schema,
151
+ setup integrations, and compatibility aliases. `liftoff update` may reconcile
152
+ only those managed-core paths. It preserves user-owned activation state,
153
+ immutable evidence, approvals, credential policies, active OpenSpec changes, and
154
+ project source.
155
+
156
+ Manifest paths are stored as path-part arrays and validated on Windows, macOS,
157
+ and Linux. Generated setup content is identified by managed content hashes; the
158
+ activation version vector and graph hash describe the behavior contract.
159
+
131
160
  ## GenAI integration configuration
132
161
 
133
162
  Generated GenAI projects expose real configuration boundaries instead of
@@ -1,269 +1,224 @@
1
- # Repository governance handoff
1
+ # Repository governance and deterministic setup
2
2
 
3
- Repository governance is a common Liftoff project choice. The default
4
- `single-maintainer-gitflow` profile generates a deterministic local handoff;
5
- `none` opts out:
3
+ Repository governance is enabled by default through the
4
+ `single-maintainer-gitflow` profile; `--governance none` opts out. Initialization
5
+ writes local managed-core artifacts only. It does not run an agent, mutate Git,
6
+ contact GitHub or Azure, configure rulesets, provision runners, deploy, or start
7
+ monitoring.
6
8
 
7
- **Local handoff generated; live enforcement is not active.**
9
+ Primary path after initialization:
8
10
 
9
- ```bash
10
- liftoff plan --governance single-maintainer-gitflow
11
- liftoff init --governance none
11
+ ```text
12
+ liftoff init my-project
13
+ cd my-project
14
+ /liftoff-setup
12
15
  ```
13
16
 
14
- Accepting the default or passing `--yes` authorizes only local project files. It
15
- does not run an agent, mutate Git, contact GitHub or Azure, configure security,
16
- install a ruleset, deploy, provision a runner, or create monitoring.
17
+ `/liftoff-setup` completes the generated bootstrap seed, then enters the
18
+ deterministic Liftoff governance engine and its read-only Phase 0 discovery. The older
19
+ `/liftoff-repository-governance` launcher is a compatibility alias for the same
20
+ engine and user-owned activation state; it is not a separate activation path.
17
21
 
18
- ## Generated files
22
+ ## Managed files and user-owned state
19
23
 
20
- An enabled profile adds durable, hash-managed artifacts:
24
+ Enabled governance adds managed-core files:
21
25
 
22
26
  ```text
23
27
  .liftoff/governance/policy.md
24
28
  .liftoff/governance/context.json
25
29
  .liftoff/governance/README.md
26
- .github/prompts/liftoff-repository-governance.prompt.md # Copilot selected
27
- .claude/commands/liftoff-repository-governance.md # Claude selected
30
+ .liftoff/governance/phase-graph.json
31
+ .liftoff/governance/compatibility.json
32
+ .liftoff/governance/credential-policy.schema.json
33
+ .github/prompts/liftoff-setup.prompt.md # Copilot selected
34
+ .github/prompts/liftoff-repository-governance.prompt.md # compatibility alias
35
+ .claude/commands/liftoff-setup.md # Claude selected
36
+ .claude/commands/liftoff-repository-governance.md # compatibility alias
28
37
  ```
29
38
 
30
- The complete canonical policy is also packaged with Liftoff at
31
- [`assets/governance/single-maintainer-gitflow/policy.md`](../assets/governance/single-maintainer-gitflow/policy.md).
32
- It covers GitFlow, zero-human-approval repository rules, designated security
33
- tools, fail-closed checks, immutable release evidence, build-once promotion,
34
- deployment and rollback, monitoring and health, DORA metrics, ruleset
35
- sequencing, negative tests, documentation, and workload adaptation.
36
-
37
- Policy version 5 also fixes platform decisions that generated projects should
38
- not repeatedly ask users to make:
39
-
40
- - Dev storage uses LRS; Staging and Production use ZRS. IaC state uses ZRS in
41
- every environment.
42
- - Database HA is off in Dev and Staging and zone-redundant in Production.
43
- - CI uses one user-assigned managed identity with OIDC federation per repository
44
- and environment, without app registrations or long-lived credentials.
45
- - The default workload is small and cost-optimised with production safeguards.
46
- Runtimes remain on Active LTS majors, with grouped dependency updates and
47
- non-LTS major updates ignored.
48
- - Slack webhooks are required environment-level GitHub Actions secrets so the
49
- alert path does not depend on private-vault connectivity.
50
- - Encrypted local bootstrap state is retained read-only for 30 days after
51
- verified remote import, then securely deleted with dated evidence.
52
- - Azure resource-provider namespaces are derived from the approved plan. When
53
- auto-registration is disabled, each missing required namespace is registered
54
- explicitly before dependent resources.
55
-
56
- These are applicable defaults, not reasons to create unused resources. A
57
- managed service is included only when application code consumes it, after its
58
- cost and known service limits are stated. When live infrastructure differs from
59
- IaC, activation planning adapts the IaC and imports the live resource rather
60
- than creating a parallel stack or forcing replacement.
61
-
62
- ## Private Staging qualification
63
-
64
- DAST for a privately networked Staging environment uses an ephemeral
65
- GitHub-hosted larger runner with Azure VNet injection. Activation reuses a
66
- suitable existing repository assignment. If none exists, policy version 5
67
- permits one narrow post-approval exception to provision the Azure network
68
- setting, organisation hosted-compute network configuration, selected-access
69
- runner group, and bounded larger runner required by that repository.
70
-
71
- Phase 0 first proves that private Staging DAST applies. It then discovers the
72
- repository's Staging subscription and tenant, existing runner resources, Azure
73
- and GitHub write authority, enterprise network policy, billing, state, names,
74
- address space, DNS, routing, costs, limits, and teardown ownership. Missing
75
- authority or an unresolved input blocks provisioning without partial mutation.
76
- No self-hosted runner is substituted.
77
-
78
- Every Azure runner-network resource, its state, egress cost, and teardown owner
79
- remain inside the repository's Staging subscription. The design cannot share a
80
- firewall, hub, route, state, or lifecycle with another repository or
81
- subscription. GitHub resources exist at organisation level but grant selected
82
- access only to the target repository and required workflows.
83
-
84
- The delegated runner subnet disables implicit default outbound access, denies
85
- unsolicited inbound connectivity, and uses exactly one egress mode:
86
-
87
- - Azure Firewall Basic only when an applicable policy requires domain-restricted
88
- egress. Its HTTPS rules use a current GitHub meta domain set without the
89
- retired static-IP template or TLS interception.
90
- - Azure NAT Gateway otherwise, with required protocols constrained by an NSG.
91
- NAT and NSG controls do not filter HTTPS by domain.
92
-
93
- NAT Gateway cannot be attached to a firewall-routed runner subnet because it
94
- takes precedence and would bypass the firewall. The approved topology must also
95
- prove non-overlapping address space, same-subscription routing or peering,
96
- private DNS, security rules, and live private Staging reachability.
97
-
98
- A standard hosted preflight verifies the assignment and labels before scheduling
99
- DAST. Azure and GitHub resources, associations, egress, DNS, and reachability
100
- must all be read back successfully. Missing or partial evidence blocks
101
- qualification rather than leaving a required job queued or reporting success.
102
- Teardown reverses those dependencies and removes the Azure network only after
103
- GitHub scheduling, assignment, and service associations are gone.
104
-
105
- ### Azure resource-provider readiness
106
-
107
- Phase 0 derives the minimal namespace inventory from every approved Azure
108
- resource type and records AzureRM's registration mode and the execution
109
- identity's subscription registration permission. A hosted-runner network always
110
- requires at least `Microsoft.Network` and `GitHub.Network`; additional providers
111
- are included only when approved state, identity, monitoring, or application
112
- resources use them.
113
-
114
- When AzureRM automatic registration is enabled and sufficient, no duplicate
115
- explicit resources are added. When
116
- `resource_provider_registrations = "none"` disables it, every missing required
117
- namespace is registered explicitly. Dependent and billable resources remain
118
- blocked until live subscription readback reports each namespace as
119
- `Registered`.
120
-
121
- Every explicit resource has a direct or transitive dependency on its namespace
122
- registration. Existing registrations are no-ops. Pending, unauthorized,
123
- unregistering, or failed states require a revised no-apply plan rather than
124
- partial provisioning. Successful registrations remain subscription capabilities
125
- during repository teardown and are not automatically unregistered.
126
-
127
- Subscription features are narrower than provider namespaces. A
128
- `SubscriptionNotRegisteredForFeature` error does not authorize registering the
129
- named feature unless the approved resource design intentionally uses it.
130
- Unexpected feature requests require correction of the resource properties,
131
- provider behavior, or API shape and a revised no-apply plan.
132
-
133
- Ordinary Firewall and NAT Standard public IPs do not require BYOIP. If such a
134
- resource requests `Microsoft.Network/AllowBringYourOwnPublicIpAddress` without a
135
- custom IP prefix, the plan must remove accidental BYOIP properties or use a
136
- supported API shape; it must not register BYOIP merely to retry.
137
-
138
- Network service-tag rules also require semantic validation.
139
- `AzurePlatformDNS` is deny-only for intentionally disabling Azure platform DNS,
140
- not a valid Allow target. Default platform DNS needs no explicit NSG allow.
141
- Custom resolvers instead receive TCP and UDP port 53 allows to their exact IP
142
- addresses.
143
-
144
- ### Private state bootstrap and retention
145
-
146
- Phase 0 prefers an existing approved private execution path to the
147
- repository-owned ZRS backend. When public access is disabled and no such path
148
- exists, an approved governance change may use encrypted local OpenTofu state for
149
- only the minimum networking, private endpoint, DNS, network setting, and
150
- restricted runner resources needed to establish access. This
151
- `bootstrap-local` phase is not remote-ready and cannot authorize application
152
- provisioning.
153
-
154
- The local state remains gitignored, single-writer, encrypted on the approved
155
- workstation, and is never transferred through GitHub artifacts, repository
156
- secrets, or ordinary messages. From the exact private runner, reviewed import
157
- declarations adopt the resources into an empty ZRS backend without copying the
158
- local state file.
159
-
160
- Remote import is complete only after private Blob access, exact live-to-state
161
- resource identity, state locking, Blob versioning, and a clean-checkout
162
- no-change plan are verified. Failure starts no retention clock and keeps normal
163
- provisioning blocked.
164
-
165
- At successful verification, the local state becomes evidence-only and read-only
166
- for exactly 30 days. It cannot run plan or apply. At expiry, its encryption key
167
- and encrypted files are removed, along with every approved temporary copy. A
168
- dated record captures the state identity or checksum, verification evidence,
169
- scheduled and actual deletion, operator, method, and outcome without containing
170
- state data or secrets.
171
-
172
- ## Release identity and automated completion
173
-
174
- Staging qualifies the release or hotfix candidate commit and binds it to the
175
- version, artifact digest, and evidence-bundle digest. A later true merge into
176
- `main` necessarily has a different SHA. Production verifies that the merge
177
- incorporates the exact qualified candidate, promotes the identical artifact,
178
- and records both identities:
39
+ User-owned execution state is separate and is never advanced by
40
+ `liftoff update`:
179
41
 
180
42
  ```text
181
- candidate SHA -> qualification -> artifact digest
182
- | |
183
- +---------- main merge SHA ----+
184
- |
185
- +-> deployment -> tag and GitHub Release
43
+ governance/activation-state.json
44
+ governance/approvals/
45
+ governance/evidence/
46
+ governance/credentials/preflight-policy.json
186
47
  ```
187
48
 
188
- Package formats may require embedded version metadata, but that value must
189
- match the authoritative `release/X.Y.Z` or `hotfix/X.Y.Z` branch name.
190
-
191
- Release and hotfix back-merges remain pull-request-only and require successful
192
- checks. Because `GITHUB_TOKEN`-created events do not normally start more
193
- workflows, the coordinating workflow explicitly dispatches validation for the
194
- back-merge head and any required post-merge work for the resulting SHA. It does
195
- not push directly to a protected branch or rely on a tag push. Tag creation,
196
- Release publication, and durable evidence stay in the successful production
197
- workflow.
198
-
199
- `context.json` contains generated project facts only. GitHub repository state,
200
- runner access, licensed features, deployments, monitoring, alert routes,
201
- traffic, and rollout capabilities remain `undiscovered`. Power Apps context
202
- explicitly marks Liftoff backend, Docker, OpenTofu, custom container promotion,
203
- and API DAST as inapplicable.
204
-
205
- ## Activate after commit and push
206
-
207
- 1. Review the policy and context.
208
- 2. Commit the project and push it to the intended GitHub repository.
209
- 3. Run `/liftoff-repository-governance` with a selected agent.
210
- 4. The agent performs read-only Phase 0 and reports repository identity,
211
- artifacts, working commands, refs, workflows and exact checks, rulesets,
212
- releases, environments, security, runners, deployments, monitoring, alerts,
213
- health depth, platform capabilities, gaps, and inapplicable controls. When
214
- private Staging DAST applies without a suitable runner, it also reports the
215
- complete subscription-local topology, one explicit egress mode, authority,
216
- costs, limits, verification, and teardown plan.
217
- 5. The agent proposes the current `main` SHA as the activation baseline,
218
- presents an ordered plan, and stops.
219
- 6. Explicitly approve or revise the conversational plan. This is not a human
220
- merge or deployment approval gate.
221
- 7. After approval, the agent creates a new OpenSpec or Spec Kit governance
222
- change, proves required contexts green and deliberately red, applies
223
- repository-scoped rulesets last, and reads live enforcement back.
224
-
225
- The user-owned `governance/activation-baseline.json` is created only after
226
- approval. Liftoff never owns or recreates it or the agent-created governance
227
- change. Complete local handoffs say `handoff-generated`, partial adoptions say
228
- `handoff-partial`, and neither state means `active`.
49
+ The complete policy is packaged at
50
+ [`assets/governance/single-maintainer-gitflow/policy.md`](../assets/governance/single-maintainer-gitflow/policy.md).
51
+ Policy version 6 treats numbered policy sections as capability chapters, not
52
+ execution order. The managed phase graph is the sole execution-order authority.
229
53
 
230
- ## Existing projects
54
+ ## Canonical phase graph
55
+
56
+ The activation graph is packaged as `.liftoff/governance/phase-graph.json` and
57
+ records phase IDs, dependencies, applicability, allowed mutations, evidence,
58
+ approvals, rollback boundaries, and terminal states:
231
59
 
232
- Configurations without `governanceProfile` normalize to the enabled default
233
- without rewriting `liftoff.config.json`:
60
+ ```text
61
+ seed-valid
62
+ -> seed-verified
63
+ -> seed-archived
64
+ -> committed
65
+ -> pushed
66
+ -> phase-0-complete
67
+ -> activation-approved
68
+ -> credential-ready
69
+ -> provider-ready
70
+ -> state-path-selected
71
+ |-> existing-private-path ----------------------|
72
+ `-> bootstrap-local -> runner-ready |
73
+ -> private-backend-proof |
74
+ -> remote-import-verified --|
75
+ -> remote-ready
76
+ -> application-foundation
77
+ -> workflow-source-ready
78
+ -> dev-proof
79
+ -> staging-qualified
80
+ -> production-rehearsed
81
+ -> green-red-proof
82
+ -> enforcement-approved
83
+ -> rulesets-applied
84
+ -> live-readback
85
+ -> bootstrap-state-disposed
86
+ ```
87
+
88
+ If policy prose, generated tasks, or an agent response orders a transition
89
+ differently, the graph wins. Provider readiness precedes `bootstrap-local`;
90
+ restricted runner readiness precedes private backend proof; private backend proof
91
+ precedes declarative remote import; and only an existing private path or verified
92
+ remote import can satisfy `remote-ready`.
93
+
94
+ ## Bootstrap seed and local baseline
95
+
96
+ Before commit/push or Phase 0, setup completes, syncs, and archives the generated
97
+ `bootstrap-<project>` OpenSpec seed. It runs only local, applicable checks:
98
+
99
+ - `liftoff validate`
100
+ - backend tests from the generated README
101
+ - frontend build when a frontend exists
102
+ - `docker compose config -q` when Compose exists
103
+ - `tofu fmt -check -recursive`
104
+ - `tofu init -backend=false`
105
+ - `tofu validate`
106
+ - strict OpenSpec validation
107
+
108
+ Absent components are recorded as inapplicable. The baseline never starts
109
+ containers, runs a live `tofu plan` or `tofu apply`, deploys, mutates GitHub, or
110
+ requires cloud credentials. A failed check keeps the seed active; rerun
111
+ `/liftoff-setup` after remediation and verified phases are not repeated.
112
+
113
+ ## Questions and approval envelopes
114
+
115
+ Deterministic defaults and discovered facts do not become conversational
116
+ questions. Setup may ask only at these authority gates:
117
+
118
+ 1. repository creation, initial commit, remote, or push;
119
+ 2. credential enrollment;
120
+ 3. billed infrastructure, policy exceptions, and cost ceiling;
121
+ 4. final ruleset enforcement;
122
+ 5. destructive cleanup, including day-30 bootstrap-state disposal;
123
+ 6. external platform blockers that require changed authority or design.
124
+
125
+ Every approval envelope records the reviewed plan digest, allowed resource
126
+ types, destinations, permissions, cost ceiling, destructive scope, policy
127
+ exceptions, expiry, and baseline SHA. Retries inside the same envelope do not
128
+ ask again; expanded resources, destinations, permissions, cost, exceptions, or
129
+ destructive effects require a new approval.
130
+
131
+ ## Credentials for runner preflight
132
+
133
+ When `GITHUB_TOKEN` cannot read required hosted-runner metadata, setup first
134
+ prefers an existing verified selected-repository GitHub App installation with the
135
+ required read permissions. Liftoff does not install or broaden an App.
136
+
137
+ If no approved App is available, setup guides one fine-grained PAT with exactly:
138
+
139
+ | Field | Value |
140
+ | --- | --- |
141
+ | Display name | `<repo>-runner-preflight-read` |
142
+ | Repository secret | `RUNNER_CONFIGURATION_READ_TOKEN` |
143
+ | Lifetime | 30 days |
144
+ | Repository scope | current repository only |
145
+ | Repository permission | metadata read |
146
+ | Organization permissions | hosted-runner read and network-configuration read |
147
+ | Writes | none |
148
+ | Workflow/job allowlist | `.github/workflows/bootstrap-import-preflight.yml` job `bootstrap-import-preflight`; `.github/workflows/private-dast-preflight.yml` job `private-dast-preflight` |
149
+
150
+ Enter the value only through Liftoff's masked input. Never paste or show the
151
+ value in chat, argv, command arguments, logs, evidence, files, or screenshots. A value
152
+ that appears in any of those places is compromised and must be manually revoked
153
+ and rotated before setup can continue.
154
+
155
+ The recorded credential policy is payload-free: it stores auth kind, display
156
+ name, secret name, owner, repository, expiry, rotation lead, permissions,
157
+ allowed workflows/jobs, non-forwarding rules, and readback evidence, never the
158
+ secret value.
159
+
160
+ ## Evidence authority and active changes
161
+
162
+ Task checkboxes are a projection of phase state, not authority. Evidence
163
+ documents carry repository identity, activation version vector, graph hash, phase
164
+ contract digest, input digest, baseline SHA, phase ID, timestamp, producer, and
165
+ result. Setup and `liftoff governance verify` reject missing, stale,
166
+ contradictory, future-version, or graph-incompatible evidence.
167
+
168
+ There may be only one active governance source of truth. An unfinished bootstrap
169
+ seed blocks Phase 0. Exactly one compatible active governance change is resumed.
170
+ Multiple overlapping changes require a schema-valid supersession or archive
171
+ record before any phase advances.
172
+
173
+ Managed updates install new policy, graph, schema, compatibility metadata, setup
174
+ integrations, and aliases without touching user-owned state. When a policy,
175
+ activation-contract, schema, or graph-hash change affects active work, status
176
+ reports `reconciliation-required`, invalidates only affected descendants, and
177
+ waits for explicit acknowledgement of the current compatible identity and exact
178
+ graph hash.
179
+
180
+ ## Private staging and bootstrap retention
181
+
182
+ Private Staging DAST uses an ephemeral GitHub-hosted larger runner with Azure
183
+ VNet injection only when genuinely applicable. Phase 0 discovers repository,
184
+ subscription, authority, billing, network, DNS, cost, teardown, and capability
185
+ facts read-only. If DAST is inapplicable, no runner networking is provisioned.
186
+
187
+ When a private ZRS backend cannot be reached and no existing private management
188
+ path is approved, the bounded `bootstrap-local` branch may create only the
189
+ access-establishing resources needed to reach the backend. Local bootstrap state
190
+ is encrypted, gitignored, single-writer, never uploaded or copied through GitHub
191
+ artifacts or secrets, and cannot authorize application provisioning.
192
+
193
+ After verified declarative import, backend identity parity, state locking, Blob
194
+ versioning, and a clean-checkout no-change plan, local state becomes read-only
195
+ evidence for exactly 30 days. Disposal deletes the encryption key and approved
196
+ temporary copies and records a dated non-secret outcome. Provider registrations
197
+ remain retained subscription capabilities and are not unregistered during
198
+ teardown.
199
+
200
+ ## Commands
201
+
202
+ The generated setup integrations call only strict, project-aware CLI commands:
234
203
 
235
204
  ```bash
236
- liftoff update --check
237
- liftoff update
205
+ liftoff governance status --json
206
+ liftoff governance plan --json
207
+ liftoff governance apply-next --json --execute
208
+ liftoff governance resume --json
209
+ liftoff governance verify --json
238
210
  ```
239
211
 
240
- Check mode previews the schema-v6 manifest and new named core artifacts without
241
- writing. Plain update applies collision-free files; differing existing files
242
- remain managed-core conflicts unless individually reviewed with `--force`. An unrecorded
243
- conflict remains outside Liftoff ownership and produces `handoff-partial`.
244
- After every conflict is removed or matches the current artifact, the next
245
- update records the full artifact set as `handoff-generated`.
246
-
247
- Projects generated with policy versions 2 through 4 review the version-5 managed-core drift
248
- before replacement. `liftoff update` changes only the local handoff; it never
249
- provisions Azure or GitHub resources. Any active downstream runner change based
250
- on an older contract must reconcile its plan and implementation with version 5
251
- before applying cloud or organisation resources.
252
-
253
- Setting `"governanceProfile": "none"` stops future rendering. Previously managed
254
- handoff files are reported once as orphans and left on disk; Liftoff never
255
- deletes them automatically or changes live repository settings.
256
-
257
- ## Capability gaps
258
-
259
- Phase 0 must report missing GitHub licenses, runner-provisioning authority,
260
- VNet-injected assignment or reachability, Staging access, monitoring routes,
261
- parallel-version mechanisms, or statistically meaningful canary traffic. It
262
- must mark controls inapplicable or blocked rather than creating a skipped,
263
- hanging, partial, duplicate, or success-shaped placeholder.
264
-
265
- The official SLSA L3 generator is the policy's only action SHA-pinning
266
- exception because its reusable workflow contains mutable internal references.
267
- The outer call is pinned as tightly as supported and the exact exception is
268
- narrow and expiring. It does not weaken pinning for any other action, create a
269
- second vulnerability allowlist, or make Grype a blocking gate.
212
+ `status`, `plan`, and `verify` are read-only. `apply-next` previews mutations
213
+ unless `--execute` is supplied, and even then executes at most one graph-ready,
214
+ evidence-ready, approved phase. Unknown subcommands, flags, or extra positionals
215
+ fail before project discovery or mutation.
216
+
217
+ ## Existing projects
218
+
219
+ Projects without `governanceProfile` normalize to the enabled default during
220
+ read, then `liftoff update --check` previews manifest v7 and managed-core drift.
221
+ Plain `liftoff update` writes v7 only after preflights pass. It never provisions
222
+ Azure or GitHub resources and never advances activation state. Setting
223
+ `"governanceProfile": "none"` stops future rendering; previously managed files
224
+ become reported orphans and remain on disk for manual review.