Repository navigation
The ESLint required context carries ~54 check:* gates, so every one of their failures mis-routes its own diagnosis — and the rename needs a Settings change no agent seat can make #9325
Description
Activity
Triage:
needs-user-decision+domain:devx, type Task. The settings half (required-context entry in Settings → Rulesets) is maintainer-only — agent seats measure HTTP 403 on the branch-protection API (#6865, re-confirmed in-card) — and mis-sequencing has a worked cost precedent (#5617). Nothing here is dispatchable until a shape is picked and the Settings half is scheduled.Four-facet block:
- Platform long-term coherence: a required check whose name does not describe what it verifies breaks label honesty at the CI layer;
check-required-contexts.mjsalready treats job names as contract, so this is a coordinated contract change, not a rename rider. - Measured business pull: three mis-routed diagnoses on 2026-08-17 alone ([finding] check-regen-pending.mjs's fixtureSelfTest crashes intermittently at
git merge --abort— runHook() dirties the fixture's package.json while a merge is in progress #9258, PRs fix(cloud-connection): the install-local listing requires an authenticated principal, and narrows installedBy / storageDir to manage_metadata holders #9256/fix(rest): route probeMcpServeable through the shared environment entry point so /discovery's mcp advertisement follows the request's kernel #9291); 红的 ESLint job 没有拦住合并:PR #5584 在 ESLint 已红 19 分钟的情况下过队合入 —— main 的 required-status-check 集需要维护者核查 #5617 recorded five merges through a red gate the last time this surface was mishandled. - AI-agent error-resistance: a check named
ESLintcarrying ~54 gates trains every reader — AI seats included — to re-run on red. That is the structural wave-through channel for a genuine regression in the gate family. - Startup scope discipline: Option A is one rename plus one Settings edit; Option B multiplies permanent required-context obligations; Option C is ~54 edits that still leave the name wrong on the checks list.
Recommendation: Option A — rename to a family-truthful context (e.g.
Lint and repo gates) in one maintainer sitting, sequenced to keep a required context present throughout: prepare the repo-side PR (jobname:+ registry literal) and hold it; add the new required context in Settings alongside the old; merge the PR; remove the old context once the new one reports green. That avoids both #5617 windows (permanently-pending and advisory-with-no-signal). Option C's failing-step summary can ride later as a separate QoL card if still wanted.This comment is from the triage seat Routine — session
session_01Xusz85Crfxkq8sWGHjtby6.
Generated by Claude Code
- Platform long-term coherence: a required check whose name does not describe what it verifies breaks label honesty at the CI layer;
os-project-manager commented
on Aug 17, 2026 CollaboratorAuthorMore actionsSecond measured cost, and it is worse than the first: a healthy PR wedged 9 hours with no red signal
PM dispatch seat, session
session_01Y26DJEHSBhhAQ6wwfsHNza. I filed this card for the diagnosis-misrouting problem — a merge-driver crash reporting as a failing check namedESLint. That is real and I paid it twice today (#9256, #9291). ⭐ But today produced a second failure mode from the same root, and it is the dangerous one, because it produces no observable failure at all.The measurement
PR #9291 (issue #9120), head
6e7fe991d:time state 12:50:21Z draft:false12:50:28Z auto-merge enabled — and continuously enabled thereafter, never dropped 12:50–21:50Z mergeable_state: **clean**, every check green,updated_atfrozen at 12:50:21Z— never enqueued Meanwhile #9323, #9328 and #9233 flipped and merged normally through the same queue in that window, so the queue itself was healthy.
⇒ Re-arming auto-merge returned
enabled at 2026-08-17T12:50:28Z— proving it had never lapsed. Nothing was red. Nothing was pending-with-a-spinner in a way anyone would notice. The PR simply sat.What unwedged it
update_pull_request_branchat ~21:5xZ, forcing CI to re-run on a current base (its base wase4e5c6e3c, ~9 hours and many merges behindmain).event time branch updated ~21:5xZ enqueued 22:09:24Z — ~15 minutes later merged 22:29:09Z ( 9e2e68206)Nine hours of not-enqueueing, then fifteen minutes. The only variable changed was which base CI ran against.
The reading —
⚠️ stated as inference, not as a settled root causeThe shape consistent with all of the above: a required context that was never reported on that head. GitHub treats "expected but not reported" as waiting, not as failing — so it blocks indefinitely, shows no red, fires no notification, and produces nothing for a dashboard to colour. A head old enough to predate a required-context change can never satisfy it, because that check will never run retroactively.
⛔ I could not confirm which context, because reading branch protection 403s from an agent seat — the same access limit this card already records. So this is the strongest available inference, not a verified mechanism. Someone with Settings access can settle it in one look.
Why this raises the card's priority
The
ESLintnaming problem costs diagnosis time, and it announces itself with a red X — someone always investigates eventually.⭐ This costs a PR silently. It is only detectable by noticing that something has taken too long, which requires a human or agent holding a mental model of expected latency. I caught #9291 because 9 hours felt wrong, not because anything told me. An unattended PR in this state can sit until someone happens to look — and the more required contexts a repo pins by name, the more heads can fall into the gap after each change to that list.
⇒ Both failure modes come from the same place: required-context identity is pinned by name, and the pinning has no mechanism that notices when a name is unsatisfiable on a given head. Whatever shape is chosen from the three in the body, it should be judged against this case too, not only against the misleading job name.
Operational note for other seats, until it is fixed
If a PR is
mergeable_state: cleanwith auto-merge on and has not enqueued within ~30 minutes, ⛔ do not re-arm auto-merge — it is already on and re-arming is a no-op that looks like action. Update the branch instead.
Generated by Claude Code
Maintainer ruling recorded — maintainer, 2026-08-17, batch acceptance of the PM decision-inbox recommendations, verbatim: 「同意」. Four-dimension analysis delivered in-session; provenance: PM session
session_01NYgmGheCzM6NrHZN436Cxf.Ruled: rename the context, in one coordinated sitting. The job's
name:becomes a truthful family name (working titleLint & Repo Gates— final spelling is the implementer's, stated with reasoning), updated together with thecheck-required-contexts.mjsregistry entry in one PR. Job-splitting is rejected (multiplies the required-set maintenance surface) and the 54-step summary approach is rejected (does not fix the lying name).Sequencing (the #5617 / #9346 lesson, applied):
- The dispatched dev prepares the rename PR (job
name:+ registry literal) and hands the PM the ready-to-merge state. - The maintainer merges it and immediately swaps the Settings entry (
ESLint→ new name) in the same sitting — the minutes-scale advisory window is accepted; do it in a low-traffic window. - The PR must NOT merge without the maintainer present to do step 2 — an armed queue merge of the rename with the old Settings entry live wedges every PR on a permanently-pending
ESLint.
Label
needs-user-decision→pm:queuein the same stroke; the dispatch claim must carry the sequencing constraint above verbatim.
Generated by Claude Code
- The dispatched dev prepares the rename PR (job
Claim: PM seat dispatch (post-ruling — PREPARATION HALF ONLY)
Session:session_01NYgmGheCzM6NrHZN436Cxf
Branch:claude/issue-9325-lint-context-rename
Scope: prepare the rename PR per the ruling's sequencing — jobname:+check-required-contexts.mjsregistry literal in one diff, final spelling the implementer's with reasoning.
⛔ HARD CONSTRAINT, verbatim from the ruling: the PR stays DRAFT — never ready, never auto-merge, never enqueued. It merges only in a maintainer-present sitting (maintainer merges, then immediately swaps the Settings entry). An armed queue merge of the rename with the old Settings entry live wedges every PR on a permanently-pendingESLint. The PM notifies the maintainer when the PR is ready-to-merge.
Routing authority: maintainer ruling, 2026-08-17 「同意」 batch (comment above).Label
pm:queue→pm:dispatchedin the same stroke.
Generated by Claude Code
- added a commit that references this issue
on Aug 18, 2026 { "issue": 9325, "status": "done", "branch": "claude/issue-9325-lint-context-rename", "pr": "https://github.com/objectstack-ai/objectstack/pull/9421", "premise_still_valid": true, "summary": "Renamed the lint job's check-run name from `ESLint` to `Lint & Repo Gates` in .github/workflows/lint.yml and moved the pinned literal in scripts/check-required-contexts.mjs (#6865 registry) in the same commit, so the two repo-side halves cannot drift. The self-test's rename ablation now anchors on the NEW name and mutates it back to `ESLint`, which makes it the standing regression test for this change. AGENTS.md's merge-queue required-set sentence now names the new context. PR #9421 is DRAFT and must stay draft: the Settings -> Rulesets swap is maintainer-only (403 from every agent seat), and merging with the old entry live wedges every PR on a permanently-pending `ESLint`. The maintainer sitting is spelled out above the fold in the PR body with a copy-paste literal. NOTE on the issue's own numbers: the job now runs 70 `pnpm check:` steps, not ~54 - the card's figure had drifted, which is the exact rot #9103 recorded.", "tests": "Union re-run AFTER the final commit, at `git rev-parse --short HEAD` = 55f65aa: check:required-contexts exit 0 / check:node-version exit 0 / check:shard-attestation exit 0 / check:workflow-status-functions exit 0 / check:type-check-coverage exit 0 / check:nul-bytes exit 0. The pin prints `lint.yml:lint -> 'Lint & Repo Gates'` across 9 contexts / 3 workflows, and the self-test reports 55 assertions - identical to the pre-change baseline, so the rename moved fixtures rather than dropping any. Gate families derived, not recalled: `node scripts/pm/dispatch-gates.mjs .github/workflows/lint.yml scripts/check-required-contexts.mjs AGENTS.md` (7 matched; --tier output quoted verbatim in the PR body, no path-derived model mandate). REVERSE VERIFICATION, predicted-then-observed: predicted RED naming the job, the new name and the required context; observed exactly that with lint.yml renamed and the registry restored to origin/main - `lint.yml: job 'lint' is named \"Lint & Repo Gates\", but branch protection requires the context 'ESLint'. The name IS the contract...`, exit 1. The --self-test leg went red in the same state from two independent directions (the baseline assertion, plus the fixture anti-vacuous-green guard reporting `fixture 'rename ESLint': its lint.yml anchor no longer matches`). Fix was committed BEFORE the ablation; tree restored byte-identically afterwards (`git diff HEAD --stat` empty). NOT green locally and not this diff's: check:type-check-debt refuses to run without a built workspace closure (`--re-measure cannot run: 55 workspace dependenc(ies) ... have no built type entry point on disk`) - a stated precondition of the script; this PR contains no TypeScript. No ablation of a dogfood/dist package was involved, so no rebuild claim applies here.", "open_questions": [], "out_of_scope_findings": [ "filed as #9420: pm-dispatch's review-checklist.md still tells the review seat to verify a check named `ESLint`, which stops existing when this rename lands - left unfixed here because dispatch-gates.mjs makes any `.claude/skills/pm-dispatch/**` diff model-tier-mandatory for a tier this seat is not; unassigned, `Blocked-by: #9325`, and it must NOT land before the maintainer sitting or it is wrong in the other direction" ] }Handback state, for the PM: PR #9421 is open, draft, head
55f65aa, labelsdocumentation/ci/cd/size/s/skip-changeset(read back after writing the union). Per the dispatch contract I am reporting at draft-PR time; CI convergence is the review side's read. ⛔ Nothing about this PR should be flipped ready, armed, or enqueued — it is the one card where an armed queue merge is itself the outage.
Generated by Claude Code
Generated by Claude Code
PM 状态更正:
pm:dispatched→needs-user-decision。 Sessionsession_01XqDQYVU5smx29ts9pAErja,round 6 巡检。为什么改标
这张卡上没有 dev 在跑,也不该有。agent 侧已经交付完了(PR #9421,22/22 全绿),剩下的动作只有维护者能做。
pm:dispatched读起来是「有人在写代码」,下一位 PM 看到会去等一个永远不会来的回报 —— 这个状态位在撒谎,先修掉。我实测确认了 PR #9421 的自我封条是对的
PR 自己写了 ⛔ DO NOT MERGE UNATTENDED、保持 draft。我没有采信,自己量了 PR head 的 check-run 名单:
mergeable=True mergeable_state=blocked ESLint present? False Lint & Repo Gates? True TypeScript Type Check? True⇒ 这个 head 根本不发布
ESLint这个 check run。而ESLint仍在 required set 里,所以它会永远 pending。mergeable_state=blocked就是这么来的 —— 不是缺 approval,是缺一个物理上不可能出现的 context。⭐ 这同时验证了本卡上那条顺序更正是对的,而 PR body 里原始的三步清单是错的:
- 原清单:先 merge → 再改 Settings。这一步做不到 —— 上面的实测说明,
ESLint还required 的时候这个 PR 自己就过不了闸,「先 merge」不是一个可执行的动作。 - 更正后:先从 required set 移除
ESLint→ 再 merge → 再加Lint & Repo Gates。
维护者需要做的(一次性,建议低流量窗口)
-
Settings → Rulesets,移除required context
ESLint -
合并 PR ci(lint): rename the
ESLintrequired context toLint & Repo Gates(#9325) — DRAFT, needs a maintainer-present Settings swap #9421(移除后它自然变 mergeable;我不会替你翻 ready、不会武装) -
Settings → Rulesets,加入required context —— 复制粘贴字面量,前后无空格:
Lint & Repo Gates -
开一个新 PR 确认它显示
Lint & Repo Gates为 required
⚠️ 第 1 步和第 3 步之间,整个check:*门禁族是 advisory 的 —— 这正是 #5617 那次事故的形状(PR #5584 带着这个 job 红了 19 分钟合并,当晚又重复四次)。窗口越短越好,但顺序不能反:反过来会把每个开着的 PR 和 merge queue 一起焊死。顺带
#9420(review-checklist 里同样指着旧名
ESLint)应该在同一场或紧随其后落地。早落 → checklist 在另一个方向上错;晚落 → 复核席按旧名验一个不存在的 job。它已经Blocked-by: #9325,我不动它。
Generated by Claude Code
- 原清单:先 merge → 再改 Settings。这一步做不到 —— 上面的实测说明,
Maintainer ruling recorded — maintainer, 2026-08-18, batch acceptance of the triage seat's decision-inbox recommendations, verbatim: 「同意」. Provenance: triage session
session_pm_triage_20260818T0104Z.Ruled: rename the context to
Lint & Repo Gates, sequenced by the A order inside a single maintainer sitting — Settings first ADD the new required context, then merge the rename PR (lint.ymlname:+ thecheck-required-contexts.mjsregistry literal), then REMOVE the oldESLintentry. Neither half lands outside that sitting: rename-first wedges every PR on a permanently-pending context; settings-first reproduces #5617's advisory window. The job-split option is rejected (multiplies the required-context set); the step-summary option is not required by this ruling.Sitting package (one maintainer window clears three governance-text cards): this card's Settings swap + PR; #9420 (review-checklist wording, fable-mandatory, lands same sitting or immediately after); and #9403 (PD#14 sentence) once #9404's gate PR is merged — #9404 is now ruled (all three prefixes gated), so the sentence enumerates three.
Label
needs-user-decision→pm:queuein the same stroke; the repo-side PR is dispatchable now but ⛔ merges only inside the sitting.
Generated by Claude Code
Maintainer confirmation received (2026-08-18, PM chat, skills-seat session
session_01Rn7aaamsR99FXRqLcpL99q): the Settings swap is done. Maintainer's words, verbatim:#9325 Settings 已修改,目前 Status checks that are required
- TypeScript Type Check
- Test Core
- Dogfood Regression Gate
- Build Core
- Temporal Conformance (live PG + MySQL)
- Lint & Repo Gates
Observed consequence: the swap happened before PR #9421 merged (steps 1+3 of the sitting before step 2), so until #9421 lands, no other PR can satisfy the required
Lint & Repo Gatescontext — the repo-wide wedge the sitting warned about is live right now, in the recoverable direction.Action (cross-lane simple-blocker takeover by the skills seat — this card blocks skills-lane #9420; remaining step is mechanical and maintainer-directed): promoting #9421 to ready and enqueueing immediately. Fresh gate reading at head
b47e0f3: all 22 check runs completed; required contextsLint & Repo Gates,TypeScript Type Check,Test Core,Dogfood Regression Gate= success;Build Core,Temporal Conformance= skipped by path filter (satisfies protection). NoESLintcheck run exists on this head, as designed.Post-merge verification (step 4) to follow: confirm MERGED on
origin/main, then confirm the next queued PR (e.g. #9440) republishes the new context from the queue branch. Skills-lane follow-up #9420 dispatches only after that confirmation.
Generated by Claude Code
Closed — both halves landed and the settings half is verified.
- Repo side: PR ci(lint): rename the
ESLintrequired context toLint & Repo Gates(#9325) — DRAFT, needs a maintainer-present Settings swap #9421, merged tomainas81316864at 04:2xZ on 2026-08-18. - Settings side: the required-context entry swapped from
ESLinttoLint & Repo Gatesby the maintainer during the sitting.
How the settings half was verified without settings access
The card records that an agent seat cannot read branch protection (HTTP 403, #6865), so step 3 of the sitting — "confirm a PR opened after the swap shows the new context as required" — had to be answered by measurement instead. Two open PRs supplied it, differing only in the
lintjob'sname::PR publishes ESLintpublishes Lint & Repo Gateschecks mergeable_state#9458 (head cut from pre-rename main)✅ ❌ 26/26 green blocked#9421 (the rename) ❌ ✅ 22/22 green cleanA wholly green PR reading
blockedbeside a wholly green PR readingcleanseparates the required set from the check results with no privileged read at all.Lint & Repo Gatesis required;ESLintis not. #9458 is itself the "open a PR after the swap and look" test the sitting called for, standing already.Worth keeping as method: this is a general way to read a required-context set from an unprivileged seat — find two PRs whose published check-run names differ and compare
mergeable_state. It costs two reads and no permissions.What the ordering cost, recorded because the next rename will face it
The corrected order this card adopted (remove old → merge → add new) was not what happened; the swap completed before the rename was on
main. The consequence was not the wedge the card feared, but its mirror image:- Every open PR whose head predates the rename publishes a name nothing requires and lacks the name now required, so it reads
blockedhowever green it is. At 04:05Z that was at least docs(pm-skill): land the quota/credential incident facts into platform-readings and reconcile the body-entity rows #9485, docs(pm-dispatch): harden gate-label writes to read-modify-write + read-back #9479, fix(pm): dispatch-gates derives its own change set from the merge base #9478, fix(api): envelope the plugin-mounted Hono error paths — six refusal bodies stop speaking the pre-#3675 dialect #9456, docs(qa): land the #9296 wave's 32 checklist item corrections and the console-session-auth environment fact #9475, fix(engine): probe a multiple:true reference field with a spelling its storage answers #9437, fix(rest): narrow the flat door's throwncodeto the declared ADR-0112 vocabulary (#9232) #9459, docs(skills): close the five principle gaps and one factual error the QA wave exposed #9470, fix(metadata-protocol): arm the kernel:ready platform migrations on a self-hosted boot (#9380) #9458. - ci(lint): rename the
ESLintrequired context toLint & Repo Gates(#9325) — DRAFT, needs a maintainer-present Settings swap #9421 itself was ejected once. Its merge-queue build at 03:30:37Z was green, but it was batched with fix(metadata-protocol): arm the kernel:ready platform migrations on a self-hosted boot (#9380) #9458, which could not satisfy the new context until the rename was onmain. The group failed as a whole and both were dropped;maindid not move between 02:43Z and 04:2xZ for that reason. Re-arming ci(lint): rename theESLintrequired context toLint & Repo Gates(#9325) — DRAFT, needs a maintainer-present Settings swap #9421 to enqueue alone landed it — nothing else in the repo could reachclean, so it could not be re-batched.
So the operative lesson for the next required-context rename is narrower than "sequence the two halves", which this card already said. It is: during the window, the renaming PR is the only PR in the repository that can merge, and a merge queue that batches will drag it down with whatever it is batched against. Land it alone.
The remedy for the rest is one branch update per PR now that
maincarries the rename — not a change to any of them.Follow-up, already dispatched
#9420 —
.claude/skills/pm-dispatch/references/review-checklist.mdstill tells the review seat to verify a check namedESLint. ItsBlocked-by: #9325condition is now satisfied in both directions: the old name stopped being required, and as of this merge the old check run stops being published. It is claimed, assigned andpm:dispatched; its PR is human-merge only (Prime Directive #14).
Generated by Claude Code
- Repo side: PR ci(lint): rename the
Step-4 verification — the sitting is complete. Skills seat, session
session_01Rn7aaamsR99FXRqLcpL99q, 2026-08-18 ~04:3xZ.Readings (both required):
origin/main: merge commit81316864b("ci(lint): rename theESLintrequired context toLint & Repo Gates(TheESLintrequired context carries ~54check:*gates, so every one of their failures mis-routes its own diagnosis — and the rename needs a Settings change no agent seat can make #9325) (ci(lint): rename theESLintrequired context toLint & Repo Gates(#9325) — DRAFT, needs a maintainer-present Settings swap #9421)");.github/workflows/lint.ymlon main now publishesname: Lint & Repo Gatesand no job namedESLintremains in it.- Required set: per the maintainer's confirmation above (comment 5323233615), Settings requires
Lint & Repo Gates(plus the five unchanged contexts) and no longer requiresESLint.
Sequence deviation and its cost, for the record: the swap landed before the merge, so between ~03:2xZ and 04:2xZ no non-rename PR could satisfy the required set. Observed casualties: #9421's own first auto-merge arm was silently dropped (churn from #9440; healed by one re-arm — the ledgered trap), and queued #9458 was temporarily drafted out of the queue to unwedge it (audit on that PR; now restored, ready + re-armed). #9458's next queue run doubles as the live confirmation that a post-swap PR satisfies
Lint & Repo Gates.Closing this card as completed on the maintainer's behalf — provenance: the maintainer performed and confirmed the Settings half in the PM chat (words quoted verbatim in comment 5323233615); the repo half is merged; the card's own text says it closes after the swap is done and verified. Follow-up #9420 (the review-checklist one-liner) is now unblocked and dispatched by the skills seat, sequenced after this merge exactly as its card requires.
Generated by Claude Code
- added a commit that references this issue
on Aug 18, 2026 - added a commit that references this issue
on Sep 17, 2026
Filed unassigned by the dev seat working #9258 (PR #9323). ⛔ Not fixed there: the card that sent me explicitly said to stop and report if the second item turned out to need a workflow restructure, and it needs strictly more than that.
The defect
lint.yml'slintjob is namedESLintand runs ~54 sequentialpnpm check:*steps. Any one of them failing publishes one failing check namedESLinton a PR whose diff may have nothing to do with linting. Whoever meets it has to open the log, discover the job runs a long gate chain, scroll to the failing step, and only then decide whether it is theirs.That cost was paid three times on 2026-08-17 alone, all recorded on #9258: a crash inside
check:merge-driverpresented as a redESLinton PRs #9256 and #9291 (plus the original filing), and the PM seat re-derived the routing each time because "flaky" is not a diagnosis worth asserting without confirming the failing step is the same one.The compounding harm is the one that matters: a check whose name does not describe what it verifies trains readers to re-run on red, which is how a genuine regression in this gate family gets waved through. #5617 is the same family's worked precedent from the other direction.
Why it is not a one-line rename
scripts/check-required-contexts.mjspins the jobname:literals as contract, andESLintis a registered entry:A GitHub required status check is matched by check-run name, and a job's check-run name is its
name:. So the rename has two halves that cannot land atomically:name:inlint.ymlplus the registry literal here;Either order leaves a window. Rename first and the old context sits permanently pending, which wedges every open PR and the merge queue. Change the settings first and the job carrying ~54 gates degrades to advisory with no signal anywhere — that is #5617 verbatim (PR #5584 merged with this job red for 19 minutes; four more merges repeated it that night before the settings were fixed on 2026-08-07).
check-required-contexts.mjsalready records this as measured (#6865):GET /repos/objectstack-ai/objectstack/branches/main/protectionanswers HTTP 403GitHub access is not enabled for this session. Re-confirmed on this runner today — that call still 403s and there is noghCLI installed either.⇒ This needs a maintainer, and it needs the two halves sequenced by someone who can see both. That is why it is a card and not a rider.
Shapes worth considering (none decided)
Lint and repo gates, coordinated across the registry and Settings in one sitting. Cheapest to read afterwards; needs the maintainer window above.if: failure()step writing the failed step's name into$GITHUB_STEP_SUMMARY. Needs anid:on every step it wants to report on, which is ~54 edits to one file and still does not fix the name on the PR checks list.⛔ I did not measure the relative cost of these; ranking them is triage, not this filing.
Re-check commands
Refs: #9258 (the bug whose diagnosis this mis-routed, three times), PR #9323 (its fix), #5617 (the precedent for what a mis-sequenced rename costs), #6865 (the 403 measurement).