Skip to content

feat(pr-convention-policy): check the pr-contract composite and describe the advisory linkage posture - #525

Merged
kyle-sexton merged 4 commits into
mainfrom
ci-perf/phase-3-contract
Sep 5, 2026
Merged

kyle-sexton merged 4 commits into
mainfrom
ci-perf/phase-3-contract

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

No related issue: melodic-software/github-iac#396 tracks Phase 3 of the ci-perf program

Summary

Phase 3 of the ci-perf program moves every consumer from the
pr-issue-linkage.yml reusable to the pr-contract composite, called as a step
inside the ci-status job, one pull request per repository over the coming
days. The pr-convention-lockstep lane read the reusable and only the
reusable: it would have gone red the moment the first consumer migrated, and
blind the moment the last one did. It has to stay green at every point of that
transition, and it has to keep catching drift on both sides of it.

Two other standards-owned surfaces still described pr-issue-linkage as a
required check that fails on a non-conforming body. After Phase 3 that is
wrong in a way that matters to anyone drafting a pull request: ci-status is
the one required check, and the body contract is advisory.

Fix

components/pr-convention-policy/lockstep-drift.mjs

  • The live gate source is now .github/actions/pr-contract/run.sh on
    ci-workflows main, plus action.yml for the allowed title types. Extractors
    and their anchors: required sections from the section_report("<name>")
    calls; closing keywords from the match(chunk, /.../) expression; no-issue
    markers from the tolower(body) ~ /.../ expression; allowed title types from
    inputs.types.default in action.yml, parsed as YAML so the anchor is the
    data key rather than the shape of the description block above it; the scope
    requirement from inputs.require-scope.default the same way. Both awk
    patterns are probed functionally, with every policy keyword and marker, and
    the probes lowercase because the analyzer does; the extractor asserts that
    lower = tolower(line) is still there rather than assuming it, which is the
    composite's equivalent of the reusable's i flag.
  • The title axes are new. The composite hardcodes the twelve standards types as
    its types default, so policy.json and the gate can now be checked against
    each other where semantic-pr's eleven-type action default never was, and
    require-scope is checked alongside it: a composite release that flipped it
    would reject every unscoped title fleet-wide while the section and type checks
    still reported agreement.
  • Per consumer the lane detects which artifact the repository runs (a uses: of
    the composite in any workflow, else the pr-issue-linkage.yml caller),
    resolves that pin, and checks the contract at that pin with the matching
    extractor. Detection requires a uses: entry with no # earlier on the line,
    so a commented-out call site left behind by a migration, or the same path in a
    lint paths: list, never selects an artifact the repository does not run. The
    composite wins where a repository carries both mid-transition; ci-workflows'
    local ./.github/actions/pr-contract reference resolves to its own tree at
    main. A repository running neither artifact fails the lane, with no
    exemption: github-iac#367 put every repository in the roster under the org
    ci-gate ruleset, so a lost caller is a gate removal wherever it happens.
  • The checks on the source-control plugin's hook validator, the org PR template
    and the distributed rule are unchanged.

.claude/rules/pr-body-contract.md (the always-loaded distributed rule): states
that ci-status is the single required check, that it fails on a
non-conforming title or a do-not-merge label, and that a body missing the
closing keyword or a section draws an advisory comment and the
needs-issue-linkage label rather than a red check. The contract itself
(sections, keywords, no-issue markers) is unchanged.

components/pr-convention-policy/README.md: names the composite as the gate
consumers run from v0.20.0 (449157aaa8e30f7b1457305d8048ebe6168e174a) with
pr-issue-linkage.yml as the predecessor each repository leaves during Phase 3,
records that the composite's twelve-type default includes security and ends
the drift against the eleven-type semantic-pr default, and describes the
advisory linkage posture.

ADRs are untouched (Phase 9 owns them), as are distribution/sync-manifest.yml,
the runner-policy component and the claude-lanes component (Phase 3b owns
those).

Verification

  • node --test components/pr-convention-policy/lockstep-drift.test.mjs components/pr-convention-policy/pr-convention-policy.test.mjs — 47 tests,
    47 pass. New fixtures cover a composite consumer, a reusable consumer, a mixed
    fleet, a types drift, a require-scope drift, a sections drift, every
    repository running neither artifact, artifact detection in all six shapes
    (pinned composite, local composite, reusable, both, neither, commented-out),
    and a composite that stops lowercasing.
  • LOCKSTEP_GITHUB_TOKEN=$(gh auth token) node components/pr-convention-policy/lockstep-drift.mjs against the real fleet —
    exit 0. Twelve repositories resolved to the reusable at their pins,
    ci-workflows to the composite it dogfoods locally; every one of the thirteen
    resolved an artifact.
  • npm run lint:md, npm run lint:hooks, and
    npx @biomejs/biome check components/pr-convention-policy clean; lefthook
    pre-commit ran on every commit (typos, editorconfig, gitleaks, markdownlint,
    biome all green).
  • git diff origin/main --stat touches four files and nothing else.
  • The pr-convention-lockstep lane on this pull request is the live proof that
    the mixed fleet passes today.

Related

  • Refs melodic-software/github-iac#396
  • Refs melodic-software/github-iac#378
  • melodic-software/ci-workflows release v0.20.0
    (449157aaa8e30f7b1457305d8048ebe6168e174a), which ships the pr-contract
    composite this lane now reads.
  • ADR-0008 (docs/adr/0008-distribute-pr-body-contract-rule.md) states the
    lockstep decision this change re-points; it is not edited here.
  • The distributed rule change reaches nine target repositories through
    distribution/sync-manifest.yml after merge, one sync pull request each.

…ibe the advisory linkage posture

Phase 3 of the ci-perf program moves every consumer from the
`pr-issue-linkage.yml` reusable to the `pr-contract` composite called as a step
inside `ci-status`, one repository at a time. The lockstep lane read the
reusable and only the reusable, so it would have gone red the moment the first
consumer migrated and blind the moment the last one did.

The live gate source is now `.github/actions/pr-contract/run.sh` on
ci-workflows `main`, plus `action.yml` for the allowed title types the
composite hardcodes as its `types` default. Per consumer the check detects
which artifact the repository runs, resolves that pin, and validates the
contract at that pin with the matching extractor, so a mixed fleet passes
throughout the transition and a drifted artifact of either kind still fails.

The distributed rule and the component README stop calling `pr-issue-linkage`
the required check: `ci-status` is the single required check, the title and the
`do-not-merge` label fail it, and a non-conforming body gets an advisory
comment and the `needs-issue-linkage` label instead of a red check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-04T20:02:26.665583Z a40ebb0 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@claude

claude Bot commented Sep 4, 2026 •

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 5m 47s —— View job


Code review complete

  • Gather context (PR body, changed files, diff)
  • Read changed files in full
  • Review lockstep-drift.mjs logic changes
  • Review test coverage in lockstep-drift.test.mjs
  • Review .claude/rules/pr-body-contract.md wording changes
  • Review README.md changes
  • Verify PR's stated test/lint results — blocked, see below
  • Post findings

Note: /review:code-review errored out (returned an empty <error> payload on two attempts) rather than loading its instructions, so I ran a manual review of the diff instead of that specific procedure.

Findings

No correctness or maintainability issues found in the diff (git diff origin/main...HEAD, 4 files, +793/-164, matching the PR's stated stat).

I traced through the new extraction/comparison logic in lockstep-drift.mjs against the fixtures in the test file and it holds together:

  • detectArtifactPin (lines 291-304) correctly prioritizes a pinned composite, then a local ./ composite reference, then the reusable pin, and the anchoring (uses: lookahead for the local-path pattern, fully-qualified strings for the pinned patterns) avoids false positives from paths: filters or comment mentions — verified against the "bare path does not match" test case.
  • parseCompositePatterns's regex extraction (match(chunk, /(.+)/)) break) correctly isolates the awk regex literal via greedy backtracking even though the literal itself contains internal escaped slashes (from the optional owner/repo group) — the greedy match still anchors on the final /)) break on the line.
  • checkFleet's three-way branch (composite / reusable / none) correctly treats "none" as a note only for the three UNSYNCED_REPOSITORIES and a hard failure elsewhere, and "unresolved" is a no-op since runLiveCheck already recorded the fetch-error.
  • The .claude/rules/pr-body-contract.md and README.md prose changes accurately reflect the new advisory-linkage/hard-gate-on-ci-status posture described in the PR body, and I found no other stale references to the old "pr-issue-linkage is the required check" framing or the removed GATE_CALLERS export anywhere else in the repo.

Unable to verify: the PR's stated verification results (node --test ... → "43 tests, 43 pass", clean Biome/markdownlint runs). This sandbox's Bash tool rejects every node/npm/npx invocation beyond node --version with "This command requires approval," and there's no interactive user to grant it, so I could not execute the test suite or linters myself (confirmed via a dedicated subagent that hit the same wall, including with dangerouslyDisableSandbox). I instead manually traced the new/changed tests against the implementation (parsing regexes, fixture shapes, checkFleet branch coverage) and didn't find a mismatch, but this is not a substitute for actually running node --test. If this matters for merge confidence, worth re-running verification somewhere with tool execution permitted.

One environment note unrelated to the PR content itself: the local working tree in this session has an uncommitted, unstaged reversion of .claude/rules/pr-body-contract.md back to its pre-PR text (visible in git status/git diff HEAD). The actual committed change on this branch (git diff origin/main...HEAD) is correct and matches the PR description — this appears to be a sandbox checkout artifact, not something in the PR itself, so no action needed on your end, but flagging it in case it's unexpected.

@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: a40ebb054c

ℹ️ 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/pr-convention-policy/lockstep-drift.mjs Outdated
Comment thread components/pr-convention-policy/lockstep-drift.mjs
Comment thread components/pr-convention-policy/lockstep-drift.mjs Outdated
Comment thread .claude/rules/pr-body-contract.md
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

Claude has reviewed this PR 1 time. The lane skips further automatic reviews after 5; deleting this comment resets the count.

kyle-sexton and others added 3 commits September 4, 2026 16:08
…ries

The comment-hygiene lane rejected a test comment quoting a closing keyword
beside an issue number; reworded without changing what the test asserts.

Artifact detection now requires a `uses:` entry with no `#` earlier on the
line. The composite path also appears in ci-workflows' own `ci.yml` as a lint
`paths:` list and as a `run.test.sh` command, and a migration leaves
commented-out call sites behind; either would otherwise select an artifact the
repository does not run and suppress detection of the one it does, so a
repository that had lost its last live caller would validate an unused artifact
instead of reporting that it runs neither. Raised by the Codex reviewer on
#525.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ies are exempt

The comment claimed the org `ci-gate` ruleset does not cover agent-plugins,
claude-code-proxy and cursor-plugins. `distribution/sync-manifest.yml` records
that github-iac#367 already extended the ruleset to all three and that each
carries the four required contexts, so that claim is stale. What is still true
is that they sit outside the `pr-body-contract-rule` sync roster, which has nine
targets. The exemption itself is unchanged and should shrink to nothing at
Phase 3.3.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ck require-scope

Two decisions from the review on #525.

The three-repository exemption is gone. agent-plugins, claude-code-proxy and
cursor-plugins were reported rather than failed while their default branches sat
outside the org ci-gate ruleset; `distribution/sync-manifest.yml` records that
github-iac#367 extended the ruleset to all three and that each carries the
required contexts, so a repository running neither contract artifact is now a
drift finding wherever it happens. `checkFleet` returns a plain error list and
the note channel is gone with the exemption it served.

`inputs.require-scope.default` joins the composite comparison, at the source and
at every pin. A composite release that flipped it would reject every unscoped
title fleet-wide while the section and type checks still reported agreement.
Either YAML spelling of the boolean is accepted; anything else is drift rather
than a coerced guess.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
kyle-sexton added a commit that referenced this pull request Sep 5, 2026
…view callers to it (#527)

No related issue: melodic-software/github-iac#403 tracks Phase 3b of the
ci-perf program

## Summary

Phase 4 and Phase 5 of the ci-perf program move the private four and
medley off
the governed runner selector and onto the managed fleet label written
literally.
Two of the files that would have to change are sync-managed by this
repository:
`claude-review.yml` in dotfiles, provisioning, github-iac and medley,
and
`claude-security-review.yml` in github-iac and provisioning. The
`managed-files-guard` lane fails a hand edit and the next sync reverts
it, so
the change is made once here and distributed.

The gate those repositories run refuses a hardcoded managed label
outright
today (`raw-self-hosted-label`, "consume the approved selector output"),
and the
four `ci.yml#ci-status` local-routing grants added in Phase 3.2 stop
applying
the moment the literal replaces the selector expression, at which point
each one
fires as an unconsumed grant while the job it was written for fires
`privileged-hosted-only`. Both halves have to land before any Phase 4
pull
request opens.

## Fix

`components/runner-policy/runner-policy.mjs`

- New routing target kind `managed-literal`: a plain string that is an
exact
  member of the new required policy key `approvedManagedRunnerLabels`,
classified after the `${{ … }}` catch-all so an unrecognised expression
that
merely mentions the label is still refused. Admission is deliberately
not a
`managedLabelPatterns` match: those patterns are an unanchored,
unbounded
DETECTION surface whose job is to catch every label-shaped string and
refuse
it, so using them to admit would invert the safe bias and hand an
unreviewed
near-miss such as `melodic-anything-ubuntu-24.04-x64` the same trust as
the
real fleet label. Entries are validated at load: surrounding whitespace,
a
known GitHub-hosted label, or a string that does not itself read as a
managed
  label is a configuration error.
Approval is unconditional in the classifier and the existing routing
gate
refuses it when routing is disabled, which is exactly how
`selector-output`
is handled, so a public repository keeps reporting
`public-self-hosted-routing`
  and a private repository with `selfHostedCi: false` keeps reporting
  `self-hosted-routing-disabled`.
- One predicate, `locallyRoutedTarget`, now stands for the two ways a
job
reaches the fleet, and every gate reads it: grant applicability and
grant
consumption (which have to stay exact complements, or a grant admits a
job and
then fires inventory drift on the same run); the reviewed
caller-permission
  waiver and the reviewed secret boundary (without which a fleet-literal
  `claude-review` caller reports `privileged-hosted-only`); the
  explicit-read-only floor; and the local-execution test inside
  `auditLocalPermissionFlow`.
- That last one closes a hole. A job reached through a repository-local
`workflow_call` whose own `runs-on` named the fleet label matched
neither the
local nor the hosted execution test, so the flow pass fell through and
emitted
  nothing: a called job inheriting a write-capable caller token ran on a
persistent host with no finding at all. medley's gateway plus its eight
  `workflow_call` workers are that shape until Phase 5 collapses them.
- `raw-self-hosted-label` keeps every case it should still catch: a
literal
containing `self-hosted`, a `vars.CI_SELF_HOSTED_LABEL` or
`CI_MANAGED_RUNNER`
reference, and a managed label on any repository that is not an enrolled
private consumer. Only the exact label a routing-enabled job resolves to
is
skipped, in `runs-on` and in an approved reusable call's `runner` input
alike.
- Two messages change and no rule id does. `privileged-hosted-only` now
says the
job requires a reviewed `localRoutingGrants` entry or a hosted
exception;
`hosted-exception-required` now says an eligible private job must name
the
governed fleet label or declare its key in `.github/runner-policy.json`.
The id stays because it appears in `THREAT-MODEL.md`, throughout the
test
  suite (25 occurrences) and in merged pull-request bodies.

`components/runner-policy/policy.json` and `policy.schema.json`: two
additions.
The code-review lane contract at
`0f8176e87e0be518f382664779655011bf95784a`
widens its reviewed input list to `runner, pr-number, timeout-minutes`,
all three
of which the reusable declares at that revision.
`approvedManagedRunnerLabels`
is a new required key carrying the two live fleet labels
(`melodic-ubuntu-24.04-x64`, `melodic-review-ubuntu-24.04-x64`), so
adding a
label to the fleet is a reviewed, data-only policy change exactly like
adding an
approved hosted label. Both labels every planned wave writes are already
in the
set, so no downstream repository change needs a policy edit; the
`kyle-*`
personal-repository namespace stays detection-only and would need its
own
reviewed entry. Making the key `required` is safe to ship because
`policy.json`,
`policy.schema.json` and `runner-policy.mjs` are one component in
`distribution/sync-manifest.yml`, so a sync moves them atomically and no
consumer
can run a new checker against an old policy.
`approvedSelectorReferences`,
`approvedSelectorReferencesByRepositoryOwner`,
`approvedSelectorInputContracts`
and `canonicalSelectorSecrets` are byte-unchanged, and the
`selector-pin` and
`selector-contract` rules are untouched: three of the five sync targets
are
still selector-routed when this reaches them, so a grammar that refused
selector
routing would turn every sync pull request red.

`components/claude-lanes/claude-review.yml`: the `select-review` job is
deleted
and `runner` is the literal `melodic-review-ubuntu-24.04-x64`. Triggers
keep
`[opened, ready_for_review, reopened]` and gain a `workflow_dispatch`
with a
required `pr-number`. The draft filter is event-guarded
(`github.event_name == 'workflow_dispatch' ||
github.event.pull_request.draft == false`),
because a dispatched run has no `github.event.pull_request` and a bare
draft
comparison would refuse the review the operator just asked for.
`timeout-minutes`
is 15, below the reusable's 30-minute default, since the lane is
advisory. Both
concurrency blocks stay, including the repository-wide `queue: max` seat
group.

`components/claude-lanes/claude-security-review.yml`: same selector
deletion,
same literal, a plain draft filter, and `synchronize` dropped. The
filter is
plain rather than event-guarded because this lane has no
`workflow_dispatch`
trigger, so `pull_request` is the only event that can start it and
`github.event.pull_request` is always present; the comment says that
adding a
dispatch trigger later means adding the guard with it. The
rationale for keeping `synchronize` was that a required
execution-evidence check must
report on the latest head, and that constraint is not live: github-iac
ADR 0011
makes agentic reviews advisory and forbids any organization ruleset from
making
their status a merge or deployment prerequisite, and
`security-review-gate` is
disabled. No `timeout-minutes` and no `pr-number`: the reusable exposes
neither
at this pin nor at `main`. Its per-pull-request group with
`cancel-in-progress: false` stays.

Both callers keep the pin they already carried,
`0f8176e87e0be518f382664779655011bf95784a`.

`components/claude-lanes/repin-policy-lockstep.mjs`: `updateTestMjs` is
gated on
a selector copy-forward having actually happened. The selector repin
target
already read zero pins from a selector-less caller and skipped, so
`copySelectorContract` could not run and `policy.json` never gained the
entry,
but the test file would have gained a constant for it anyway on the next
ci-workflows tag.

README and THREAT-MODEL record the new target kind, the widened grant
applicability, the new threat row for a fleet label named where routing
is not
enabled, and the accepted residual: the literal has no hosted recovery
fallback
and no failure sentinel, so a job queues when no runner is online. That
is a
different control's job (fleet queue-depth alerting, and a second host),
and it
is written down rather than implied.

## Verification

- `npm run test:runner-policy` exits 0: 287 tests, 287 pass, up from
274.
Thirteen new cases plus one rewritten. New coverage: a fleet literal
admitted on a
  private `selfHostedCi: true` repository; refused on public with
  `public-self-hosted-routing` and on `selfHostedCi: false` with
`self-hosted-routing-disabled`; a config claiming `private` under public
visibility evidence raising the configuration error the CLI reports as
exit 2;
a hosted literal still requiring a named exception on an enrolled
private
  repository and still clean on public and on `selfHostedCi: false`; a
write-token job on the fleet label refused without a grant, admitted
with a
matching one, and refused with the "outside the reviewed local-routing
grant"
message when the map differs; a fleet-literal job with omitted
permissions
still refused; a grant keyed to a fleet-literal reusable-call job still
surfacing as `local-routing-grant-drift`; a reusable call whose `runner`
input
  is the fleet review label admitted under `allowedCallerPermissions`; a
  repository-local call whose jobs run on the fleet label reported as
  `local-reusable-permissions`; the Phase 3.2 `ci-status` grant shape
auditing clean both selector-routed and on the literal; five unreviewed
  near-miss and adjacent-text label shapes refused; and three
  `approvedManagedRunnerLabels` entries that must fail configuration.
- Every one of those new cases was run against the unmodified grammar
first and
failed there: thirteen failures on `origin/main`'s `runner-policy.mjs`,
zero
  after.
- The two lane-caller tests that were keyed to `/select-runner.yml@` now
recognise a managed label as well, and both assert that at least one
caller
was actually checked, so they cannot shrink to nothing when a caller
drops its
  selector job.
- `bash components/claude-lanes/claude-lanes.test.sh`: 32 assertions,
all pass.
Both rewritten callers materialize through `sync-manifest.sh apply` and
lint
clean under `actionlint` 1.7.12 at every managed target. Harness note
for the
next person running this locally: `sync-manifest.sh apply` compares the
source
worktree bytes against the indexed object, so an uncommitted, unstaged
edit to
a component file fails the suite with "source worktree bytes differ from
the
  indexed object" rather than with anything about the edit. Stage first.
- `node --test components/claude-lanes/repin-policy-lockstep.test.mjs`:
7 tests,
  7 pass.
- `bash components/claude-lanes/repin-callers.test.sh`: 116 assertions,
exit 0.
- `GITHUB_REPOSITORY=melodic-software/standards
CI_REPOSITORY_VISIBILITY=public
  npm run lint:runner-policy` exits 0.
- `npm run lint:md` clean; `npx @biomejs/biome check
components/runner-policy
  components/claude-lanes` reports only the pre-existing
`noTemplateCurlyInString` warning on `repin-policy-lockstep.mjs:300`.
lefthook
  pre-commit ran on both commits and was never bypassed.
- Acceptance run required by the transition window: this branch's
checker and
this branch's `policy.json` against a scratch clone of each sync
target's
  current `origin/main` `.github/` tree, with `GITHUB_REPOSITORY` and
`CI_REPOSITORY_VISIBILITY` set per target. All five exit 0: dotfiles 0,
github-iac 0, provisioning 0, medley 0, claude-code-plugins 0 (public).
The
same five run against `origin/main`'s checker and policy also exit 0, so
this
  change neither breaks nor newly silences any of them.

## Related

- Refs melodic-software/github-iac#403
- Refs melodic-software/github-iac#378
- Phase 3.5 landed in #525, which is still open; that pull request and
this one
  touch disjoint components.
- After merge this reaches five targets through
`distribution/sync-manifest.yml`, one sync pull request each: dotfiles
and
  medley take `runner-policy` and `claude-review-caller`, github-iac and
  provisioning take those plus `claude-security-review-caller`, and
claude-code-plugins takes `runner-policy` only. Each sync pull request
must be
green on its own `runner-policy` lane and must merge before that
repository's
Phase 4 or Phase 5 pull request opens. `distribution/sync-manifest.yml`
is not
  edited here; no target list changes.
- A separate github-iac pull request amends ADR 0011 to record that
`security-review-gate` stays disabled and that the security lane
therefore
drops `synchronize`. It is not in this repository and is not opened
here.

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor Author

Lane claim: babysit-loop

  • Instance: ccr-session-babysit-loop-20260905
  • Head SHA pinned: 9b95c565e5826e7eb908f9bc4f1f9d16a75e0815
  • Claimed at: 2026-09-05T03:38:00Z, expires 2026-09-05T04:38:00Z
  • Observed state at claim: mergeable_state=clean, 30/30 checks success, no blocking labels.

Advancing this PR through the repo's tracked merge configuration. This claim is released when the lane finishes or the expiry passes, whichever comes first.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

Lane release: babysit-loop — not merged, held on the Phase 3.3 apply

Lease released; the claim above is withdrawn. No merge, no push, no thread resolution was performed. Head is unchanged at 9b95c565e5826e7eb908f9bc4f1f9d16a75e0815.

Why this did not merge, despite mergeable_state=clean and 30/30 green.

The scout read this PR as independent and closest to done. That is wrong, and the evidence is on this PR and its tracker:

  1. The reply on the codex P2 thread for .claude/rules/pr-body-contract.md states this PR merges only after the Phase 3.3 ruleset change is applied, so the distributed sentence is true fleet-wide at merge time.
  2. melodic-software/github-iac#396, comment of 2026-09-05T01:27:25Z, names this PR directly: "Items 3.4 and 3.5 (standards#525 and the nine syncs) wait on that apply."
  3. github-iac#401 ("require ci-status alone on ci-gate") did merge at 2026-09-05T01:38:39Z, but merging is only the first of the three owner steps that comment lists. The apply has not run:
    • the newest deploy.yml run in github-iac is 33879436763 at 2026-09-04T13:41:04Z, which predates the Link checker report #401 merge; nothing has been dispatched since.
    • GET /repos/melodic-software/standards/rules/branches/main still returns four required contexts: pr-title / pr-title, pr-issue-linkage / pr-issue-linkage, do-not-merge / do-not-merge, ci-status.

So ci-status is not yet the single required check. Merging now would sync a rule file asserting that it is to nine target repositories, which is the exact outcome the codex finding raised and the author's reply deferred rather than dismissed.

Remaining owner-only steps (from github-iac#396): dispatch deploy.yml in github-iac and approve the github-iac-production environment. Once rules/branches/main returns ci-status alone, this PR is unblocked on that axis.

Second, independent hold. The deterministic merge gate could not run in this session, so merge-readiness is unproven, never merge-ready. gh here is 2.45.0 and lacks the closingIssuesReferences and baseRefOid fields the gate and snapshot request, and this session's GraphQL endpoint is restricted to a pinned PR-review set (HTTP 403), which gh pr view --json and review-thread resolution both need. Command attempted:

bash "${CLAUDE_PLUGIN_ROOT}/bin/source-control-babysit-merge" melodic-software/standards#525 --allowed-owners melodic-software --self-logins @me

It exited 2 with a RuntimeError before evaluating anything, so there is no blockers list and no ready field. Per the lane's safety contract, live mergeStateStatus and the check rollup are not a substitute verdict, and no merge was attempted by any other route.

Also noted, not acted on: the branch is diverged from main, ahead 4 / behind 2. The base does not require up-to-date branches, so this is not blocking. Refreshing was skipped deliberately: it would re-run 30 lanes for a PR that is held anyway and will want re-verification after the ruleset flips.

Instance ccr-session-babysit-loop-20260905.


Generated by Claude Code

@kyle-sexton
kyle-sexton merged commit 36019f2 into main Sep 5, 2026
1 check passed
@kyle-sexton
kyle-sexton deleted the ci-perf/phase-3-contract branch September 5, 2026 08:18
kyle-sexton added a commit to melodic-software/cursor-plugins that referenced this pull request Sep 5, 2026
…27)

No related issue: melodic-software/github-iac#396 tracks Phase 3 of the
ci-perf program

## Summary

Deletes the three pull-request contract workflow callers that
`ci-status` has
replaced: `.github/workflows/pr-title.yml`,
`.github/workflows/do-not-merge.yml` and
`.github/workflows/pr-issue-linkage.yml`. Nothing else changes; `ci.yml`
is
untouched.

Since cursor-plugins#26 (merged as
`855cc8994109fc1a32066780b8ebb29c787cc887`)
the `ci-status` job runs the `pr-contract` composite, which performs the
same
three checks in one job: the Conventional Commits title check, the
`do-not-merge` label check, and the issue-linkage check. Phase 3.3 then
reduced
the org `ci-gate` ruleset to require only `ci-status` on every enrolled
default
branch (github-iac run 33954697296), and the standards lockstep re-point
(melodic-software/standards#525) merged, so the three callers no longer
back a
required check and nothing reads them.

## Fix

- `git rm .github/workflows/pr-title.yml`
- `git rm .github/workflows/do-not-merge.yml`
- `git rm .github/workflows/pr-issue-linkage.yml`

Three files, 77 deletions, no insertions.

No `exempt-authors` value carries over. This repository's
`pr-issue-linkage.yml` caller passed only `runner: ubuntu-24.04`, so the
`pr-contract` step in `ci.yml` needs no new input and `ci.yml` is not
edited.

The reusable workflows in `melodic-software/ci-workflows`
(`semantic-pr.yml`,
`do-not-merge-gate.yml`, `pr-issue-linkage.yml`) are not touched; they
are
retired separately in Phase 7. The `do-not-merge` and
`needs-issue-linkage`
labels are still real and stay: `pr-contract` reads the first and writes
the
second.

## Verification

Run locally in the worktree at
`5351c25ef8687438054ee47ed1265a4664a9b512`:

- `grep -rl "pull_request_target" .github/workflows/` returns nothing.
The
three deleted callers held the last `pull_request_target` triggers in
this
  repository.
- `ls .github/workflows/ | grep -cE
"^(pr-title|do-not-merge|pr-issue-linkage(-self)?)\.yml$"` prints `0`.
- `actionlint .github/workflows/*.yml`: one finding, the pre-existing
`SC2016:info` note inside the `links` lane of `ci.yml` at `:181:9`,
present
  byte-identical on `origin/main`. Nothing new.
- `zizmor --persona regular .github/workflows/`: `8 findings (3
suppressed)`,
  `1 low, 4 medium`, versus `17 findings (3 ignored, 9 suppressed)`,
`1 low, 4 medium` on `origin/main`. The five reported findings are the
same
four `warning[artipacked]` and one `help[adhoc-packages]` in `ci.yml`.
The
  drop is the deleted files' own findings and suppressions. Nothing new.
- `yq '.permissions' .github/workflows/ci.yml` prints `contents: read`,
not
  null.
- `git diff origin/main --stat` shows only the three deletions.

The repository has no `package.json`, no lefthook and no test that
enumerates
workflow files. A repository-wide grep for `pr-title`, `do-not-merge`
and
`pr-issue-linkage` across Markdown, YAML, JSON, JavaScript, PowerShell,
Python
and shell files found no documentation or test that describes the
deleted
workflows as checks; the only surviving mentions are two comment lines
in
`ci.yml` that name the three contract answers the `ci-status` predicate
covers,
which stay correct.

## Related

Refs melodic-software/github-iac#396
Refs melodic-software/github-iac#378

Co-authored-by: Claude Fable 5.1 <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