code-foundry 0.37.1 → 0.37.3

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.
@@ -402,7 +402,7 @@ jobs:
402
402
  needs.detect.outputs.enabled == 'true' &&
403
403
  needs.detect.outputs.rust_available == 'true' &&
404
404
  needs.detect.outputs.rust_changed == 'true'
405
- uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4
405
+ uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
406
406
  with:
407
407
  languages: rust
408
408
  build-mode: ${{ needs.detect.outputs.rust_build_mode }}
@@ -413,7 +413,7 @@ jobs:
413
413
  needs.detect.outputs.enabled == 'true' &&
414
414
  needs.detect.outputs.rust_available == 'true' &&
415
415
  needs.detect.outputs.rust_changed == 'true'
416
- uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4
416
+ uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
417
417
  with:
418
418
  category: /language:rust/${{ steps.scope.outputs.scope_id }}
419
419
  upload-database: false
@@ -31,7 +31,7 @@ jobs:
31
31
  cancel-in-progress: true
32
32
  steps:
33
33
  - name: Checkout
34
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
34
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
35
35
  with:
36
36
  persist-credentials: false
37
37
  fetch-depth: 0
@@ -245,44 +245,14 @@ jobs:
245
245
  fi
246
246
  node "$RUNNER_TEMP/code-foundry/src/cli.mjs" release validate-prs
247
247
  for pr in "${release_prs[@]}"; do
248
- echo "Waiting for required checks on release PR #$pr"
249
- checks_seen=false
250
- for attempt in $(seq 1 60); do
251
- : "$attempt"
252
- if required_count=$(gh pr checks "$pr" \
253
- --repo "$GITHUB_REPOSITORY" \
254
- --required \
255
- --json name \
256
- --jq 'length' 2>/dev/null); then
257
- if [ "$required_count" -gt 0 ]; then
258
- checks_seen=true
259
- break
260
- fi
261
- fi
262
- sleep 5
263
- done
264
- if [ "$checks_seen" != true ]; then
265
- echo "Required checks were not registered for release PR #$pr within the readiness window." >&2
266
- exit 1
267
- fi
268
- gh pr checks "$pr" \
269
- --repo "$GITHUB_REPOSITORY" \
270
- --required \
271
- --watch \
272
- --fail-fast \
273
- --interval 10
274
- # gh pr checks --watch only waits for checks registered when the
275
- # watch starts; a ruleset may register additional required checks
276
- # afterwards (observed: "Validation / Gate" appearing after
277
- # "Tauri 2 / Linux" had passed), which leaves the PR blocked by
278
- # branch policy at merge time. Poll mergeStateStatus and accept
279
- # only states GitHub reports as mergeable: CLEAN, or UNSTABLE with
280
- # mergeable MERGEABLE. UNSTABLE is still mergeable when only
281
- # non-required checks are failing or still running (observed: Kilo
282
- # Code Review running after every required check passed); keep
283
- # waiting for BLOCKED/BEHIND/UNKNOWN, fail fast on
284
- # DIRTY/CONFLICTING, and fail closed on a bounded timeout so the
285
- # workflow never sleeps indefinitely.
248
+ # GitHub's merge state is the authoritative required-check gate.
249
+ # `gh pr checks --required` is not reliable for ruleset-backed
250
+ # required contexts in private repositories: it can return an
251
+ # empty result even while the required aggregate check is present
252
+ # and green. Polling mergeStateStatus avoids that discovery race;
253
+ # GitHub reports MERGEABLE only after branch policy permits the
254
+ # requested merge strategy. Non-required checks may leave the PR
255
+ # UNSTABLE, so accept that state only with mergeable MERGEABLE.
286
256
  echo "Waiting for release PR #$pr to become mergeable under branch policy"
287
257
  merge_state=UNKNOWN
288
258
  mergeable=UNKNOWN
@@ -506,12 +476,12 @@ jobs:
506
476
  ref: ${{ needs.release.outputs.tag_name }}
507
477
  - name: Setup Node (trusted)
508
478
  if: env.NPM_TOKEN == ''
509
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
479
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
510
480
  with:
511
481
  node-version: 24
512
482
  - name: Setup Node (token)
513
483
  if: env.NPM_TOKEN != ''
514
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
484
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
515
485
  with:
516
486
  node-version: 24
517
487
  registry-url: https://registry.npmjs.org
@@ -215,7 +215,7 @@ jobs:
215
215
  cache-save: ${{ github.event_name != 'pull_request' }}
216
216
  - name: Install cargo-audit
217
217
  if: steps.applicability.outputs.applicable == 'true'
218
- uses: taiki-e/install-action@6a1bd70eaac3c8bdf093356838d7ee09fda951cf # v2
218
+ uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2
219
219
  with:
220
220
  tool: cargo-audit
221
221
  - name: Audit dependencies
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.37.3](https://github.com/0xPlayerOne/code-foundry/compare/v0.37.2...v0.37.3) (2026-08-23)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * release-required-check-discovery ([#392](https://github.com/0xPlayerOne/code-foundry/issues/392)) ([d086cb5](https://github.com/0xPlayerOne/code-foundry/commit/d086cb5b6d1dc25eb28b6551ae56467887637296))
9
+
10
+ ## [0.37.2](https://github.com/0xPlayerOne/code-foundry/compare/v0.37.1...v0.37.2) (2026-08-23)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **ci:** stabilize runners and release reconciliation ([#387](https://github.com/0xPlayerOne/code-foundry/issues/387)) ([ea2c503](https://github.com/0xPlayerOne/code-foundry/commit/ea2c503cb6ea9b944ffa5b70ff7fbfc3d56d3a10))
16
+
3
17
  ## [0.37.1](https://github.com/0xPlayerOne/code-foundry/compare/v0.37.0...v0.37.1) (2026-08-08)
4
18
 
5
19
 
package/docs/RELEASES.md CHANGED
@@ -57,8 +57,9 @@ reject any non-`rebase` `merge_strategy` only when `staging-release` is
57
57
  configured, and always reject a non-`rebase` `release_merge_strategy`; the
58
58
  release workflow fails closed instead of falling back to `merge`. Both keep
59
59
  `main` fully linear, which is what makes the post-release reconciliation
60
- possible: release-only main commits cannot be discarded because they are
61
- allowed metadata-only, and all non-metadata drift is rejected before mutation.
60
+ possible. The final branch trees are inspected before mutation; validated
61
+ main-only changes are inherited by `staging`, while unpromoted staging work is
62
+ replayed on top of `main`.
62
63
 
63
64
  The `staging` → `main` reconciliation exists only in the `staging-release`
64
65
  topology. Patch-equivalent divergence between `main` and `staging` is treated
@@ -67,8 +68,8 @@ as aligned. When `staging` has pending commits that are not yet represented on
67
68
  detached worktree rooted at `main`, and then updates `staging` with an exact
68
69
  `--force-with-lease` to prevent
69
70
  unintended branch rewrites. There is no unconditional mirror force-push and no
70
- fallback synchronization commit path. `direct` repositories skip this step
71
- entirely.
71
+ fallback synchronization commit path. Indeterminate history, replay conflicts,
72
+ and stale leases fail closed. `direct` repositories skip this step entirely.
72
73
 
73
74
  `auto` selects a supported manifest. Use `simple` with `version.txt` for a
74
75
  repository without a package manifest and `none` for a repository that should
package/docs/WORKFLOWS.md CHANGED
@@ -97,9 +97,11 @@ it opens (or reuses) a generated `code-foundry/reconcile/main-to-staging`
97
97
  pull request whose head contains the exact target tip (the `main` tip for a
98
98
  fast-forward, the replay tip when staging-only commits are replayed) and whose
99
99
  body documents the reconciliation. Reruns reuse the open pull request instead
100
- of duplicating it; unexpected code divergence, replay conflicts, authentication
101
- errors, and ambiguous or stale pull request state still fail the job closed,
102
- and exact-lease protection stays in place for every direct push.
100
+ of duplicating it. Validated changes that landed directly on `main` are synced
101
+ back into `staging`; unpromoted staging commits are replayed on top. Indeterminate
102
+ history, replay conflicts, authentication errors, and ambiguous or stale pull
103
+ request state still fail the job closed, and exact-lease protection stays in
104
+ place for every direct push.
103
105
 
104
106
  For this reconciliation path, maintainer PATs and administrator roles are not
105
107
  authorized bypasses; the job deliberately authenticates with `github.token`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "0.37.1",
3
+ "version": "0.37.3",
4
4
  "description": "A fast, language-aware repository factory for agent-ready workflows, testing, security, and release automation.",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-or-later",
@@ -361,6 +361,12 @@ function renderWorkflow(content, config, repository, ref, rustCodeql) {
361
361
  rendered = rendered.replace(/^(\s+unit-runner:)\s+.*$/m, `$1 ${config.unit_runner}`)
362
362
  }
363
363
  if (workflow === 'validation') {
364
+ // The mode classifier is a normal runner job in the caller rather than a
365
+ // reusable-workflow input. Keep it on the configured default runner so
366
+ // consumers that cannot use ubuntu-slim do not fail before validation.
367
+ if (config.runner) {
368
+ rendered = rendered.replace(/^ mode:\n name: Mode\n runs-on:\s+.*$/m, ` mode:\n name: Mode\n runs-on: ${config.runner}`)
369
+ }
364
370
  /** @type {Record<string, string|undefined>} */
365
371
  const runnerInputs = {
366
372
  'ci-runner': config.ci_runner ?? config.runner,
@@ -220,7 +220,7 @@ function compareVersions(a, b) {
220
220
  * Classify the relationship between main and staging using the final tree delta
221
221
  * when available. Historical commit paths can include equivalent workflow or
222
222
  * configuration changes that are no longer present in the branch delta, so the
223
- * final trees are the source of truth for release-only reconciliation. When
223
+ * final trees are the source of truth for reconciliation. When
224
224
  * directChangedPaths is supplied, unexpected paths in historical main-only
225
225
  * commits are ignored only when they are absent from the final tree delta
226
226
  * (their content is already identical in both branches); unexpected main-only
@@ -281,9 +281,9 @@ export function classifyReconciliation(input) {
281
281
  }
282
282
  if (!stagingOnlyCommits.length) {
283
283
  return {
284
- action: 'fail',
285
- reason: 'branch content differs outside release metadata.',
286
- unexpected,
284
+ action: 'fast-forward',
285
+ targetSha: mainSha,
286
+ reason: 'main contains validated changes that staging must inherit.',
287
287
  }
288
288
  }
289
289
  }
@@ -300,7 +300,11 @@ export function classifyReconciliation(input) {
300
300
  [...new Set(mainOnlyCommits.flatMap((commit) => commit.changedPaths || []))],
301
301
  allowed,
302
302
  ).filter((path) => directTreePaths === null || directTreePaths.has(path))
303
- if (unexpectedMain.length) {
303
+ // Without a final-tree comparison, retain the historical fail-closed
304
+ // behavior. When the final delta is known, main is the validated release
305
+ // source of truth: replay any staging-only work on top instead of deadlocking
306
+ // every later release because a hotfix landed directly on main.
307
+ if (unexpectedMain.length && directTreePaths === null) {
304
308
  return {
305
309
  action: 'fail',
306
310
  reason: 'main contains commits that are not release metadata.',
@@ -373,7 +377,7 @@ export function buildReconciliationPullRequestBody(input) {
373
377
  '',
374
378
  `Merging this pull request synchronizes \`${targetHead}\` with the exact target tip above; no other commits are introduced.`,
375
379
  '',
376
- 'Code Foundry reconciles only release metadata. Unexpected code divergence, replay conflicts, authentication failures, and ambiguous or stale state fail the release job closed and are never pushed around branch protection. Later releases retry the direct push first; when branch policy still rejects it, this pull request is updated instead of duplicated.',
380
+ `Code Foundry treats validated \`${sourceBase}\` as the shipped source of truth and preserves unpromoted \`${targetHead}\` work by replaying it on top. Indeterminate history, replay conflicts, authentication failures, and ambiguous or stale state fail the release job closed and are never pushed around branch protection. Later releases retry the direct push first; when branch policy still rejects it, this pull request is updated instead of duplicated.`,
377
381
  )
378
382
  return lines.join('\n')
379
383
  }