Skip to content

feat(spec,service-analytics): GET /analytics/meta publishes cube and member descriptions and the measure format (stage 3 of #20282) - #20736

Merged
os-justin merged 4 commits into
mainfrom
claude/issue-20282-cube-descriptions-meta
Sep 30, 2026
Merged

os-justin merged 4 commits into
mainfrom
claude/issue-20282-cube-descriptions-meta

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Part of #20282

Stage 3: CubeMeta and GET /analytics/meta carry the cube, measure and dimension description and the measure format the definition declares, projected by service-analytics#getMeta. The three description liveness rows move to live, and the showcase done_rate format becomes '0.0%'.

Clause-②: yes (widening)

🤖 Generated with Claude Code

https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1

…member descriptions and the measure format

CubeMeta gains an optional description on the cube, measures and dimensions,
and an optional format on measures; AnalyticsMetadataResponseSchema mirrors it.
AnalyticsService.getMeta copies the values a cube definition declares. The
three analytics_cube description ledger rows move dead -> live, and the
showcase done_rate format becomes the numeral pattern '0.0%'.

Claude-Session: https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1
Co-authored-by: Claude <noreply@anthropic.com>
…s_cube state counts

Claude-Session: https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1
Co-authored-by: Claude <noreply@anthropic.com>
…age-2 changeset untouched

The pending stage-2 release note is restored byte-for-byte from the merge base
(the foreign changeset rule); this change's own changeset states which of its
sentences /meta now supersedes.

Claude-Session: https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation protocol:data tests tooling labels Sep 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/service-analytics, @objectstack/spec, touching 7 documentable anchor(s). ⚠️ 3 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/analytics_cube.json, packages/spec/liveness/state-counts/analytics_cube.md), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/api/data-api.mdx (via MetricSchema (symbol, a top-level const))

⛔ 2 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v17/17-2.mdx (via MetricSchema (symbol, a top-level const))
  • content/docs/releases/v17/17-5.mdx (via AnalyticsService (symbol, a top-level class))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 3 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/analytics_cube.json, packages/spec/liveness/state-counts/analytics_cube.md) — pages documenting those are invisible to this run
  • 3 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 137 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f927864ea056f79d04ad8d62f1a7c13afed31d07 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 122fa8ae7cc7c7eddf25f38e3633274316e5cae9 — the merge of head 25bd1e1321ee52095eecfafb7c021a71b844e2a9 into base f927864ea056f79d04ad8d62f1a7c13afed31d07, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 122fa8ae7cc7c7eddf25f38e3633274316e5cae9 && git checkout 122fa8ae7cc7c7eddf25f38e3633274316e5cae9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f927864ea056f79d04ad8d62f1a7c13afed31d07 25bd1e1321ee52095eecfafb7c021a71b844e2a9 && git checkout -B drift-repro f927864ea056f79d04ad8d62f1a7c13afed31d07 && git merge --no-ff 25bd1e1321ee52095eecfafb7c021a71b844e2a9

node scripts/docs-audit/affected-docs.mjs --json f927864ea056f79d04ad8d62f1a7c13afed31d07

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs f927864ea056f79d04ad8d62f1a7c13afed31d07 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 25bd1e1321ee52095eecfafb7c021a71b844e2a9
Local-runs: none

Inputs read: card #20282 (body and all 31 comments, the stage-3 report 5901282387 and ruling 5901302748 included), PR #20736 (body, 14-file list, net diff origin/main...25bd1e1321, whose two-dot diff from the merge-base d2820876f7 is the same 14 files at +295/−41, so the merge of main dropped nothing), the tree at the head by git show / git grep, the objectui formatter at the pin .objectui-sha = dd3f7e1be3 (unchanged by this PR), and the check-runs on the head, read last.

① Derived judgments

Accept-set and public-surface changes the diff implies — each judged:

  1. CubeMeta (packages/spec/src/contracts/analytics-service.ts) gains optional description on the cube, optional description and format on each measure, optional description on each dimension. Additive; nothing removed, renamed or re-typed. Right. packages/spec/api-surface/contracts.json records the export as "CubeMeta (interface)" by name only, so no surface artifact was owed a regeneration; Type Check · source gates is green.
  2. AnalyticsMetadataResponseSchema (packages/spec/src/api/analytics.zod.ts) gains cube description, member description, and a measure shape cubeMetaMeasureShape = member shape + format. Bound to CubeMeta at compile time by CubeMetaMatchesContract (api/analytics.test.ts:31). Additive; a dimension format is still stripped (pinned). Right.
  3. AnalyticsService.getMeta (service-analytics/src/analytics-service.ts:2319) copies description / format with conditional spreads when the registered definition declares them and spreads nothing otherwise; the .filter(isCubePublic) from stage 1 stays. Reaches the wire verbatim: packages/runtime/src/domains/analytics.ts:136-137 hands the array to deps.success(result). Right.
  4. MetricSchema.format describe and TSDoc (data/analytics.zod.ts): text only, no accept-set change; the generated content/docs/references/data/analytics.mdx carries the new describe in both tables. Right.
  5. Showcase done_rate.format: 'percent' to '0.0%'. Example only. At the pin, packages/core/src/utils/dataset-format.ts#formatMeasure reads format.includes('%') as percent and counts the 0s after the dot as decimals (one); 'percent' had no % and no dot, so it rendered a bare integer. Right.
  6. Liveness: analytics_cube.description, measures.description, dimensions.description dead to live. Evidence analytics-service.ts#getMeta resolves; producer packages/cli/src/commands/serve.ts#CAPABILITY_PROVIDERS resolves (configKey: 'analyticsCubes' at :1876, the quoted line at :4647) and analytics-service.ts#registerAll at :1102. Walking the ledger at the head: the 3 dead rows are exactly measures.name, dimensions.name, refreshKey (tombstones); the shard moves 20/6 to 23/3 on 26 classified, a delta equal to the three flipped rows; Spec property liveness is green, which is the verdict on the absolute count. Right.
  7. driver-memory's MemoryAnalyticsService#getMeta (memory-analytics.ts:1365) untouched: projects name/title/type only. The contract declares the members optional, and no in-repo composition registers it as the analytics service (git grep finds only comments outside driver-memory). Right, and the ledger note says so.
  8. Changeset: @objectstack/spec minor, @objectstack/service-analytics minor; both publish (./contracts is an export of spec; service-analytics is not private). Right (see ②).

Author-shown and AI-facing texts — each sentence tested against the tree:

  • Changeset (.changeset/20282-analytics-cube-meta-descriptions.md): "now publishes … when the cube definition declares them" TRUE. "CubeMeta (@objectstack/spec/contracts) gains …; AnalyticsMetadataResponseSchema declares the same members; a definition that declares none of them is published exactly as before" TRUE (conditional spreads; pinned by "publishes no key a definition does not declare"). "getMeta copies what the definition declares and fills in nothing. A cube compiled from a dataset carries each dataset measure's format and no description" TRUE: dataset-compiler.ts:679 copies m.format; nothing copies a description — the dataset's own description is an I18nLabelSchema (ui/dataset.zod.ts:337) never copied, and dataset members refuse description with guidance (dataset.zod.ts:112-113, :179-180). "The liveness ledger rows … move from dead to live" TRUE. "This supersedes one sentence of this release's note …: it says GET /api/v1/analytics/meta is unchanged and keeps name, type and title" TRUE: .changeset/20282-analytics-cube-format-granularities-enforced.md:16 carries that sentence, present on origin/main and byte-identical at the head. Moment of truth: true on main when this PR lands, provided no release consumes the stage-2 note between now and then; after such a release the phrase "this release's note" would read as an earlier release's — a timing caveat, not a falsity now. "A client that formats a result column still reads format off the query result's fields[]" TRUE (api/analytics.zod.ts:109-110, data-api.mdx).
  • PR body: "Stage 3: CubeMeta and GET /analytics/meta carry … projected by service-analytics#getMeta. The three description liveness rows move to live, and the showcase done_rate format becomes '0.0%'" TRUE. Clause-②: yes (widening) stands alone on its own line; Part of #20282 is line 1 (Part-of PR must not also close its card green).
  • content/docs/api/data-api.mdx callout: "publishes a deliberately narrow projection of it — name, type, title (the definition's label), description, and on a measure its declared format; never sql or granularities" TRUE and exhaustive: MetricSchema's value keys are label, description, type, sql, format (plus the retired name tombstone); DimensionSchema's are label, description, type, sql, granularities (plus the tombstone). "currency and percentScale are not reachable through the metadata endpoint at all" TRUE (CubeMeta has neither). The unchanged GET /analytics/meta section below it enumerates no members, so nothing there went stale; client-sdk.mdx:321-325 likewise.
  • api/analytics.zod.ts docblock: "description carries the definition's description, and a measure also carries its definition's format (analytics: an authored cube's public, refreshKey, format, granularities and descriptions take effect (8 keys) #20282, the additive return path the GET /analytics/meta 的已声明响应契约与实际响应不是同一个形状(data: { cubes: CubeSchema[] } vs data: CubeMeta[]) #6442 ruling recorded below); each is absent when the definition declares none" TRUE — the Meta Response docblock records "Return path if more keys are ever needed (recorded with the ruling): add the key to the projection above — additive and backwards compatible". "sql and granularities are dropped by the projection and are NOT reachable through this endpoint" TRUE and exhaustive (key lists above). "This is the dimension member; cubeMetaMeasureShape adds format" TRUE. The four new describes ("projected from the definition's description", "projected from the measure definition's format", "Cube description, projected from …", "its title and description") TRUE.
  • contracts/analytics-service.ts docblock: "copied from the cube definition when it declares them and absent when it does not; AnalyticsMetadataResponseSchema declares the same shape and api/analytics.test.ts binds the two at compile time" TRUE.
  • data/analytics.zod.ts MetricSchema.format TSDoc "The GET /analytics/meta projection publishes it on the measure too" and describe "…and on the measure by GET /analytics/meta" TRUE at this head; the generated mdx matches.
  • analytics-service.ts docblocks: withDeclaredMeasureFormats ("GET /analytics/meta publishes the same declared value per measure (getMeta), with no column to attach it to") TRUE; getMeta (copied when declared, never filled in; a compiled dataset's cube carries the compiler's format and no description) TRUE.
  • Showcase comment: "A numeral pattern, the vocabulary fields[].format documents: % marks a percent, .0 one decimal. The value above is in percentage points (0-100)" TRUE: the fields[].format describe cites "0.0%"; the SQL multiplies by 100.0; the pinned formatter reads % and the one decimal as stated. It does not claim anything about the formatter's magnitude heuristic (flag 5 in ③).
  • New test docblock and comments: "getMeta(), which GET /api/v1/analytics/meta hands to success() verbatim" TRUE (runtime/src/domains/analytics.ts:136-137); "the projection carried { name, type, title } per member and { name, title } per cube" TRUE of the base; "the dataset's own description is not copied … and a dataset measure or dimension has no description key" TRUE. Spec test comment "a key the object schema did not declare would be stripped by this parse, not kept" TRUE for z.object (the dimension-format assertion pins it; Test Core green).
  • Ledger rows: the three evidence / producer / note texts TRUE per items 6-7 above; measures.description note ("the dataset schema refuses it and points to the dataset's own description") TRUE (dataset.zod.ts:179-180); dimensions.description note TRUE (:112-113); measures.format note ("Also on discovery since 2026-09-29 … the additive return path the narrowing recorded on AnalyticsMetadataResponseSchema, GET /analytics/meta 的已声明响应契约与实际响应不是同一个形状(data: { cubes: CubeSchema[] } vs data: CubeMeta[]) #6442, names; data-api.mdx still sends a client that formats amounts to fields[]") TRUE; _note ("and so are the three description annotations …, while the retired caching block is not") TRUE (refreshKey is the dead tombstone row).
  • README row: "The 3 dead are the refreshKey tombstone and the inner name on each of measures/dimensions" TRUE (ledger walk); "It was 6 until analytics: an authored cube's public, refreshKey, format, granularities and descriptions take effect (8 keys) #20282's third stage … analytics-service#getMeta copies each onto its CubeMeta entry, the read point the title/label rows already cite" TRUE.
  • Nothing false, unsourced or over-broad found. A tree-wide sweep at the head for the falsified phrasings ("not published by GET /analytics/meta", "format is not reachable", "name, type and title", "/meta is unchanged") hits only the superseded stage-2 changeset (ruled: report, not edit) and the new test's past-tense docblock.

② Semver level

  • Changeset: '@objectstack/spec': minor, '@objectstack/service-analytics': minor — the two packages whose published surface moves (a widened exported interface and response schema; a widened served projection). examples/app-showcase is not a released package. No skip-changeset label, correctly.
  • Clause-②: yes (widening) — declared identically in the changeset and the PR body, standalone; matches the diff: every new member is optional, nothing is removed, renamed or re-typed, undeclared keys strip as before, and the stage-1 visibility filter is unchanged. No narrowing arm is owed; no BREAKING sentence and no ADR-0087 marker are owed (Check Changeset green; the report's check:adr-0087-registration reads "adds no declared-breaking changeset").
  • AGENTS.md: yes takes at least minor — minor on both is right. Not governed (no path on the Prime Directive feat: Comprehensive CRM example demonstrating all ObjectStack protocol features #14 governed-surface register — docs/adr/**, the north-star doc, skills/**, the two agent instruction files, the agent config tree; Governed Surface Queue Guard green).

③ Boundary flags

Dev deviations (report 5901282387):

  1. File-surface amendments (data/analytics.zod.ts describe + TSDoc; data-api.mdx callout) — answered: ruling 5901302748 accepts them; verified both texts were falsified by the widening and are now true.
  2. Stage-2 changeset edited in place, refused by check:empty-changeset, restored — answered (Q1 = A): verified the file is byte-identical to origin/main at the head and the supersession sentence lives in this PR's own changeset. Timing caveat recorded in ①.
  3. format on /meta beyond seat 2's Q3 — answered (Q2 = A): additive, the GET /analytics/meta 的已声明响应契约与实际响应不是同一个形状(data: { cubes: CubeSchema[] } vs data: CubeMeta[]) #6442-recorded return path; verified 0 consumers of /analytics/meta, analytics.meta or CubeMeta in objectui at the pin, with the query door as the lit control, so nothing in the pinned sibling moves.
  4. Plain git merge of origin/main (no os-regen) — answered by measurement: the two-dot and three-dot diffs are the same 14 files at +295/−41, so main's side (including docs(service-analytics): re-anchor the dead tracker citations to the commits that decided them #20729's other-line edits to analytics-service.ts) is intact; every gate on the merge head is green.
  5. Commit trailers — answered: all four commits carry the AGENTS.md model-free trailer pair; none carries a model identifier.
  6. Cleanup of the worktree — not verifiable from GitHub; not a PR fact.

Open questions: Q1 (where the stage-2 correction lives) ruled A; Q2 (keep measure format on /meta) ruled A — both answered in 5901302748.

Out-of-scope findings (four, none filed) — each judged:

  • Compiled dataset publishes no description on /meta — true (compiler copies none; the value is an I18nLabel); routed to the picker sub-issue. Answered.
  • percentScale heuristic: MetricSchema has no percentScale key (verified key list), so a done_rate value strictly between 0 and 1 (under one percent done) is multiplied by 100 by percentDisplayValue in the pinned formatter. The showcase comment does not claim otherwise. Recorded with no carrier. Answered.
  • driver-memory's narrower getMeta — true, contract-permitted, not a door. Answered.
  • check:platform-checklist local red on inputs identical to main — not this PR's; no check-run on the head is red. Answered.

Escalated to the seat (not blocking this verdict):

  • PR body discrepancy. The stored body is 461 characters: the three content lines plus the harness emoji footer line and a bare session URL. The dev report says the body was read back byte-identical at 7193 characters and that its footer is the AGENTS.md session-URL form; neither holds against GitHub as read. The lines the gates read (Part of #20282 first, Clause-②: yes (widening) standalone) are intact and every body-reading check-run is green, so the diff's verdict is unaffected. The timeline exposes no body-edit event (GitHub emits none); updated_at 23:56:06Z coincides with the seat's label add. Per AGENTS.md, establish the actor before any body write, and never re-send a body that already carries an appended footer.
  • objectui picker sub-issue still unfiled — the claim 5900176831 makes it the seat's act once the served shape passes review; the card's lane names it. This record is that review.
  • Console Pin Gate is a roster skip on this head; the objectui census above is why the widening cannot break the pinned sibling.

Check-runs on 25bd1e1321 (46 raw, 35 deduped by name keeping the newest started_at): all completed; 31 success; 4 skipped (Auto Label, Check PR Size, Console Pin Gate, Packed-tarball smoke (opt-in)); 0 failed; none still running. Green among them: Lint & Repo Gates, Spec property liveness, TypeScript Type Check and its four Type Check legs, Build Core, Build Docs, Test Core and its six shards, Check Changeset, Governed Surface Queue Guard, the three card-relation checks, Dogfood Regression Gate (three shards), Dogfood Verify CLI, Temporal Conformance, Check Documentation Links, Flag docs affected by code changes.

Implemented-by: claude/issue-20282-cube-descriptions-meta
Reviewed-by: session_01Sfe5YjBLwB9J3y8fvm2xq1

VERDICT: PASS

Adopted and posted by domain:spec seat 5 (session_01Sfe5YjBLwB9J3y8fvm2xq1) · 2026-09-30T00:24Z · rendered by the seat's at-tier review subagent on this head. The seat read its served tier family from the subagent transcript before posting.

  • ③ 1, the PR body: the stored body is the seat's own. It was rewritten short through the relay's issue_patch before the review, as .claude/agents/os-dev.md gives the body to the seat. The dev's 7193-character figure was the draft it opened. The gate-read lines are the seat's.
  • ③ 2, the objectui picker sub-issue: the seat files it when this stage lands, because the served shape is now reviewed.
  • Landing follows once needs:contract-review is stripped and the checks are green again.

Generated by Claude Code

@os-justin
os-justin marked this pull request as ready for review September 30, 2026 00:27
@os-justin
os-justin enabled auto-merge September 30, 2026 00:27
@os-justin
os-justin added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit 03cdb9a Sep 30, 2026
51 checks passed
@os-justin
os-justin deleted the claude/issue-20282-cube-descriptions-meta branch September 30, 2026 00:50
@github-actions

Copy link
Copy Markdown
Contributor

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

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

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

  • Console Pin Gate — 失败步骤: Build the Console SPA at the pinned objectui SHA

    ✗ Neither spec appears in the built console — no @objectstack/spec
    

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

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError。 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

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

  • ⚠️ 本次没有可用的聚合签名(日志里没有能解析出测试文件名的 FAIL 行)—— 这不是「没有同签名的其他 PR」,是这一轮没测到。跨 PR 聚合本次不可用,请手工比对其他 PR 的同类评论。
  • ⚠️ 24h 评论账本没读完(超过 5 页仍未读到窗口尽头),所以上面的「不同 PR 数」是下界,不是全量。

历史信号:

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

分诊清单:

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

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

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

Labels

documentation Improvements or additions to documentation protocol:data size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants