release-skill 0.1.1 → 0.1.4

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 (108) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/.codex-plugin/plugin.json +3 -3
  4. package/CHANGELOG.md +89 -0
  5. package/INSTALL.md +216 -5
  6. package/INSTALL.zh-CN.md +358 -0
  7. package/README.md +411 -67
  8. package/README.zh-CN.md +377 -59
  9. package/adapters/claude/.claude-plugin/marketplace.json +1 -1
  10. package/adapters/claude/.claude-plugin/plugin.json +1 -1
  11. package/adapters/claude/bin/release-skill.bundle.mjs +79284 -0
  12. package/adapters/claude/bin/release-skill.mjs +34 -0
  13. package/adapters/claude/native/safe-write/binding.gyp +40 -0
  14. package/adapters/claude/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
  15. package/adapters/claude/native/safe-write/prebuilds.json +24 -0
  16. package/adapters/claude/native/safe-write/src/safe_write.cc +2032 -0
  17. package/adapters/claude/schemas/.render-manifest.json +37 -0
  18. package/adapters/claude/schemas/approval-record.schema.json +115 -0
  19. package/adapters/claude/schemas/artifact-lock.schema.json +111 -0
  20. package/adapters/claude/schemas/artifact-plan.schema.json +52 -0
  21. package/adapters/claude/schemas/artifact-policy.schema.json +76 -0
  22. package/adapters/claude/schemas/evidence-event.schema.json +89 -0
  23. package/adapters/claude/schemas/release-plan.schema.json +860 -0
  24. package/adapters/claude/schemas/release-project.schema.json +736 -0
  25. package/adapters/claude/schemas/release-run.schema.json +342 -0
  26. package/adapters/claude/skills/release-assess/SKILL.md +5 -6
  27. package/adapters/claude/skills/release-help/SKILL.md +14 -18
  28. package/adapters/claude/skills/release-prepare/SKILL.md +16 -6
  29. package/adapters/claude/skills/release-publish/SKILL.md +7 -7
  30. package/adapters/claude/skills/release-reconcile/SKILL.md +6 -6
  31. package/adapters/claude/skills/release-setup/SKILL.md +95 -0
  32. package/adapters/claude/skills/release-verify/SKILL.md +7 -7
  33. package/adapters/codex/.codex-plugin/plugin.json +2 -2
  34. package/adapters/codex/bin/release-skill.bundle.mjs +79284 -0
  35. package/adapters/codex/bin/release-skill.mjs +34 -0
  36. package/adapters/codex/native/safe-write/binding.gyp +40 -0
  37. package/adapters/codex/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
  38. package/adapters/codex/native/safe-write/prebuilds.json +24 -0
  39. package/adapters/codex/native/safe-write/src/safe_write.cc +2032 -0
  40. package/adapters/codex/schemas/.render-manifest.json +37 -0
  41. package/adapters/codex/schemas/approval-record.schema.json +115 -0
  42. package/adapters/codex/schemas/artifact-lock.schema.json +111 -0
  43. package/adapters/codex/schemas/artifact-plan.schema.json +52 -0
  44. package/adapters/codex/schemas/artifact-policy.schema.json +76 -0
  45. package/adapters/codex/schemas/evidence-event.schema.json +89 -0
  46. package/adapters/codex/schemas/release-plan.schema.json +860 -0
  47. package/adapters/codex/schemas/release-project.schema.json +736 -0
  48. package/adapters/codex/schemas/release-run.schema.json +342 -0
  49. package/adapters/codex/skills/release-assess/SKILL.md +12 -6
  50. package/adapters/codex/skills/release-help/SKILL.md +21 -18
  51. package/adapters/codex/skills/release-prepare/SKILL.md +23 -6
  52. package/adapters/codex/skills/release-publish/SKILL.md +14 -7
  53. package/adapters/codex/skills/release-reconcile/SKILL.md +13 -6
  54. package/adapters/codex/skills/release-setup/SKILL.md +102 -0
  55. package/adapters/codex/skills/release-verify/SKILL.md +14 -7
  56. package/bin/release-skill-cli.mjs +807 -0
  57. package/bin/release-skill.bundle.mjs +79284 -0
  58. package/bin/release-skill.mjs +23 -732
  59. package/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
  60. package/native/safe-write/prebuilds.json +22 -2
  61. package/native/safe-write/src/safe_write.cc +11 -2
  62. package/package.json +8 -2
  63. package/references/02-project-config.md +55 -4
  64. package/references/05-evidence-and-errors.md +6 -2
  65. package/schemas/release-plan.schema.json +556 -65
  66. package/schemas/release-project.schema.json +406 -29
  67. package/schemas/release-run.schema.json +165 -18
  68. package/scripts/build-bundle.mjs +133 -0
  69. package/skills/release-assess/SKILL.md +5 -6
  70. package/skills/release-help/SKILL.md +14 -18
  71. package/skills/release-prepare/SKILL.md +16 -6
  72. package/skills/release-publish/SKILL.md +7 -7
  73. package/skills/release-reconcile/SKILL.md +6 -6
  74. package/skills/release-setup/SKILL.md +95 -0
  75. package/skills/release-verify/SKILL.md +7 -7
  76. package/skills-src/release-assess/SKILL.md +5 -6
  77. package/skills-src/release-help/SKILL.md +14 -18
  78. package/skills-src/release-prepare/SKILL.md +16 -6
  79. package/skills-src/release-publish/SKILL.md +7 -7
  80. package/skills-src/release-reconcile/SKILL.md +6 -6
  81. package/skills-src/release-setup/SKILL.md +95 -0
  82. package/skills-src/release-verify/SKILL.md +7 -7
  83. package/src/adapters/contract.mjs +3 -0
  84. package/src/adapters/git-github.mjs +84 -2
  85. package/src/adapters/npm.mjs +5 -13
  86. package/src/adapters/plugin-marketplace.mjs +132 -52
  87. package/src/adapters/push-snapshot.mjs +84 -17
  88. package/src/artifacts/policy.mjs +4 -7
  89. package/src/artifacts/safe-fs-backend-internal.mjs +69 -21
  90. package/src/commands/prepare.mjs +244 -20
  91. package/src/commands/publish.mjs +46 -0
  92. package/src/commands/reconcile.mjs +152 -0
  93. package/src/commands/setup.mjs +1525 -0
  94. package/src/commands/verify.mjs +122 -26
  95. package/src/core/approval.mjs +4 -6
  96. package/src/core/config.mjs +42 -8
  97. package/src/core/errors.mjs +4 -0
  98. package/src/core/pkg-root.mjs +22 -0
  99. package/src/core/plan.mjs +132 -4
  100. package/src/core/previous-public-baseline.mjs +21 -1
  101. package/src/core/run.mjs +4 -4
  102. package/src/core/trusted-resource.mjs +96 -0
  103. package/src/core/verification-gates.mjs +451 -0
  104. package/src/docs/version-gate.mjs +164 -0
  105. package/src/producers/build-adapters.mjs +512 -55
  106. package/src/snapshot/frozen.mjs +221 -7
  107. package/src/snapshot/public-map.mjs +7 -4
  108. package/src/snapshot/scan.mjs +2 -1
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "name": "release-skill",
11
11
  "source": "./",
12
- "version": "0.1.1",
12
+ "version": "0.1.4",
13
13
  "description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification"
14
14
  }
15
15
  ]
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "release-skill",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification",
5
5
  "author": {
6
6
  "name": "release-skill contributors"
7
7
  },
8
8
  "license": "MIT",
9
- "skills": "./skills/"
9
+ "skills": "./adapters/claude/skills/"
10
10
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "release-skill",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification",
5
5
  "author": {
6
6
  "name": "release-skill contributors"
7
7
  },
8
8
  "license": "MIT",
9
- "skills": "./skills/",
9
+ "skills": "./adapters/codex/skills/",
10
10
  "interface": {
11
11
  "displayName": "Release Skill",
12
12
  "shortDescription": "Safe preparation and frozen GitHub/npm publishing",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "defaultPrompt": [
21
21
  "Assess this project for release readiness.",
22
- "Prepare a release plan for version 0.1.1.",
22
+ "Prepare a release plan for version 0.1.4.",
23
23
  "Help me understand the release workflow."
24
24
  ]
25
25
  }
package/CHANGELOG.md CHANGED
@@ -3,6 +3,95 @@
3
3
  All notable changes to the `release-skill` plugin will be documented in this
4
4
  file. The format is based on [Keep a Changelog](https://keepachangelog.com/).
5
5
 
6
+ ## [0.1.4] - 2026-07-19
7
+
8
+ ### Added
9
+
10
+ - **Docs version hard gate**: the English and Chinese README and INSTALL each
11
+ carry a machine-readable `release-skill:release-version` marker that must
12
+ equal the `package.json` version, and the CHANGELOG must carry a formal
13
+ heading for the current version. Any drift fails closed in
14
+ `pnpm test:release` before prepare. A release freezes only the current
15
+ truth: human docs are never auto-refreshed and must be updated, reviewed,
16
+ and approved first.
17
+ - **Auditable frozen commit timestamps**: production `prepare` samples the
18
+ plan freeze time once, validates it before any Git write, and binds it to
19
+ `GIT_AUTHOR_DATE`/`GIT_COMMITTER_DATE` and each unit's
20
+ `frozenSnapshot.commitTimestamp` (schema-required); plans missing the field
21
+ are rejected instead of silently rebuilt.
22
+
23
+ ### Fixed
24
+
25
+ - **Self-contained installed CLI smoke**: the v0.1.3 self-release selected
26
+ `help --json`, which correctly treats Git as a required environment
27
+ dependency, while npm smoke intentionally exposes only the Node runtime.
28
+ The CLI now supports `--version --json`, and self-release verification uses
29
+ that dependency-free entry to bind the installed CLI name and exact version
30
+ without widening the isolated process `PATH`.
31
+ - Added a real subprocess regression that runs the installed-style version
32
+ entry with the Node-only `PATH` and proves an unrelated injected path is not
33
+ inherited.
34
+
35
+ ## [0.1.3] - 2026-07-19
36
+
37
+ > `0.1.2` was an internal release candidate and was never published to npm or
38
+ > GitHub Releases. Its fixes are included here; `0.1.3` is the next public
39
+ > release after `0.1.1`.
40
+
41
+ ### Added
42
+
43
+ - **Create-once first-use setup**: `release-skill setup` performs deterministic,
44
+ read-only discovery of packages, plugin manifests, Git remotes, legacy
45
+ `public-release.json`, public-file hints, and project quality scripts. It
46
+ reports `NEEDS_INPUT` or `LOCAL_ONLY_DETECTED` honestly and writes only an
47
+ absent `.release-skill/project.yaml` after answers and the exact
48
+ `setupDigest` are confirmed.
49
+ - **Discoverable `release-setup` skill**: Claude and Codex adapters now guide
50
+ users through candidate review, explicit gate selection, fact-drift handling,
51
+ and the safe handoff to `release-assess` without regenerating human content.
52
+ - **Project verification gates**: `snapshot-verify` runs selected commands in a
53
+ disposable writable copy of the frozen public snapshot;
54
+ `consumer-verify` runs after an exact isolated npm/Claude/Codex installation.
55
+ Gate definitions, exact execution-input digests, and bounded output digests
56
+ are frozen into plan/run evidence.
57
+ - **Identity-bound create-once setup**: the final facts/answers digest and
58
+ config bytes are bound immediately before a directory-handle-relative,
59
+ no-follow create. v0.1.3 ships a digest-registered `darwin-arm64` prebuild;
60
+ unsupported platforms fail closed instead of using pathname writes.
61
+ - **Explicit production branch strategies**: projects can create an immutable
62
+ release branch, fast-forward an existing branch from an exact bound baseline,
63
+ or initialize an absent standard branch and make a separately approved,
64
+ observable, reconcilable default-branch change.
65
+
66
+ ### Changed
67
+
68
+ - Existing `public-release.json` snapshot commands are surfaced only as
69
+ migration candidates. Discovery never grants execution authority; gate and
70
+ legacy-hook side effects still require separate explicit acknowledgements.
71
+ - Compatibility configurations for artifact-graph, flow-architect, loop-agent,
72
+ and agent-method-registry now bind real tag/channel/baseline semantics and
73
+ project-owned verification behavior. glaf4-test is represented as local-only
74
+ instead of receiving an invented remote channel.
75
+ - README and installation guidance now begin with safe setup, explain the three
76
+ branch strategies, and distinguish pre-freeze hooks from frozen-snapshot and
77
+ installed-consumer gates.
78
+
79
+ ### Fixed
80
+
81
+ - **GitHub CLI Release-missing plain text compatibility**: `gh release view`
82
+ returns plain text `release not found` when the target release does not
83
+ exist; the previous implementation only recognized an HTTP 404 exit code.
84
+ The adapter now maps that specific plain text to a missing-release
85
+ decision without misclassifying `repository not found` or permission
86
+ errors as a target release absence.
87
+ - **Plugin consumer install verification transport semantics**: frozen
88
+ snapshots are sealed as read-only, but Git and plugin installation
89
+ transport restores owner write permission on extraction. Verification
90
+ now normalizes ordinary write permission from transport semantics and
91
+ continues to strictly verify path, type, content, size, and executable
92
+ intent. The frozen source digest is still compared against the plan and
93
+ must not be back-filled from observed results.
94
+
6
95
  ## [0.1.1] - 2026-07-18
7
96
 
8
97
  ### Fixed
package/INSTALL.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Installation Guide
2
2
 
3
+ [简体中文](INSTALL.zh-CN.md)
4
+
5
+ <!-- release-skill:release-version: 0.1.4 -->
3
6
  ## Prerequisites
4
7
 
5
8
  - Node.js 22.0.0 or later
@@ -7,9 +10,10 @@
7
10
 
8
11
  ## Install from npm (recommended)
9
12
 
10
- This repository is currently preparing the v0.1.1 release. Use the npm path
11
- only after `npm view release-skill version` returns `0.1.1` (or newer). Before
12
- that publication is verified, use the source checkout instructions below.
13
+ A public version is complete only after its immutable production plan has been
14
+ approved, published, and reached `VERIFIED`. For a newer source checkout, use
15
+ the npm path only after `npm view release-skill version` returns that exact
16
+ version; before then, use the source checkout instructions below.
13
17
 
14
18
  ```bash
15
19
  npm install -g release-skill
@@ -61,7 +65,124 @@ instructions above; do not mix the two entry paths in one run.
61
65
  "${CLI[@]}" help
62
66
  ```
63
67
 
64
- To check if your project is ready for release governance:
68
+ If `.release-skill/project.yaml` is absent, keep the full read-only report in a
69
+ temporary file and inspect only its deterministic `compactSummary`:
70
+
71
+ ```bash
72
+ PROJECT=/path/to/your/project
73
+ SETUP_SESSION="$(mktemp -d "${TMPDIR:-/tmp}/release-setup.XXXXXX")"
74
+ REPORT="$SETUP_SESSION/discovery.json"
75
+ ANSWERS="$SETUP_SESSION/answers.json"
76
+ BOUND_REPORT="$SETUP_SESSION/bound.json"
77
+ printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
78
+
79
+ "${CLI[@]}" setup --root "$PROJECT" --json > "$REPORT" || test "$?" -eq 2
80
+ node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if(!r.compactSummary){console.error("compactSummary missing");process.exit(2)}process.stdout.write(JSON.stringify(r.compactSummary,null,2)+"\n")' "$REPORT"
81
+ ```
82
+
83
+ The summary is a review view, not authorization; `setupDigest` binds the full
84
+ facts, candidates, and answers. If `proposalConflicts` is non-empty, a human
85
+ must correct the conflicting repository/mapping authority and rerun setup.
86
+ Do not guess. With no conflicts, mechanically extract the proposal:
87
+
88
+ ```bash
89
+ SETUP_SESSION='/session-directory-absolute-path-printed-above'
90
+ PROJECT='/project-absolute-path-printed-above'
91
+ REPORT="$SETUP_SESSION/discovery.json"
92
+ ANSWERS="$SETUP_SESSION/answers.json"
93
+ BOUND_REPORT="$SETUP_SESSION/bound.json"
94
+ node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if((r.proposalConflicts??[]).length){console.error("proposal conflicts require human resolution");process.exit(2)}if(!r.recommendedAnswers){console.error("recommendedAnswers missing");process.exit(2)}fs.writeFileSync(process.argv[2],JSON.stringify(r.recommendedAnswers,null,2)+"\n",{flag:"wx",mode:0o600})' "$REPORT" "$ANSWERS"
95
+ "${CLI[@]}" setup --root "$PROJECT" --answers "$ANSWERS" --json > "$BOUND_REPORT"
96
+ node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if(!r.compactSummary||!r.setupDigest){console.error("bound setup report incomplete");process.exit(2)}process.stdout.write(JSON.stringify({compactSummary:r.compactSummary,setupDigest:r.setupDigest},null,2)+"\n")' "$BOUND_REPORT"
97
+ printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
98
+ ```
99
+
100
+ After one explicit human confirmation of the bound summary and exact digest,
101
+ create once with that confirmed digest literal. The result must be
102
+ `CONFIG_CREATED`; a second setup must be `ALREADY_CONFIGURED`, then run assess.
103
+
104
+ ```bash
105
+ SETUP_SESSION=<session-directory-absolute-path-printed-above>
106
+ PROJECT=<project-absolute-path-printed-above>
107
+ ANSWERS="$SETUP_SESSION/answers.json"
108
+ CREATED_REPORT="$SETUP_SESSION/created.json"
109
+ POST_REPORT="$SETUP_SESSION/post-setup.json"
110
+ ASSESS_REPORT="$SETUP_SESSION/assess.json"
111
+ "${CLI[@]}" setup --root "$PROJECT" --answers "$ANSWERS" \
112
+ --write --confirm-setup <confirmed-setupDigest> --json > "$CREATED_REPORT"
113
+ "${CLI[@]}" setup --root "$PROJECT" --json > "$POST_REPORT"
114
+ set +e
115
+ "${CLI[@]}" assess --root "$PROJECT" --offline --json > "$ASSESS_REPORT"
116
+ ASSESS_EXIT=$?
117
+ set -e
118
+ [ "$ASSESS_EXIT" -eq 0 ] || [ "$ASSESS_EXIT" -eq 1 ] || exit "$ASSESS_EXIT"
119
+ node -e 'const fs=require("node:fs");const [c,p,a]=process.argv.slice(1).map(x=>JSON.parse(fs.readFileSync(x,"utf8")));if(c.status!=="CONFIG_CREATED"||p.status!=="ALREADY_CONFIGURED"||!["ASSESSED","NEEDS_INPUT","BLOCKED"].includes(a.status)){process.exit(2)}process.stdout.write(JSON.stringify({created:c.status,postSetup:p.status,assessment:{status:a.status,summary:a.summary,gapCount:(a.gaps??[]).length,blockingCodes:(a.gaps??[]).filter(g=>g.severity==="error").map(g=>g.code)}},null,2)+"\n")' "$CREATED_REPORT" "$POST_REPORT" "$ASSESS_REPORT"
120
+ node -e 'require("node:fs").rmSync(process.argv[1],{recursive:true,force:false})' "$SETUP_SESSION"
121
+ ```
122
+
123
+ Indirect interpreter/package-manager scripts are `SIDE_EFFECTS_UNPROVEN` and
124
+ remain unselected. Register a project-specific hook/gate only through a reviewed
125
+ incremental edit: edit `projectConfig.hooks`, or edit `verificationGates` and
126
+ add the same id to `selectedGateIds`, then rerun the bound dry-run. Human files use `mode: preserve`; explicit cross-unit shared
127
+ sources use `sourceScope: workspace`.
128
+
129
+ ### Advanced schema reference—not the first-run path
130
+
131
+ The following wrapper documents the schema. Do not hand-write it during normal
132
+ setup; use the mechanically extracted `recommendedAnswers`.
133
+
134
+ ```json
135
+ {
136
+ "projectConfig": {
137
+ "apiVersion": "release-skill/v1",
138
+ "kind": "ReleaseProject",
139
+ "project": { "name": "my-project", "defaultBranch": "main" },
140
+ "releaseUnits": [{
141
+ "id": "my-project",
142
+ "source": ".",
143
+ "publicRepo": "owner/my-project",
144
+ "version": { "source": "package.json", "tagTemplate": "v{version}" },
145
+ "distributions": [{
146
+ "type": "npm",
147
+ "package": "my-project",
148
+ "access": "public",
149
+ "provenance": false,
150
+ "tag": "latest",
151
+ "registry": "https://registry.npmjs.org",
152
+ "publisher": "my-npm-username"
153
+ }],
154
+ "publicFiles": [
155
+ { "from": "README.md", "to": "README.md", "mode": "preserve" },
156
+ { "from": "package.json", "to": "package.json", "mode": "preserve" }
157
+ ],
158
+ "requiredPublicFiles": ["README.md", "package.json"],
159
+ "previousPublicBaseline": { "mode": "none" },
160
+ "production": {
161
+ "branchTemplate": "release/{tag}",
162
+ "branchStrategy": "create-release-branch"
163
+ }
164
+ }]
165
+ },
166
+ "selectedGateIds": []
167
+ }
168
+ ```
169
+
170
+ This wrapper is reference data only. Normal setup uses the machine proposal;
171
+ `mode: none` is valid only when no public version exists. When a reviewed gate
172
+ is added incrementally, its id must exactly match `selectedGateIds`, and a
173
+ snapshot gate plus its dependencies must be present in `publicFiles`. See the
174
+ [README setup section](README.md#first-use-deterministic-setup-without-loading-the-full-report).
175
+
176
+ An existing config is never regenerated or overwritten. A project with no
177
+ discoverable GitHub/npm channel reports `LOCAL_ONLY_DETECTED` rather than
178
+ claiming production readiness.
179
+
180
+ The automatic create-once write uses the digest-registered `darwin-arm64`
181
+ native prebuild shipped in v0.1.3. Other platforms fail closed with
182
+ `SAFE_WRITE_UNAVAILABLE`; keep the dry-run report and create the reviewed file
183
+ manually instead of enabling an unsafe pathname fallback.
184
+
185
+ After the config exists, check release readiness:
65
186
 
66
187
  ```bash
67
188
  "${CLI[@]}" assess --root /path/to/your/project --offline --json
@@ -139,12 +260,100 @@ hooks:
139
260
  build:
140
261
  command: [npm, run, build]
141
262
  test:
142
- command: [npm, test]
263
+ command:
264
+ - node
265
+ - -e
266
+ - "const p=require('./package.json'); if (!p.name) process.exit(1)"
143
267
  ```
144
268
 
145
269
  See the [full README](README.md) for hook parameter constraints and safety
146
270
  requirements.
147
271
 
272
+ ### Advanced: verification gates (optional)
273
+
274
+ Use a `snapshot-verify` gate for checks that should run against a disposable
275
+ writable copy of the frozen public snapshot. Use `consumer-verify` for commands
276
+ that must run from an exact isolated npm/Claude/Codex installation root. Gate
277
+ commands are executable arrays, not shell strings, and must declare unit,
278
+ distribution when applicable, cwd, timeout, and environment allowlist.
279
+
280
+ ```yaml
281
+ verificationGates:
282
+ - id: package-contract
283
+ phase: snapshot-verify
284
+ scope: { unit: my-project }
285
+ command: [node, -e, "const p=require('./package.json');if(!p.name)process.exit(1)"]
286
+ cwd: .
287
+ timeoutMs: 30000
288
+ envAllowlist: []
289
+ ```
290
+
291
+ This self-contained example reads only a mapped public file. A replacement
292
+ script and every dependency it needs must exist in the frozen public snapshot;
293
+ the gate cannot borrow tests, development dependencies, or `node_modules` from
294
+ the parent workspace.
295
+
296
+ Prepare and verify require `--acknowledge-gate-side-effects` whenever their
297
+ planned phase contains gates. Hooks and gates are project processes without a
298
+ network sandbox; release-skill limits their inputs and evidence but cannot
299
+ guarantee that a custom command will not modify files or access the network.
300
+ Never register Git push, tag, default-branch changes, GitHub Releases, or npm
301
+ publish as a hook/gate; those are controlled plan actions.
302
+
303
+ ### Production branch strategy
304
+
305
+ Every production unit selects one explicit strategy:
306
+
307
+ - `create-release-branch` creates an absent immutable release branch;
308
+ - `advance-existing-branch` fast-forwards an existing branch from the exact
309
+ bound public baseline using an ordinary non-force push;
310
+ - `initialize-default-branch` creates an absent standard branch and may add an
311
+ explicit default-branch action only when `setAsDefaultBranch` and
312
+ `expectedCurrentDefaultBranch` are both reviewed.
313
+
314
+ Remote drift, a non-fast-forward update, or an unexpected default branch stops
315
+ for human intervention. No strategy overwrites remote history. Create-only refs
316
+ use `--force-with-lease=<ref>:` solely as an atomic absence assertion; advancing
317
+ an existing branch uses an ordinary non-force push.
318
+
319
+ ```yaml
320
+ # create-release-branch: target must be absent
321
+ previousPublicBaseline: { mode: none } # true first public release only
322
+ production:
323
+ branchTemplate: release/{tag}
324
+ branchStrategy: create-release-branch
325
+ ```
326
+
327
+ ```yaml
328
+ # advance-existing-branch: ref must exactly equal refs/heads/<target>
329
+ previousPublicBaseline:
330
+ mode: bound
331
+ repo: owner/my-project
332
+ ref: refs/heads/main
333
+ commit: 0123456789abcdef0123456789abcdef01234567
334
+ production:
335
+ branchTemplate: main
336
+ branchStrategy: advance-existing-branch
337
+ ```
338
+
339
+ ```yaml
340
+ # initialize-default-branch: main must be absent; current default must match
341
+ previousPublicBaseline:
342
+ mode: bound
343
+ repo: owner/my-project
344
+ ref: refs/heads/old-public-branch
345
+ commit: 0123456789abcdef0123456789abcdef01234567
346
+ production:
347
+ branchTemplate: main
348
+ branchStrategy: initialize-default-branch
349
+ setAsDefaultBranch: true
350
+ expectedCurrentDefaultBranch: old-public-branch
351
+ ```
352
+
353
+ The last two strategies require online production prepare. Any mismatch stops
354
+ for review; update the human-owned config only after inspecting real remote
355
+ state, and never force-push or weaken the baseline.
356
+
148
357
  ## Protect Human-Owned Content
149
358
 
150
359
  README text, slogans, examples, layout, and other manually curated source files
@@ -167,6 +376,8 @@ When an existing public copy has drifted, choose explicitly:
167
376
  ## Next Steps
168
377
 
169
378
  - Read the [full README](README.md) for the complete workflow guide.
379
+ - Run `"${CLI[@]}" setup --root <your-project> --json` when the project has no
380
+ configuration; keep its default dry-run behavior until human decisions are complete.
170
381
  - Run `"${CLI[@]}" assess --root <your-project> --offline` to evaluate your project's release readiness.
171
382
  - Run `"${CLI[@]}" prepare --root <your-project> --offline` (release-skill pipeline writes
172
383
  locally only; user-configured hooks may perform remote operations) to generate