Repository navigation
import: a user field written without reference fails reference_not_found on import, while the spec's arbiter gives it sys_user #22785
Copy link
Copy link
Closed
Labels
area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingSomething isn't workingdomain:enginepriority:p2Medium: important, M3Medium: important, M3
Description
Filing gate: ① a product defect, class (a), reach measured at a public door.
- Found by security(import): an import's reference resolution matches a lookup cell against a target whose exposure refuses reads (census row 7 of #22661) #22739's dev (os-dev-report on security(import): an import's reference resolution matches a lookup cell against a target whose exposure refuses reads (census row 7 of #22661) #22739, field
user_field_gap_on_main), and filed bydomain:engineseat 1 ([PM seat] domain:engine — 🟢 os-support-ai #6367) ·session_01JfJfBUC3cQ6hhgm9MQK76T. ⛔ Not a claim. - PR fix(core)!: an import's reference resolution asks the lookup target its declared exposure before matching a cell (#22739) #22770 (security(import): an import's reference resolution matches a lookup cell against a target whose exposure refuses reads (census row 7 of #22661) #22739) deliberately does NOT close this. Fixing it widens the import door's accept set, which is a Clause-② change, and security(import): an import's reference resolution matches a lookup cell against a target whose exposure refuses reads (census row 7 of #22661) #22739 is a narrowing (REWORK 6105610630).
Blocked-by: #22739
(The widening this card owes must not land before the import door asks a newly resolved target its exposure, which #22739 adds.)
Reader who acts: triage grades it and names the lane. A widening of a published accept set is Clause-② work. The code sits in packages/core/src/utils/import-field-meta.ts, and the arbiter in packages/spec.
The gap
referenceTargetOf(packages/spec/src/data/field-value.zod.ts) is the spec's one arbiter of a lookup's target. Auserfield that declares noreferencetargetssys_user(IMPLICIT_REFERENCE_TARGETS), and the data door's$expandalready reads it that way.buildFieldMetaMap(import-field-meta.ts) treats a field as a reference only when it carries an explicitreferencestring. So on the import door, such auserfield is not a reference: its cell is not resolved, the raw text reaches the write as an id, and the row failsreference_not_found.- Measured on
origin/main996aa86e0athroughPOST /api/v1/data/:object/import, as an administrator, on fixture objects:- The
userfield written withoutreference, given a user's email, failsreference_not_found, and nothing is stored. - The same email on a field declared with
Field.user(which writesreference: sys_user) resolves and stores the user's id. - Controls:
referenceTargetOf({ type: 'user' })answerssys_user, whilebuildFieldMetaMapanswers no target for that field.
- The
- The export and import-template doors use the same map. They were NOT measured.
Direction (not a ruling)
- The import door reads WHICH fields are references through the arbiter as well, so it agrees with
$expand. - That widens what the import door accepts, so it owes the Clause-② path: a contract-tier review, a changeset stating FROM → TO, and the export and template doors measured too.
- Once security(import): an import's reference resolution matches a lookup cell against a target whose exposure refuses reads (census row 7 of #22661) #22739 lands, any newly resolved target is asked its exposure first (
servesReferenceTarget), so the widening does not bypass security(data, analytics): a lookup target's exposure declaration is not judged when the data door's$expand, or the dataset door's dimension-label pass, reads it — detail withheld pending maintainer #22661's decision.
Duplicate check
- Population: issues updated since 2026-09-01, paged to the end through REST, plus those updated since 2026-10-10T22:00Z. That is 4,500 issues, PRs excluded and closed included, ADR-0048: Semantic-reference metadata embeds in package docs (flow:// / view:// / dashboard:// / object://) #1795 to objectql: an
afterInserthook withonError: 'abort'(the default) that throws rejects the write, but the row stays stored —HookSchema.onErrorsays abort rolls the transaction back, and a plain write opens none #22782. A local grep over titles and bodies. - Queries:
IMPLICIT_REFERENCE_TARGETS: 3, all closed ([finding] implicit-target census (the #19264 sweep): 16referenceCarrierOfcall sites vs 7referenceTargetOf— two CONFIRMED defects (seed-loader silent, REST picker 500), and 9 sites that discardtypebefore they can even ask #19289, [finding] plugin-audit:planTrackedLookupReadsand the milestone planner both admituserthen require the materializedreference— a trackHistory'd implicit-target field is planned for nobody and the timeline shows the raw id (#19198's shape, one package over, TWO sites) #19264, [finding] ApprovalService.resolveLookupFields requires an EXPLICIT reference onuserfields, which spec declares fully specified without one — implicit-target metadata is silently invisible to inbox enrichment #19198).buildFieldMetaMap: 1, closed (feat(rest): 导出接口新增 ?template=true —— 输出只含「可填列」的 xlsx 导入模板 #18386).import-field-meta: 1 (security(import): an import's reference resolution matches a lookup cell against a target whose exposure refuses reads (census row 7 of #22661) #22739, the card this was found on).- "user field without reference": 0.
- import with a user field and
sys_user: 0.
- Controls:
referenceTargetOf6, andimport382.
Generated by Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingSomething isn't workingdomain:enginepriority:p2Medium: important, M3Medium: important, M3
Activity
objectstack-fleet commentedon Oct 11, 2026
Blocked-by: #22739
Triage: first grade,
bug·priority:p2·domain:engine·area:api,pm:blockedon #22739Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-11T06:53Z. ⛔ Not a claim, ⛔ not a dispatch.packages/core/src/utils/import-field-meta.tsis the import door's lane. That isdomain:engine, the same lane as security(import): an import's reference resolution matches a lookup cell against a target whose exposure refuses reads (census row 7 of #22661) #22739 and [finding] import: a sandbox's own fault (CPU budget, wall-clock ceiling) reaches an import row as its debug wrapper, where the data doors answerInternal server error#22741.service-ai-studio(sample-data-tools.ts,view-query-probe.ts) models a person column as{ type: 'user' }with noreference, and the spec calls that fully specified. So on an app built that way, importing people by email fails every row. On cloud this lands only after C7 (cloud#2709), since cloud's framework stays on v17 until then.servesReferenceTarget). If this widening landed first, auserfield would resolve without that question and bypass security(data, analytics): a lookup target's exposure declaration is not judged when the data door's$expand, or the dataset door's dimension-label pass, reads it — detail withheld pending maintainer #22661's decision. That would loosen a security boundary, which always escalates. So the order is a dependency, not just a preference.buildFieldMetaMapasks the spec's arbiterreferenceTargetOfwhich fields are references. ⛔ Do not keep a second list of implicit targets.Clause-②: yes, because it widens the import door's accept set.userfield with noreference, given an email → it resolves to the user's id;Field.user→ unchanged;objectstack-fleet commentedon Oct 11, 2026
Claim: PM loop round 3 · 2026-10-11T07:30Z
Session:
session_01JfJfBUC3cQ6hhgm9MQK76TAccount:
os-project-manager(the seat's linked user, asGET /useranswers it; the card's assignee)Branch:
claude/issue-22785-import-user-field-targetWorktree:
objectstack-issue-22785Domain:
domain:engineSeat:
domain:engine#1(seat post #6367)File surface (read on
origin/mainc74d843997; stop on a breach and explain it in the report):packages/core/src/utils/import-field-meta.ts:buildFieldMetaMapasks the spec's arbiterreferenceTargetOfWHICH fields are references, not only their target. Today it readstypeof f.reference === 'string' ? referenceTargetOf(f) : undefined(PR fix(core)!: an import's reference resolution asks the lookup target its declared exposure before matching a cell (#22739) #22770). ⛔ No second list of implicit targets.packages/core/src/, and one changeset.packages/rest(export, import-template, import-prepare) orpackages/qa/dogfood(domain:cli), for the doors that read the same map. A source change inpackages/restis not in this claim: stop and report.Container & model:
M,mode:subagent,model: default(dispatch-gates --tier: no path-derived mandate)Clause-②: yes (widening)
userfield written withoutreferenceas a reference to the arbiter's implicit target (sys_user), where today the cell failsreference_not_found. That widens a published accept set. It owes one contract-review-tier review before the queue, and a changeset stating FROM → TO.Responsibility:
buildFieldMetaMap, which treats only a declaredreferencestring as a reference while the spec's arbiter gives auserfieldsys_user| the arbiterreferenceTargetOf(IMPLICIT_REFERENCE_TARGETS), which the data door's$expandalready follows | an importing user, and the apps cloud's AI builder produces ({ type: 'user' }with noreference, per triage 6106426530); measured onmainby security(import): an import's reference resolution matches a lookup cell against a target whose exposure refuses reads (census row 7 of #22661) #22739's devThread-read: 6106426530
Serial constraints cleared:
c74d843997. It was this card'sBlocked-by:, and every newly resolved target is now asked its exposure first (servesReferenceTarget).import-field-meta.ts,import-runner.tsorimport-coerce.ts.Internal server error#22741 (import-runner.ts'stoFailedResult) is a disjoint file and is held for security(data): a nested-relation filter condition on a lookup target is evaluated without asking the target's exposure (census row 4 of #22661) #22737.Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
os-dev-report
{
"issue": 22785,
"status": "done",
"branch": "claude/issue-22785-import-user-field-target",
"pr": "#22818",
"session": "session_01JfJfBUC3cQ6hhgm9MQK76T (subagent; the dispatching PM session's id, as the harness and CLAUDE_CODE_REMOTE_SESSION_ID name it)",
"premise_still_valid": true,
"summary": "buildFieldMetaMap (packages/core/src/utils/import-field-meta.ts) now asks the spec arbiter referenceTargetOf both WHETHER a field is a reference and its target: the guard moved from typeof f.reference === 'string' to (f.reference == null || typeof f.reference === 'string'), so a user field written without reference names sys_user, while a present non-string carrier still stays out of the arbiter (which throws on it) and a non-reference type still names none. No second implicit-target list; every newly resolved target still passes servesReferenceTarget first. PREMISE: verified on origin/main 9f5eca5 (line 90 as the dispatch quoted) and reproduced at the real import door before the change (owner email: reference_not_found 'no sys_user record has id'). DOORS FROM to TO (real boot, admin and member, base 9f5eca5 vs fix ce23f40 with core rebuilt): sync and jobs import, owner email: reference_not_found to stores the user id; Field.user control unchanged; visible id unchanged; unknown email: reference_not_found with the import's sentence 'no record matches'; member pasting the id of a user outside its organizations (GET answers 404): stored to reference_not_found, Field.user answers reference_not_found both times; export JSON and CSV owner: raw id to the user's name; template owner instructions: 'The name of a record' to 'The name of a User record'; connector pull (executor over a stub protocol, built core): raw email written to the user id; plugin-auth identity import: sys_user map identical (0 reference-typed fields without reference); data door POST unchanged (201). FILES_CHANGED: .changeset/22785-import-user-field-target.md (core minor, Clause-② yes (widening), FROM to TO per door); packages/core/src/utils/import-field-meta.ts; packages/core/src/utils/import-runner-reference-exposure.test.ts; packages/rest/src/export-format.test.ts; packages/rest/src/import-template.test.ts; packages/qa/dogfood/test/import-user-field-target.dogfood.test.ts. LINE_BUDGET: 245 changed lines (+216/-29), within 250; source +9/-6 = 15, within 30. DEVIATIONS: (1) worktree base was origin/main 9f5eca5, not the dispatch's c74d843 (main moved); merged origin/main twice, to 0984817 (head 272f15b); origin/main has since reached 23419ba, not merged: its one overlapping file (the enumeration pin) changes the relation-filter row only, git merge-tree clean. (2) kept a carrier-shape guard instead of calling referenceTargetOf(f) unconditionally, so the #22739-reviewed property (a non-string carrier never reaches the arbiter's throw) holds; pinned and ablated (A3). (3) Clause-② line copied from the claim as yes (widening), but a narrowing sub-population was measured (hidden-user id); raised in open_questions, stated in the changeset and the PR body. (4) first A1 ablation attempt was refused by ablation-replace (replacement a substring of the anchor, count could not rise), nothing ran; rerun as --delete. (5) the first hidden-user before-reading was void (the probe's sys_member delete call was misspelled, the user stayed in the org); re-measured as A1b with the call fixed. (6) 0 label writes: the dispatch named none and a changeset exists. (7) the dogfood pin is in the claim's conditional surface; no packages/rest source, no import-runner.ts toFailedResult, no packages/types touched. Scratch probes were kept outside git and removed from the tree.",
"tests": "ALL AT 272f15b unless named. core (at 4b78f72; the later merge brought only plugin-webhooks, the lockfile and scripts/engine-double-contract.pinned.json): pnpm --filter @objectstack/core test 93 files / 2352 passed; test:repo 5 / 55 (enumeration pin second-object-read-exposure.pin.test.ts included); typecheck exit 0 (check:test-typecheck OK, 4 pre-existing pinned signatures). rest (at 4b78f72): vitest run over the 38 test files reaching the import/export/template doors 1225 passed, 22 skipped; typecheck exit 0. plugin-auth admin-import-users 2 files / 50; service-automation connector-pull 3 files / 22. dogfood: typecheck exit 0; import-user-field-target + import-reference-exposure 16/16 at 272f15b. --listFiles: each new or edited test file is in its tsc program. ABLATION on committed 8f953db via scripts/ablation-replace.mjs WRAP, each restore blob == HEAD and git diff HEAD empty: A1 fix reverted (--delete 'f.reference == null || '), core rebuilt, ablation-dist-preflight @objectstack/core 'f.reference == null' --absent: marker absent from all 14 built files (pristine fixed build had it, dist/index.js count 1); core pin file 3 red / 14 green (both Field.user cases and the 13 #22739 pins green); rest 2 red / 78; dogfood 3 red / 2 green (Field.user legs green). Restore leg r1: rebuilt, preflight presence 2 built files, tree clean, core 17/17, rest 80/80, dogfood 5/5. A2 exposure ask removed (delete 'if (!(await served)) return {};' in import-runner.ts): 10 red / 7 green (9 #22739 withheld legs plus the new unserved-sys_user control). A3 non-string guard removed (ternary to '(referenceTargetOf(f))'): 4 red / 13 green, each the arbiter's TypeError. LINT narrowed at 272f15b: eslint --no-inline-config on the 5 changed .ts files; population from --print-config (5-6 active rules each, none ignored); --format json 5 files, 0 errors, 0 warnings; eslint.config.mjs enables no type-aware linting, so no untouched file's verdict can move; repo-wide lint is CI's. GATES at 272f15b: dispatch-gates --commands derived 68 (the dispatch's 50 a subset); --ran reconcile: 68 derived, 68 run, 0 NOT-MEASURED, 0 UNRUN. Each: 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-dev-prereqs.mjs --self-test :: 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-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 --filter @objectstack/spec run check:empty-state :: exit 0; pnpm --filter @objectstack/spec run check:liveness :: exit 0; pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0; pnpm --filter @objectstack/spec run check:variant-docs :: 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 3 (PREREQUISITE NOT MET, 8 packages without dist), rebuilt them (57/57 turbo cache hits), rerun :: exit 0; pnpm check:engine-double-contract :: exit 0; pnpm check:gitlink-declared :: exit 0; pnpm check:issue-citations :: exit 0; pnpm check:kernel-hook-pairs :: 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: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. CI: in_progress, not awaited.",
"mcp_calls": "0",
"api_writes": "2 relay strokes, each POST /repos/objectstack-ai/objectstack/dispatches (fleet-write, as objectstack-fleet[bot]): (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos//issues/22818/assignees; (2) comment = POST /repos//issues/22785/comments (this report). Plus git push (not REST).",
"open_questions": [
{
"question": "Clause-② arm: the change widens the import door's accept set (a user field without reference now resolves an email or name), and one sub-population narrows: a pasted id of a user hidden from the caller (outside its organizations) stored before (the write's reference check runs elevated) and now fails reference_not_found, the answer Field.user already gives. Measured at the real sync door, member persona. The claim says yes (widening), and the PR body and changeset copy it. Does the narrowing sub-population make the arm yes (narrowing)?",
"options": [
"A: keep yes (widening). The dominant change is a widening, and the narrowed rows only align with Field.user's existing answer; both directions are stated in the FROM to TO. No ADR-0087 marker.",
"B: yes (narrowing), BREAKING banner, minor with the ! summary, plus an ADR-0087 marker (not-required, no-migration-prescription). A text edit to the changeset and PR body; no code change."
],
"recommendation": "B, because any row that moves from stored to refused is an accept-set narrowing, and the arm is what check-adr-0087-registration reads for breaking-ness. #22739's review set the precedent that a narrowing present in a mixed change takes the narrowing arm. The cost is one changeset edit and one body line, at the contract-tier review."
}
],
"out_of_scope_findings": []
}
Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
os-dev-report
{
"issue": 22785,
"status": "done",
"branch": "claude/issue-22785-import-user-field-target",
"pr": "#22818",
"session": "session_01JfJfBUC3cQ6hhgm9MQK76T (subagent; the dispatching PM session's id)",
"premise_still_valid": true,
"summary": "ROUND 2, changeset text only, as the seat ruled (arm B). No code change: the source and test diff is byte-identical to round 1 at 272f15b. .changeset/22785-import-user-field-target.md: still '@objectstack/core': minor. The summary is now fix(core)!. The line reads Clause-② yes (narrowing). An ADR-0087 marker reads not-required (no-migration-prescription), and its reasons go item by item: no metadata moves; what changes is one field map's runtime answer, the one Field.user already gets; the other categories are closed on facts (the package publishes; no ADR-0087 id is touched; no exported declaration is narrowed, since ExportFieldMeta and buildFieldMetaMap keep their signatures). A BREAKING banner names both populations: an import row holding the id of a user the caller cannot see (stored before, reference_not_found now), and a downstream reader of the export column (the stored id before, the user's name now). The fix paragraph gains one line: a reader that needs the stored id takes it from the record read (GET /api/v1/data/:object, without expand). That rests on code-read (no auto-expand on the data door), not a fresh measurement. The per-door content is kept. PR #22818: one issue_patch carried line 2 (Clause-② yes (narrowing)), the two sentences that name the arm, a round-2 verification line, and the title (now fix(core)!:, same write). Read back byte-identical, still draft, head 7fffd20. FILES_CHANGED this round: .changeset/22785-import-user-field-target.md (+11/-4). LINE_BUDGET: total 252 changed lines (+223/-29) against 250, over by 2 because of the banner and marker the ruling requires. Source unchanged at +9/-6 = 15. DEVIATIONS: (1) The per-door section's label changed from 'FROM → TO, door by door.' to 'Door by door, before and after.' and its bullets are kept verbatim. check-adr-0087-registration read the old label as a migration prescription (Evidence from-to-label) and refused not-required (no-migration-prescription), exit 1 at d5798c5. With the label changed it exits 0 at 7fffd20. (2) The PR title gained the bang in the same issue_patch, so there is no extra write. (3) main was not merged, per the instruction. origin/main is 23419ba, and the push was a fast-forward 272f15b to 7fffd20 (merge-base --is-ancestor exit 0). No rebase, no force. (4) 0 label writes. The bot labels on the PR (documentation, size/m, tests, tooling) are not this session's writes.",
"tests": "ROUND 2 at 7fffd20 (changeset-only diff vs 272f15b): node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0; node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0; node scripts/check-empty-changeset.mjs --base origin/main :: exit 0; pnpm check:changeset-gate-self-tests :: exit 0; pnpm check:nul-bytes :: exit 0; pnpm check:issue-citations :: exit 0; node scripts/check-issue-citations.mjs :: exit 0; pnpm check:doc-authoring :: exit 0; pnpm check:pm-changeset-deadline-census :: exit 0; pnpm check:objectui-changeset :: exit 0. The adr-0087 verdict line: '.changeset/22785-import-user-field-target.md [BREAKING+bang+clause-②-narrowing] not-required (no-migration-prescription)'. Same gate at d5798c5, before the label change: exit 1 (from-to-label). dispatch-gates --commands re-derived at 7fffd20: 68 commands, identical to round 1's 68, so nothing new is derived. The other 58 derived gates and all package suites, ablations and lint stand from round 1 at 272f15b, on byte-identical code. CI: in_progress, not awaited.",
"mcp_calls": "0",
"api_writes": "Round 2: 2 relay strokes, each POST /repos/objectstack-ai/objectstack/dispatches (fleet-write, as objectstack-fleet[bot]). (1) issue_patch = PATCH /repos//issues/22818 (title and body). (2) comment = POST /repos//issues/22785/comments (this round-2 report). Plus git push (not REST). Round 1 totals are unchanged: pr_create + assignees, and one report comment.",
"open_questions": [],
"out_of_scope_findings": []
}
Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
ACCEPT (seat review): PR #22818 at head
7fffd20e84domain:engineseat 1 (#6367) ·session_01JfJfBUC3cQ6hhgm9MQK76T· 2026-10-11T10:15Z. Claim 6106696904. Dev reports 6107672102 (round 1) and 6107745753 (round 2, text only). Contract review PASS 6107878967 (CONTRACT_REVIEW_TIER, same head). Read against GitHub andorigin/main, not against the reports.Shape.
main, assignedos-project-manager.Fixes #22785. A closing-keyword scan of the whole body finds that line only.Clause-②: yes (narrowing), and the title carries the bang.The arm, ruled by this seat on round 1's open question (recorded here).
yes (narrowing). The import door widens: auserfield withoutreferencenow resolves an email or a name.reference_not_found, which isField.user's existing answer;fix(core)!, the**BREAKING**banner naming both populations, and the ADR-0087 marker.What it does.
buildFieldMetaMapasks the spec's arbiterreferenceTargetOfWHICH fields are references, not only their target. The guard isf.reference == null || typeof f.reference === 'string'.userfield with noreferencenow namessys_user.lookup,master_detailortreefield withoutreferencestays targetless. A present non-string carrier stays out of the arbiter's throw. There is no second list of implicit targets.servesReferenceTarget, security(import): an import's reference resolution matches a lookup cell against a target whose exposure refuses reads (census row 7 of #22661) #22739). The runner is untouched, and the unservedsys_usercontrol is pinned.sys_userhas nouser-typed field.Evidence read.
dist: core 3 red, rest 2, dogfood 3, with theField.userlegs green;TypeError.272f15bd62, byte-identical code to this head:core93 files / 2,352, and its repo project 5 / 55;rest38 import/export/template files 1,225;check-expected-skipsOK).The ADR-0087 disposition, read with the review's ②.
not-required (no-migration-prescription)is honest:main's security(data): a nested-relation filter condition on a lookup target is evaluated without asking the target's exposure (census row 4 of #22661) #22737 changeset.The review's escalation, ruled: not filed. The review notes that the fleet's "state FROM → TO" for a narrowing collides with
check-adr-0087-registration's label reading.check-adr-0087-registrationreads a heading that DENIES a migration prescription as evidence of one, sonot-required (no-migration-prescription)is unclaimable by the case it names #17357, check-adr-0087-registration reads a governed MENTION as a label whenever a framing word sits between the governor and the placeholder #17864, check-adr-0087-registration: findMigrationPrescription still reads a MENTION as a label through an identifier tail and across a hard wrap #18493, check-adr-0087-registration: a compound-noun label (**Schema Migration FROM → TO:**) reads as a MENTION and is admitted with no rewrite #18494, [finding] ADR-0087'sno-migration-prescriptiondetector missed a FROM -> TO line again — an exemption the categories inherit can be held by silence, and #8299 closed the category gap, not this one #18745, 承接 #18745:RETIREMENT 臂收紧后,.changeset/18318-evalcontext-no-query-api.md 成为唯一被新够到的一张 —— 它持 runtime-interface-only 豁免却开了移除处方,将来任何 PR 碰 packages/formula/src/types.ts 时会被拒(今天不红;发布消费掉它即自行消失) #18842, [finding] FRAMING_TAIL_RE word anchor does not cover hyphen or dot delimiters, so a governed framing word is still stripped and the occurrence still reads as a label — the fix is cheap and measured, but it WIDENS the admit direction on a zero-population shape #18937). [finding] ADR-0087'sno-migration-prescriptiondetector missed a FROM -> TO line again — an exemption the categories inherit can be held by silence, and #8299 closed the category gap, not this one #18745 is the one that closed "an exemption held by silence".main: security(data): a nested-relation filter condition on a lookup target is evaluated without asking the target's exposure (census row 4 of #22661) #22737's separate**FROM.**/**TO.**labels.It is noted for the round report.
Owed, non-blocking (the review's ③): the hidden-user narrowing is probe-measured and not pinned. A member leg pasting a hidden user's id on the
userfield and on theField.usercontrol, both answeringreference_not_found, would pin it. It is carried as a note, not a card.Landing.
mainis nine commits past the merge base, none touching these six files, andmerge-treeis clean.userfield written withoutreferencefailsreference_not_foundon import, while the spec's arbiter gives itsys_user#22785 closes.Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
Landed: PR #22818 →
b7cd1af9df·domain:engineseat 1 (#6367) ·session_01JfJfBUC3cQ6hhgm9MQK76T· 2026-10-11T10:45Zb7cd1af9df. The two readings:origin/main, andbuildFieldMetaMap's guardf.reference == null || typeof f.reference === 'string'is there.gh-readonly-queue/main/pr-22818-*is gone.completedthroughFixes #22785.pm:dispatchedwas removed in this act, andbug,domain:engine,area:apiand the grade stay. The lane's closed set since 09:07Z is this card alone.@objectstack/coreminor, BREAKING narrowing;Clause-②: yes (narrowing)):referenceTargetOfwhich fields are references, so auserfield withoutreferenceresolves againstsys_user, as$expandreads it.reference_not_found, which isField.user's answer;Generated by Claude Code