code-foundry 1.43.1 → 1.43.2

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.43.2](https://github.com/0xPlayerOne/code-foundry/compare/v1.43.1...v1.43.2) (2026-10-03)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * require candidate asset qualification before stable promotion ([#705](https://github.com/0xPlayerOne/code-foundry/issues/705)) ([f42e4f5](https://github.com/0xPlayerOne/code-foundry/commit/f42e4f5fb063ea22fa25791a13c75c90d41bf17a))
9
+
3
10
  ## [1.43.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.43.0...v1.43.1) (2026-10-03)
4
11
 
5
12
 
@@ -115,29 +115,30 @@ See [Merge queue validation](merge-queues.md) before enabling it.
115
115
 
116
116
  ## Validation and quality
117
117
 
118
- | Key | Values | Purpose |
119
- | ----------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
120
- | `performance` | `auto`, `true`, `false` | Discover, require, or disable performance checks. |
121
- | `performance_command` | JSON argv array or array of argv arrays | Ordered commands for a non-package performance harness. |
122
- | `performance_profile` | empty or `node-package` | Shared package import, memory, archive, and dependency audit. |
123
- | `performance_budget_file` | repository-relative path | Budget file for `node-package`; defaults to `performance-package-budgets.json`. |
124
- | `eval` | `auto`, `true`, `false` | Discover, require, or disable the deterministic eval tier. |
125
- | `eval_command` | JSON argv array | Explicit harness command when there is no `eval` package script. |
126
- | `eval_report_file` | repository-relative path | Report validated against the eval contract; defaults to `eval-results/result.json`. |
127
- | `eval_budget_file` | repository-relative path | Optional budget file; defaults to `eval-budgets.json`. |
128
- | `eval_runner` | runner label | Runner for the `Validation / Eval` lane; defaults to the repository runner. Browser evals need a Chrome-capable runner such as `ubuntu-latest`. |
129
- | `required_capabilities` | comma-separated task names | Fail closed when a required task or coverage evidence is unavailable. |
130
- | `coverage_enforcement` | `auto`, `required`, `off` | Shared coverage-report policy. |
131
- | `coverage_minimum` | `0`–`100` | Minimum percentage; defaults to `80`. |
132
- | `coverage_metrics` | `lines`, `functions`, `branches`, `statements` | Metrics checked by the coverage gate. |
133
- | `coverage_report` | comma-separated repository paths | Istanbul JSON summary or LCOV evidence files. |
134
- | `filter_<task>` | comma-separated repository path globs | Skip a lane when no changed path matches; see [Lane path filters](#lane-path-filters). |
135
- | `rust_sccache` | `true`, `false` | Install sccache and wrap rustc so compile artifacts survive manifest/lockfile churn. |
136
- | `rust_nextest` | `true`, `false` | Install cargo-nextest and prefer `cargo nextest run` over `cargo test` in Rust test lanes. |
137
- | `e2e_shards` | `1`–`8` | Fan the `Validation / Test / E2E` job into one runner per shard. The repository's `test:e2e`/`e2e` script receives `E2E_SHARD_INDEX` and `E2E_TOTAL_SHARDS` and partitions itself (Playwright takes `--shard=$E2E_SHARD_INDEX/$E2E_TOTAL_SHARDS`); each shard owns a runner-local test database, so shards stay isolated. |
138
- | `release_batching_schedule` | five-field numeric cron | Batch Release Please into scheduled windows. Ordinary pushes skip the producer; release-PR squashes and manual dispatches still run. Batched releases are created privately as drafts and published with prerelease visibility atomically. Manual dispatches publish stable hotfixes. Absent, releases publish per merge. Requires a single root Release Please package. |
139
- | `release_batching_prerelease` | `true`, `false` | Defaults to `true` with a schedule. Sync enables `draft` and `force-tag-creation` in Release Please; the producer publishes the draft with the selected visibility. `false` keeps scheduled releases stable-visible. |
140
- | `release_batching_soak_hours` | `1`–`336` | Generate a daily promoter that promotes the newest prerelease when the oldest candidate since the last stable has soaked this many hours, stitching batch notes. Requires a batching schedule and prerelease publication. Set `STABLE_PROMOTION_HELD=true` in repository Actions variables to hold scheduled and manual promotion; `force` overrides the hold or soak, and `version` selects a plain semantic version. |
118
+ | Key | Values | Purpose |
119
+ | ----------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
120
+ | `performance` | `auto`, `true`, `false` | Discover, require, or disable performance checks. |
121
+ | `performance_command` | JSON argv array or array of argv arrays | Ordered commands for a non-package performance harness. |
122
+ | `performance_profile` | empty or `node-package` | Shared package import, memory, archive, and dependency audit. |
123
+ | `performance_budget_file` | repository-relative path | Budget file for `node-package`; defaults to `performance-package-budgets.json`. |
124
+ | `eval` | `auto`, `true`, `false` | Discover, require, or disable the deterministic eval tier. |
125
+ | `eval_command` | JSON argv array | Explicit harness command when there is no `eval` package script. |
126
+ | `eval_report_file` | repository-relative path | Report validated against the eval contract; defaults to `eval-results/result.json`. |
127
+ | `eval_budget_file` | repository-relative path | Optional budget file; defaults to `eval-budgets.json`. |
128
+ | `eval_runner` | runner label | Runner for the `Validation / Eval` lane; defaults to the repository runner. Browser evals need a Chrome-capable runner such as `ubuntu-latest`. |
129
+ | `required_capabilities` | comma-separated task names | Fail closed when a required task or coverage evidence is unavailable. |
130
+ | `coverage_enforcement` | `auto`, `required`, `off` | Shared coverage-report policy. |
131
+ | `coverage_minimum` | `0`–`100` | Minimum percentage; defaults to `80`. |
132
+ | `coverage_metrics` | `lines`, `functions`, `branches`, `statements` | Metrics checked by the coverage gate. |
133
+ | `coverage_report` | comma-separated repository paths | Istanbul JSON summary or LCOV evidence files. |
134
+ | `filter_<task>` | comma-separated repository path globs | Skip a lane when no changed path matches; see [Lane path filters](#lane-path-filters). |
135
+ | `rust_sccache` | `true`, `false` | Install sccache and wrap rustc so compile artifacts survive manifest/lockfile churn. |
136
+ | `rust_nextest` | `true`, `false` | Install cargo-nextest and prefer `cargo nextest run` over `cargo test` in Rust test lanes. |
137
+ | `e2e_shards` | `1`–`8` | Fan the `Validation / Test / E2E` job into one runner per shard. The repository's `test:e2e`/`e2e` script receives `E2E_SHARD_INDEX` and `E2E_TOTAL_SHARDS` and partitions itself (Playwright takes `--shard=$E2E_SHARD_INDEX/$E2E_TOTAL_SHARDS`); each shard owns a runner-local test database, so shards stay isolated. |
138
+ | `release_batching_schedule` | five-field numeric cron | Batch Release Please into scheduled windows. Ordinary pushes skip the producer; release-PR squashes and manual dispatches still run. Batched releases are created privately as drafts and published with prerelease visibility atomically. Manual dispatches publish stable hotfixes. Absent, releases publish per merge. Requires a single root Release Please package. |
139
+ | `release_batching_prerelease` | `true`, `false` | Defaults to `true` with a schedule. Sync enables `draft` and `force-tag-creation` in Release Please; the producer publishes the draft with the selected visibility. `false` keeps scheduled releases stable-visible. |
140
+ | `release_batching_soak_hours` | `1`–`336` | Generate a daily promoter that promotes the newest prerelease when the oldest candidate since the last stable has soaked this many hours, stitching batch notes. Requires a batching schedule and prerelease publication. Set `STABLE_PROMOTION_HELD=true` in repository Actions variables to hold scheduled and manual promotion; `force` overrides the hold or soak, and `version` selects a plain semantic version. |
141
+ | `release_batching_qualification_workflow` | workflow filename (for example `release-assets.yml`) | Require the latest release-event run of this workflow for the candidate tag’s exact source commit to succeed before stable promotion. Requires a batching soak. Running, missing, failed, or cancelled runs hold promotion, including named and forced promotions; `force` only bypasses hold and soak. The promoter receives read-only Actions access. |
141
142
 
142
143
  Supported task capabilities are `format`, `lint`, `type_check`, `build`, `unit`,
143
144
  `integration`, `e2e`, `smoke`, `eval`, and `performance`. `coverage` is a policy
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "1.43.1",
3
+ "version": "1.43.2",
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": {
@@ -754,6 +754,7 @@ on:
754
754
 
755
755
  permissions:
756
756
  contents: write
757
+ actions: read
757
758
 
758
759
  concurrency:
759
760
  group: promote-stable
@@ -769,6 +770,7 @@ jobs:
769
770
  env:
770
771
  GH_TOKEN: \${{ github.token }}
771
772
  SOAK_HOURS: '__SOAK_HOURS__'
773
+ QUALIFICATION_WORKFLOW: '__QUALIFICATION_WORKFLOW__'
772
774
  VERSION: \${{ inputs.version }}
773
775
  FORCE: \${{ inputs.force }}
774
776
  STABLE_PROMOTION_HELD: \${{ vars.STABLE_PROMOTION_HELD }}
@@ -777,6 +779,19 @@ jobs:
777
779
  repo="$GITHUB_REPOSITORY"
778
780
  summary="$GITHUB_STEP_SUMMARY"
779
781
 
782
+ # Force bypasses hold and soak, but never asset qualification.
783
+ require_qualification() {
784
+ [ -z "$QUALIFICATION_WORKFLOW" ] && return 0
785
+ local candidate_sha conclusion
786
+ candidate_sha="$(gh api "repos/$repo/commits/$1" --jq '.sha')" || return 1
787
+ [ -n "$candidate_sha" ] && [ "$candidate_sha" != "null" ] || return 1
788
+ conclusion="$(gh run list --repo "$repo" --workflow "$QUALIFICATION_WORKFLOW" --event release --commit "$candidate_sha" --limit 1 --json conclusion --jq '.[0].conclusion // "missing"')" || return 1
789
+ if [ "$conclusion" != "success" ]; then
790
+ echo "Asset qualification for $1 is $conclusion; holding stable promotion." | tee -a "$summary"
791
+ return 1
792
+ fi
793
+ }
794
+
780
795
  # The repository variable applies equally to scheduled and manual runs.
781
796
  if [ "$STABLE_PROMOTION_HELD" = "true" ] && [ "$FORCE" != "true" ]; then
782
797
  echo "Stable promotion is held." | tee -a "$summary"
@@ -788,6 +803,10 @@ jobs:
788
803
  echo "::error::version must be a plain semantic version" >&2
789
804
  exit 1
790
805
  fi
806
+ if ! require_qualification "v$VERSION"; then
807
+ echo "Qualification unavailable or unsuccessful; holding v$VERSION." | tee -a "$summary"
808
+ exit 0
809
+ fi
791
810
  gh release edit "v$VERSION" --repo "$repo" --prerelease=false --latest
792
811
  echo "Promoted v$VERSION to stable by name." | tee -a "$summary"
793
812
  exit 0
@@ -833,6 +852,11 @@ jobs:
833
852
  exit 0
834
853
  fi
835
854
 
855
+ if ! require_qualification "$tip"; then
856
+ echo "Qualification unavailable or unsuccessful; holding $tip." | tee -a "$summary"
857
+ exit 0
858
+ fi
859
+
836
860
  # Stitch the batch's notes oldest→newest so the stable release
837
861
  # documents everything stable users are getting, not just the tip.
838
862
  jq -r '.[] | "## " + .tag + "\\n\\n" + (.body // "")' <<<"$batch" > batch-notes.md
@@ -878,6 +902,16 @@ function validateReleaseBatchingConfig(config) {
878
902
  `Unsupported release_batching_prerelease: ${config.release_batching_prerelease}; use true or false.`
879
903
  )
880
904
  }
905
+ if (config.release_batching_qualification_workflow) {
906
+ if (
907
+ !/^[A-Za-z0-9_.-]+\.ya?ml$/.test(config.release_batching_qualification_workflow) ||
908
+ !config.release_batching_soak_hours
909
+ ) {
910
+ throw new Error(
911
+ 'Unsupported release_batching_qualification_workflow: use a workflow filename with a batching soak.'
912
+ )
913
+ }
914
+ }
881
915
  if (config.release_batching_soak_hours) {
882
916
  const hours = Number(config.release_batching_soak_hours)
883
917
  if (!Number.isInteger(hours) || hours < 1 || hours > 336) {
@@ -902,7 +936,10 @@ function validateReleaseBatchingConfig(config) {
902
936
  export function renderPromoteStable(config) {
903
937
  const soakHours = Number(config.release_batching_soak_hours ?? '')
904
938
  if (!Number.isInteger(soakHours) || soakHours < 1 || soakHours > 336) return null
905
- return PROMOTE_STABLE_TEMPLATE.replaceAll('__SOAK_HOURS__', String(soakHours))
939
+ return PROMOTE_STABLE_TEMPLATE.replaceAll('__SOAK_HOURS__', String(soakHours)).replaceAll(
940
+ '__QUALIFICATION_WORKFLOW__',
941
+ config.release_batching_qualification_workflow ?? ''
942
+ )
906
943
  }
907
944
 
908
945
  /**