Skip to content

feat(runner-policy): admit review-tier variable as a governed selector input - #155

Merged
kyle-sexton merged 3 commits into
mainfrom
feat/runner-policy-review-tier-selector-input
Jul 16, 2026
Merged

feat(runner-policy): admit review-tier variable as a governed selector input#155
kyle-sexton merged 3 commits into
mainfrom
feat/runner-policy-review-tier-selector-input

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • canonicalSelectorInputs.self-hosted-label may now be either ${{ vars.CI_SELF_HOSTED_LABEL }} (default fleet tier) or ${{ vars.CI_REVIEW_SELF_HOSTED_LABEL }} (dedicated capped review tier). A claude-review caller passes the review variable from a separate select-review job so its review workload routes to that tier while the repository's other self-hosted jobs keep the default.
  • exactCanonicalMap becomes set-membership: a canonical value is one exact governed expression or an exact set of them. Fail-closed is preserved — any expression outside the reviewed set is rejected. A single-string canonical value keeps identical exact-match behavior, so the string-valued selector-secret, reusable-secret, and reusable caller-permission maps are unchanged.
  • Schema gains canonicalSelectorInputMap (each value is a nonWhitespaceString or a nonEmptyUniqueStringArray); canonicalSelectorSecrets stays string-only.
  • Pins the ci-workflows#123 merge commit select-runner.yml@cdc5917c15aade1995bd810b60d818cadc635b52 in approvedSelectorReferencesByRepositoryOwner.melodic-software (the revision that admits melodic-review-ubuntu-24.04-x64 in the selector's strict allowlist), registered in the allowlist drift-guard test.
  • Tests: the review variable is admitted; an ungoverned self-hosted-label expression is rejected (selector-pin, "must be one of"); and an end-to-end claude-review caller (dedicated select-review job + runner from its output under the feat(runner-policy): review privileged reusable callers #140 caller-perms waiver) audits to zero findings. That last test doubles as the flip agent's executable spec and proves the review label threads through claude-review's optional-default path without tripping the hardcoded default-label routing-condition guards.
  • README documents the two-expression allowance and notes that the required-no-default local runner-input form still routes only to the default tier.

Scope / retained fallback

The consumer runner fallback || 'ubuntu-24.04' is intentionally retained for now — it is the selector-failure recovery path. The floor-conversion wave (owner directive: zero hosted minutes on private repos) will revisit inert hosted fallbacks separately; this PR keeps them so it stays a focused input-contract change.

Merge order

  1. ci-workflows#123 — merged (admits the label in the selector's strict allowlist).
  2. This PR — SHA pin included; mergeable on green.
  3. github-iac#141 (provisions CI_REVIEW_SELF_HOSTED_LABEL) can merge in parallel.
  4. Campaign A flip consumes all three.

This PR and the wave-12 reusable-contract PR both touch components/runner-policy/policy.json, but in disjoint objects — this one edits canonicalSelectorInputs and approvedSelectorReferencesByRepositoryOwner; wave-12 edits approvedReusableWorkflowContracts. Whichever merges second rebases onto the first; no semantic conflict.

Validation

  • node --test components/runner-policy: 146 passed (3 new + the drift-guard updated for the new SHA).
  • Biome, markdownlint, typos, editorconfig, gitleaks (lefthook): clean.
  • Schema compiles under Ajv 2020 at module load; shipped policy.json validates.

Related

  • Refs melodic-software/github-iac#78 (epic), melodic-software/provisioning#135 (review-tier governance decision, step 3), melodic-software/provisioning#141 (tier config).
  • Companion PRs: ci-workflows#123 (selector admission, merged), melodic-software/github-iac#141 (org variable).

No linked issue.

🤖 Generated with Claude Code

https://claude.ai/code/session_01K3QehVwmWzkBLpKokNCkkt

…r input

Allow the selector self-hosted-label input to be either
${{ vars.CI_SELF_HOSTED_LABEL }} (default fleet tier) or
${{ vars.CI_REVIEW_SELF_HOSTED_LABEL }} (dedicated capped review tier), so a
claude-review caller can route to the review tier through a separate
select-review job while the repository's other self-hosted jobs keep the
default (provisioning#135). exactCanonicalMap becomes set-membership; a
single-string canonical value keeps identical exact-match behavior, so the
string-valued secret and caller-permission maps are unchanged. The schema
gains canonicalSelectorInputMap (a string or a non-empty unique array).
Tests cover the admitted review variable, a rejected ungoverned expression,
and an end-to-end claude-review caller routing to the review tier with zero
findings. README documents the two-expression allowance and the
required-no-default default-tier limit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3QehVwmWzkBLpKokNCkkt
@claude

claude Bot commented Jul 16, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 3m 53s —— View job


Review: feat(runner-policy): admit review-tier variable as a governed selector input

  • Load tools and set up todo list
  • Read changed files and diff
  • Check REVIEW.md for review criteria
  • Analyze schema changes
  • Analyze policy logic changes
  • Analyze test coverage
  • Analyze README documentation
  • Post review findings

The change is architecturally sound and fail-closed. No blocking correctness or security issues found. Notes below, ordered by significance.


Pre-merge hard dependency (informational, not a code defect)

The PR body correctly flags this, but worth re-stating explicitly in the review record: the approvedSelectorReferencesByRepositoryOwner.melodic-software array in policy.json does not yet contain the select-runner.yml SHA that admits melodic-review-ubuntu-24.04-x64. Without that entry, a consumer's select-review job references an un-approved revision and the audit rejects it at selector-pin. The PR body requires ci-workflows#123 to merge first and its merge-commit SHA to be appended here before this PR merges. This is an intentional, documented hold — just making sure a reviewer doesn't accidentally approve a merge before that commit lands.


🟡 Nit — rawManagedLabel misclassifies a mis-placed review-tier expression

runner-policy.mjs lines 1395–1404

function rawManagedLabel(value, policy) {
  const trimmed = value.trim();
  if (trimmed.toLowerCase().includes("self-hosted")) { return true; }
  if (/CI_(?:SELF_HOSTED_LABEL|MANAGED_RUNNER)/i.test(trimmed)) { return true; }
  return policy.managedLabelRegexes.some((pattern) => pattern.test(trimmed));
}

CI_REVIEW_SELF_HOSTED_LABEL contains neither the hyphenated self-hosted substring nor the alternation CI_(SELF_HOSTED_LABEL|MANAGED_RUNNER) after CI_. If a consumer mistakenly placed ${{ vars.CI_REVIEW_SELF_HOSTED_LABEL }} directly in runs-on, the raw-self-hosted-label rule would not fire. The workflow is still rejected — the general expression check at line 1370 produces a runner-target-contract finding instead — so enforcement is intact. The only consequence is rule misclassification in the finding output.

If diagnostic fidelity matters for downstream consumers parsing finding rules, extending the alternation to CI_(?:(?:REVIEW_)?SELF_HOSTED_LABEL|MANAGED_RUNNER) would give the right rule name. Fix this →


🟡 Nit — optionalCanonicalSelectorInputs schema type not upgraded

policy.schema.json line 53

"optionalCanonicalSelectorInputs": { "$ref": "#/$defs/stringMap" },

canonicalSelectorInputs now references canonicalSelectorInputMap (which allows string | string[]), but optionalCanonicalSelectorInputs remains stringMap (string-only). This is internally consistent today — no optional input currently needs two canonical expressions, and the review-tier label was added as a required input. If a future optional input ever needs the same two-expression treatment, that would require another schema change. A brief schema comment (or doc note in the README alongside the existing paragraph) explaining the deliberate asymmetry would prevent a future contributor from wondering why only one of the two maps supports arrays.


Correctness: set-membership logic is correct

runner-policy.mjs lines 748–774

for (const [name, expected] of Object.entries(required)) {
  const allowed = Array.isArray(expected) ? expected : [expected];
  if (!allowed.includes(actual[name])) {
    return `${location}.${name} must be ${canonicalExpectation(expected)}`;
  }
}

The Array.isArray branch is transparent to single-string canonicals (they're wrapped in a one-element array and includes behaves identically). The new code path is only triggered when policy.json contains an array-valued canonical. The fail-closed invariant holds: any expression absent from the reviewed set is rejected.


Test coverage is sufficient

Three new tests cover the three meaningful cases introduced:

  • line 1418 — review variable admitted
  • line 1430 — ungoverned variable rejected with must be one of (correct given the change from string to array canonical)
  • line 1445 — end-to-end claude-review caller with a dedicated select-review job audits to zero findings, proving the label threads through without tripping the hardcoded CI_SELF_HOSTED_LABEL routing-condition guards in selfHostedSelectorConditionStatus and unroutableFailureStatus (which are only reachable via required-no-default mode, not the optional-default path this caller uses)

The rejection-message assertion at line 1442 (/selector inputs\.self-hosted-label must be one of/) correctly reflects the new array-valued canonical producing canonicalExpectation(["...", "..."])"one of [...]".


Summary: Two nits (rule misclassification edge case, undocumented schema asymmetry), one documented hard merge-order dependency. No blocking issues. Enforcement is fail-closed throughout.

…eview tier

Add select-runner.yml@cdc5917c (the ci-workflows#123 merge commit, which admits
melodic-review-ubuntu-24.04-x64 in the strict allowlist) to the melodic-software
owner-scoped approved selector references, and register it in the allowlist
drift-guard test. Completes the review-tier admission chain: a consumer's
select-review job pins this revision to route claude-review to the review tier.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3QehVwmWzkBLpKokNCkkt
@kyle-sexton
kyle-sexton marked this pull request as ready for review July 16, 2026 19:47
@claude

claude Bot commented Jul 16, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 22s —— View job


  • Read the new commit and understand what changed
  • Review the selector SHA pin changes
  • Update comment with findings

Review of d0cdc03 — selector SHA pin

This commit resolves the one hard merge-order dependency flagged in the prior review: the select-runner.yml@cdc5917c SHA (ci-workflows#123 merge commit) is now in approvedSelectorReferencesByRepositoryOwner.melodic-software.

Placement is correct. The new SHA lands only in the owner-scoped list, not in approvedSelectorReferences (the global base list). That's the right call — cdc5917c admits melodic-review-ubuntu-24.04-x64, which is melodic-software-specific and should not be globally available to arbitrary owners.

Test coverage is complete. The drift-guard test at runner-policy.test.mjs:1045 now asserts the exact allowlist shape including REVIEW_TIER_SELECTOR_SHA, and the per-SHA loop at line 1071 verifies that a workflow pinned to this revision audits to zero findings under a melodic-software owner identity. Both checks are required and both are present.

SHA format: 40-character full SHA (cdc5917c15aade1995bd810b60d818cadc635b52) — consistent with every other entry in the list.

No new issues. The two nits from the prior review (rawManagedLabel regex misclassification, optionalCanonicalSelectorInputs schema asymmetry) are unchanged — they were already assessed as non-blocking.


This PR is now complete per its stated merge pre-conditions. The blocking hold is resolved; the enforcement chain is closed; tests confirm zero findings end-to-end.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d0cdc03017

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread components/runner-policy/policy.json
Comment thread components/runner-policy/policy.json
Add the cdc5917c review note to the selector revision lockstep paragraph -
it documents that this revision admits melodic-review-ubuntu-24.04-x64, that
the control-plane job still runs on the default fleet label, and that a review
lane must pin it because older pins fail closed on the review label. Update the
approved-revision counts (seven to eight total, four to five owner-scoped
strict-scheduling).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3QehVwmWzkBLpKokNCkkt
@claude

claude Bot commented Jul 16, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 2m 0s —— View job


  • Load tools and set up todo list
  • Read the new commit (db209f7) and understand what changed
  • Analyze Codex P2 findings against current state
  • Post review findings

Review of db209f7 — selector trust note

This commit adds the cdc5917c review note to the selector revision lockstep paragraph in README.md and updates the counts (seven → eight total, four → five owner-scoped).

Codex P2 finding #2 (policy.json:15) is resolved by this commit. The trust note now documents that cdc5917c15aade1995bd810b60d818cadc635b52 adds melodic-review-ubuntu-24.04-x64 to the strict self-hosted-only allowlist, that the control-plane job still runs on the default fleet label, and critically: "A review lane must pin this revision: older approved revisions do not admit the review-tier label, and a self-hosted-only selector at an older pin fails closed on it (unapproved-label)." The Codex reviewer evaluated a pre-note state that no longer exists.


Codex P2 finding #1 — canonical inputs are not SHA-scoped

policy.json line 174–177

The Codex finding is technically correct in its observation: selectorStatus() approves CI_REVIEW_SELF_HOSTED_LABEL for any approved selector SHA, not only for cdc5917c. A consumer that pins to an older globally-approved SHA (e.g. 99ac2f8c) and passes CI_REVIEW_SELF_HOSTED_LABEL will pass the policy audit. At runtime, however, the older selector rejects the label with unapproved-label — fail-closed semantics hold.

The claim that this "defeats the selector lockstep" overstates the risk. No runner routing bypass is possible: the selector's internal allowlist is the enforcement layer, and the README now explicitly documents the fail-closed behavior for this exact scenario. The current layered design (canonical inputs are SHA-agnostic; the selector enforces its own allowlist) is intentional — making canonical inputs SHA-aware would require a significant schema redesign (a SHA → allowed inputs map), and the fail-closed runtime outcome removes the security rationale for doing so.

The finding does identify a real developer-experience gap: a consumer could pass audit and then receive a confusing unapproved-label failure at runtime with no audit-time signal. The README's guidance ("A review lane must pin this revision") is the mitigation, and it's now present. This is non-blocking.


This PR is complete. All three commits reviewed; no new blocking issues. Codex finding #2 is resolved; finding #1 is addressed by documentation and is non-blocking given fail-closed runtime enforcement. The two earlier nits (rawManagedLabel regex, optionalCanonicalSelectorInputs schema asymmetry) remain non-blocking and unchanged.

@kyle-sexton
kyle-sexton merged commit b6c03c5 into main Jul 16, 2026
41 checks passed
@kyle-sexton
kyle-sexton deleted the feat/runner-policy-review-tier-selector-input branch July 16, 2026 20:15
kyle-sexton added a commit that referenced this pull request Jul 16, 2026
…racts (#156)

## Summary

Register `runner-input` contracts in
`components/runner-policy/policy.json` for two floor-conversion
reusables, both pinning ci-workflows PR #124's squash-merge commit
`3dfb18452a8c6059a22e62456390d84feb10b42f` (the reviewed source that
carries the governed `runner` input):

- `link-check.yml` — `allowedInputs: ["runner", "args"]`,
`allowedCallerPermissions: {contents: read, issues: write}`.
- `pulumi-version-drift-check.yml` — `allowedInputs: ["runner"]`,
`allowedCallerPermissions: {contents: read, issues: write}`.

Each carries `allowedCallerPermissions` because its rolling
tracking-issue lane writes issues through the caller `GITHUB_TOKEN`; the
waiver is honored only while the call is genuinely selector-routed, and
the reusables' own permissions are unchanged. This also corrects the
now-false README claim that the Pulumi version-drift monitor "remains
fixed to explicit GitHub-hosted images," adds a review note for both
contracts, and extends the runner-policy golden fixture
(`runner-policy.test.mjs`) to assert them. `hostedExceptionReasons` is
**unchanged** — enum-tightening is the separate last wave and must not
land before every consumer has dropped its floor exceptions.

## Why

Wave 2 of the private-repo hosted-floor elimination
(melodic-software/github-iac#78, decision of record 2026-07-16).
ci-workflows PR #124 (Wave 1) added the governed `runner` input to these
reusables' source; this PR registers the reviewed contracts so each
private consumer (Wave 3) can add a `select-runner` job, route the
reusable to the fleet, and drop its `hosted-control-plane` /
`privileged-control-plane` exception. `policy.json` is the upstream
source of truth synced to five consumers, so the contract belongs here.

## Deferred — standards-sync

The third floor-conversion reusable, `standards-sync.yml`, is
**intentionally not registered here.** Its caller `GITHUB_TOKEN` is
read-only (`sync.yml` declares `permissions: contents: read`; all writes
go through a minted App token), but a `runner-input` contract that
passes secrets must carry `allowedCallerPermissions`, which the
validator requires to include at least one `write`
(`runner-policy.mjs:186-198`). There is no honest caller write to
declare, so registering it would bake a least-privilege inaccuracy into
the managed contract. This is a contract-model gap (the secrets waiver
is coupled to a write requirement) routed to the runner-policy component
owner for a "reviewed secrets + read-only caller" contract shape;
`standards-sync` keeps its hosted-only contract until that lands.

## Test plan

- [x] `npm run test:runner-policy` — passing with two new golden
assertions on the registered contracts: 143/143 on this branch base, and
146/146 verified against a local rebase onto current `main` (post #155
review-tier admission, #153 dependabot-policy component).
- [x] `npm run lint:runner-policy`
(`GITHUB_REPOSITORY=melodic-software/standards`) — `Runner policy
passed` on both the branch base and the current-`main` rebase (the #155
validator).
- [x] biome, markdownlint — clean (pre-commit).
- [x] Merge SHA finalized to `3dfb184…` (PR #124 squash-merge) across
`policy.json` (both contract keys), the golden-fixture constant, and the
README review note.

## Related

No linked standards issue. Cross-repo references:

- Wave 2 of melodic-software/github-iac#78 (private-repo hosted-floor
elimination epic).
- Depends on melodic-software/ci-workflows#124 (merged) — source of the
pinned reusable SHA.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01K3QehVwmWzkBLpKokNCkkt

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
kyle-sexton added a commit that referenced this pull request Jul 17, 2026
…ier (#158)

## What

- Add a `select-review` job resolving `${{
vars.CI_REVIEW_SELF_HOSTED_LABEL }}` through the governed selector
(pinned `select-runner@cdc5917c`).
- Route the `review` job's runner from the selector output to the fleet
claude-review reusable (pinned `claude-review@4dbb0dfc`), permissions
exactly per the reviewed caller-perms waiver.
- Drop the `privileged-control-plane` hosted exception for
`claude-review.yml#review`.

## Why

Campaign A of the zero-hosted directive (epic
melodic-software/github-iac#78): automated review moves to the dedicated
capped review tier. Shape matches this repo's own runner-policy E2E
fixture (#155); `runner-policy.mjs --root .` passes locally with zero
findings.

Supersedes the closed draft #142.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01K3QehVwmWzkBLpKokNCkkt

---------

Co-authored-by: Claude Fable 5 (1M context) <noreply@anthropic.com>
kyle-sexton added a commit that referenced this pull request Jul 18, 2026
## What

Two changes to the managed `runner-policy` component that stop a paid
hosted label from silently becoming the governed fallback:

1. **Remove `ubuntu-slim` from `approvedHostedRunnerLabels`.** It can no
longer be an explicit `runs-on` target, a matrix value, or the governed
   fallback default. `ubuntu-24.04` is the sanctioned free fallback; the
   `ubuntu-slim` tier was eliminated (billed even on public repos).
2. **Add a `fallbackLabelAllowlist` policy field** (default
   `["ubuntu-24.04"]`) and require `governedReusableRunnerInput.default`
   to be a member — a gate strictly tighter than
   `approvedHostedRunnerLabels`. A label can be an approved explicit
target yet still be barred from becoming the silent recovery fallback.

## Why this shape (and not the originally-scoped per-workflow rule)

The initial framing was a per-workflow finding rejecting any
non-allowlisted
literal in the hosted-fallback arm of a selector `runs-on`. The
validator's
architecture does not have that gap: the selector-output arm
(`${{ needs.X.outputs.runner || '<label>' }}`) is already pinned by
`routeStatus` to exactly `governedReusableRunnerInput.default`, and the
ternary arm (`… && '<fleet>' || '<label>'`) is rejected wholesale as
unresolvable dynamic routing. A consumer cannot write `|| 'ubuntu-slim'`
unless the policy default itself is `ubuntu-slim`. The real
silent-return
path is therefore the **policy default**, validated only against
`approvedHostedRunnerLabels` (which still contained `ubuntu-slim`). This
PR
closes it at that single source, plus removes the label so bare
`runs-on: ubuntu-slim` also dies.

## Compatibility

- **Default allowlist does not break any consumer.** All consumer
selector
  fallbacks are `|| 'ubuntu-24.04'` (org-verified 2026-07-18) and
  `ubuntu-24.04` is the default, so it is in the default allowlist. No
  consumer `runner-policy.json` references `ubuntu-slim`.
- This repository's own workflows pass the audit under CI conditions
  (`CI_REPOSITORY_VISIBILITY=private`, owner evidence present): "Runner
  policy passed.", exit 0.

## schemaVersion

Not bumped. `schemaVersion` has no runtime semantics (never read by
`runner-policy.mjs`; it is a declarative `const` marker), no test
hardcodes
it, and prior schema field-additions (#140, #155) did not bump it.
`policy.json`
and `policy.schema.json` are `managed` and sync verbatim as one unit, so
no
consumer ships a hand-authored policy the new required field could
reject.

## Tests

`node --test components/runner-policy/runner-policy.test.mjs` — 213
pass, 0
fail (was 208; +5). New config-level cases, matching the real
`ConfigurationError` architecture rather than a per-workflow finding:

- required-field presence for `fallbackLabelAllowlist`;
- default not in the allowlist (approved `windows-2025`) rejects;
- `ubuntu-slim` default now rejects as not-approved (locks the removal);
- shipped `|| 'ubuntu-24.04'` selector route passes clean;
- allowlist extended to admit a second approved default passes clean.

Also updated the existing "selector recovery derives its literal
fallback"
test to extend `fallbackLabelAllowlist` alongside its `default`
override.

`lint:md`, `biome check`, and the runner-policy self-audit are green.

## Reconciliation checklist

- [x] Cross-doc reconciliation run. Updated `README.md` (fallback
passage)
and `THREAT-MODEL.md` (residual-risk bullet) to state the new allowlist
  bound; both are consistent additions, not restatements.
`conventions/review/ai-review-bot-composition.md` checked — its
"default"
  usage is bot-composition, unrelated; not contradicted.
- [x] No other doc in the catalog references the fallback default or the
  approved-label set in a way this change contradicts.

## Related

No linked issue: this PR delivers the fallback-allowlist guardrail
directly
without a tracking issue.

- melodic-software/ci-workflows#141 — companion
- melodic-software/medley#1570 — companion
- melodic-software/ci-workflows#143 — context for why the `ubuntu-slim`
  tier is dead

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_015hTQ64MDYGvqVUEPPWQV6Q

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
kyle-sexton added a commit to melodic-software/ci-runner that referenced this pull request Jul 18, 2026
## Summary

Delivers the ci-runner-alignment audit: a full-surface review of the
self-hosted CI system (ci-runner, provisioning, ci-workflows selector,
standards runner-policy, github-iac routing governance) against GitHub's
official documentation, fetched 2026-07-18.

- `docs/topics/ci-runner-alignment/REPORT.md` — headline synthesis,
severity-ordered triage index, per-divergence verdicts D2–D12 (D1
withdrawn as phantom), aligned findings, unused-features dispositions
with adopt/skip/defer + triggers, limitations appendix. Every claim
cites an official source.
- `docs/topics/ci-runner-alignment/PLAN.md` — locked Brief +
architect-filled Plan (single-file report layout decision, phase
records, acceptance-criteria PASS table).
- `docs/topics/ci-runner-alignment/design/design-resolution.md` — Tier C
early-exit record (docs-only stage).

Verdict counts: 6 confirmed, 5 needs-decision, 1 withdrawn. IMPORTANT
findings: D11 (30-day runner minimum-version SLA + critical-CVE no-grace
clause) and D12 (queue monitor scheduler is a silent SPOF via
public-repo 60-day auto-disable). Dispositions on needs-decision items
are reserved for the one-by-one walkthrough; follow-up fixes/issues land
after it.

## Related

No linked issue — the audit's follow-up fixes and issues are filed
per-repo after the user walkthrough, not closed by this report PR.

- melodic-software/github-iac#141 — review-tier org variable
(audit-verified merged; D2 evidence)
- melodic-software/standards#155 — runner-policy review-tier admission
(D2 evidence)
- melodic-software/provisioning#146 — claude-review routed through the
governed selector (D2 evidence)
- `docs/topics/runner-performance/` — closed perf topic the D3
capacity-clamp verdict rests on

## Verification

- markdownlint-cli2 exit 0 over the topic directory.
- Mechanical report checks: 11 divergence entries, verdict + official
citation in every entry, zero memory-tier references.
- All 29 cited URLs verified against same-day research artifacts (3
cross-repo PR URLs live-verified merged with matching titles).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01PDxVbV5HvMA7pji43USWcQ

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant