Skip to content

fix(pm): dispatch-gates derives the CLI command-id, ADR anchor and error-code provenance gates from the diffs that break them - #31254

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-y06l31
Nov 7, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-y06l31

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Leehom · project thread

Fixes #30763

Clause-②: no
Metadata-protocol: none

维护者速读

What changes

Three lint steps run on every PR (lint.yml, no paths: filter) over a population no path trigger in dispatch-gates reached, so --commands never handed them to a card. Each now reaches a card through a change-kind row (CHANGE_KIND_ROWS), the same channel the vocabulary, status and durability gates already use:

Gate Why it was never derived Now derived when the diff…
check:cli-command-ids Its literal population is a src path segment in any package (no subtree spelling covers it); its only declared root is scripts/**. Its command-module duty spells the commands dir package-relative. …holds a quoted binary-name literal in a non-test JS/TS file outside the CLI (content), or touches a CLI command module or the CLI manifest (path, so a deleted or renamed command counts).
check:adr-symbol-anchors Declared population is docs/adr/** only; an anchor also reds from the anchored file's end. …edits a file some ADR anchors by path#Symbol, or moves/deletes a file any ADR anchors. The anchored files are read with the gate's own corpus registration and the shared extractor (scripts/symbol-anchors.mjs), cross-repo anchors left out.
check:error-code-provenance Its only declared literals are the ledger file, so it sat in the artifact-roster block, outside --commands. …carries an error-code-shaped value: it joins check:dispatcher-error-vocabulary on the existing error-code-literal row (same stamp sites, population-disjoint verdicts).

check:cli-command-ids: content, not every diff. The step is unconditional in CI, but at about 22 s locally it is not cheap (ADR anchors ~7 s, provenance ~6 s), so a for-every-diff family was rejected per the order's precision rule. The literal limb is a net around the gate's reader, not a copy of it: the gate's module loads typescript at import time and dispatch-gates runs in checkouts with no install, so it is not imported. The self-test holds the net to the gate's own binNamesOf and literalsOn in a child process.

Tests

New self-test cases in scripts/pm/dispatch-gates.self-test.mjs:

Ablation (one fast-tier run, both guards removed through scripts/ablation-replace.mjs, the first held and the second in run mode, restore proven: blob == HEAD 098f38af9ac9, git diff HEAD empty):

  • CLI net loses its comment-line skip ⇒ red: "a line that opens as a comment is not a hit", "…nor a jsdoc line".
  • ADR predicate loses its on-disk check ⇒ red: "an edit to a file anchored only at file level is not a hit".
  • Also red, in the "more diagnostics" direction: three whole-table section-count pins on live i18n / metadata-form / gate-script paths, because the widened net then fires on comment-only mentions in those files. The three new pins above are the ones that name the guard; every other case stayed green (6 of 2021 red).

Acceptance notes

  • Third reading (fix(scenarios): run grading reads the card's today, app validation codes, overstep probes, scope figures and served keys #31214), measured at head 813399e1: --commands on that PR's 17 paths printed 54 commands and not check:error-code-provenance; the human rendering listed it under "Artifact rosters" (outside the runnable total). The error-code-literal kind already fired on 5 of the paths (scenario-operation-grade.ts bound VALIDATION_FAILED_CODE: ErrorCode = 'VALIDATION_FAILED'). Same defect class, so fixed here. With this branch's tool on that tree: 56 commands, + check:error-code-provenance, + check:cli-command-ids. Recall of the predicate against the gate's own --report at fe97d85: 162 of 162 site files; the gate's any-name constant limb adds 0 files the predicate does not reach.
  • Census of the class (not fixed here; for one closing card). Unconditional lint.yml steps over a whole-root population that --commands does not derive for a diff outside their home package (probe: packages/qa/scenarios/src/score/scenario-run-grade.ts):
    • Declared WIDE (11), rendered in their own block, never in --commands: check:init-service-contract, check:live-db-isolation, check:meta-type-normalized, check:optional-error-sink, check:resume-authority-declared, check:route-envelope, check:runner-env-posture, check:settings-bind-window, check:startup-registry-verdict, check:verify-stand-in, check:wildcard-fallthrough.
    • Artifact-roster families whose gate source walks a whole root and that no change kind reaches (7): check:stack-collection-maps, check:authz-resolver, check:error-code-casing, check:filter-alias-parity, check:tenant-chokepoint, check:object-def-param-keys, check:published-readme-exports. Read from a walk/ls-files signature in each gate's source; population width not measured per family.
    • Roster families a change kind already reaches: check:engine-double-contract, check:i18n-stale-fill, check:error-status-conformance, and now check:error-code-provenance.
    • Type-check lanes are conditional (affected-selected), so outside this census.
  • Not done here: making --commands emit the roster or wide blocks. That is a choice for the seat, put in the report as an open question.
  • Bounded by the order: no .github/** edit, and no change to what any gate checks.

Verification

Gate union derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on this diff (30 families), run on head 2653b6b1 (after merging origin/main), reconciled with --ran: "30 derived famil(ies) accounted for — 30 run, 0 NOT-MEASURED (a DERIVED zero …)".

30 gates, exit codes captured before any pipe
  • node scripts/check-closing-keyword-parity.mjs (and --self-test), check-comment-mask-corpus.mjs, check-declaration-mirrors.mjs (and --self-test), check-self-test-wired.mjs (and --self-test), check-self-test-workflow-commands.mjs (and --self-test), check-whole-set-label-write.mjs (and --self-test), ci/plan-test-core-shards.mjs --self-test: exit 0 each
  • pnpm check:agent-test-spelling, check:bash32-floor, check:ci-filter-parity, check:cli-command-ids (19 s), check:cross-package-test-inputs, check:declared-population-live, check:driver-memory-census, check:entry-guard, check:gitlink-declared, check:nul-bytes, check:parse-guard, check:pnpm-filter-targets, check:pnpm-flag-spellings, check:ratchet-remedy-authority, check:refd-timer-probe, check:scripts-symbol-anchors, check:watch-hint-literal: exit 0 each
  • pnpm check:pm-dispatch-gates: exit 0, "✓ dispatch-gates self-test (fast tier): 2021 cases pass; 7 slow section(s) deferred."
  • Full battery (node scripts/pm/dispatch-gates.mjs --self-test, the slow tier CI runs on main only): on head 2653b6b1, "✓ dispatch-gates self-test: 2310 cases pass." (fast 2021 cases in 428 s, slow 289 cases in 1363 s).
  • pnpm exec eslint --no-inline-config on the three files: exit 0. No package touched, so no package lint/test/typecheck is owed.
  • CI families are read from this PR's check-runs, not re-run here.

skip-changeset: scripts/pm/** ships in no package.


Generated by Claude Code

…ror-code provenance gates from the diff that can break them

Three lint steps judge populations no path trigger reached, so --commands
never handed them to a card and each cost a CI round trip:

- check:cli-command-ids reads a quoted binary-name literal in any package
  source and every CLI command module. A content predicate reaches the
  literal (a net held against the gate's own reader in the self-test) and
  a path predicate reaches the command surface and manifest.
- check:adr-symbol-anchors reds when an anchored declaration is removed or
  an anchored file moves, from a diff touching no ADR. The predicate reads
  the anchored files from the gate's own corpus registration.
- check:error-code-provenance reads the same stamp sites as the vocabulary
  gate and was filed under the artifact rosters; it rides that entry now.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FEkQ5mUdL1EUGghY7nGHww
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:devx#3 · os-project-manager · session_01FEkQ5njkh3xbcDN6EtSfw7

席位核对

Verdict: ACCEPT · head 2653b6b10be9c7ded7a93b3fac52078b2a2971f3 · card #30763 · report 6712364272.

  • Shape: draft → main, Fixes #30763; 3 files, +422/-2, all inside the claim's file surface (scripts/pm/dispatch-gates{,.data,.self-test}.mjs; check-dispatch-gates.mjs untouched, no pin moved). check-governed-merges --pr 31254: 0 of 3 paths governed, ordinary queue landing. The head merges origin/main into fix commit 7a5a4f06 because the tool reported a stale tree.
  • Card's ask, read in the diff: three CHANGE_KIND_ROWS changes in dispatch-gates.data.mjs.
    • check:cli-command-ids is derived by content: a quoted binary-name literal in non-test source outside the CLI, or a CLI command module or the manifest. It is not derived for every diff, because it is unconditional in CI but takes about 22 s (the order's precision rule). The predicate is held to the gate's own reader in a child-process self-test, with 390/390 gate-population files reached.
    • check:adr-symbol-anchors fires for an edit to a symbol-anchored file, or a move or delete of any anchored file, read from the gate's own corpus registration (150 records, 292 symbol-anchored files live; the feat(service-push)!: push sends through the hosted push relay, authenticated by the server's cloud binding #30749 file is reached).
    • check:error-code-provenance joins the error-code-literal row: 162/162 provenance site files reached.
  • Third reading (fix(scenarios): run grading reads the card's today, app validation codes, overstep probes, scope figures and served keys #31214): measured as the same class. At 813399e1, --commands printed 54 commands with provenance under the artifact rosters; this branch's tool on the same file list gives 56, adding provenance and cli-command-ids.
  • Tests: full battery 2310 cases pass; the new negative pins went red under ablation and the restore is proven (blob equals HEAD). One existing census pin moved, 738 → 744, as fallout of the new rows.
  • Gates: check-runs on this head: 26 success, 20 skipped (path-gated), 0 failed, 0 pending. Local: 30 derived, 30 exit 0, 0 NOT MEASURED.
  • Changeset: scripts/pm/** ships in no package ⇒ skip-changeset correct. Clause-②: no.
  • Open question, ruled by the seat: option A. --commands keeps the derived list and --ran counts derived families only; the rest of the class (11 declared WIDE plus 7 whole-root roster families) closes family by family in dispatch-gates: 18 whole-root lint families are never derived by --commands for a diff outside their home package #31257.
  • Landing: under 「按照 pm-dispatch 规则复核过的都授权」 (2026-10-25T11:35Z) and 「你应该使用 pm-dispatch 技能审核和落地pr」 (2026-11-07T16:59Z): pr_ready + automerge_enable now.

Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant