Commit 841a71e
fix(plugin-approvals): resolve a reference field's target through
Fixes #19198
Clause-②: no
## The defect
`ApprovalService.resolveLookupFields` admitted `type: 'user'` fields but
resolved their target from the **materialized `reference` carrier**. The
spec declares the opposite for exactly that type —
`IMPLICIT_REFERENCE_TARGETS` in
`packages/spec/src/data/field-value.zod.ts`, re-read verbatim on
`origin/main` at `7d0f911da` before this branch was cut:
> `user` is the only member: `field.zod` defines it as "a lookup
specialized to the `sys_user` system object … target fixed to the
`sys_user` system object", and the `Field.user()` builder — unlike
`Field.lookup(reference, …)` / `Field.masterDetail(reference, …)` —
takes NO target argument and writes `reference: 'sys_user'` itself. The
target is a CONSTANT OF THE TYPE, so `reference` on a `user` field
materializes that constant; it does not supply it. Metadata authored
without it (hand-written JSON, an AI author, a Studio form) is fully
specified, not under-specified.
So the one spelling the contract calls **complete** was the one the
reader refused — and it refused it **silently**: no refusal, no
diagnostic, the field simply absent from `payload_display`, and a
business reviewer reading a raw user id where every other reference
field showed a name. `referenceTargetOf` lives in that same module
precisely to supply the constant (Framework#4443 / cloud#983 fixed the
identical blindness at the `$expand` gate and in the expansion engine).
## The repair
`resolveLookupFields` now asks `referenceTargetOf` — the spec's single
arbiter of what a reference field points at — instead of reading the
carrier.
- **Nothing else widens.** The admitted types are unchanged (`lookup`,
`master_detail`, `user`). A `lookup` / `master_detail` whose
author-chosen target is absent still names nothing, is still left out,
and still issues no read; `tree` is deliberately not added (see
acceptance notes).
- **The unreadable-carrier behaviour is unchanged.** `referenceTargetOf`
reads the carrier through `referenceCarrierOf`, so the `TypeError` is
still raised for an object- or array-valued `reference` and is still
caught **per field**, and the existing pins in
`src/lookup-field-reference-carrier.test.ts` pass untouched. The warning
line now names this reader in its own prefix, because the message the
arbiter throws names itself.
- **No authoring change.** Metadata that already spells `reference:
'sys_user'` resolves to the same target it always did. Making authors
restate the constant was rejected on the card as the 消费端宽容 direction the
charter rejects.
## Tests — silence is the defect, so both halves are pinned
New `src/implicit-reference-target-lookup.test.ts` (5 cases):
1. a `{ type: 'user' }` field with no `reference` resolves to
`sys_user`, **and** that value is asserted to equal `referenceTargetOf({
type: 'user' })` — so a hand-copied `sys_user` literal in this package
would not satisfy it;
2. implicit and materialized spellings answer **identically**;
3. an author-chosen target that names nothing is still left out, with no
warning;
4. **the consumer-level pin**: on an object whose ONLY reference field
is the implicit-target one, the enrichment now issues exactly one
`sys_user` read for the payload's id (`toHaveLength(1)`, ids `['u7']`)
and produces `payload_display = { assignee: 'Grace Hopper' }`. The read
is the half a happy-value assertion cannot see — before the repair that
read was never issued at all;
5. the opposite direction: a genuinely targetless `lookup` produces
**no** read against any referenced object and leaves `payload_display`
unset, so "the implicit target is enriched" cannot be read as
"everything is enriched now".
**Reverse verification (ablation), run from the committed state through
`scripts/ablation-replace.mjs`** — anchor hit 1 time, blob `703a308132`
→ `b1fa2e3f0300` on disk, mutation replacing the arbiter call with the
pre-repair carrier read:
```
Test Files 1 failed | 1 passed (2)
Tests 3 failed | 6 passed (9)
```
Cases 1, 2 and 4 go red (`expected undefined to deeply equal { key:
'owner', reference: 'sys_user' }`; `expected [] to have a length of 1
but got +0`); cases 3 and 5 stay green because they are the controls,
and the whole sibling carrier suite stays green — the mutation is
narrow. Restored and proven restored: blob back to `703a308132`,
identical to HEAD, `git diff HEAD` empty.
## Gates
Everything below was captured with the exit code read **before** any
pipe, at `aef74f0fa`.
- `pnpm --filter @objectstack/plugin-approvals test` — exit 0, **49
files / 780 tests passed**.
- `pnpm --filter @objectstack/plugin-approvals typecheck` — exit 0, all
three legs this package's script names (`tsc --noEmit`, `tsc --noEmit -p
tsconfig.scripts.json`, `check:test-typecheck`). The test-layer ledger
is unmoved: `8 file(s) / 324 error(s) / 27 pinned signature(s)` — the
new test file adds none and takes no entry.
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--commands` derived **61 families**; all 61 were run and reconciled with
`--ran`: *"61 derived famil(ies) accounted for — 61 run, 0 NOT-MEASURED
(a DERIVED zero — all 61 recorded an exit code and none of them is 3)."*
- Six of those first answered **exit 3 = PREREQUISITE NOT MET = NOT
MEASURED** (`check:dts-closure`, `check:dual-build-cjs-loads`,
`check:i18n`, `check:lean-entry-closure`,
`check:sourcemap-no-sources-content`, `check:type-check-debt`). Each
prerequisite was cleared — the dependency closure, then `turbo run
build` over all packages — and each re-run to **exit 0**. None is
reported as a zero.
- `pnpm lint` (`eslint . --no-inline-config`, the repo's only style
authority) — exit 0 over the whole tree, so no narrowing is being
claimed.
- `grep os-regen .gitattributes` read on the spot: no path in this diff
is merge-driver managed.
## Acceptance notes
Noted, not filed — each states who would meet it:
- **`tree` is a reference type this enrichment still does not admit.**
`REFERENCE_VALUE_TYPES` has four members; `resolveLookupFields` carries
three, and `plugin-audit` deliberately carries the same three
(`audit-writers.ts`: *"`tree` is NOT on the list: it carries no
`reference`"*). Admitting it would widen what the inbox resolves rather
than repair what it silently dropped, which is not this card. Successor:
whoever next touches the shared three-type vocabulary in either package.
- **The warning text moved.** The reader's name is now in the approvals
prefix rather than inherited from the arbiter's message, because
`referenceTargetOf` takes no reader label. The existing assertion on it
still passes unchanged.
Reported to the dispatching seat rather than filed here (dev agents
report findings with dedupe words; they do not file): one class-(b)
sibling of this defect in `plugin-audit`, and a reading that partly
falsifies this card's own unverified note about the analytics resolver.
## Not this PR
`packages/spec` is read-only on this lane — `referenceTargetOf` and
`IMPLICIT_REFERENCE_TARGETS` are imported and nothing in them is edited.
No release-notes page is touched.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01AhQASwqJr2Z7XfGWUdvnbF)_
---------
Co-authored-by: Claude <noreply@anthropic.com>referenceTargetOf (#19263)1 parent fb33767 commit 841a71e
3 files changed
Lines changed: 238 additions & 24 deletions
File tree
- .changeset
- packages/plugins/plugin-approvals/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
Lines changed: 48 additions & 24 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
59 | | - | |
| 59 | + | |
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
| |||
5762 | 5762 | | |
5763 | 5763 | | |
5764 | 5764 | | |
5765 | | - | |
| 5765 | + | |
| 5766 | + | |
| 5767 | + | |
| 5768 | + | |
| 5769 | + | |
| 5770 | + | |
| 5771 | + | |
| 5772 | + | |
| 5773 | + | |
| 5774 | + | |
| 5775 | + | |
| 5776 | + | |
| 5777 | + | |
| 5778 | + | |
| 5779 | + | |
| 5780 | + | |
| 5781 | + | |
| 5782 | + | |
| 5783 | + | |
| 5784 | + | |
| 5785 | + | |
| 5786 | + | |
| 5787 | + | |
| 5788 | + | |
| 5789 | + | |
| 5790 | + | |
| 5791 | + | |
| 5792 | + | |
| 5793 | + | |
| 5794 | + | |
| 5795 | + | |
| 5796 | + | |
| 5797 | + | |
| 5798 | + | |
| 5799 | + | |
| 5800 | + | |
| 5801 | + | |
| 5802 | + | |
| 5803 | + | |
| 5804 | + | |
| 5805 | + | |
| 5806 | + | |
| 5807 | + | |
| 5808 | + | |
5766 | 5809 | | |
5767 | 5810 | | |
5768 | 5811 | | |
5769 | 5812 | | |
5770 | 5813 | | |
5771 | 5814 | | |
5772 | 5815 | | |
5773 | | - | |
5774 | | - | |
5775 | | - | |
5776 | | - | |
5777 | | - | |
5778 | | - | |
5779 | | - | |
5780 | | - | |
5781 | | - | |
5782 | | - | |
5783 | | - | |
5784 | | - | |
5785 | | - | |
5786 | | - | |
5787 | | - | |
5788 | | - | |
5789 | | - | |
5790 | | - | |
5791 | | - | |
5792 | 5816 | | |
5793 | 5817 | | |
5794 | | - | |
| 5818 | + | |
5795 | 5819 | | |
5796 | 5820 | | |
5797 | | - | |
5798 | | - | |
| 5821 | + | |
| 5822 | + | |
5799 | 5823 | | |
5800 | 5824 | | |
5801 | 5825 | | |
| |||
Lines changed: 178 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
0 commit comments