Repository navigation
Commit 11137d4
fix(lint): the dataset save door's object-reference-unknown hint names the dependency declaration under a package closure (#27937)
<!-- claude-projects-attribution: {"github_login":"marchtian"} -->
_Requested by **田騏** · [project
thread](https://claude.ai/code/project/chan_01VmuUhXU9SSUzqJYyXSmYSi?thread=cmsg_01VmuUhXU9SSUzqJYyXSmYSiEosMC3zDfHaauURHFNq1GJ)_
Fixes #27827
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:运行时保存门在软件包闭包下拒收一个
dataset(其基础对象不在闭包内)时,`object-reference-unknown` 的修复提示改为"在 manifest 的
`dependencies` 里声明对定义该对象的软件包的依赖";三扇门(flow 触发、列表视图、dataset)共用同一个提示构造函数。
- **为什么改**:原提示叫作者"指向本 stack 的对象",把人和 AI 都引离真正有效的修法(ADR-0141
D1:声明依赖);另两扇门早已给出声明依赖的处方,dataset 门是唯一的例外。
- **风险与回滚**:只动提示文字,判定、严重级别、message 都不变;无闭包(CLI、未指明软件包的写入)时提示与今天逐字相同。flow
门的提示措辞随共用形式微调(引号与语序),回滚即 revert 本 PR。
-
**先看**:`packages/lint/src/object-graph.ts`(`closureDependencyRemedy`)、`packages/lint/src/validate-object-references.ts`(闭包分支)、`packages/lint/src/reference-integrity-suite.ts`(把
`packageScope` 交给该规则)。
- **两分钟验证**:`pnpm --filter @objectstack/lint exec vitest run
src/runtime-gate.dataset-writes.test.ts
src/runtime-gate.package-closure.test.ts`,预期全绿,其中 #27827 两个 describe
块覆盖有闭包/无闭包两向。
- **需要你做的**:无,席位落地。
## What changes
At the runtime save door a dataset written into a package is judged
against that package's closure (`narrowObjectsToPackageClosure`). A base
object outside it lands on rung ② of `validateObjectReferences` and is
refused `422` with `object-reference-unknown`. Under a closure the fix
line now names the manifest `dependencies` declaration, the prescription
the flow trigger and list view doors print for the same closure.
- **The fact, handed over the same way.** `validateObjectReferences`
takes `options.packageScope`, the shape `validateFlowTriggerReadiness`
and `validateListViewFieldRefs` take. Its reference-integrity member
passes `ctx.packageScope` through, as `validateListViewFieldRefs`'
member does. The gate states `packageScope` only when it narrowed the
snapshot (`packageScopeInForce`), so the rule is never told "closure"
about an unnarrowed snapshot.
- **One shared prescription, not a third copy.**
`closureDependencyRemedy(object, packageId, alternative)` sits in
`object-graph.ts`, the module all three doors already import
(`suggestName` lives there). The flow door
(`flow-trigger-unknown-object`), the list view door
(`list-view-object-outside-closure`) and the dataset door
(`object-reference-unknown`) build their line from it; each passes its
own second remedy.
- **Only the hint moves.** The ladder, severity, message and
`where`/`path` are identical with and without a closure. A site's own
sharper remedy (the view container's namespace prescription) still wins,
and the platform rung ④ is untouched (narrowing keeps platform objects,
so a prefixed miss is never a closure case).
- **`os explain object-reference-unknown`** gains a paragraph for the
closure case, so it no longer contradicts the new fix line.
### The hint, before and after
| Door | Before | After |
|:--|:--|:--|
| dataset base object, closure in force | `Point it at one of this
stack's objects, or at a platform object by its full name (the platform
user object is "sys_user", not "user")` | `` Declare a dependency on the
package that defines "OBJECT" in the `dependencies` of "PACKAGE"'s
manifest, or point it at an object inside that closure `` |
| dataset base object, no closure (CLI, unpackaged write) | the `Point
it at …` line | unchanged |
| flow trigger (both positions) | `` Declare a dependency on the package
that defines 'OBJECT' in the manifest `dependencies` of package
'PACKAGE', or set KEY to an object inside that closure `` | `` Declare a
dependency on the package that defines "OBJECT" in the `dependencies` of
"PACKAGE"'s manifest, or set KEY to an object inside that closure `` |
| list view | `` Declare a dependency on the package that defines
"OBJECT" in the `dependencies` of "PACKAGE"'s manifest, or bind the view
to an object inside that closure `` | unchanged |
The shared form is the list view door's wording, because the runtime
package-dependency door comments and ADR-0141 already quote it ("declare
a dependency … in the `dependencies` of P's manifest"). Unifying changes
the flow door's printed words: double quotes in place of single, and
"PACKAGE's manifest" in place of "the manifest `dependencies` of package
'PACKAGE'". No pin asserted the flow door's exact sentence. Its pins
(the hint contains the package id, `dependencies` and the re-pointed
key) hold as written, and the new shared-prescription pin asserts its
full new text.
## Tests
- `runtime-gate.dataset-writes.test.ts`, new block "the base-object fix
line names the dependency declaration under a package closure (#27827)".
Through the real door, both directions:
- closure in force: the full new hint for an undeclared package's
object, and the same fix for a name that exists nowhere.
- the own package and a declared dependency are admitted.
- no closure: the stranger's object resolves, and a ghost gets today's
hint byte for byte. An empty package id states no closure. The direct
`validateObjectReferences` call (the CLI reading) gives the same rule,
severity, message and today's hint.
- the verdict is identical both ways; only the hint differs.
- `runtime-gate.package-closure.test.ts`, new block: the dataset door
under the shared `packagedTenant` closure. It also pins that the three
doors print one prescription: the same declaration clause, each with its
own alternative, asserted in full.
- `validate-object-references.test.ts`: the unit-level pins. These cover
the closure hint, the unchanged verdict, a site's sharper remedy winning
under a closure, and an untouched platform rung. The one-line-fix
coverage control now also requires the closure line to have fired (at
most 200 chars). The `os explain` pin requires the closure paragraph.
- **Pin flipped:** `reference-integrity-suite.test.ts` "wires the same
function the package exports" asserted `run ===
validateObjectReferences` by identity. The member is now an adapter that
hands over `ctx.packageScope`, so the pin asserts what the member
answers instead: the exported function's answer without a closure and
with the context's closure, on a stack that carries a real miss, and the
two answers differ.
<details><summary>Local runs (head 45b851c)</summary>
- `pnpm --filter @objectstack/lint test`: Test Files 178 passed (178),
Tests 7639 passed, 5 skipped (7644). Lock VERDICT command-exit 0.
- `pnpm --filter @objectstack/lint typecheck`: exit 0
(`check:test-typecheck: OK`).
- Targeted run, the 7 touched suites: Test Files 7 passed, Tests 428
passed.
</details>
<details><summary>Ablation (one, on the tested behaviour)</summary>
The closure branch was disabled through `scripts/ablation-replace.mjs`
on the committed head, with anchor `(closure` replaced by `(false &&
closure` in `validate-object-references.ts` (anchor 1 → 0, blob
`38f25ec47981` → `f71aad39f462`). The four suites that pin it ran under
that mutation: Test Files 4 failed (4), Tests 8 failed / 130 passed.
Every #27827 closure-direction pin went red, plus the flipped member pin
and the one-line coverage control. The no-closure pins stayed green, as
they should, since they assert today's hint. The mutation was restored:
blob after restore `38f25ec47981` == HEAD, `git diff HEAD` empty. The
tests import `src/` directly, so no `dist/` leg applies.
</details>
## Acceptance notes
- **Not changed, on purpose:** the verdict sentence ("resolves to no
object defined in this stack. The reference is inert at runtime —
nothing reports the miss.") still reads stack-relative under a closure,
while the flow and view doors' messages name the closure. The order
fixed severity and verdict as out of scope; this is noted only.
- **Related observation, from the card, not this PR's scope:** an
`object` write's field lookup to a name that exists nowhere is judged by
no door (`validateObjectReferences` is not dispatched on an `object`
write). This belongs with the #25805 reopen.
## Verification
Independent review: none run (quota); the seat records the contract
review.
Gates: the derived local family list (`dispatch-gates.mjs --commands`)
was run on the final diff, with each exit code recorded before any pipe
and `--ran` reconciled; the readings are in the os-dev-report on the
card. CI runs the full farm.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
Co-authored-by: Claude <noreply@anthropic.com>1 parent 9900366 commit 11137d4
11 files changed
Lines changed: 319 additions & 16 deletions
File tree
- .changeset
- packages/lint/src
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
612 | 612 | | |
613 | 613 | | |
614 | 614 | | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
615 | 638 | | |
616 | 639 | | |
617 | 640 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
97 | 97 | | |
98 | 98 | | |
99 | 99 | | |
100 | | - | |
101 | 100 | | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
102 | 115 | | |
103 | 116 | | |
104 | 117 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
224 | 224 | | |
225 | 225 | | |
226 | 226 | | |
227 | | - | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
228 | 241 | | |
229 | 242 | | |
230 | 243 | | |
| |||
310 | 323 | | |
311 | 324 | | |
312 | 325 | | |
313 | | - | |
| 326 | + | |
| 327 | + | |
314 | 328 | | |
315 | 329 | | |
316 | 330 | | |
| |||
769 | 783 | | |
770 | 784 | | |
771 | 785 | | |
772 | | - | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
773 | 789 | | |
774 | 790 | | |
775 | 791 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3961 | 3961 | | |
3962 | 3962 | | |
3963 | 3963 | | |
| 3964 | + | |
| 3965 | + | |
| 3966 | + | |
| 3967 | + | |
| 3968 | + | |
| 3969 | + | |
| 3970 | + | |
| 3971 | + | |
| 3972 | + | |
| 3973 | + | |
| 3974 | + | |
3964 | 3975 | | |
3965 | 3976 | | |
3966 | 3977 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
41 | 42 | | |
42 | 43 | | |
43 | 44 | | |
| |||
242 | 243 | | |
243 | 244 | | |
244 | 245 | | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
245 | 335 | | |
246 | 336 | | |
247 | 337 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
582 | 582 | | |
583 | 583 | | |
584 | 584 | | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
177 | 177 | | |
178 | 178 | | |
179 | 179 | | |
180 | | - | |
| 180 | + | |
181 | 181 | | |
182 | 182 | | |
183 | 183 | | |
| |||
496 | 496 | | |
497 | 497 | | |
498 | 498 | | |
499 | | - | |
500 | | - | |
501 | | - | |
| 499 | + | |
| 500 | + | |
502 | 501 | | |
503 | 502 | | |
504 | 503 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
398 | 398 | | |
399 | 399 | | |
400 | 400 | | |
| 401 | + | |
401 | 402 | | |
402 | 403 | | |
403 | 404 | | |
| |||
990 | 991 | | |
991 | 992 | | |
992 | 993 | | |
993 | | - | |
994 | | - | |
995 | | - | |
| 994 | + | |
| 995 | + | |
996 | 996 | | |
997 | 997 | | |
998 | 998 | | |
| |||
0 commit comments