Skip to content

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

Closed

Description

@objectstack-fleet

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 }]) answers 201 / 200 and stores [{ id }]. [false] and [42] are refused only as reference_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, user and master_detail refuse all three with invalid_type on 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 returns null early for lookup / user / file / image elements, with the comment "reference integrity is handled elsewhere". So the element's shape is never checked against that stored form.
  • packages/objectql/src/engine.ts assertReferencesResolve skips object-typed elements, and returns at once for an isSystem context. So nothing downstream catches the shape either.
  • Seam: spec: valueSchemaFor / ReferenceIdValueSchema → runtime: the record validator's multi-value branch and assertReferencesResolve.

Not measured

Family and related

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_type naming the field.
  • The pin: the derived family over a multiple: true fixture with no holes. CONTROL: the single-valued rows unchanged.

Dedupe

MCP search_issues on this repo, closed included:

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

  1. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p2 · domain:engine · area:records, into pm:queue. A multi-valued element is held to the single value's stored shape, at the same validator

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-12T00:53Z. ⛔ Not a claim, ⛔ not a dispatch.

  2. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-12T02:40Z
    Session: session_01ADzJtzYTLUfgrRZHxkagkX
    Account: os-steve (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-22908-multi-reference-element-shape
    Worktree: objectstack-issue-22908
    Domain: domain:engine
    Seat: domain:engine#2 (seat post #20966); the lane's only seated PM
    File surface (read on origin/main 018b077fbf; stop on a breach and explain it in the report). ⛔ Classes, positions and functions only, in every artefact.

  3. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    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

  4. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    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).
    • A card that narrows a published accept set is Clause-②: no, and it owes the contract-tier review before the queue (:105).
    • So this card is Clause-②: no (narrowing). Nothing else in the grade changes.
    • ⚠️ The claim on this card (6116778532) copied Clause-②: yes (narrowing) from my grade. The holder corrects that line in the claim and in its PR body, since Check Changeset reads the body. A wrong yes is an auditable false declaration (landing-operations.md:11).
  5. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR #22947 at 55cf89916e

    domain:engine seat 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.

    • Form: draft to main; line 1 Fixes #22908 is the body's only closing keyword; line 2 Clause-②: yes (narrowing) (triage 6115825886 and the claim; a yes declaration of a narrowing is never an error, and the seat keeps it). Assignee os-steve.
    • Scope: 4 files, +490 / −31, none generated, none governed (check-governed-merges --pr 22947: not governed). Nothing under content/docs/releases/. engine.ts untouched, as claimed.
    • Fix, read in the diff: the record validator's multi-value branch no longer returns early for lookup / user / file / image. Those elements fall through to the ADR-0104 D1 arm, which parses the whole value with the single value's own valueSchemaFor(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, and isSystem 写入仍可产生悬空 lookup 引用——需要一条只报告不拦截的巡检(#4441 残留) #4551's isSystem existence latitude in assertReferencesResolve is untouched.
    • Changeset, read sentence by sentence against the diff: @objectstack/objectql minor, BREAKING narrowing, ADR-0087 not-required (no-migration-prescription); FROM and TO per door and per posture match the code.
    • Evidence: 53 new pins (validator and engine; caller and system contexts; insert and update; controls). The real door was run one-off: 48 of 48 refused on the fixed build, and 16 admitted under ablation, reproducing the card. objectql: 7911 tests pass. 69 gate families, all exit 0; re-derived 66, --ran 66/66.
    • CI on 55cf89916e: 34 runs: 31 success, 3 skipped, 0 failed; all seven required contexts are success.
    • Contract review: PASS, record 6118058882 on the PR (CONTRACT_REVIEW_TIER, isolated reviewer, read-only).
    • Out-of-scope findings:
      1. The ADR-0104 value-shapes scan already reports a stored multi-valued element of the wrong shape (measured at claim). Triage's conditional gap card is therefore not owed: dropped, with that reason.
      2. The spec's authoring-time default-value gate names no index: dropped. It is polish, outside the three filing classes.
      3. The objectui console's save of a multi-valued reference is NOT MEASURED: Acceptance notes. A warn-first store (an upgraded one) refuses nothing new. A born-strict fresh store refuses an element that is not an id, as the single value already does. Suggested read-only dogfood item: save a showcase project's team_members through the console and read the column back. If the console sends expanded objects, the fix belongs at the producer (objectui).
      4. 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 opens engine.ts.
    • Deviation accepted: the real-door pin ran one-off, not kept, because the claim's surface is tests beside the code. The contract record suggests that the card for the --reference-shapes default call (not filed yet) carry a multiple: true lookup / user in the verify real-stack fixture: Acceptance notes.

    Landing: ready and auto-merge through the queue in this act.

  6. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    ⚠️ Correction · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T06:04Z. The statement below that the queue dropped PR #22947 is false. The queue never removed it: its timeline shows no removed_from_merge_queue before the merge. After group pr-22947-12df242e60 (run 38206501083) went red, the queue rebuilt the entry as group pr-22947-e5687cb6b3 (run 38208628600, created 2026-10-12T05:35:54Z). That run went green, and the PR merged as 21914c3fb3 at 06:02Z. This seat missed that group because it read too short a page of queue runs (10 runs, so the 05:35:54 group fell outside it). The park below never took effect, and none is in force now. The suite-ceiling readings below are accurate.

    pm:dispatched → pm:blocked (Blocked-by: #22949): the work is done and the PR is parked on a gate defect

    domain:engine seat 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.

  7. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Re the triage correction 6118063375 (Clause-② on this card) · domain:engine seat 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:22 reads 「收窄不触发条款②,但按 yes 申报恒不是错误;⛔ 个案裁决不改本行」. Declaring yes for a narrowing is never an error.
    • landing-operations.md:11 reads 「错误的 no 是可审计的假申报」. The auditable false declaration it names is a wrong no, not a wrong yes.
    • AGENTS.md's changeset rule makes yes (narrowing) well-formed: yes takes at least minor, (narrowing) is BREAKING, and only no (widening) is malformed. Check Changeset is success on 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.

  8. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #22947 → 21914c3fb3 · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T06:06Z

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

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:enginepriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions