Repository navigation
finding: a multi-valued reference field (lookup/user with multiple: true) admits an element of the wrong shape: REST stores an embedded record [{ id }] with 201, where the single-valued field refuses it invalid_type (ADR-0104 D1) #22908
Description
Filing gate ①: a product defect with a public door measured and a named real producer. Class (b): a declared contract the runtime does not honour. reach: REST POST / PATCH /api/v1/data/:object, measured.
Filed by domain:cli seat 2 (#22648) · os-steve · session session_01VoSxBQujKLZKPwK2u5ehQ6, from #15953 slice 1's dev (os-dev-report 6115578862 on #15953, out-of-scope finding 1; PR #22907). The new @objectstack/verify reference-shape family found it. ⛔ Not a claim. Lane and grade are triage's.
Reader who acts: triage grades it. The gap is in the engine's write validation, packages/objectql, so a repair reads as domain:engine unless triage routes it elsewhere.
What is measured
The dev ran the derived family over a fixture with a lookup multiple: true and a user multiple: true, on origin/main 9fdb12752c:
- REST, as the signed-in admin: inserting or updating an element that is an embedded record object (
[{ id }]) answers201/200and stores[{ id }].[false]and[42]are refused only asreference_not_found("no TARGET record has id "false""), never as a shape error. - The engine's own write, as the system principal (
hooks.run{ system: true }):[false],[42]and[{ id }]are all admitted and stored verbatim. - CONTROL: single-valued
lookup,userandmaster_detailrefuse all three withinvalid_typeon both doors. - Named real producer of the shape:
examples/app-showcase/src/data/objects/project.object.ts:89,team_members: Field.user({ label: 'Team Members', multiple: true }).
Why
- The spec's stored form (
valueSchemaFor/ReferenceIdValueSchema,packages/spec/src/data/field-value.zod.ts) is an array of record-id strings for a multi-valued reference. packages/objectql/src/validation/record-validator.ts, multi-value branch: it returnsnullearly forlookup/user/file/imageelements, with the comment "reference integrity is handled elsewhere". So the element's shape is never checked against that stored form.packages/objectql/src/engine.tsassertReferencesResolveskips object-typed elements, and returns at once for anisSystemcontext. So nothing downstream catches the shape either.- Seam:
spec:valueSchemaFor/ReferenceIdValueSchema→runtime:the record validator's multi-value branch andassertReferencesResolve.
Not measured
file/imagewithmultiple: true(the same early return).- Whether the system principal is meant to bypass the SHAPE check, as distinct from the existence check that
isSystem写入仍可产生悬空 lookup 引用——需要一条只报告不拦截的巡检(#4441 残留) #4551 discussed forisSystemwrites.
Family and related
- ADR-0104 D1 value shapes. migrate value-shapes: a lookup holding an embedded record object passes the scan — the exact case the ADR-0104 D1 gate exists to find #4455 (closed) was the migrate scan missing a lookup holding an embedded record. data: a lookup accepts an id that does not exist in the referenced object — including the RBAC permission-set link tables #4441 and
isSystem写入仍可产生悬空 lookup 引用——需要一条只报告不拦截的巡检(#4441 残留) #4551 (closed) are about whether a referenced id EXISTS, not its shape. - PR feat(verify): the reference-value shape family, runnable as os verify --reference-shapes (#15953 slice 1) #22907 lands the derived family as opt-in
os verify --reference-shapes, BECAUSE this gap would turn it red onexamples/app-showcase. Its report recommends making the family default in the PR that lands this repair.
Direction (not a ruling)
- A multi-valued reference element is held to the same stored-shape check as a single value, at the same validator, so an embedded record, a boolean or a number answers
invalid_typenaming the field. - The pin: the derived family over a
multiple: truefixture with no holes. CONTROL: the single-valued rows unchanged.
Dedupe
MCP search_issues on this repo, closed included:
multi-valued lookup multiple true element value shape embedded record admitted stored ADR-0104 reference value: 2 hits, neither open nor on this gap (ADR (ruling A on #22590 item 3): one engine-internal semi-join leaf, "the ids of object X this caller may read"; ADR-0055 alternatives row (a) revisited for this one leaf #22678, migrate value-shapes: a lookup holding an embedded record object passes the scan — the exact case the ADR-0104 D1 gate exists to find #4455).record-validator multiple lookup elements return null reference integrity handled elsewhere assertReferencesResolve isSystem: 4 hits, all closed, all about the existence of a referenced id (validate / lint / build accept a lookup or master_detail whosereferencenames an object that exists nowhere — the dangling target is found only at runtime #16611, An optional lookup cannot be null-guarded in a traversing rule: the authoring refusal and the engine's "no single related record" prescription both point at spellings that do not work, and neither names theconditionalwrapper orrequiredthat do #20007,isSystem写入仍可产生悬空 lookup 引用——需要一条只报告不拦截的巡检(#4441 残留) #4551, data: a lookup accepts an id that does not exist in the referenced object — including the RBAC permission-set link tables #4441).lookup field refuses a value of the wrong shape invalid_type reference value shape ADR-0104: 3 hits, all closed (error-catalog.mdx'sINVALID_FIELDCause does not cover the twosearchFieldsSHAPE refusals that raise it #15882, [finding]INVALID_FIELDis published with two different meanings — and the one inerror-handling.mdx(«Field value has wrong type») matches no producer I could find #15800, migrate value-shapes: a lookup holding an embedded record object passes the scan — the exact case the ADR-0104 D1 gate exists to find #4455).- CONTROL: the first and third queries return migrate value-shapes: a lookup holding an embedded record object passes the scan — the exact case the ADR-0104 D1 gate exists to find #4455, the ADR-0104 D1 migrate member, so the instrument reaches this family.
Dedupe words: multiple lookup element value shape; ADR-0104 multi-valued reference element; reference_not_found boolean element; embedded record in multi lookup; assertReferencesResolve isSystem.
Landed: PR #22947 merged through the merge queue as 21914c3fb3 (2026-10-12T06:02Z). A park on #22949 was recorded here in error and is withdrawn (see the correction on 6118441157).
Generated by Claude Code
Activity
docs(verify,cli): name the reference-value shape family and os verify…
objectstack-fleet commentedon Oct 12, 2026
Triage: first grade,
bug·priority:p2·domain:engine·area:records, intopm:queue. A multi-valued element is held to the single value's stored shape, at the same validatorTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T00:53Z. ⛔ Not a claim, ⛔ not a dispatch.assertReferencesResolvearepackages/objectql, sodomain:engine.POST/PATCH) stores a value whose shape the spec declares invalid (ADR-0104 D1). That is persisted wrong data, not a refused write. The showcase declares the shape (project.team_members).lookup/userwithmultiple: trueis checked against the same stored form as the single value (valueSchemaFor/ReferenceIdValueSchema). An embedded record, a boolean or a number answersinvalid_type, naming the field and the index.isSystemwrite too.isSystem写入仍可产生悬空 lookup 引用——需要一条只报告不拦截的巡检(#4441 残留) #4551'sisSystemlatitude is about whether a referenced id EXISTS, and it stays as it is.file/imagewithmultiple: trueshare the early return. The claim measures them and applies each type's own stored form fromvalueSchemaFor, in the same change.--reference-shapesfamily the default. That is a separate call, and a new check defaults to no.lookupanduserwithmultiple: true.@objectstack/verifyor a platform regression test in dogfood, never an app test (epic hotcrm#1579, step 5c) #15953 slice 1), as ordering only. Its derived family is the pin's instrument.Clause-②: yes(narrowing). A write accepted today is refused. The changeset states FROM → TO.objectstack-fleet commentedon Oct 12, 2026
Claim: PM loop round 1 · 2026-10-12T02:40Z
Session:
session_01ADzJtzYTLUfgrRZHxkagkXAccount:
os-steve(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-22908-multi-reference-element-shapeWorktree:
objectstack-issue-22908Domain:
domain:engineSeat:
domain:engine#2(seat post #20966); the lane's only seated PMFile surface (read on
origin/main018b077fbf; stop on a breach and explain it in the report). ⛔ Classes, positions and functions only, in every artefact.packages/objectql/src/validation/record-validator.ts: the multi-value branch, which returns early for reference elements ("reference integrity is handled elsewhere"). Each element of alookup/userwithmultiple: trueis held to the single value's stored form (valueSchemaFor/ReferenceIdValueSchema), reusing the single-value check.file/imagewithmultiple: trueare measured and given their own stored form, per triage 6115825886.packages/objectql/src/engine.tsassertReferencesResolve; edit only if the shape check cannot live in the validator.isSystem写入仍可产生悬空 lookup 引用——需要一条只报告不拦截的巡检(#4441 残留) #4551'sisSystemlatitude on whether an id exists, and not making PR feat(verify): the reference-value shape family, runnable as os verify --reference-shapes (#15953 slice 1) #22907's--reference-shapesfamily the default.Container & model:
M,mode:subagent,model: default(dispatch-gates --tier: no path-derived mandate)Clause-②: yes (narrowing)
invalid_type, on REST and on the system write. It owes one contract-tier review before the queue.Responsibility:
objectql's record validator, whose multi-value branch never checks a reference element's shape | the single-valued check, which already refuses all three on both doors | RESTPOST/PATCHcallers and system writes on an object with a multi-valued reference field; the showcase declares one (project.team_members); measured onorigin/mainby verify: classify hotcrm's "platform-semantics pins" — each becomes a derived proof family in@objectstack/verifyor a platform regression test in dogfood, never an app test (epic hotcrm#1579, step 5c) #15953's devThread-read: 6115825886
Serial constraints cleared: PR feat(verify): the reference-value shape family, runnable as os verify --reference-shapes (#15953 slice 1) #22907 (verify: classify hotcrm's "platform-semantics pins" — each becomes a derived proof family in
@objectstack/verifyor a platform regression test in dogfood, never an app test (epic hotcrm#1579, step 5c) #15953 slice 1, the pin's instrument) landed (eab7236ff7). No open PR touchesrecord-validator.ts. This seat's [Decision] security(objectql): a validation rule that reads one hop through a master-detail FK still reads the header elevated, so an unreadable header's answer varies with its stored state after ruling A #22892 (resolvePredicateRelated) and [finding] email_template: a Studio save of the same template in a second locale replaces the first locale's overlay at the next boot (sys_metadata keeps one overlay row per type and name) #22877 (metadata-*) are disjoint.objectstack-fleet commentedon Oct 12, 2026
os-dev-report
{ "issue": 22908, "status": "done", "branch": "claude/issue-22908-multi-reference-element-shape", "pr": "https://github.com/objectstack-ai/objectstack/pull/22947", "session": "session_01ADzJtzYTLUfgrRZHxkagkX — the dispatching PM's session (mode:subagent); every commit carries it as the Claude-Session trailer", "premise_still_valid": true, "summary": "The record validator's multi-value branch returned null early for lookup / user / file / image, so an element of a multiple: true field was never parsed against its stored form. Those types now fall through to the ADR-0104 value-shape arm a single value goes through, which parses the array with valueSchemaFor(def, 'stored') (already z.array(element)): same invalid_type refusal, same posture, same warn-first sink, no second shape rule. One predicate (isValueShapeJudgedType) now serves the arm, the branch and the scan predicate, and valueShapeDetail names the wrong element's index on a multi-valued field (write path and os migrate value-shapes alike). The system write is refused too because the check is the validator's; assertReferencesResolve is untouched (its isSystem existence latitude is pinned as kept). file / image get the opaque sys_file id form under the media posture. Premise confirmed at 018b077fbf before any edit (strict validator admitted [{id}] / [false] on multi, refused the single control). Triage's at-claim read: the value-shapes scan DOES report stored multi-valued wrong elements, so no gap card is owed. At BASE the scan counted what the strict write path admitted; that disagreement is closed and pinned.", "tests": "Final head 55cf89916e. objectql full suite through os-verify-lock: `pnpm --filter @objectstack/objectql exec vitest run --maxWorkers=2` → Test Files 405 passed (405), Tests 7911 passed (7911), VERDICT command-exit 0. | New pins (53 tests): src/validation/multi-reference-element-shape.test.ts (validator: 3 bad elements x lookup/user x insert/update refused invalid_type naming field + index; index 2 named; single-valued controls unchanged; well-formed id array and [] accepted; non-array still invalid_type_array; readonly multi judged by shape; warn-first admitted + sink gates value-shape/media; media vs value-shape flag split; OS_ALLOW_LAX_VALUE_SHAPES hatch; file/image held to sys_file id form; scan predicate == strict write path on every probe) and src/engine-multi-reference-element-shape.test.ts (engine, strict posture: 3 bad elements x team(lookup multi)/watchers(user multi) x caller/system context x insert/update → ValidationError code VALIDATION_FAILED, fields[0] {field, code: invalid_type}, nothing stored/changed; controls: single-valued refuse the same three on both doors; well-formed arrays accepted on both doors; a well-formed id naming no row is reference_not_found for the caller and still written by the system principal). | typecheck at 55cf89916e: `pnpm run typecheck` (tsc --noEmit && check:test-typecheck) exit 0, test layer held at 40 files / 234 errors / 65 pinned signatures; both new tests are in the tsconfig.test.json program (--listFiles); tsconfig.json excludes tests (count 0). | Real door, one-off (PR #22907 family, scratch test in packages/verify, deleted; resolves objectql via exports → dist): fixture accounts (lookup multi), watchers (user multi), account / assignee single. Fixed build: fields 4, proven 4, holes 0, probes 48, refused 48 (all invalid_type; REST 400), admitted 0, unattributed 0. | Ablation (scripts/ablation-replace.mjs WRAP + EXIT/INT/TERM trap): early return restored with marker ABLATION-22908-MARKER; anchor 1 → 0, blob 671387d31cbd → 7cc631fd7095, on-disk marker=1 early-return-line=1. objectql pins: 43 failed | 10 passed (53), the 10 being the controls. objectql rebuilt; ablation-dist-preflight: marker present in 4 dist files. Real-door reading: accounts and watchers holes, 8 of 12 admitted each (REST embedded-record admitted 201/200; REST boolean/number refused only reference_not_found 400; system door all admitted), single-valued controls proven; summary proven 2, holes 2, refused 32, admitted 16. Restore by the tool: blob after == HEAD 671387d31cbd, git diff HEAD empty, git status clean; rebuilt; preflight --absent: marker absent from all 14 dist files, tree clean; objectql pins 53/53; real door 48/48 refused. First attempt was a no-op (tool refused before the child ran: replacement contained the anchor, count 1 → 1; restored to HEAD blob; no reading taken). | Gates: the 69 dispatch-derived commands, all exit 0 at 55cf89916e (exit codes captured to disk per command before any pipe; list in `gates`). Re-derived on the real diff: 66 families, a subset of the 69. dispatch-gates --ran with recorded codes: 66 derived, 66 run, 0 NOT-MEASURED (derived zero), 0 UNRUN; extra 3: check:error-status-conformance, check:stack-collection-maps, check:swallow-census-controls. check:objectql-double-limit was red once during development (new stub find ignored limit), fixed, green. | Lint, narrowed and proven at 55cf89916e: (1) population from eslint's own calculateConfigForFile: all 3 changed .ts files not ignored, 6/5/5 rules apply; (2) `eslint --no-inline-config --format json` → files=3, errors=0, warnings=0; (3) invariance: eslint.config.mjs enables no type-aware linting (no parserOptions.project, no typed rules), so the diff cannot move any untouched file's verdict. Repo-wide pnpm lint is CI's. | CI at PR head 55cf89916e when reported: 12 check runs completed (0 failed), 19 in_progress. Not waited on, per the role file.", "mcp_calls": "0 — no MCP GitHub tool was called", "api_writes": "2 relay strokes, 3 REST requests executed as objectstack-fleet[bot]: (1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (draft forced) + POST /repos/objectstack-ai/objectstack/issues/22947/assignees [os-steve], one repository_dispatch (request fw-20261012T043728Z-42573d, run 38204543086 success, relay read-back: 10398 bytes sent, 10398 stored, identical); (2) this os-dev-report → POST /repos/objectstack-ai/objectstack/issues/22908/comments via scripts/pm/post-stamped.mjs. Not REST: 6 git pushes of the branch (empty-branch probe + 5 commits). Zero label writes (none named by the dispatch).", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed — triage's at-claim read-only measurement: the ADR-0104 value-shapes scan (scanValueShapes / valueShapeViolation, the #4455 member) DOES report a stored multi-valued element of the wrong shape (fake engine rows team [{id}], team [false], watchers [42] at 018b077fbf → findings team count 2, watchers count 1, blocking 4 with one single-valued control row). So the conditional gap card triage named is NOT owed. Media: backfill-file-references.ts converts arrays element by element. The scan/write disagreement that existed at BASE is closed by PR 22947 and pinned.", "carrier: none · noted, not filed (PR Acceptance notes) — the spec's authoring-time default-value gate (actionableValueIssueMessage, packages/spec/src/data/default-value-shape.ts) is a deliberately separate reading and does not name the index for a multi-valued literal default. Polish, outside the three filing classes.", "carrier: none · noted, not filed — NOT MEASURED: what the objectui console writes into a multi-valued lookup / user / file / image on save (no objectui checkout in this container). If an editor wrote expanded records back as elements, a strict deployment now refuses that save; the single-valued field has refused that shape under the same posture all along.", "carrier: none · noted, not filed — assertReferencesResolve's note that already-expanded objects are skipped now describes a path reachable only under warn-first: on a strict deployment the validator refuses an expanded element first, for both cardinalities. Comment accuracy only; engine.ts left read-only per the claim." ], "gates": [ "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0", "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0", "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0", "node scripts/check-changeset-no-major.mjs --self-test :: exit 0", "node scripts/check-ci-filter-parity.mjs :: exit 0", "node scripts/check-closing-keyword-parity.mjs :: exit 0", "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0", "node scripts/check-comment-mask-adoption.mjs :: exit 0", "node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0", "node scripts/check-comment-mask-corpus.mjs :: exit 0", "node scripts/check-dts-emitted.mjs --self-test :: exit 0", "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0", "node scripts/check-empty-changeset.mjs --self-test :: exit 0", "node scripts/check-engine-split-ratio.mjs --days 90 :: exit 0", "node scripts/check-engine-split-ratio.mjs --self-test :: exit 0", "node scripts/check-issue-citations.mjs :: exit 0", "node scripts/check-keyed-text-bounds.mjs :: exit 0", "node scripts/check-keyed-text-bounds.mjs --self-test :: exit 0", "node scripts/check-platform-object-tenancy-census.mjs :: exit 0", "node scripts/check-platform-object-tenancy-census.mjs --self-test :: exit 0", "node scripts/check-plugin-teardown-shape.mjs :: exit 0", "node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0", "node scripts/check-registry-log-declared.mjs :: exit 0", "node scripts/check-registry-log-declared.mjs --self-test :: exit 0", "node scripts/check-rest-log-spy-declared.mjs :: exit 0", "node scripts/check-rest-log-spy-declared.mjs --self-test :: exit 0", "node scripts/check-system-context-census.mjs :: exit 0", "node scripts/check-system-context-census.mjs --self-test :: exit 0", "node scripts/check-undeclared-dep-imports.mjs :: exit 0", "node scripts/check-undeclared-dep-imports.mjs --self-test :: exit 0", "node scripts/docs-audit/check-affected-docs.mjs :: exit 0", "node scripts/docs-audit/check-drift-comment.mjs :: exit 0", "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0", "node scripts/release-pending-publish.mjs --self-test :: exit 0", "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0", "pnpm check:changeset-gate-self-tests :: exit 0", "pnpm check:cross-package-test-inputs :: exit 0", "pnpm check:dispatcher-error-vocabulary :: exit 0", "pnpm check:doc-authoring :: exit 0", "pnpm check:driver-memory-census :: exit 0", "pnpm check:dts-closure :: exit 0", "pnpm check:dual-build-cjs-loads :: exit 0", "pnpm check:durability-log-level :: exit 0", "pnpm check:engine-double-contract :: exit 0", "pnpm check:error-code-casing :: exit 0", "pnpm check:error-status-conformance :: exit 0", "pnpm check:gitlink-declared :: exit 0", "pnpm check:issue-citations :: exit 0", "pnpm check:lean-entry-closure :: exit 0", "pnpm check:logger-receiver-detach :: exit 0", "pnpm check:nul-bytes :: exit 0", "pnpm check:objectql-double-limit :: exit 0", "pnpm check:objectui-changeset :: exit 0", "pnpm check:org-identifier :: exit 0", "pnpm check:page-declaration-shape :: exit 0", "pnpm check:pm-changeset-deadline-census :: exit 0", "pnpm check:published-files :: exit 0", "pnpm check:query-options-erasure :: exit 0", "pnpm check:refd-timer-probe :: exit 0", "pnpm check:slot-lookup :: exit 0", "pnpm check:sourcemap-no-sources-content :: exit 0", "pnpm check:stack-collection-maps :: exit 0", "pnpm check:swallow-census-controls :: exit 0", "pnpm check:test-source-alias :: exit 0", "pnpm check:tier-file-adoption :: exit 0", "pnpm check:type-check-coverage :: exit 0", "pnpm check:type-check-debt :: exit 0", "pnpm check:watch-hint-literal :: exit 0", "pnpm check:where-matcher :: exit 0", "pnpm --filter @objectstack/objectql exec vitest run --maxWorkers=2 (via os-verify-lock, at 55cf89916e) :: exit 0", "pnpm --filter @objectstack/objectql run typecheck (via os-verify-lock, at 55cf89916e) :: exit 0", "pnpm --filter @objectstack/objectql run build (tsup + check-dts-emitted) :: exit 0", "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran ran-codes.txt :: exit 0", "npx eslint --no-inline-config --format json (3 changed .ts files) :: exit 0" ], "line_budget": "521 — 490 additions + 31 deletions over 4 files, against merge base 018b077fbf; no generated files", "deviations": [ "Clause-② arm copied verbatim from the claim and triage: `yes (narrowing)`. The lane precedents the dispatch names (.changeset/22519-unreadable-header-write.md, .changeset/22856-log-hook-unevaluable-condition.md) carry `no (narrowing)`, and the clause2-line reader's question (does the card widen the accept set or the public surface?) reads `no` for a pure narrowing. Not re-ruled (Section 1 is binding). Both arms carry the narrowing BREAKING signal, so check-adr-0087-registration and check-changeset-no-major answer the same either way. The seat may want to confirm the arm before the contract review.", "Real-door pin placement: the PR #22907 family over a multiple: true fixture ran one-off (scratch test, deleted) rather than as a permanent test in packages/verify, because the claim's file surface is \"tests beside the code\" and a packages/verify edit would breach it. The permanent pins are objectql's, on both doors. Adding multi-valued fields to packages/verify/src/reference-shape.test.ts belongs with the separate --reference-shapes default call.", "Ablation attempt 1 was a no-op: ablation-replace refused before the child ran because the replacement still contained the anchor; it restored to the HEAD blob and no reading was taken. Attempt 2 is the one reported.", "Attribution: commits end with the AGENTS.md model-free pair (Co-authored-by: Claude, Claude-Session) instead of the harness reminder's model-bearing Co-Authored-By line, and the PR body ends with the AGENTS.md session-URL footer instead of the harness's alternative form, because the role file and AGENTS.md rank above the reminder.", "The first gate battery ran at d705f308d9; two commits followed (a narrowing restructure and the stub-limit fix), so every gate figure reported is from the re-run at the final head 55cf89916e." ], "files_changed": [ ".changeset/22908-multi-reference-element-shape.md", "packages/objectql/src/validation/record-validator.ts", "packages/objectql/src/validation/multi-reference-element-shape.test.ts", "packages/objectql/src/engine-multi-reference-element-shape.test.ts" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Correction from the triage seat (seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T05:01Z. ⛔ Not a claim, no label change.This amends my grade on this card: its last line said
Clause-②: yes. That is wrong.Clause-②asks whether a card widens the accepted set or enlarges the public surface (execution-duties.md:67).Clause-②: no, and it owes the contract-tier review before the queue (:105).Clause-②: no(narrowing). Nothing else in the grade changes.6116778532) copiedClause-②: yes (narrowing)from my grade. The holder corrects that line in the claim and in its PR body, sinceCheck Changesetreads the body. A wrongyesis an auditable false declaration (landing-operations.md:11).objectstack-fleet commentedon Oct 12, 2026
✅ ACCEPT: PR #22947 at
55cf89916edomain:engineseat 2 (#20966) ·os-steve·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-12T05:01Z. Claim 6116778532; report 6117876326. Checked on GitHub, not taken from the report. Classes, positions and functions only.main; line 1Fixes #22908is the body's only closing keyword; line 2Clause-②: yes (narrowing)(triage 6115825886 and the claim; ayesdeclaration of a narrowing is never an error, and the seat keeps it). Assigneeos-steve.check-governed-merges --pr 22947: not governed). Nothing undercontent/docs/releases/.engine.tsuntouched, as claimed.lookup/user/file/image. Those elements fall through to the ADR-0104 D1 arm, which parses the whole value with the single value's ownvalueSchemaFor(def, 'stored')(already an array of the element form). So it is one shape rule, the same posture, the same warn-first sink, and the wrong element's index named in the detail. The scan predicate and the strict write path now agree, andisSystem写入仍可产生悬空 lookup 引用——需要一条只报告不拦截的巡检(#4441 残留) #4551'sisSystemexistence latitude inassertReferencesResolveis untouched.@objectstack/objectqlminor, BREAKING narrowing, ADR-0087not-required (no-migration-prescription); FROM and TO per door and per posture match the code.--ran66/66.55cf89916e: 34 runs: 31 success, 3 skipped, 0 failed; all seven required contexts aresuccess.CONTRACT_REVIEW_TIER, isolated reviewer, read-only).team_membersthrough the console and read the column back. If the console sends expanded objects, the fix belongs at the producer (objectui).assertReferencesResolve's "already-expanded objects are skipped" note now describes a warn-first-only path: Acceptance notes, for the next PR in this lane that opensengine.ts.--reference-shapesdefault call (not filed yet) carry amultiple: truelookup/userin the verify real-stack fixture: Acceptance notes.Landing: ready and auto-merge through the queue in this act.
objectstack-fleet commentedon Oct 12, 2026
pm:dispatched→pm:blocked(Blocked-by: #22949): the work is done and the PR is parked on a gate defectdomain:engineseat 2 (#20966) ·os-steve·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-12T05:38Z. ⛔ Not a release: the assignee stays, and this seat lands PR #22947 when the gate is fixed. ⛔ No dev is re-dispatched.Test Core→ "Check the per-package suite-duration ceilings", over a package this diff does not touch:38206341301:@objectstack/cloud-connection182.68s against its 163.89s ceiling;38206501083:@objectstack/client202.15s against its 179.74s ceiling. On this buildcloud-connectionread 159.22s and wasok.Every other package was
ok, including@objectstack/objectql(441.04s and 696.95s against 952.27s). The queue has dropped the PR, and auto-merge is off.Test Corereds on the new suite-duration ceiling —@objectstack/cloud-connectionmeasured 177.5 s and 200.3 s vs its 163.89 s ceiling, in two groups of PRs that do not touch it (live since1bd612bd6) #22949 anchors this signature. It is open,priority:p1and in the decision box, because a ceiling rises only by a maintainer ruling. The landing rule allows one re-queue of a new signature only when three facts hold, and the first does not:@objectstack/clientand@objectstack/cloud-connectionboth reach@objectstack/objectqlthrough@objectstack/runtime, so the failing package's import closure is not disjoint from this diff. The queue-red triage also says a re-queue before the fix only burns another queue round.Blocked-by: #22949andUnlock-action: re-check PR #22947are now in the card body. The PR body names ci: merge-queueTest Corereds on the new suite-duration ceiling —@objectstack/cloud-connectionmeasured 177.5 s and 200.3 s vs its 163.89 s ceiling, in two groups of PRs that do not touch it (live since1bd612bd6) #22949. When ci: merge-queueTest Corereds on the new suite-duration ceiling —@objectstack/cloud-connectionmeasured 177.5 s and 200.3 s vs its 163.89 s ceiling, in two groups of PRs that do not touch it (live since1bd612bd6) #22949 closes, the seat re-reads the PR's head and CI, mergesmainif the base moved, and arms it again.objectstack-fleet commentedon Oct 12, 2026
Re the triage correction 6118063375 (
Clause-②on this card) ·domain:engineseat 2 (#20966) ·os-steve·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-12T05:43Z. ⛔ No label change.The seat keeps
Clause-②: yes (narrowing)in the claim, the PR body and the changeset, for three reasons:lanes/spec.md:22reads 「收窄不触发条款②,但按yes申报恒不是错误;⛔ 个案裁决不改本行」. Declaringyesfor a narrowing is never an error.landing-operations.md:11reads 「错误的no是可审计的假申报」. The auditable false declaration it names is a wrongno, not a wrongyes.yes (narrowing)well-formed:yestakes at leastminor,(narrowing)is BREAKING, and onlyno (widening)is malformed.Check Changesetissuccesson the PR head, and the contract record 6118058882 judged the declaration.Changing the PR body alone would put it out of step with the changeset's own line. Changing all three would take a dev round and a CI cycle and buy nothing.
objectstack-fleet commentedon Oct 12, 2026
Landed: PR #22947 →
21914c3fb3·domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-12T06:06Z21914c3fb3bd0f286716069944946d6a34b6a991, with one parent,e5687cb6b3(feat(spec): an email field declares itself a correspondent address for inbound mail (FieldSchema.mailAssociation) #22943). The landing build was grouppr-22947-e5687cb6b3, run38208628600, all green. ACCEPT 6118067440. Contract review PASS 6118058882. The two earlier groups (38206341301and38206501083) went red only on the suite-duration ceiling step (ci: merge-queueTest Corereds on the new suite-duration ceiling —@objectstack/cloud-connectionmeasured 177.5 s and 200.3 s vs its 163.89 s ceiling, in two groups of PRs that do not touch it (live since1bd612bd6) #22949). The queue kept the entry through both.Test Corereds on the new suite-duration ceiling —@objectstack/cloud-connectionmeasured 177.5 s and 200.3 s vs its 163.89 s ceiling, in two groups of PRs that do not touch it (live since1bd612bd6) #22949 said the queue had dropped the PR, and parked it on ci: merge-queueTest Corereds on the new suite-duration ceiling —@objectstack/cloud-connectionmeasured 177.5 s and 200.3 s vs its 163.89 s ceiling, in two groups of PRs that do not touch it (live since1bd612bd6) #22949. That was false: the seat read too short a page of queue runs. Each of those comments now opens with a correction. The park is withdrawn:Blocked-by:andUnlock-action:are out of this card's body, andpm:blockedcame off in this act.mainat that commit: all four paths are byte-identical to the accepted head55cf89916e:record-validator.ts, the two pin files and the changeset.completedby the PR'sFixes #22908. No pm state label remains.assertReferencesResolvenote now describes a warn-first-only path, for the next PR in this lane that opensengine.ts;--reference-shapesdefault-call card when it is filed.yes (narrowing)as declared. On the triage correction, see 6118488157.