Skip to content

fix(objectql,rest,metadata-core)!: a datasource definition's stored row is served only to datasource administrators (#27884) - #28465

Merged
objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/project-thread-zvc337
Oct 31, 2026
Merged

objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/project-thread-zvc337

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

domain:server#1 · os-tesla · session_01L9qibwurKjbb54r3yD6yJg

Requested by Tesla · project thread

Fixes #27884

Clause-②: no (narrowing for readers below datasource administration)
Metadata-protocol: none

维护者速读

  • 改了什么:数据源定义(datasource / external_catalog)所在的元数据存储行,现在只对持有 manage_platform_settings 的数据源管理员提供;与 /meta 类型读取门用的是同一张“类型→能力”表,没有新增规则、权限名或键。
  • 为什么改:同一份数据源定义原来在两个出口对两组调用者开放,按裁决 A 统一为同一组读者;连接配置的问题也由本卡关闭。
  • 风险与回滚:低于数据源管理员的读者不再能看到这些行(BREAKING 读集收窄,changeset 已写明补救);管理员与系统读取不变;回滚即还原本 PR。
  • 先看:packages/metadata-core/src/stored-metadata-type-read-admission.ts(唯一的那张表),再看 packages/objectql/src/stored-metadata-type-read-gate.ts。
  • 两分钟验证:pnpm --filter @objectstack/objectql exec vitest run src/stored-metadata-type-read-gate.test.ts 与 pnpm --filter @objectstack/rest exec vitest run src/meta-type-read-stored-row-parity.test.ts。
  • 需要你做的:席位的契约复审(收窄一侧)后落地。

What changes

A stored-row read exit admits only datasource administrators.

  • One row. The type-to-capability table that the metadata read door already used moves to @objectstack/metadata-core as STORED_METADATA_TYPE_READ_CAPABILITIES (datasource, external_catalog → manage_platform_settings), with storedMetadataTypesWithheldFrom(caller) and isCapabilityGatedStoredMetadataType(type). @objectstack/rest keeps exporting META_TYPE_READ_CAPABILITIES, now the same frozen object; the metadata read door answers exactly as before.
  • The stored row. The engine applies that same row to every caller-context read of the stored-metadata tables (find, findOne, count, aggregate): a caller without a type's capability is served no row of that type, and a read of such a row's id answers as a read of a row that does not exist. Holders of the capability, platform administrators among them, are served everything as before; system reads are unchanged.
  • Events. A record-change event of a row of a gated type carries no metadata body to any subscriber.
  • Flows. A flow run under a user identity is a caller like any other: below datasource administration its read of a gated type is served no row. A flow run under the system identity is unchanged.
  • Docs. The isSystem census page gains the row for the new gate's system-read exemption (generated register refreshed).
  • No new rule, permission name or key. No packages/spec change, no packages/metadata-protocol/src/protocol.ts change.

Why

Ruling A on #27884 (record 6545628488): one document admits one set of callers at every exit that serves it, reusing the one capability row the /meta type gate names. Caller-aware redaction and a redactor-type parameter are out of scope.

Verification

  • Unit pins (objectql): an administrator reads the row whole; a caller below datasource administration and a plain reader are served no gated row on find / findOne / count / aggregate; the history table is gated by the same row; a system read is not narrowed; the composed predicate names exactly the withheld types; events of gated rows withhold the body while an ungated row keeps it.
  • Parity pins (rest): META_TYPE_READ_CAPABILITIES is the shared frozen row, and for six callers the metadata door refuses a type exactly when the stored-row gate withholds it.
  • Dogfood (booted stack, platform security composition): an administrator is served the row whole; callers below datasource administration are served nothing; for each caller the stored row is served exactly when the metadata door serves the definition.
  • Ablations, each red then restored byte-identical: gate removed (4 objectql pins red), row withheld from everyone (3 red, the administrator pin among them), event arm removed (2 red), a second copy of the row in rest (3 parity pins red), gate removed from the built objectql dist (dogfood + parity pins red; and, separately, the 3 user-identity flow pins red with the other 22 in those files green).
  • Suites: objectql 506 files / 9836 tests passed; metadata-core + rest 21 files / 875 tests passed; sibling reader suite @objectstack/service-automation 244 files / 3105 tests passed (its flow get_record pins on the stored-metadata family now run their projection cases under the system identity and pin that a user-identity run below datasource administration is served no row); typecheck of the three packages exit 0; scoped eslint over the touched files exit 0; derived gates all exit 0 on the final head (record below); full @objectstack/dogfood battery (record below).

Verification record, final head 0b381cd7:

  • node scripts/pm/dispatch-gates.mjs --commands on 0b381cd7 → 96 derived commands, all run with </dev/null, all exit 0; dispatch-gates --ran → 96 derived, 96 run, 0 NOT-MEASURED, 0 UNRUN.
  • Fixed during the sweep: check:objectql-double-limit (pin driver honours the limit), check:query-options-erasure (typed query options, test surface back to 236), check:where-matcher (pin matcher refuses unknown combinators), check:system-context-census (census row 18d + regenerated register).
  • pnpm --filter @objectstack/dogfood test (whole battery on 1e838c5c, under the verify lock, concurrent with a gate sweep): 361 files passed, 3 skipped, 1 failed — automation-authoring-doors-durable.dogfood.test.ts, a 5000 ms test timeout on a flow update under the shared load; that file re-run alone: 7/7 passed. The commits after it change prose, a changeset line and service-automation tests only; the new dogfood file re-ran on de1f609b: 4/4 passed.
  • @objectstack/service-automation whole suite on 0b381cd7: 244 files / 3105 tests passed.
  • npx eslint over the touched source and test files: exit 0.

Clause-② and Metadata-protocol are declared on the lines above and in the changeset.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (packages/spec untouched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes (scoped to the touched files).
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: n/a.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English (the 维护者速读 section is the maintainer's Chinese digest).
  • The Before Submitting list in CONTRIBUTING.md is done.

Acceptance notes

  • Readers below datasource administration are no longer served stored datasource or federation-catalog rows; the remedy is to grant manage_platform_settings or read through the datasource admin door as such a caller.
  • Contract review: PASS at 0b381cd7.

https://claude.ai/code/session_01L9qibwurKjbb54r3yD6yJg

🤖 Generated with Claude Code

…ata rows only to holders of the type's read capability

One read row for datasource-family documents, shared by the /meta type gate
and a new engine read gate on the stored-metadata tables; realtime events of
those rows carry no body.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibwurKjbb54r3yD6yJg
… with the /meta type gate, and event body withholding

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibwurKjbb54r3yD6yJg
… read gate; pin matcher refuses unknown combinators

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibwurKjbb54r3yD6yJg
…ot how they read

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibwurKjbb54r3yD6yJg
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling labels Oct 31, 2026
@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/metadata-core, @objectstack/objectql, @objectstack/rest, touching 13 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/metadata-core/src/index.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

30 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 80a9f99222a62c336659bef6e8dcabd7ffb7b1b3.

⛔ 11 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/metadata-core/src/index.ts) — pages documenting those are invisible to this run
  • 2 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 212 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 — 34 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 80a9f99222a62c336659bef6e8dcabd7ffb7b1b3 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from e6c799ce6779b274e70e5e08e12bcd4cf5478d4f — the merge of head 0b381cd7e53fee03d03f07f96f6fcbfe2ba7525f into base 80a9f99222a62c336659bef6e8dcabd7ffb7b1b3, 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 e6c799ce6779b274e70e5e08e12bcd4cf5478d4f && git checkout e6c799ce6779b274e70e5e08e12bcd4cf5478d4f
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 80a9f99222a62c336659bef6e8dcabd7ffb7b1b3 0b381cd7e53fee03d03f07f96f6fcbfe2ba7525f && git checkout -B drift-repro 80a9f99222a62c336659bef6e8dcabd7ffb7b1b3 && git merge --no-ff 0b381cd7e53fee03d03f07f96f6fcbfe2ba7525f

node scripts/docs-audit/affected-docs.mjs --json 80a9f99222a62c336659bef6e8dcabd7ffb7b1b3

⚠️ 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 80a9f99222a62c336659bef6e8dcabd7ffb7b1b3 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

…tates the rule only

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9qibwurKjbb54r3yD6yJg
…istration is served no stored datasource row

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

Copy link
Copy Markdown
Contributor Author

triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract-review-claim: session_01L9qibw58ehQ2gRHP2h2Puz · head de1f609b0f2bb9202ae3009d5ed22010a61d694c · 2026-10-31T19:44Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#1 · os-tesla · session_01L9qibz3ZUbZ8Qcn1rDw9yc

Head moved · 2026-10-31T19:45Z

The head is now 0b381cd7, so the contract review claimed at de1f609b (2026-10-31T19:44Z) should be taken at 0b381cd7. The new commit is test-only and lives in @objectstack/service-automation. Four flow get_record pins expected a runAs:'user' run to be served a capability-gated stored row. The PR's rule now withholds that row.

  • The projection and keyed-hash pins now run under runAs:'system'.
  • The user-identity cases now pin the other side of the rule: no row is served, and the run receives nothing from it.
  • An ablation (gate removed) turns the three new pins red.
  • The whole package passes: 244 files, 3105 tests.

For the review: one narrowing this PR states. A flow's user-identity run context carries permission-set names but no system capabilities. So a runAs:'user' flow is withheld gated stored rows, whoever triggered it. That fails closed and sits within the ruling's arm. Making a flow run aware of the caller's capabilities is out of this card's scope.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract-review-hold: head de1f609b0f2bb9202ae3009d5ed22010a61d694c is red · 2026-10-31T19:47Z

Claim 6548265017 stands; no record on this head (a PASS is never written on a red head).

  • Read at this stamp: card [Decision] secrets: should a read of a datasource's definition keep serving external.credentialsRef to every reader that can read the definition? (item 3 of #27818, the maintainer's) #27884 (ruling A 6545628488, claim 6545739621, dev report 6547945667), the PR diff (12 files, +610/−13 against merge-base 630b407, merge-tree clean), check-runs: 50 latest-per-name, 34 success + 14 skipped, 2 failed (Test Core, Test Core 8/8).
  • The red: @objectstack/service-automation pnpm run test exited 1 — 4 tests in 2 files (job 124633119907): src/builtin/get-record-stored-metadata-family.integration.test.ts (3: the runAs:'user' findOne and find branches, and the crypto-provider case) and src/builtin/get-record-stored-metadata-filter-refusal.integration.test.ts L352 (runAs:'user', scalar-column filter). Each reads the stored datasource row (pin_flow_ds / pin_filter_ds) as the triggering user and expects the projected body; under this PR a caller below datasource administration is served no row, so the CEL path rec.metadata finds no key, rec[0] is out of bounds, and row is null.
  • Reading: the behaviour is the ruling (a flow get_record node is an exit that serves the document, and it now admits the readers the /meta door admits). The pins are stale, not the gate: the runAs:'user' cases become "served no row" pins (or run as a holder of manage_platform_settings), and their control is a system-context door read, so "like the door" for a runAs:'user' run is now "no row". The runAs:'system' cases keep their shape.
  • Outside the PR's own sweep: the body's suite list names objectql, metadata-core, rest and the dogfood battery; service-automation is a sibling reader of the family that the derived gates do not run. Worth naming in the next dev report's tests line.
  • Contract content otherwise reads clean: one table in @objectstack/metadata-core, the same frozen object at the rest exit (parity pin), the engine gate registered in the constructor on both family tables with isSystem and context-less reads exempt, the event arm fail-closed for every subscriber, Clause-②: no (narrowing) + Metadata-protocol: none + the ADR-0087 not-required (no-migration-prescription) marker on a ! title (Check Changeset green), three patch bumps. The record follows on the next green head, with the delta from de1f609b.

Owner: domain:server#1 (seat session_01L9qibz3ZUbZ8Qcn1rDw9yc; card thread session_01L9qibwurKjbb54r3yD6yJg). On the next head the lane re-claims and records the delta.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract-review-claim: session_01L9qibw58ehQ2gRHP2h2Puz · head 0b381cd7e53fee03d03f07f96f6fcbfe2ba7525f · 2026-10-31T20:15Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 0b381cd7e53fee03d03f07f96f6fcbfe2ba7525f
Local-runs: none
Scope: PR #28465 (Fixes #27884, ruling A 6545628488; claim 6545739621; dev report 6547945667), 14 files, +670/−20 against merge-base 630b407, merge-tree clean. Hold 6548302963 on de1f609b (service-automation pins red); the delta de1f609b → 0b381cd7 is one commit, test-only (2 service-automation files, +60/−7): the three runAs:'user' family cases and the scalar-filter case become "served no row" pins (output null / [], no sentinel and no configuration in the run), the runAs:'system' cases keep the projected-body shape, the crypto-provider case runs as system; no source file moved.
Inputs: card #27884 (triage 6513852880, decision letter 6538434026, rulings B 6522945866 then A 6545628488), the PR body and changeset, the full diff, origin/main for every cited symbol, check-runs (read 2026-10-31T20:16Z: all 50 latest-per-name check-runs completed, 38 success + 12 skipped, none failed, none running) — 50 checks

① Ruling → code

  • Letter A: the stored-row read exit admits only readers holding the capability the /meta type gate names for the type; the same row at the one other exit; event exits withhold the body; admins and system reads unchanged; the save-door half of B dropped. The diff is exactly that: STORED_METADATA_TYPE_READ_CAPABILITIES (datasource, external_catalog → manage_platform_settings) moves to @objectstack/metadata-core with storedMetadataTypesWithheldFrom(caller) and isCapabilityGatedStoredMetadataType(type); @objectstack/rest META_TYPE_READ_CAPABILITIES is that same frozen object (parity pin toBe); the engine registers storedMetadataTypeReadGate in its constructor on STORED_METADATA_BODY_OBJECTS (sys_metadata, sys_metadata_history, the family's one definition in @objectstack/spec/kernel) and AND-composes type $nin withheld into find / findOne / count / aggregate for a caller lacking a row's capability; redactEventMetadataBody drops the body of a gated type for every subscriber (fail-closed arm).
  • Admission predicate is the /meta gate's: metaTypeReadRefusal (main L2114) reads systemPermissions.includes(capability) with no isSystem arm and refuses an anonymous caller; storedMetadataTypesWithheldFrom withholds every listed type from a caller with no capability set. Same cohort at both exits, pinned for six callers.
  • Exemptions match the posture every engine read gate takes: isSystem and context-less reads (loader, /meta store reads, boot) are not narrowed; census row 18d names storedMetadataTypeReadFilter as the isSystem exemption and the register table carries it.
  • No save-door change, no spec change, no protocol.ts change, no new key or permission name: as the letter binds.

② Declarations

③ Pins and ablations

  • objectql: admin whole row; org-admin and plain reader served no gated row on all four reads (a get of the id answers null, not a refusal); history table by the same row; system read not narrowed; composed predicate exact; events of gated rows carry no body while an ungated row keeps it. rest: same frozen object; six-caller parity. Dogfood: booted stack, organization_admin_no_bypass holder and a plain member served nothing on list / query / get, metadata door 403, per-caller parity data-door ⇔ meta-door. The body records five ablations each red then restored.
  • engine-realtime-stored-metadata-body.test.ts re-pinned from "projected datasource body" to "withheld whole", with the ungated case moved to a view row: the [security] Family closeout: stored metadata bodies (stored datasource credential material included) are still reachable outside the redacting doors at several further positions — detail withheld pending maintainer #21120 pin's intent (no credential on the wire) still holds, strengthened.
  • The de1f609b red (four runAs:'user' flow get_record pins in service-automation expecting a projected datasource row for a reader below datasource administration) is fixed on this head by re-pinning those four cases to "served no row" (both family tables, both node branches) and keeping the projected-body pins on runAs:'system'; Test Core 8/8 green.

④ Traps and should-fix

  • A flow get_record node is an exit that serves the document: under A a runAs:'user' run below datasource administration is served no row, which the fixed pins now state. runAs:'system' runs keep the projected body.
  • A list for the next card on the family: the derived gates do not run sibling readers' suites (service-automation here); the dev report's tests line should name them.
    SHOULD_is fixed on this head by re-pinning those four cases to "served no row" (both family tables, both node branches) and keeping the projected-body pins on runAs:'system'; Test Core 8/8 green.

Implemented-by: claude/project-thread-zvc337
Reviewed-by: triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#1 · os-tesla · session_01L9qibz3ZUbZ8Qcn1rDw9yc

维护者速读

  • 改了什么:数据源定义的存储行,现在只提供给数据源管理员读取,不论从哪个出口读,与元数据读取门的准入一致。持有该能力的人和系统读取不受影响。
  • 为什么改:你在 15:47 对批次 [WIP] Fix issue in job step execution #433 的「同意」(裁定 A)。
  • 风险与回滚:这是收窄。以用户身份运行(runAs:'user')的流程也读不到这类行,属于故障时关闭(fail-closed)。需要读取的调用方授予 manage_platform_settings 即可。回滚即 revert。
  • 先看:packages/objectql/src/stored-metadata-type-read-gate.ts,以及 @objectstack/metadata-core 中唯一一份类型到能力的对照表。
  • 两分钟验证:pnpm --filter @objectstack/objectql exec vitest run src/stored-metadata-type-read-gate.test.ts,全部通过。
  • 需要你做的:无,席位落地。

席位意见:契约复审 PASS,按裁定 A 原样实现,公开文字保持在规则层面。可以直接落地。

席位核对

ACCEPT · seat domain:server#1 · head 0b381cd7 · 2026-10-31T20:27Z

  1. Shape: Fixes #27884. Draft, base main, 14 files, +670/−20, with three patch changesets (metadata-core, objectql, rest), a ! title and the ADR-0087 not-required marker. No packages/spec path. protocol.ts is untouched.
  2. Ruling: A 6545628488. The type-to-capability table now exists once, and both exits read it. A single engine gate covers the stored-metadata family's reads. Events withhold the body of a gated row. Capability holders and system reads are unchanged, and there is no save-door change.
  3. Contract review: lane PASS 6548616937 at this head, after the hold 6548302963 on de1f609b. The PR declares Clause-②: no (narrowing) and Metadata-protocol: none.
  4. Gates / check-runs:
    • Dev report 6547945667 plus the thread's sweep line on 0b381cd7: 96/96 derived commands exit 0, --ran shows 0 NOT-MEASURED and 0 UNRUN, and six ablations went red.
    • Suites: the sibling reader suite @objectstack/service-automation passes at 244 files / 3105 tests.
    • On head 0b381cd7: 50 check-runs completed, 38 success, 12 skipped, 0 failed.
  5. Accepted deviations:
    • A runAs:'user' flow is withheld gated rows, because a flow user context carries no system capabilities. This fails closed and is within A.
    • The public text was trimmed to rule level before review.
    • The body opens with the seat signature line, as the relay requires.
  6. Landing: check-governed-merges --pr 28465 reports NOT governed. The seat readies the PR and arms auto-merge under the maintainer's 「按 pm-dispatch 审过的pr你可以自主落地」.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 31, 2026 20:28
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 31, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

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

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

分类:failure —— 按下面的日志分诊。

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

  • Live E2E UI — 失败步骤: Run the live e2e specs(日志不可读,点进 job 看)

↳ 失败原因 是判读的关键:超时(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 队列共有 2 个失败构建(不含本次)。

分诊清单:

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

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

@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 31, 2026
Merged via the queue into main with commit 119931d Oct 31, 2026
58 checks passed
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 size/l tests tooling

Projects

None yet

1 participant