Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 50 additions & 29 deletions .github/workflows/maint-68-sync-consumer-repos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,36 +116,57 @@ jobs:
base_sha="$INPUT_BASE_SHA"
source_commit="$INPUT_HEAD_SHA"

if [ "$scope" = "auto" ]; then
scope="full"
if [ "$REQUESTED_PHASE" = "promote" ] && [ -n "$CANARY_EVIDENCE_JSON" ]; then
evidence_rows=$(jq -ce '
if type == "array" then .
elif (.results | type) == "array" then .results
else error("promotion evidence must be an array or contain results")
end
' <<<"$CANARY_EVIDENCE_JSON")
scope=$(jq -er '
[.[].plan_scope // "full"] | unique |
if length == 1 then .[0]
else error("mixed plan scopes in canary evidence")
if [ "$REQUESTED_PHASE" = "promote" ]; then
[ -n "$CANARY_EVIDENCE_JSON" ] || {
echo "::error::Promotion requires canary evidence"
exit 1
}
evidence_rows=$(jq -ce '
if type == "array" then .
elif (.results | type) == "array" then .results
else error("promotion evidence must be an array or contain results")
end
' <<<"$CANARY_EVIDENCE_JSON")
evidence_scope=$(jq -er '
[.[].plan_scope // "full"] | unique |
if length == 1 then .[0]
else error("mixed plan scopes in canary evidence")
end
' <<<"$evidence_rows")
if [ "$scope" = "auto" ]; then
scope="$evidence_scope"
elif [ "$scope" != "$evidence_scope" ]; then
echo "::error::Requested scope $scope does not match promotion evidence scope $evidence_scope"
exit 1
fi

# Promotion evidence is authoritative for every plan scope. Falling
# back to the dispatch workflow's GITHUB_SHA can mix a later main
# commit into an already-authorized full-plan delivery.
source_commit=$(jq -er '
[.[].source_commit // ""] | unique |
if length == 1 and .[0] != "" then .[0]
else error("missing or mixed promotion source commit")
end
' <<<"$evidence_rows")

if [ "$scope" = "source-delta" ]; then
base_sha=$(jq -er '
[.[].scope_base_sha // ""] | unique |
if length == 1 and .[0] != "" then .[0]
else error("missing or mixed source-delta base SHA")
end
' <<<"$evidence_rows")
if [ "$scope" = "source-delta" ]; then
base_sha=$(jq -er '
[.[].scope_base_sha // ""] | unique |
if length == 1 and .[0] != "" then .[0]
else error("missing or mixed source-delta base SHA")
end
' <<<"$evidence_rows")
source_commit=$(jq -er '
[.[].source_commit // ""] | unique |
if length == 1 and .[0] != "" then .[0]
else error("missing or mixed source-delta head SHA")
end
' <<<"$evidence_rows")
fi
else
jq -e 'all(.[]; (.scope_base_sha // "") == "")' \
<<<"$evidence_rows" >/dev/null || {
echo "::error::Full-plan promotion evidence must not contain a source-range base"
exit 1
}
base_sha=""
fi
elif [ "$scope" = "auto" ]; then
scope="full"
fi

case "$scope" in
Expand Down Expand Up @@ -177,8 +198,8 @@ jobs:
exit 1
}
fi
source_commit="${source_commit,,}"
base_sha="${base_sha,,}"
source_commit=$(printf '%s' "$source_commit" | tr '[:upper:]' '[:lower:]')
base_sha=$(printf '%s' "$base_sha" | tr '[:upper:]' '[:lower:]')
{
echo "plan_scope=$scope"
echo "scope_base_sha=$base_sha"
Expand Down
2 changes: 1 addition & 1 deletion docs/WORKFLOW_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ _Inline Gate helper_
- **`maint-62-integration-consumer.yml`** — Nightly + release-triggered integration tests that reuse `reusable-10-ci-python.yml` across multiple matrices and file/resolve the `integration-test` issue via the load-balanced API client (no extra app mint).
- **`maint-65-sync-label-docs.yml`** — Syncs `docs/LABELS.md` into every registered consumer repo (plus the integration tests repo) when the source doc changes or on demand, using the shared registered-repo helper and PAT gating for cross-repo pushes.
- **`maint-66-monthly-audit.yml`** — First-of-month workflow that gathers workflow-run stats, runs the API wrapper guard, and files/updates the monthly audit issue; relies on the shared API client so no extra npm installs or App-token mints are needed.
- **`maint-68-sync-consumer-repos.yml`** — Daily/manual manifest-driven consumer sync that validates template/scripts, hashes the template set, records a prospective per-repo matrix, and opens stable sync PRs. Scheduled reconciliation uses the full manifest; bounded source repairs may instead select only manifest entries changed across an exact base/head range, including transitive `requires` targets declared by the typed manifest. Promotion reconstructs that immutable source-delta scope from Maint 71 evidence so later `main` drift cannot join the delivery. Empty source deltas stop before consumer fan-out, while manifest changes fail closed to full scope. Normal runs are fail-closed to the configured canaries, and explicit repo filters may only narrow that canary set. Candidate corrections refresh `sync/workflows-candidate`; a later `promote` run requires same-plan, green, review-clear Maint 71 evidence and refreshes `sync/workflows-delivery` in each non-canary. Every successful write wave dispatches the matching Maint 71 candidate or campaign selector, so the generated lane does not depend on a human handoff. Before an actual head mutation, Maint 68 disables auto-merge, restores draft state, and applies the staging hold; an unchanged base/tree preserves the existing review lifecycle. Each consumer job mints a repository-scoped Workflows App token and creates the exact staged Git tree through GitHub's Git database API without custom author/committer fields, so GitHub signs the commit. Tree or signature mismatches fail before the delivery branch is published. Release publication is not a second sync trigger.
- **`maint-68-sync-consumer-repos.yml`** — Daily/manual manifest-driven consumer sync that validates template/scripts, hashes the template set, records a prospective per-repo matrix, and opens stable sync PRs. Scheduled reconciliation uses the full manifest; bounded source repairs may instead select only manifest entries changed across an exact base/head range, including transitive `requires` targets declared by the typed manifest. Promotion reconstructs the exact source commit for every plan scope, plus the immutable base for source-delta plans, from Maint 71 evidence so later `main` drift cannot join the delivery. Empty source deltas stop before consumer fan-out, while manifest changes fail closed to full scope. Normal runs are fail-closed to the configured canaries, and explicit repo filters may only narrow that canary set. Candidate corrections refresh `sync/workflows-candidate`; a later `promote` run requires same-plan, green, review-clear Maint 71 evidence and refreshes `sync/workflows-delivery` in each non-canary. Every successful write wave dispatches the matching Maint 71 candidate or campaign selector, so the generated lane does not depend on a human handoff. Before an actual head mutation, Maint 68 disables auto-merge, restores draft state, and applies the staging hold; an unchanged base/tree preserves the existing review lifecycle. Each consumer job mints a repository-scoped Workflows App token and creates the exact staged Git tree through GitHub's Git database API without custom author/committer fields, so GitHub signs the commit. Tree or signature mismatches fail before the delivery branch is published. Release publication is not a second sync trigger.
- **`maint-69-sync-integration-repo.yml`** — Keeps Workflows-Integration-Tests aligned with `templates/integration-repo/`, regenerates `requirements.lock`, and pushes updates using PATs; no GitHub App token mint is required because the workflow stays inside the two repos.
- **`maint-69-sync-labels.yml`** — Propagates the canonical `.github/labels-core.yml` set to every registered consumer repo (or a provided subset), reusing the registered-repo helper + load-balanced API client without any additional App-token minting.
- **`maint-70-fix-integration-formatting.yml`** — Manual formatter for Workflows-Integration-Tests that resolves the repo default branch, applies `black`+`ruff` fixes, and pushes via PAT only when a token is available; runs read-only otherwise.
Expand Down
2 changes: 1 addition & 1 deletion docs/ci/WORKFLOWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ Scheduled health jobs keep the automation ecosystem aligned:
* [`health-78-backplane-contract.yml`](../../.github/workflows/health-78-backplane-contract.yml) Workflows-internal gate that runs on PRs touching the run-contract/v1 contract set (schemas, registry, validator, fixtures): asserts the three schemas load as valid draft 2020-12 JSON Schema, `config/backplane_participants.json` keeps the required shape, and the bundled valid/invalid fixtures behave (the validator self-smoke).
* [`health-83-dependency-sync-efficiency.yml`](../../.github/workflows/health-83-dependency-sync-efficiency.yml) publishes a weekly, fixture-backed advisory report for dependency-bot, consumer-sync, and dev-tool-sync maintenance and also runs once for each completed immutable sync plan. It completely paginates the trailing reporting window and measures stable-delivery force pushes, draft/ready cycles, reviewer events, and review-to-seal convergence; all-time history remains explicitly incomplete. The dedicated efficiency tracker (`#2897`) changes only when the material-evidence fingerprint changes.
* [`health-84-langsmith-observability.yml`](../../.github/workflows/health-84-langsmith-observability.yml) independently monitors LangSmith dashboard/conformance cadence, cloud trace freshness, and intentional pause review dates. It upserts one durable health issue and adds `needs-human` plus `agent:needs-attention` while degraded (daily schedule, manual dispatch).
* [`maint-68-sync-consumer-repos.yml`](../../.github/workflows/maint-68-sync-consumer-repos.yml) coalesces workflow-template updates into stable `sync/workflows-candidate` and `sync/workflows-delivery` PRs. Scheduled reconciliation uses the full typed manifest; a bounded source repair may use an exact base/head source-delta plan, whose immutable scope and transitive manifest-declared `requires` targets are carried through Maint 71 canary evidence into promotion. Manifest edits require full scope. Explicit repo filters cannot broaden the canary phase; non-canaries are written only by a plan-bound `promote` run carrying green, review-clear Maint 71 evidence. A successful candidate write wave dispatches the Maint 71 candidate selector; promotion dispatches the fleet campaign selector. Actual head changes first restore draft/staging holds, while exact base/tree no-ops preserve the current review lifecycle. Mutating jobs use a repository-scoped Workflows App token to create GitHub-verified commits and fail before publication if the API result is unsigned or its tree differs from the staged tree.
* [`maint-68-sync-consumer-repos.yml`](../../.github/workflows/maint-68-sync-consumer-repos.yml) coalesces workflow-template updates into stable `sync/workflows-candidate` and `sync/workflows-delivery` PRs. Scheduled reconciliation uses the full typed manifest; a bounded source repair may use an exact base/head source-delta plan, whose immutable scope and transitive manifest-declared `requires` targets are carried through Maint 71 canary evidence into promotion. Every promotion reconstructs its exact source commit from that evidence; source-delta promotion also reconstructs the exact base, so a later `main` commit cannot join either plan scope. Manifest edits require full scope. Explicit repo filters cannot broaden the canary phase; non-canaries are written only by a plan-bound `promote` run carrying green, review-clear Maint 71 evidence. A successful candidate write wave dispatches the Maint 71 candidate selector; promotion dispatches the fleet campaign selector. Actual head changes first restore draft/staging holds, while exact base/tree no-ops preserve the current review lifecycle. Mutating jobs use a repository-scoped Workflows App token to create GitHub-verified commits and fail before publication if the API result is unsigned or its tree differs from the staged tree.
* [`maint-69-sync-integration-repo.yml`](../../.github/workflows/maint-69-sync-integration-repo.yml) syncs integration-repo templates to Workflows-Integration-Tests repository (template push, manual dispatch with dry-run support).
* [`maint-69-sync-labels.yml`](../../.github/workflows/maint-69-sync-labels.yml) syncs core functional labels from labels-core.yml to consumer repos (push to labels-core.yml, manual dispatch with dry-run support).
* [`maint-70-fix-integration-formatting.yml`](../../.github/workflows/maint-70-fix-integration-formatting.yml) applies Black and Ruff formatting fixes to Integration-Tests repository files (manual dispatch for CI formatting failures).
Expand Down
12 changes: 7 additions & 5 deletions docs/ops/CONSUMER_REPO_MAINTENANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,11 +320,13 @@ gh workflow run maint-68-sync-consumer-repos.yml \
-f scope_head_sha=<repair-merge-commit>
```

Maint 71 writes that same scope and immutable range into every canary evidence
row. `phase=promote` with `delivery_scope=auto` recovers the exact range from
the evidence, checks out that historical source head, and recompiles the same
scoped plan. A later commit on `main` therefore cannot silently join an
authorized delivery. Do not substitute a moving branch name for either SHA.
Maint 71 writes that same scope, source commit, and immutable range into every
canary evidence row. Every `phase=promote` run recovers the exact source commit
from the evidence; a source-delta promotion also recovers its exact base. The
workflow checks out that historical source head and recompiles the same plan.
A later commit on `main` therefore cannot silently join an authorized delivery,
including a full-plan promotion. Do not substitute a moving branch name for
either source-delta SHA.
Before any checked-out source script runs, Maint 68 requires the resolved source
commit to be an ancestor of the workflow dispatch ref and the scope base to be
an ancestor of that source. New source-delta delivery commits also bind the full
Expand Down
Loading
Loading