Skip to content

Hold the isSystem census page to the code: committed AST census, population gate, converted anchors - #13051

Open
os-elon wants to merge 9 commits into
mainfrom
claude/issue-12962-issystem-census-gate
Open

Hold the isSystem census page to the code: committed AST census, population gate, converted anchors#13051
os-elon wants to merge 9 commits into
mainfrom
claude/issue-12962-issystem-census-gate

Conversation

@os-elon

@os-elonos-elon commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Fixes#12962

content/docs/permissions/system-context.mdx calls itself "the authority" and says it is "built by census over the whole repo, not by recall". Nothing held it to either claim. This PR ships the census as a committed instrument, four gates over it, and the anchor conversion those gates keep true — in one PR, so the conversion is verified rather than asserted.

What landed

FileWhat it is
scripts/isystem-census.mjsthe committed AST census of ExecutionContext.isSystem reads (--json for the whole thing)
scripts/doc-line-anchors.mjsa reusable reader for file:line anchors in docs prose — the second page costs a ledger, not a parser
scripts/check-system-context-census.mjsthe gate: four checks, a --self-test, and a --fix that repairs rot and refuses to repair population
content/docs/permissions/system-context.mdx13 anchors converted, the count table re-derived, the two "nothing holds this" callouts replaced by what CI now holds
.github/workflows/lint.ymlfolded into the existing Docs anchors resolve to real headings step

The census is an AST walk, and that is measured rather than asserted

The card measured a regex pass silently losing 6 real sites in report-service.ts to a quote desync and 11 more to (ctx?.session as any)?.isSystem casts. The census parses through scripts/ts-parse.mjs (so a file that does not parse refuses instead of scoring clean) and classifies every appearance of the identifier by where the parser puts it.

Re-derived at 8cb96ec41b, independently of the page:

isystem-census: 109 ExecutionContext.isSystem read sites
packages 20 · files 45
identifier roles: read 115, declaration 21, key 308, other 9
subtracted as unrelated metadata fields: 6

That reproduces the page's headline exactly, so the card's premise holds: 109 sites across 20 packages, 45 files. The 6 subtracted reads are the Object.isSystem / EmailTemplate.isSystem / Environment.isSystem collision; the subtraction ledger is keyed by (file, receiver) and carries no line numbers, because a ledger of line numbers rots exactly like the anchors this exists to stop rotting — and it rots invisibly, since a stale row still subtracts a live site.

Gate B is the mandatory one, and the reason is the card's own sentence

A gate that only checks what the page already says can never find what the page failed to say.

Four checks run:

CheckWhat fails
Population (census to page)an elevation read in the code with no anchor on the page
Resolution (page to code)a spelling that matches no tracked file, matches two, or names a line the file does not have
Countsany stated number that disagrees with the census — and a count sentence that stopped matching, so the check cannot go quietly vacuous
Classificationan anchor that is neither a read site nor a declared non-read citation

The 28 deliberate non-read anchors (the four isSystem declarations, the sys_-prefix helpers, the guard block row 2 cites, the prose targets in the "does NOT do" table) sit in NON_READ_ANCHORS, and each row carries a needle rather than a line: a literal that must appear on exactly one line of the file. The gate locates the line and requires the page to name it. So every one of the 145 anchors is enforced and mechanically repairable, and the ledger is self-retiring — a needle matching zero lines, or two, is a finding.

Ablation — predicted, then observed

Both legs mutated in place so line counts did not move (a whole-line delete would have shifted every anchor below it and drowned the reading). No rebuild is in the loop: these scripts read and parse source directly, nothing resolves through a dist/. Each leg proved its mutation on disk by counting the removed and injected text, restored with git checkout HEAD -- (absolute path) under a trap, and verified the restore by blob hash against the HEAD blob plus an empty git diff HEAD.

A — a site deleted from the code, its row left standing (if (context?.isSystem) return allFields; neutralised in security-plugin.ts). Predicted: the Classification check names the orphaned anchor and the census-derived counts drop by one. Observed, exactly:

[anchor-is-not-a-read-site] the page anchors .../security-plugin.ts:4441 ...
[declared-count] `headline-sites` says 109, the census says 108
[declared-count] `table-elevation-reads` says 109, the census says 108
[declared-count] `ruling-sites` says 109, the census says 108 (10 findings total)

B — a read site arrives with no row (a metadata-field read in explain-engine.ts re-pointed at a context receiver). Predicted: Population names the site, the census ledger reports its now-stale row, counts move up. Observed, and with the control that matters:

[stale-ledger-row] NON_ELEVATION_READS names .../explain-engine.ts (receiver `schema`) but no such read exists
[site-without-a-row] .../explain-engine.ts:638 reads `execCtxZZ.isSystem` and NO row on the page anchors it
[declared-count] `headline-sites` says 109, the census says 110 (9 findings total)
resolution-only findings under the same mutation: 0

⭐ That last line is the card's thesis reproduced mechanically: under a mutation that adds an unanchored elevation read, every anchor still resolves and an anchor-only gate is all green, while the population check names the site by file:line.

The green control is the page as it now stands: the same gate exits 0 on it. And the gate's own matching rules — the thing a clean tree cannot tell working from weakened — are covered by --self-test cases (21 at that commit, 27 after round 2 below), including the green control, both red controls above, ambiguity, out-of-range, three ledger failure modes, and the --fix refusal.

The anchor conversion

Ruling kept: the spelling stays a mechanically resolvable path suffix (objectql/src/engine.ts, never a bare engine.ts where the basename is ambiguous). 13 anchors moved:

  • 10 pure rot since the page's stated commit — security-plugin.ts 4287/4438/4516/3800, sharing-plugin.ts:991, and five rest-server.ts anchors — all repaired by --fix, which maps a file's anchors to its census sites in line order only when the two counts agree;
  • 3 imprecise from the start, fixed by hand because no mechanical mapping is honest for them: registry.ts:450 (a /** line) to the applySystemFields declaration at :459; crud-nodes.ts:314 (a comment) to the stampSystemInsertOwner call at :318; and row 2's 24832630 brace-to-brace range, replaced by a single anchor at the step 3.5 comment, since } admits no unique needle.

Where it is wired, and why not a new gate step

Folded as two commands into the existing Docs anchors resolve to real headings step, per the triage's preferred route. That job carries no paths filter, so the census runs on code-only PRs — the ones that add a read site, which is the whole point — and the fold costs no new check context, no new check:* manifest key and no new required-status entry for one page. The --self-test invocation is what check:self-test-wired requires; it verifies green.

Not done here, deliberately

The mechanism generalises to any docs page carrying file:line anchors, and doc-line-anchors.mjs is shaped so a second page is cheap — but no second page is converted here. Startup scope discipline; that is its own card.

Verification

The first round's evidence, all at 687ed07a84:

  • node scripts/check-system-context-census.mjs --self-testall cases passed (21 cases)
  • node scripts/check-system-context-census.mjsOK — 109 elevation read sites in 20 packages across 45 files, all anchored; 145 anchors resolve, 27 declared non-read
  • derived family (node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, 5 paths, 48 families): 42 runnable-here gates exit 0, including check:doc-anchors, check:doc-authoring, check:docs-single-h1, check:doc-frontmatter, check:role-word, check:entry-guard, check:parse-guard, check:self-test-wired, check:step-collectors, check:required-contexts, check:ci-filter-parity, check:nul-bytes
  • the two convention-triggered obligations for adding a gate script: bare-root-worklist --self-test OK (40 recorded verdicts, none stale), check:pm-dispatch-gates834 cases pass
  • check:type-check-debt after building the package closure: check-type-check-coverage: OK — 65/78 workspace packages type-checked
  • the four docs gates that needed built packages, re-run after turbo run build: check:doc-formula-expressions, check:doc-security-posture, pnpm --filter @objectstack/spec check:docs, check:skill-examples (260 prose examples type-check) — all exit 0
  • repo-wide pnpm lintVERDICT command-exit 0, no eslint output

Repair round — the gate failed on its own page, and the page's numbers were made true

The first CI run went red on exactly one of 39 checks: node scripts/check-system-context-census.mjs, this PR's own gate, on this PR's own page. Two declared counts disagreed with the census by one (table-lines-total 1804 vs 1805, table-lines-tests 1010 vs 1011).

The counter was not what changed — the declaration went stale under a moving main. On the branch tree alone the gate exits 0 and the census reports lines 1804 (tests 1010, sources 794), exactly what the page says. CI evaluates the PR's merge with main, and main had landed #13026 (cf71d73f84, 00:25Z) after the declarations were written. That commit adds one corpus line:

packages/client/src/meta-delete-item-carriers.test.ts:440
return engine.find('sys_metadata', { where: { name }, context: { isSystem: true } });

One line in a test file, so it counts in linesTotaland in linesInTests: the two +1s are the same line counted twice. total − tests stayed 794 — the non-test half never moved, which is why table-lines-sources was not among the findings.

main merged into the branch here (a merge commit, never a rebase; the base is now db39dfc1c9), and every figure re-derived after the merge — a number derived before it is stale by the time it is pushed. Against that tree two further main-side commits move the counts again: #13060 (one more test line) and #13065 (four source lines in security-plugin.ts, plus a five-line import block at :66 that pushed all eight of that file's anchors down by five).

Repaired, and only in the two shapes the failure admits — the page's numbers made true, the criterion untouched:

  • 9 anchors re-pointed at the same code they always named: security-plugin.ts1387→1392, 1409→1414, 1560→1565, 2486→2491, 3803→3808, 4290→4295, 4441→4446, 4519→4524, and field.zod.ts:1436→1440 (that one rewritten by --fix).
  • 6 decomposition counts re-measured: lines 1804→1810, in tests 1010→1012, in non-test sources 794→798, identifier appearances 809→813, keys 308→310, comments/strings 356→358.

The census population did not move: 109 elevation read sites in 20 packages across 45 files, before the merge and after. No tolerance was widened, no declaration deleted, no check relaxed; the gate, its criterion and its 20 self-test cases are byte-identical.

Proved in both directions with the same command on the same tree, exit status captured before any pipe:

before (merged tree, page unrepaired): exit 1
[declared-count] `table-lines-total` says 1804, the census says 1810
[declared-count] `table-lines-tests` says 1010, the census says 1012
check-system-context-census: 24 problem(s) over 145 anchors and 109 census sites.
after (merged tree, page repaired): exit 0
check-system-context-census: OK — 109 elevation read sites in 20 packages across
45 files, all anchored; 145 anchors resolve, 27 declared non-read.

Re-run at the final commit 3128edb8df:

  • node scripts/check-system-context-census.mjs --self-testcheck-system-context-census --self-test: all cases passed
  • node scripts/check-system-context-census.mjscheck-system-context-census: OK — 109 elevation read sites in 20 packages across 45 files, all anchored; 145 anchors resolve, 27 declared non-read.
  • check:nul-bytescheck-nul-bytes: OK (scanned 7284 text file(s) ... no raw ASCII control bytes)
  • the docs-path families over the repaired page: check:doc-anchors, check:doc-authoring, check:docs-single-h1, check:docs-redirects, check:role-word, check-doc-frontmatter, check-docs-section-name, check-doc-route-spelling, check-section-landing-index — all exit 0

⚠️ One property this round measured and the reviewer should weigh: the table-lines-*, table-appearances, table-keys and table-prose declarations are whole-corpus text counts including tests, so any PR that adds or removes a line mentioning isSystem anywhere under packages/ or examples/ moves them — and because CI scores the merge commit, an open PR can be turned red by a merge to main it never touched. That is what happened here. The anchor and population checks are self-repairing in the same situation (--fix handles pure rot); these six text counts are not.

⇒ That warning became the blocker it describes, and round 2 below is the fix.

Round 2 — the six whole-corpus text counts stop being ENFORCED (PM ruling, option B)

The warning above became the blocker it predicted, and the PM reversed its own ruling to direct option B into this PR.

⚠️The premise, stated as exactly what is measured. An earlier reading of this — that the PR had been ejected from the merge queue — was retracted by the PM before this round finished: this repo's merge-queue-triage posts a comment naming the failing job when it ejects a build, a sibling PR ejected in the same window has exactly that comment, and this PR has none. Why it is not in the queue is unexplained, and nothing here rests on it. What is measured, and what the ruling rests on: the declared counts were stale against today's main, so a merge attempt reds on them whenever it happens. CI scores the PR's merge with main, and the merge queue re-derives that merge against a newermain on every attempt, in a repo that merges roughly eighteen times a working day. That makes these six counts a landing hazard rather than a maintenance cost — which is true whether or not an ejection ever occurred.

The diagnosis was confirmed before anything was changed

Merged today's main in (a merge commit, ⛔ never a rebase) and ran the gate on the merged tree first. Exit 1, on exactly the predicted declarations:

::error::[declared-count] `table-lines-total` says 1810, the census says 1811 (the decomposition table: text lines, tests included).
::error::[declared-count] `table-lines-tests` says 1012, the census says 1013 (the decomposition table: text lines in tests).
check-system-context-census: 4 problem(s) over 145 anchors and 109 census sites.

⚠️ The other two findings are a refinement the proxy could not see, and they change the prognosis a little: permission-set-projection.ts:987 had rotted to :1009. So option B alone would not have made this PR green — the anchor still had to be repaired. It was, by --fix, which re-anchored it and left every count alone.

⭐ The measurement that decides it: what moves, and what does not

Every figure the page declares, re-derived by the committed census over five trees: this PR's original base, the pre-queue main, two later mains, and the merged tree this PR now carries.

Declared figuredb39dfc1c98a483b38b8ca1965f2b556470d86bfmerged
sites109109109109109✅ enforced
packages2020202020✅ enforced
files4545454545✅ enforced
plugin-sharing's share2020202020✅ enforced
collision subtraction66666✅ enforced
role: declarations2121212121✅ enforced
role: reads115115115115115✅ enforced
role: other99999✅ enforced
lines in the corpus18101811181118111811⛔ dropped
— in tests10121013101310131013⛔ dropped
— in non-test sources798798798798798⛔ dropped
identifier appearances813813813813813⛔ dropped
object-literal keys310310310310310⛔ dropped
comments and strings358358358358358⛔ dropped

Not one census-derived figure moved across any of the five trees, while the text counts moved again in the very window this PR sat out — and they had already moved six times the night before (#13026, then #13060 and #13065: 1804→1810, 1010→1012, 794→798, 809→813, 308→310, 356→358). The three columns to the right of db39dfc1c9 are three unrelated merges this PR never touched.

⚠️ Three of the six dropped rows happen to be flat across these refs. They are dropped for what they MEASURE, not for how they behaved this week: linesInSources, identifierAppearances and the object-literal key count all move with any non-test source edit that mentions the flag, and the night before they all moved.

⚠️And the honest other half, since anchors are not among the survivors and also red the gate. Anchor line-number churn, measured the same way (diffing the census site keys across the same refs): db39dfc1c98a483b38b8 moved exactly 1 of 109 anchors, and the other three hops moved 0. So anchor rot is real but roughly an order of magnitude rarer than text-count churn, and one --fix invocation repairs it against six hand re-measurements. B removes the expensive half; it does not promise zero repair rounds.

What changed

  • The six move out of DECLARED_COUNTS into a new UNENFORCED_TEXT_COUNTS, with the measurement above recorded beside them.
  • They are still required to be present: a row reworded off the page is [unenforced-count-missing]. Only the comparison is dropped, so "not enforced" cannot decay into "not there".
  • They are required to be dated: the page must carry a measured on DATE at REF marker, or the gate refuses with [unenforced-counts-undated]. ⛔ The date and the ref are deliberately not compared to anything — requiring them to be fresh would re-introduce the churn this removes.
  • On the page, the decomposition table gains a CI column marking each row enforced or dated, and a paragraph saying which is which and why.
  • The POPULATION, RESOLUTION and CLASSIFICATION checks and every census-derived count are untouched. An empty census still refuses. B narrows what is declared, never what is enforced about the contract.

The self-test case ZONE 1 rule 4 owes, and it watches the criterion rather than restating it

Seven cases were added (21 → 27), and the two that matter run over the realDECLARED_COUNTS and UNENFORCED_TEXT_COUNTS, not a fixture stand-in:

 ok CRITERION: every ENFORCED count holds still under whole-corpus text drift
ok CRITERION: all six UNENFORCED text counts DO move under that same drift -- 6 row(s); unmoved:

The drift is what an unrelated merge does here: one test line naming the flag, one non-test source line carrying an isSystem: true key, one comment. Move a text count back into the enforced list and the first case fails naming it by id; delete a row from the unenforced list and the second case fails for being vacuous. The other five pin the behaviour: a stale text count is not a finding, a vanished row is, an undated table is, and an anchor rot or a population change still reds on the very same page.

Both directions, on the real tree, at the final commit

Four mutations of the tree at edfb39846a, each proving the mutation landed on disk before reading anything, each restored with git checkout HEAD -- (absolute path) under a trap and verified by blob hash against the HEAD blob plus an empty git diff HEAD. Shapes predicted in the script before it ran; all four matched.

⛔ No rebuild leg is owed and none was faked: the gate runs as node scripts/check-system-context-census.mjs and reads scripts/ and the tracked sources directly — nothing resolves through a package exports map or a dist/.

MutationPredictedObserved
a test file gains one line naming the flagGREEN — this is the whole pointexit 0, census linesTotal 1812 linesInTests 1014. Under the old gate this was exit 1 with two [declared-count] errors
a cited source file gains a line at the top (anchor rot)REDexit 1, 16 problems: 7 [site-without-a-row], 8 [anchor-is-not-a-read-site], 1 [ledger-row-unused]
a new elevation read appears (population)REDexit 1, 8 problems: [site-without-a-row] ...security-plugin.ts:6983 plus headline-sites says 109, the census says 110, table-reads says 115, the census says 116, and five more
a row deleted from the page and the date removedREDexit 1: [unenforced-count-missing] naming table-lines-tests, and [unenforced-counts-undated]

⭐ The third row is the answer to "did B weaken the gate": the surviving role counts caught the probe's declaration and read, and the population check named the new site by file:line.

Verification, at the final commit edfb39846a

The union was re-run after the last commit, and the gate families were re-derived at that commit (dispatch-gates --repo objectstack-ai/objectstack, 5 paths, 49 families — identical to the pre-merge derivation, no new family). Exit codes captured before any pipe (redirect to a file, then EXIT=$?, then read the file); ⛔ no PIPESTATUS anywhere.

  • node scripts/check-system-context-census.mjscheck-system-context-census: OK — 109 elevation read sites in 20 packages across 45 files, all anchored; 145 anchors resolve, 27 declared non-read.
  • node scripts/check-system-context-census.mjs --self-testcheck-system-context-census --self-test: all cases passed (27 cases)
  • the two convention obligations for editing a gate script: node scripts/pm/bare-root-worklist.mjs --self-test exit 0, pnpm check:pm-dispatch-gates exit 0
  • 47 of the 49 derived families exit 0 here, including check:doc-anchors, check:doc-authoring, check:docs-single-h1, check:docs-redirects, check:role-word, check:docs-audit-scope, check-doc-frontmatter, check-docs-section-name, check-doc-route-spelling, check-section-landing-index, check:entry-guard, check:parse-guard, check:self-test-wired, check:watch-hint-literal, check:ci-filter-parity, check:step-collectors, check:required-contexts, check:nul-bytes
  • four of them refused until their closure was built, and pass after turbo run build: check:doc-formula-expressions, check:doc-security-posture, pnpm --filter @objectstack/spec check:docs (231 generated files in sync), check:skill-examples (260 prose examples type-check)
  • check:nul-bytescheck-nul-bytes: OK (scanned 7292 text file(s) ... no raw ASCII control bytes), plus a direct control-byte scan of both changed files

⚠️Two declared narrowings, so the reviewer is not reading a claim I did not measure.

  1. check:type-check-debt is not reported here in either direction. It answers a standalone run with a refusal — --re-measure cannot run: 23 workspace dependenc(ies) ... have no built type entry point on disk — which is explicitly not a finding, and clearing it means building the whole workspace, which is CI's run. This round's diff contains no TypeScript, so nothing in it can move a TypeScript debt number.
  2. Repo-wide pnpm lint was narrowed to the changed files, and here is why that narrowing is a measurement rather than a skip: (a) the linted population is read from ESLint itself, not guessed — --format json reports content/docs/permissions/system-context.mdx as "File ignored because no matching configuration was supplied", so the population of this diff is the single file scripts/check-system-context-census.mjs; (b) the count is read from that same JSON: 2 entries, 1 actually linted, 0 errors, 0 warnings; (c) untouched files cannot move, because this repo runs one eslint.config.mjs which "never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file" (its own words, at line 327), and that config is not in this diff.

skip-changeset: this PR changes docs, scripts/ and one workflow step. No package source, so it publishes nothing.

Related: #12802 corrected the anchors and deliberately left the enforcement unbuilt; #12942 held lint.yml and the root package.json when the card was written and has since landed, though this PR needed neither.

Repair round authored in Claude Code session https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw

Generated by Claude Code

@github-actionsgithub-actionsBot added size/xl ci/cd documentation Improvements or additions to documentation labels Aug 29, 2026
@os-elonos-elon added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed documentation Improvements or additions to documentation ci/cd labels Aug 29, 2026 — with Claude
`main` moved under the open PR and the page's live numbers went stale:
* +5 line rot in `plugin-security/src/security-plugin.ts` (the import block
#13065 added at :66 pushed every anchored read down five lines), plus the
`field.zod.ts` `readonly` citation `--fix` re-anchored mechanically.
* Six decomposition-table counts re-measured against the merged tree:
lines 1804->1810, in tests 1010->1012, in sources 794->798, identifier
appearances 809->813, keys 308->310, comments/strings 356->358.
The census population itself did NOT move: 109 elevation read sites in 20
packages across 45 files, before and after. The gate, its criterion and its
self-test are untouched -- the page's numbers were made true, not the check
made lenient.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPrUz21stTFhJRUirdc4yw
@github-actionsgithub-actionsBot added ci/cd documentation Improvements or additions to documentation labels Aug 29, 2026
@os-elon
os-elon marked this pull request as ready for review August 29, 2026 04:54
@os-elon
os-elon enabled auto-merge August 29, 2026 04:55
@os-elon
os-elon added this pull request to the merge queueAug 29, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Aug 29, 2026
… census page
The six raw text counts (lines carrying the identifier, the test/source split,
identifier appearances, object-literal keys, the prose remainder) are properties
of the whole corpus, not of the elevation population the page certifies. They
move whenever any file under packages/ or examples/ gains or loses a line
mentioning isSystem -- a test, a seed object, a comment -- and because CI scores
a PR's MERGE with main and the merge queue re-derives that merge against a newer
main on every attempt, a page carrying them races a moving target.
Measured on this branch: three unrelated merges to main moved those six numbers
eight times in one night, while every census-derived figure held flat across the
same refs -- 109 sites, 20 packages, 45 files, 6 ledger subtractions, 21/115/9
role counts, at db39dfc, 8a483b3, ca1965f and the merged tree.
So they move out of DECLARED_COUNTS into UNENFORCED_TEXT_COUNTS: still required
to be PRESENT on the page and to carry a dated measurement marker, never
compared. The POPULATION, RESOLUTION and CLASSIFICATION checks and every
census-derived count are untouched, and an empty census still refuses.
Seven self-test cases pin the new criterion, two of them over the real lists:
every entry of DECLARED_COUNTS must hold still under a whole-corpus text drift,
and all six UNENFORCED_TEXT_COUNTS must move under it -- so re-adding a text
count to the enforced list fails the self-test by name.
Also re-anchors permission-set-projection.ts:987 to :1009 (pure line rot from
today's main, repaired by --fix).
@os-elon
os-elon added this pull request to the merge queueAug 29, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Aug 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33242330316 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test: FAIL test/serve-publishes-bound-port.e2e.test.ts > #13062 `os serve --port 0` — the request that can never be the answer > announces the BOUND port on all three channels, and ↳ 失败原因: (这条 FAIL 之后 12 行内没有可识别的原因行 —— 点进 job 看)
    @objectstack/cli:test: FAIL test/serve-publishes-bound-port.e2e.test.ts > #13062 the non-zero half — nothing an ordinary boot publishes may move > follows the DEV AUTO-SHIFT onto the port it really ↳ 失败原因: @objectstack/cli:test: Error: ENOENT: no such file or directory, open '/tmp/os-bound-port-home-GsIAgo/runtime.env_local.json'
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 8 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

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

Labels

ci/cddocumentationImprovements or additions to documentationsize/xlskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-elon@claude