Skip to content

ci(half-state-patrol): call objectstack's composite action pinned to a sha, with the no-anchor opt-in (objectui#11174) - #11332

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-11174-half-state-patrol-composite-action-r2
Oct 1, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-11174-half-state-patrol-composite-action-r2

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #11174
Clause-②: no. CI wiring only; no published contract or accept set moves.

objectui's half of objectstack-ai/objectstack#18471 (ruling 只做②). The half-state patrol stops checking out objectstack main unpinned and running the sweeper from it. It now calls objectstack's composite action at a pinned 40-character sha, using the no-anchor opt-in that objectstack-ai/objectstack#20793 (decision A) declared for this board. Dispatched by domain:devx seat 2, session https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh, claim comment 5924897388.

What changed

  • .github/workflows/half-state-patrol.yml. These steps are gone: the objectstack checkout (no ref:, so main), the node objectstack-tooling/scripts/pm/check-half-states.mjs step, the inline resolve-anchor, update-anchor, summary and fail steps, and the ANCHOR_ISSUE env.
    • One step replaces them: uses: objectstack-ai/objectstack/.github/actions/half-state-patrol@0c5a71b0942d54e56ad365f0b2a173fd84c1c5e1.
    • It passes github-token: secrets.GITHUB_TOKEN, anchor-issue: '', anchor-optional: true and closed-floor: '2026-08-28'.
    • actions/checkout and actions/setup-node (node '22') stay in the caller. The action needs both: the checkout is the swept subject, and the action has no Node pin of its own.
    • Unchanged: the trigger, schedule, permissions, concurrency, job key and job name. The job name is "Live half-state sweep", the check-run name that scripts/dependabot-merge-gate.mjs classifies. To confirm, both versions were parsed with yaml and on, permissions, concurrency, jobs.patrol.name, runs-on and timeout-minutes all compare SAME.
    • The prose adopted from upstream is deleted. The header now holds only what belongs to this board: the pin and how to bump it, the no-anchor decision (objectui#8740), and the closed-card floor (objectui#5985). The file shrinks to about a third of its old length.
  • content/docs/guide/ci-cd-pipeline.md, Half-State Patrol section. It now describes the action call, the pin and how to bump it, the four inputs, the no-anchor configuration and its accepted cost, the PR-run blind spot, the floor, and a hand-run recipe. The recipe gains PM_SWEEP_CLOSED_FLOOR=2026-08-28 and a note to check out the pinned sha to reproduce a run.
    • The Trigger line and the inventory row are unchanged; both are still true.
  • scripts/__tests__/ci-cd-pipeline-doc.test.ts.
    • The objectui#8043 block compared PM_SWEEP_* env keys, and the workflow no longer sets any. It now compares the section against the patrol step's parsed with: inputs (via yaml), in both directions. It also holds the floor value, the anchor configuration (empty anchor-issue + anchor-optional: true), and the 40-hex shape of the ref.
    • One SWEEP_DECLARED_NON_RUN_COMMANDS entry is added, for half-state-patrol.yml: scripts/pm/check-half-states.mjs. The section names objectstack's sweeper, and the job now has no run: step at all. This is the same dual-eligible shape as the existing check-links.yml entry.
  • scripts/check-action-ref-convention.mjs and its test (see the surface note below).
    • The sha spelling is off-convention for this repository's Action Ref Convention gate, so it gets a DECLARED_EXCEPTIONS entry with its reason and issue.
    • That gate's two non-vacuity cases used to replace the real table with a synthetic one. They now append the synthetic entry to it, so they hold whatever the real table carries.
    • The table's docblock no longer says "deliberately empty". It now says that an entry is matched by workflow and action, not by spelling, and names where this entry's "sha, never a branch" half is held.

The pin

  • Sha: 0c5a71b0942d54e56ad365f0b2a173fd84c1c5e1. This is objectstack origin/main's tip, read at 2026-10-01T04:46:15Z with git -C /home/user/objectstack fetch origin main and then git rev-parse origin/main. Its commit date is 2026-10-01T03:32:30Z (fix(metadata-protocol): a packaged action or permission set's refusal names its own sanctioned path (ADR-0126 Regime C rows) objectstack#21026).
  • Ancestry: git merge-base --is-ancestor 79114850f0f559dcb4fb432f5bcfc12947a03de6 0c5a71b0942d54e56ad365f0b2a173fd84c1c5e1 gives exit 0. An "is an ancestor" answer proves itself even on the shallow objectstack clone, so no control leg is owed. git rev-list --count between them gives 127 commits.
  • Not the action's own last commit. The pin is main's tip, as the Q2 ruling requires. At the pin, both action.yml (blob 2df36034) and scripts/pm/check-half-states.mjs (blob fa35f635) are byte-identical to what 79114850f landed. So today the two choices run the same code. The tip rule is what keeps that true on the next bump.
  • Input names read off action.yml at the pin:
    • declared: anchor-issue, anchor-optional, closed-floor, github-token;
    • passed: the same four;
    • passed but undeclared: none; required but not passed: none.
  • Ruling sources: the Q2 ruling A is comment 5905360637, the handover is 5908038257, and anchor-optional comes from ci(half-state-patrol): a declared anchor-optional input lets a board with no anchor issue run summary-only (default off) objectstack#20812.

Acceptance evidence: what this PR's own run can and cannot show

  • This PR's pull_request run of Half-State Patrol exercises the pin, the inputs and the transport on a real runner. The action's Locate the patrol sources step judges github-token and the anchor-optional spelling on every event, pull_request included, and the sweep runs.
  • But it skips both anchor steps, so it cannot show the opt-in. The live reading is the first scheduled run (cron 37 1,7,13,19 * * *) or workflow_dispatch run after this lands. The expected result:
    • Resolve the anchor issue writes configured=false and emits the ::notice:: naming anchor-optional: true;
    • Update the pinned anchor issue is skipped;
    • the run is green.

Tests

Every check below was run on head ec0c6e49, except where a line names a13f4e5f. That earlier head differs only by the header-comment edit in the second commit.

  • actionlint 1.7.7 (release binary; actionlint is not wired in this repository): actionlint -shellcheck= -pyflakes= .github/workflows/half-state-patrol.yml gives exit 0.
    • Positive control: the same file with permissions: misspelled gives exit 1, unexpected key "permissionz".
    • ⚠️ actionlint cannot check a remote composite action's inputs. That check is the action.yml read under The pin.
  • vitest run scripts/__tests__/ (through os-verify-lock, --maxWorkers=2) on ec0c6e49: 177 files passed and 2 skipped (179); 5374 tests passed and 2 skipped (5376); VERDICT command-exit 0. The same result on a13f4e5f.
  • Targeted: pnpm exec vitest run scripts/__tests__/ci-cd-pipeline-doc.test.ts scripts/__tests__/check-action-ref-convention.test.ts gives 2 files and 104 tests passed. On the base it gave 101.
  • tsc -p tsconfig.scripts.json --listFiles on a13f4e5f gives exit 0, and both edited test files are in the program. ec0c6e49 changes only the workflow YAML, which is outside that program and outside the lint population below.
  • Gates, all exit 0:
    • pnpm check:doc-fences, pnpm docs:check-links, pnpm check:control-bytes, pnpm check:action-ref-convention, pnpm check:new-line-citations (0 new citations), pnpm check:test-path-roots and node scripts/check-shell-escape-residue.mjs;
    • node scripts/check-changeset-presence.mjs: "no changeset is owed". Nothing under a released package's source or contract moves, so no changeset is added and no label is applied;
    • node scripts/check-governed-queue-guard.mjs --test over the five paths: NOT GOVERNED.
  • ESLint, narrowed to this diff: eslint --format json over the three lintable files reports 3 files, 0 errors and 0 warnings. The YAML and the Markdown are not in the lint population.
    • The population is lint:root, which is eslint . minus packages/, examples/, apps/ and docs/. The three files sit inside it.
    • The narrowing excludes nothing that could move:
      • eslint.config.js has no parserOptions or projectService, so the linting is not type-aware;
      • eslint-rules/*.js read no files (readFileSync/existsSync/readdirSync give zero hits);
      • so no untouched file's verdict can change.

Ablations (one-shot; nothing kept)

Each ablation ran through objectstack's scripts/ablation-replace.mjs in WRAP mode on committed head a13f4e5f. In each, the anchor hit once, the blob changed, and the file was restored with blob == HEAD and git diff HEAD empty.

  1. @0c5a71b0… changed to @main: exactly 1 red, "pins the action to a 40-character sha … never a branch". check-action-ref-convention.test.ts stayed green, which is the hole that pin covers: the exception matches by workflow and action, not by spelling.
  2. anchor-issue: '' changed to '9857': exactly 1 red, "describes the anchor configuration the step actually passes".
  3. closed-floor deleted: 2 red, "names only inputs the workflow actually passes" and "quotes the closure floor".
  4. The doc's github-token bullet stripped of its name: 1 red, "names every input the workflow passes".
  5. The gate without the new entry, run as scan(root, { exceptions: [] }) with no file mutated: 1 offender, half-state-patrol.yml … [sha].

Surface note for the seat

The claim's surface lists the workflow, the doc section, ci-cd-pipeline-doc.test.ts and "any other git grep half-state-patrol hit whose assertion moves". This PR also edits scripts/check-action-ref-convention.mjs and scripts/__tests__/check-action-ref-convention.test.ts.

  • Neither file was a grep hit before this change. Both read this workflow's text, and their verdict moves with it, so they fall under the original claim's definition of the surface (5905159945: "the tests or scripts that read this workflow's text").
  • The ruling's sha pin is off-convention for the blocking Action Ref Convention gate, and that gate admits exactly one form of exception: a DECLARED_EXCEPTIONS entry.
  • No other workflow and nothing in objectstack is touched. The seat may want to amend the claim's surface to match.

Acceptance notes (noted, not filed)

  • Prose drift in workflows this claim excludes:
    • merge-queue-head-patrol.yml's header still says half-state-patrol.yml "fails when its anchor variable is unset". That has been false since objectui#8740. Its env comment cites "the reason half-state-patrol.yml states"; the new header keeps that sentence, so the citation still resolves.
    • changeset-guard.yml, performance-budget.yml, lockfile-dedupe.yml and the docblock of render-budget-comment.test.ts say this workflow lists scripts/invoked-as.mjs in its paths. That has been false since objectui#10208, not because of this PR.
    • Carrier: none.
  • Dependabot. Its github-actions ecosystem runs monthly here. Whether it proposes bumps for a sha-pinned ref to a non-tagged action path inside a monorepo is NOT MEASURED. If it does, the bump arrives as a PR touching this file, which runs the patrol, so it is a reviewed moment in any case.

Generated by Claude Code

claude added 2 commits October 1, 2026 04:56
…a sha, with the no-anchor opt-in (objectui#11174)

The patrol no longer checks out objectstack `main` unpinned and runs the
sweeper from it. It calls
objectstack-ai/objectstack/.github/actions/half-state-patrol at a 40-character
objectstack commit sha (objectstack main's tip as read at implementation time,
which contains 79114850f where `anchor-optional` was declared), passing
`github-token`, an empty `anchor-issue` beside `anchor-optional: true` (this
board's supported no-anchor configuration, objectui#8740), and
`closed-floor: '2026-08-28'`. Trigger, schedule, permissions, concurrency and
the job name are unchanged. The header prose adopted from upstream is gone; what
remains is this board's own: the pin and how to bump it, the no-anchor decision,
and the closed-card floor.

Every pin of the old shape moves with it:
- the Half-State Patrol section of content/docs/guide/ci-cd-pipeline.md;
- ci-cd-pipeline-doc.test.ts: the objectui#8043 block now compares the section
  against the patrol step's parsed `with:` inputs instead of `PM_SWEEP_*` env
  keys, and holds the sha shape of the ref; the sweeper path the section names
  is declared as a non-run command (the job has no `run:` step any more);
- the sha spelling is a declared exception in check-action-ref-convention.mjs,
  and that gate's non-vacuity tests append their synthetic entries to the real
  table instead of replacing it.

Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh
Co-authored-by: Claude <noreply@anthropic.com>
…i#11174)

The no-anchor paragraph quoted the maintainer's Chinese closing words on
objectui#7852; AGENTS.md rule #-1 keeps code comments English, so the header
now names the closure instead of quoting it.

Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

CI red that is not this PR's: Spec Main Shape Gate. domain:devx seat 2 (objectui#10917), session_01TdiauJaVCHuj45EzZGUxHh, 2026-10-01T05:37Z.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 1, 2026 07:15
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 1, 2026 07:15
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 1, 2026
Merged via the queue into main with commit 2c274e3 Oct 1, 2026
43 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11174-half-state-patrol-composite-action-r2 branch October 1, 2026 07:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd configuration documentation Improvements or additions to documentation tests

Projects

None yet

2 participants