code-foundry 1.11.0 → 1.13.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.
@@ -7,6 +7,7 @@ on:
7
7
  branches: [main, staging]
8
8
  types:
9
9
  - ready_for_review
10
+ - synchronize
10
11
 
11
12
  # Default every caller job to no repository permissions. Individual jobs grant
12
13
  # only the scopes their own validation path consumes.
@@ -20,9 +21,10 @@ concurrency:
20
21
  jobs:
21
22
  mode:
22
23
  name: Mode
23
- # The mode classifier is only needed for pull requests. Main pushes use
24
- # the dedicated default-branch CodeQL lane below.
25
- if: vars.CI_BILLING_PAUSED != 'true' && github.event_name == 'pull_request'
24
+ # The mode classifier is only needed for ready pull requests. Main pushes
25
+ # use the dedicated default-branch CodeQL lane below; draft updates do not
26
+ # allocate a validation runner.
27
+ if: vars.CI_BILLING_PAUSED != 'true' && github.event_name == 'pull_request' && github.event.pull_request.draft == false
26
28
  runs-on: ubuntu-slim
27
29
  timeout-minutes: 10
28
30
  permissions:
@@ -62,7 +64,7 @@ jobs:
62
64
  validation:
63
65
  name: Validation
64
66
  needs: mode
65
- if: vars.CI_BILLING_PAUSED != 'true' && github.event_name == 'pull_request'
67
+ if: vars.CI_BILLING_PAUSED != 'true' && github.event_name == 'pull_request' && github.event.pull_request.draft == false
66
68
  # Reusable workflows can only maintain or reduce the caller job's scopes.
67
69
  # The audit tier needs security-events: write for CodeQL uploads.
68
70
  permissions:
package/AGENTS.md CHANGED
@@ -103,13 +103,14 @@ This repository uses the `direct` workflow. Topic pull requests target `main`.
103
103
  - Open every ordinary pull request as a draft. Use `gh pr create --draft` or
104
104
  set `draft: true` in the GitHub API; never create a ready ordinary pull
105
105
  request as a shortcut.
106
- - Keep ordinary pull requests in draft while making commits. The generated
107
- Draft Guard resets a ready ordinary pull request to draft on creation,
108
- reopening, or a new commit, and runner-heavy validation starts only after an
106
+ - Keep ordinary pull requests in draft while preparing them. The generated
107
+ Draft Guard converts ready ordinary pull requests to draft when they are
108
+ opened or reopened, and runner-heavy validation starts only after an
109
109
  explicit `ready_for_review` transition.
110
110
  - Run local validation and finish review preparation before marking an ordinary
111
- pull request ready. After any later commit, mark it ready again only after
112
- the current head is ready for review.
111
+ pull request ready. Ready pull requests stay ready when new commits arrive,
112
+ and validation reruns for the current head; draft updates allocate no
113
+ validation runner until the pull request is ready.
113
114
  - This contract is mandatory for every agent scope. Nested `AGENTS.md` files
114
115
  may add stricter rules but must not weaken or replace it.
115
116
  - Release Please version pull requests are managed by the Code Foundry release
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.13.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.12.0...v1.13.0) (2026-09-09)
4
+
5
+
6
+ ### Features
7
+
8
+ * **fleet:** add declared inventory and resumable canary rollouts ([#536](https://github.com/0xPlayerOne/code-foundry/issues/536)) ([6aa86d4](https://github.com/0xPlayerOne/code-foundry/commit/6aa86d4cd85cdbd4041c70d8c01d8e351e21fc0b))
9
+
10
+ ## [1.12.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.11.0...v1.12.0) (2026-09-09)
11
+
12
+
13
+ ### Features
14
+
15
+ * **cloudflare:** verify candidates before protected version promotion ([#535](https://github.com/0xPlayerOne/code-foundry/issues/535)) ([5dd9afa](https://github.com/0xPlayerOne/code-foundry/commit/5dd9afa8418718823844875b0aedce926b887184))
16
+
3
17
  ## [1.11.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.10.1...v1.11.0) (2026-09-09)
4
18
 
5
19
 
package/README.md CHANGED
@@ -76,12 +76,13 @@ The standard workflow triggers are:
76
76
 
77
77
  Automated feature/fix and staging-promotion pull requests open as drafts.
78
78
  The trusted Draft Guard is a fallback for manually created or reopened ready
79
- PRs and for new commits to ordinary ready PRs: it converts them to drafts
80
- without checking out PR code. It verifies the event head and update timestamp
81
- before changing state, and excludes Release Please version PRs whose release
82
- workflow owns readiness. Pull-request validation runs only on the
83
- ready-for-review transition. Converting a PR to draft runs only the lightweight
84
- cancellation control. Scheduled and manually dispatched audits are unaffected.
79
+ PRs: it converts them to drafts without checking out PR code. It verifies the
80
+ event head and update timestamp before changing state, and excludes Release
81
+ Please version PRs whose release workflow owns readiness. Pull-request
82
+ validation runs on the ready-for-review transition and on new commits while a
83
+ PR remains ready; draft updates allocate no validation runner. Converting a PR
84
+ to draft runs only the lightweight cancellation control. Scheduled and manually
85
+ dispatched audits are unaffected.
85
86
 
86
87
  Jobs are language-aware and skip irrelevant setup inside the applicable
87
88
  aggregate checks. TypeScript uses Oxlint, Oxfmt, and Bun's native
@@ -179,15 +179,23 @@ shards. Do not split a single crate by arbitrary non-Rust directories: use
179
179
  ## Cloudflare Workers deployments
180
180
 
181
181
  Repositories that deploy to Cloudflare Workers can opt into GitHub-native
182
- deployments (Preview/Production environments with deployment statuses, like
183
- Vercel's integration) by adding a small caller for the runtime's reusable
184
- `cloudflare-deploy.yml` workflow. The workflow runs `wrangler versions upload`
185
- for pull-request previews and `wrangler deploy` for production, records a
186
- GitHub deployment plus status with the workers.dev URL, and respects
187
- `CI_BILLING_PAUSED`. It requires the `CLOUDFLARE_API_TOKEN` and
188
- `CLOUDFLARE_ACCOUNT_ID` secrets in the consumer repository. Bun consumers may
189
- also pass `build-script`, `install-working-directory`, and `bun-version`; the
190
- runtime installs the frozen lockfile and builds the Worker before invoking
182
+ verified delivery (fixed `Preview`/`Production` environments, candidate
183
+ verification, and version-identity promotion) by adding a caller for the
184
+ runtime's reusable `cloudflare-delivery.yml` workflow. Use the same immutable
185
+ 40-character Code Foundry commit SHA for both the reusable workflow ref and
186
+ `runtime-ref`; configure required reviewers and branch restrictions on the
187
+ `Production` environment. The workflow requires the
188
+ `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` secrets in the consumer
189
+ repository. See [Verified Cloudflare delivery](./cloudflare-delivery.md) for
190
+ binding policy, canary, rollback, and evidence requirements.
191
+
192
+ The legacy `cloudflare-deploy.yml` workflow remains available for direct
193
+ (unverified) deployments. It runs `wrangler versions upload` for previews and
194
+ `wrangler deploy` for production, records a GitHub deployment plus status, and
195
+ respects `CI_BILLING_PAUSED`. Its legacy-compatible Wrangler default is `latest`;
196
+ callers should prefer `local` or provide an exact `wrangler-version` for
197
+ reproducibility. Bun consumers may pass `build-script`, `install-working-directory`, and `bun-version`;
198
+ the runtime installs the frozen lockfile and builds the Worker before invoking
191
199
  Wrangler. Bun-backed callers invoke Wrangler through `bunx` so OpenNext's
192
200
  production delegation resolves the workspace-local `opennextjs-cloudflare`
193
201
  binary; callers without `build-script` retain the npm/npx path.
@@ -15,9 +15,9 @@ belong to the run that produced them, not the source tree.
15
15
  | Format, lint, type-check, and build | 15 s | Bound the local CI feedback loop |
16
16
  | Runtime dependencies | 0 | Keep the installed CLI dependency-free |
17
17
  | Development dependencies | 4 | Prevent unreviewed toolchain growth |
18
- | Packed artifact | 200 kB | Bound registry transfer and install cost |
19
- | Unpacked artifact | 750 kB | Bound installed footprint |
20
- | Packed files | 80 | Detect accidental release contents |
18
+ | Packed artifact | 210 kB | Bound registry transfer and install cost |
19
+ | Unpacked artifact | 800 kB | Bound installed footprint |
20
+ | Packed files | 90 | Detect accidental release contents |
21
21
 
22
22
  The performance workflow disables build-cache reads and writes for this task.
23
23
  That makes timing comparisons independent of a warm protected-branch cache and
package/docs/README.md CHANGED
@@ -14,6 +14,7 @@ its own names, environments, and deployment details.
14
14
  - [Caching and remote caching](CACHING.md)
15
15
  - [Performance budgets and baselines](PERFORMANCE.md)
16
16
  - [Required capabilities and task evidence](required-capabilities.md)
17
+ - [Declarative fleet inventory and staged rollouts](fleet-rollouts.md)
17
18
 
18
19
  ## Repository-specific documentation
19
20
 
package/docs/WORKFLOWS.md CHANGED
@@ -15,19 +15,19 @@ pull_request:
15
15
  # direct topology: branches: [main]
16
16
  ```
17
17
 
18
- The generated validation caller listens for `ready_for_review` and `push` to
19
- `main`. Draft pull requests register no validation checks and allocate no
20
- validation runner; main pushes run only the default-branch CodeQL lane, while
21
- full validation remains pull-request-only.
22
- A separate lightweight Draft Guard runs from the trusted base branch on
23
- `opened`, `reopened`, and `synchronize`; it converts ordinary ready pull
24
- requests back to draft without checking out pull-request code. It rechecks the
25
- current head and update timestamp before mutating state, so a stale event
26
- cannot undo a later draft or ready transition. Release Please version heads are
27
- excluded because the release workflow owns their state. A separate draft-control
28
- caller listens for `converted_to_draft` and cancels queued or running
29
- pull-request workflows without creating skipped validation jobs. Marking a pull
30
- request ready again starts validation for the current head.
18
+ The generated validation caller listens for `ready_for_review` and
19
+ `synchronize`. Its jobs require the pull request to remain ready, so draft
20
+ updates allocate no validation runner; main pushes run only the default-branch
21
+ CodeQL lane, while full validation remains pull-request-only. A separate
22
+ lightweight Draft Guard runs from the trusted base branch on `opened` and
23
+ `reopened`; it converts ordinary ready pull requests back to draft without
24
+ checking out pull-request code. It rechecks the current head and update
25
+ timestamp before mutating state, so a stale event cannot undo a later draft or
26
+ ready transition. Release Please version heads are excluded because the
27
+ release workflow owns their state. A separate draft-control caller listens for
28
+ `converted_to_draft` and cancels queued or running pull-request workflows.
29
+ Marking a pull request ready starts validation, and each new commit on a ready
30
+ pull request starts it again for the current head.
31
31
 
32
32
  The separate `validation-audit.yml` caller is pinned to the configured released
33
33
  runtime and handles scheduled and manual audits:
@@ -108,7 +108,7 @@ opt in or out without a code change.
108
108
  | Security | Profile, audits, and public-only Dependency Review |
109
109
  | CodeQL | GitHub-native code scanning, kept separate from CI |
110
110
  | Draft PR | Create/update development pull requests |
111
- | Draft Guard | Keep ordinary PRs draft until `ready_for_review` |
111
+ | Draft Guard | Keep opened/reopened ordinary PRs draft until `ready_for_review` |
112
112
  | Release PR | Promote `staging` into `main` (staging-release topology only) |
113
113
  | Release | Release Please, GitHub release, and optional npm publication |
114
114
 
@@ -0,0 +1,188 @@
1
+ # Verified Cloudflare delivery
2
+
3
+ The opt-in `cloudflare-delivery.yml` workflow builds and uploads a candidate,
4
+ validates its actual version bindings, runs an HTTP smoke probe and the required
5
+ repository-owned verification command, then promotes **that version ID** after
6
+ GitHub environment approval. Production promotion uses the Cloudflare deployment
7
+ API and never rebuilds the application. The existing `cloudflare-deploy.yml`
8
+ remains available for direct deployments and initial provisioning.
9
+
10
+ ## Adoption
11
+
12
+ Call the new reusable workflow using an immutable, reviewed 40-character Code
13
+ Foundry commit SHA and pass the same `runtime-ref`. Required inputs are
14
+ `worker-name`, `artifact-path`, and `verify-command`.
15
+
16
+ ```yaml
17
+ jobs:
18
+ delivery:
19
+ # Replace REVIEWED_SHA with the same reviewed 40-character SHA in both places.
20
+ uses: 0xPlayerOne/code-foundry/.github/workflows/cloudflare-delivery.yml@REVIEWED_SHA
21
+ permissions:
22
+ contents: read
23
+ deployments: write
24
+ with:
25
+ runtime-ref: REVIEWED_SHA
26
+ mode: production
27
+ worker-name: company-site
28
+ artifact-path: dist
29
+ verify-command: '["bun", "run", "test:deployed"]'
30
+ production-url: https://example.com
31
+ smoke-path: /health
32
+ canary-percentage: 10
33
+ canary-verify-command: '["bun", "run", "test:canary"]'
34
+ secrets:
35
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
36
+ CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
37
+ ```
38
+
39
+ `artifact-path` is relative to `working-directory`; `install-working-directory`
40
+ selects the lockfile root. The selected output tree is hashed before and after
41
+ upload; changes during upload fail. Include all built code/assets in that tree
42
+ and disable duplicate custom build steps. This digest identifies the declared
43
+ local build tree, not a Cloudflare-signed digest of every uploaded configuration
44
+ field. The Worker version ID is the authoritative identity for promotion.
45
+
46
+ Wrangler defaults to the installed, lockfile-resolved version. Explicit overrides
47
+ must be exact versions, never `latest`, floating majors, or semver ranges. Pin a
48
+ Wrangler version supporting `WRANGLER_OUTPUT_FILE_PATH` and version-1
49
+ `version-upload` records. Missing preview URLs and output-schema mismatches fail.
50
+ Bun remains the installation path, consistent with the existing deploy workflow.
51
+
52
+ The repository verification command receives `BASE_URL` and
53
+ `FOUNDRY_DEPLOYMENT_PHASE` (`candidate`, `canary`, or `production`). It must check
54
+ critical journeys, redirects, assets, and application-specific behavior. The
55
+ built-in smoke probe requires a successful 2xx response and does not follow
56
+ redirects. Deploy credentials are not supplied to verification steps and are
57
+ removed from the verification child environment as defense in depth. Install any
58
+ browser binaries required by your verification command explicitly.
59
+
60
+ When `canary-percentage` is below 100, `canary-verify-command` is required and
61
+ must prove that the live request served the candidate rather than the baseline.
62
+ It receives `FOUNDRY_EXPECTED_VERSION_ID`, `FOUNDRY_DEPLOYMENT_ID`, and
63
+ `FOUNDRY_CANARY_PERCENTAGE`; use a version-aware response/header or an equivalent
64
+ application check. A command that only observes a successful production URL is
65
+ not sufficient.
66
+
67
+ ## Approvals, ordering, and evidence
68
+
69
+ Create and protect the fixed `Preview` and `Production` GitHub environments
70
+ before adoption. The workflow references them at the **job** level; naming an
71
+ environment does not itself configure reviewers or branch restrictions. Configure
72
+ required reviewers and branch restrictions on `Production` separately. Production
73
+ execution requires the current default-branch commit and
74
+ rechecks freshness after approval and before final promotion. Fork PRs and
75
+ `pull_request_target` execution are excluded.
76
+
77
+ Per-repository/Worker/mode concurrency never cancels a running promotion. GitHub
78
+ concurrency is not a FIFO queue; stale-source rejection is still necessary.
79
+ Other deployment systems and dashboard edits are outside this lock. The helper
80
+ also checks that its deployment has not been replaced before a subsequent
81
+ promotion or rollback, but the Cloudflare API check/write is not an atomic CAS.
82
+ Migrate one application to one deployment owner; do not leave competing legacy
83
+ and new production workflows active.
84
+
85
+ Outputs include preview URL, exact version ID, source SHA, declared build-tree
86
+ SHA-256 digest, Cloudflare deployment ID, and GitHub application deployment ID.
87
+ Explicit application deployment records receive in-progress and success/failure
88
+ statuses, in addition to GitHub's environment-job records. Sanitized candidate and
89
+ production JSON evidence is uploaded even on failure. Binding values, API bodies,
90
+ and credentials are not copied into those reports. Forced runner termination may
91
+ prevent final status steps; the GitHub job still reflects cancellation/failure.
92
+
93
+ ## Stateful resources and isolation
94
+
95
+ Without a policy file, non-resource bindings (for example strings, secrets, and
96
+ static assets) are allowed; resource/service bindings fail closed. The uploaded
97
+ version's actual bindings are inspected through the Cloudflare API. Durable
98
+ Object bindings or exports are rejected: use a repository-specific migration and
99
+ preview workflow instead of pretending version preview supports that topology.
100
+
101
+ A reviewed read-only policy can allow smoke testing a candidate that shares
102
+ production resources:
103
+
104
+ ```json
105
+ {
106
+ "schemaVersion": 1,
107
+ "readOnlyBindings": [{ "name": "DB", "type": "d1" }],
108
+ "rollbackSafe": false
109
+ }
110
+ ```
111
+
112
+ Pass its relative path as `binding-policy-file`. This declaration is **not a
113
+ sandbox**: the repository owner must ensure its test routes cannot mutate shared
114
+ data. A version preview does not automatically create isolated KV, R2, D1, or
115
+ service resources, and a GET route can still have side effects.
116
+
117
+ For separately provisioned preview Workers, `isolatedBindings` entries can compare
118
+ the actual binding's resource identifiers with expected preview identifiers and
119
+ assert that they differ from declared production identifiers:
120
+
121
+ ```json
122
+ {
123
+ "schemaVersion": 1,
124
+ "isolatedBindings": [
125
+ {
126
+ "name": "DB",
127
+ "type": "d1",
128
+ "expected": { "id": "preview-database-id" },
129
+ "production": { "id": "production-database-id" }
130
+ }
131
+ ]
132
+ }
133
+ ```
134
+
135
+ Use the field names returned for that binding type by the Version API. Resource
136
+ provisioning and the correctness of production-identifier declarations remain
137
+ repository-owned. Isolated preview bindings are rejected in production mode to
138
+ prevent accidentally promoting staging resources. A version from a different
139
+ Worker cannot be promoted across Workers; production mode uploads and tests its
140
+ own candidate on the production Worker with reviewed read-only tests.
141
+
142
+ ## Canary and rollback policy
143
+
144
+ A percentage below 100 first routes that share to the candidate, verifies it,
145
+ and then promotes the same version to 100 and verifies again. A canary requires
146
+ one prior baseline serving 100% and the explicit `canary-verify-command` above.
147
+ A single load-balanced HTTP request may hit the old version; the command must
148
+ observe the expected version ID. Set `canary-percentage: 100` when that
149
+ version-aware observability is not configured.
150
+
151
+ Automatic rollback is off. Enabling `auto-rollback` also requires an explicit
152
+ `rollbackSafe: true` policy and both current and prior versions to be free of
153
+ stateful bindings/DO exports. The policy must additionally account for external
154
+ side effects that binding inspection cannot detect. Rollback restores the exact
155
+ previous traffic split only when this run's deployment is still current. Failure
156
+ remains a failed deployment even after rollback. Resource data, migrations,
157
+ external API side effects, routes, and non-versioned settings are never rewound.
158
+ The evidence file records prior versions for manual recovery when automation is
159
+ unsafe or unavailable. Recovery itself must be verified operationally.
160
+
161
+ This workflow targets already-provisioned Workers with version previews enabled.
162
+ Manage initial Worker/route/trigger setup and non-versioned settings separately;
163
+ the deployment API intentionally changes version routing only.
164
+
165
+ ## Legacy workflow hardening
166
+
167
+ `cloudflare-deploy.yml` now uses real job environments, non-cancelling concurrency,
168
+ structured Wrangler output, exact/local Wrangler selection, reusable outputs, and
169
+ in-progress/failure deployment records. Its legacy-compatible default remains
170
+ `latest`; callers should prefer `local` or an exact version for reproducibility. A
171
+ production URL can be supplied with `deployment-url` when API output contains only
172
+ route patterns. It is still a **direct, unverified deployment**; adopt
173
+ `cloudflare-delivery.yml` for candidate verification and guarded promotion.
174
+
175
+ ## References and testing
176
+
177
+ The implementation follows Cloudflare's structured Wrangler output and version
178
+ routing APIs:
179
+
180
+ - https://developers.cloudflare.com/workers/wrangler/system-environment-variables/
181
+ - https://developers.cloudflare.com/workers/versions-and-deployments/
182
+ - https://developers.cloudflare.com/api/resources/workers/subresources/scripts/subresources/versions/methods/get/
183
+ - https://developers.cloudflare.com/api/resources/workers/subresources/scripts/subresources/deployments/methods/create/
184
+
185
+ Run `node --test test/cloudflare-delivery.test.mjs`. Tests use deterministic API
186
+ responses and never deploy a Worker. Before production rollout, run the new
187
+ workflow against a disposable Worker and protected test environments, including
188
+ smoke failure and rollback scenarios.
@@ -0,0 +1,139 @@
1
+ # Declarative fleet inventory and staged rollouts
2
+
3
+ Place `code-foundry-fleet.json` in the directory passed to `--root`. Its presence
4
+ opts that fleet into inventory-based discovery and controlled upgrades, without
5
+ changing legacy directory discovery for existing users.
6
+
7
+ ```json
8
+ {
9
+ "schemaVersion": 1,
10
+ "cohorts": ["canary", "applications"],
11
+ "repositories": [
12
+ {
13
+ "repository": "owner/package-canary",
14
+ "path": "packages/package-canary",
15
+ "cohort": "canary",
16
+ "profile": "published-package",
17
+ "expected": { "git_workflow": "direct" },
18
+ "requiredCapabilities": ["unit", "performance"],
19
+ "validation": [
20
+ ["bun", "install", "--frozen-lockfile"],
21
+ ["bun", "run", "test:unit"],
22
+ ["bun", "run", "test:consumer"],
23
+ ["bun", "run", "performance:check"]
24
+ ],
25
+ "requiredChecks": ["Validation / Gate"]
26
+ },
27
+ {
28
+ "repository": "owner/application",
29
+ "path": "applications/application",
30
+ "cohort": "applications",
31
+ "validation": [
32
+ ["bun", "install", "--frozen-lockfile"],
33
+ ["bun", "run", "type-check"],
34
+ ["bun", "run", "test:unit"]
35
+ ],
36
+ "requiredChecks": ["Validation / Gate"]
37
+ }
38
+ ]
39
+ }
40
+ ```
41
+
42
+ Repository names in the example are placeholders. Populate the actual fleet
43
+ before use. Paths are relative to the manifest, may be arbitrarily nested, and
44
+ must not escape through `..`, absolute paths, or symlinks. Missing checkouts and
45
+ origin mismatches remain visible as blocked inventory entries rather than silently
46
+ disappearing. There is no automatic clone or repository-settings mutation.
47
+
48
+ `profile` is a descriptive inventory annotation; it does not install tools or
49
+ activate a quality profile. `expected` maps scalar `.github/code-foundry.yml` keys
50
+ to desired values; `requiredCapabilities` audits declarations in that same file.
51
+ The runtime-upgrade operation does not silently author missing capability policy.
52
+ Adopt those requirements in consumer repositories before requiring them here.
53
+
54
+ ## Commands
55
+
56
+ ```sh
57
+ code-foundry fleet status --root /path/to/fleet
58
+ code-foundry fleet upgrade --root /path/to/fleet --dry-run
59
+ code-foundry fleet upgrade --root /path/to/fleet --create-pr
60
+ ```
61
+
62
+ Run from the intended released Code Foundry installation/checkout. The existing
63
+ source-version guard still rejects mismatched `--version` requests. Manifest mode
64
+ requires `--create-pr` or `--dry-run` and never syncs original checkouts in place.
65
+ `--force` does not bypass dirty-tree safety in manifest mode. Dry-run reports
66
+ inventory, target version, and configuration drift without network calls, running
67
+ consumer commands, or modifying files. Status likewise audits local facts; it does
68
+ not pretend to verify remote branch protection or environment settings.
69
+
70
+ The first incomplete cohort is the only cohort allowed to create PRs. All
71
+ non-excepted members of each earlier cohort must have a matching managed upgrade
72
+ PR that is merged, successful explicitly named required checks on its head SHA,
73
+ no still-pending/failed checks, and the target runtime/configuration still present
74
+ on its current base branch. Neutral/skipped required checks do not qualify.
75
+ Unknown, inaccessible, closed-without-merge, stale, or failed evidence does not
76
+ unlock subsequent cohorts. One local validation failure stops remaining work.
77
+
78
+ Each repository must supply explicit validation argv arrays. Include locked
79
+ installation, application checks, and genuine consumer compatibility tests where
80
+ relevant. No shell splitting is used. Commands run in an isolated detached
81
+ worktree, have bounded execution time, and must not rewrite the candidate source.
82
+ Validation is not a security sandbox: commands run as the invoking user with its
83
+ inherited environment and network access. Treat the manifest and every validation
84
+ command as trusted code; do not use this feature with unreviewed manifests or
85
+ credentials that the checks should not access.
86
+ Only files changed by Code Foundry sync are staged; generated test evidence and
87
+ other untracked files are not swept into the commit. A commit-hook change to the
88
+ validated Git tree is rejected before publishing.
89
+
90
+ This implementation does not create an automatic scheduler, mark PRs ready,
91
+ merge PRs, lower checks, or bypass review. After reviewing and validating canaries,
92
+ merge their PRs normally and run the fleet command again to advance the cohort.
93
+ A repository already at the target version with no managed PR does not establish
94
+ canary evidence; choose a real upgrade canary rather than treating an empty diff
95
+ as successful rollout validation.
96
+
97
+ ## Resuming and intentional exceptions
98
+
99
+ The target version and complete repository policy produce a deterministic branch
100
+ and PR marker. Repeated runs return an existing matching open PR instead of
101
+ creating duplicates. If push succeeded but PR creation failed, the next run
102
+ recognizes the managed commit and recorded tree identity, reruns consumer
103
+ validation, and creates the missing **draft** PR without force-pushing. Unknown
104
+ branches or commits with mismatched tree markers are preserved and blocked for
105
+ manual review. Local managed refs preserve committed work after a failed push.
106
+ The marker is an ownership/recovery guard, not a cryptographic signature.
107
+
108
+ PR creation is draft-first in both manifest and legacy discovery modes. A PR that
109
+ a human has already made ready is not silently converted back or modified.
110
+
111
+ An entry may include a reviewed time-limited exception:
112
+
113
+ ```json
114
+ { "exception": { "reason": "Pending consumer compatibility work", "expires": "2026-10-01" } }
115
+ ```
116
+
117
+ Exceptions appear explicitly in inventory/rollout output. Expired/invalid dates
118
+ fail parsing. The command's existing `--exclude` flag is also honored. Excluding
119
+ all canaries never satisfies a canary gate or unlocks later cohorts. Update the
120
+ manifest deliberately when cohort membership or compatibility policy changes.
121
+
122
+ ## Evidence and tests
123
+
124
+ Upgrade output is schema-versioned JSON with target version, aggregate status,
125
+ per-repository cohort/status, PR link, and local validation command exit statuses.
126
+ Failed command output is not copied into reports, avoiding accidental credentials
127
+ in logs; reproduce the declared command locally for full debugging output. A
128
+ failed rollout returns a nonzero exit status. Pending PRs are not failures and do
129
+ not grant permission to advance a cohort. Worktree cleanup failures preserve the
130
+ isolated path and report it rather than deleting unknown paths.
131
+
132
+ `node --test test/fleet-manifest.test.mjs` includes actual local Git repositories,
133
+ bare remotes, isolated worktrees, validation failure, orphan-branch recovery,
134
+ clean-original preservation, and canary advancement. Only GitHub responses are
135
+ fixture-backed; no real fleet repositories or remote PRs are modified by tests.
136
+
137
+ GitHub CLI contracts:
138
+ https://cli.github.com/manual/gh_pr_list
139
+ https://cli.github.com/manual/gh_pr_create
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "1.11.0",
3
+ "version": "1.13.0",
4
4
  "description": "A fast, language-aware repository factory for agent-ready workflows, testing, security, and release automation.",
5
5
  "homepage": "https://github.com/0xPlayerOne/code-foundry#readme",
6
6
  "bugs": {