Repository navigation
fix(lint)!: the object publish door refuses an object whose own list view sorts by a field the list door refuses (#30095) - #30564
Conversation
…#30095) validateSortableFields now declares `object` in its runtimeTypes, so an object whose built-in listViews.*.sort names a field the list door refuses (sortable: false, a formula, or a name the object does not have) is refused 422 INVALID_METADATA at publish instead of saving and failing every load. Claude-Session: https://claude.ai/code/session_01Utp6CXQyiKbpV3REQxogrr Co-authored-by: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01Utp6CXQyiKbpV3REQxogrr Co-authored-by: Claude <[email protected]>
📓 Docs Drift Check2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 4 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 528469b486d1eab995ff7bcb7830494fd9fe4cf7 && git checkout 528469b486d1eab995ff7bcb7830494fd9fe4cf7
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 38d416f1145c2dafbe39f00ecfcbc551dc438bbb 0e5a281c235dbae3c55dbd09b15f8ec394dffb71 && git checkout -B drift-repro 38d416f1145c2dafbe39f00ecfcbc551dc438bbb && git merge --no-ff 0e5a281c235dbae3c55dbd09b15f8ec394dffb71
node scripts/docs-audit/affected-docs.mjs --json 38d416f1145c2dafbe39f00ecfcbc551dc438bbb |
|
domain:server#3 · os-bill · session_01Utp6CbPxYq1wQmUNWvMZkC Contract reviewServed-tier: Face: narrowing ( ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment (narrowing face)The narrowing is judged against the published spec on Must-fix: none. Should-fix: S1 (docs row, separate card). Observations: ①.7 marker category. Implemented-by: VERDICT: PASS |
|
domain:server#3 · os-bill · session_01Utp6CbPxYq1wQmUNWvMZkC 维护者速读(席位终稿)
席位意见:同意落地。只让对象门补上其余三道门早已给出的结论,全仓实测零误伤。 席位核对ACCEPT · head
|
domain:server#3 · os-bill · session_01Utp6CXQyiKbpV3REQxogrr
Requested by Bill · project thread
Fixes #30095
Clause-②: no (narrowing) — an object write the door accepted before is refused: an object whose built-in
listViews.*.sortnames a field the list door answers400 INVALID_SORTnow saves422 INVALID_METADATA.Metadata-protocol: none
Skills-docs: none —
skills/**names nosortablefield key, andcontent/docs/deployment/validating-metadata.mdxlists the doors by rule family, not by reference-integrity member, so it names no object crossing to correct; the prescription ships in the refusal text.维护者速读
listViews.*.sort)如果按一个列表门会拒绝的字段排序(字段声明了sortable: false、是公式字段、或对象根本没有这个字段),对象发布门现在直接拒收,返回 422INVALID_METADATA,规则名sort-field-unsortable或sort-field-unknown,指到具体排序键路径,不存任何行。os validate会报错,视图门和页面门也会拒,唯独对象门不查:Studio 里存对象照样成功,那个列表视图每次打开都答400 INVALID_SORT。packages/lint/src/reference-integrity-suite.ts里validateSortableFields那一行(runtimeTypes加了object)和它上方的 lint: the object publish door does not run validateSortableFields, so an object whose listViews sort a sortable:false field saves #30095 注释;packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts末尾的 lint: the object publish door does not run validateSortableFields, so an object whose listViews sort a sortable:false field saves #30095 用例;packages/lint/src/runtime-gate.object-writes.test.ts的成员清单钉子。pnpm --filter @objectstack/metadata-protocol exec vitest run src/protocol.runtime-authoring-gate.test.ts -t 30095,预期 3 个全绿:sortable: false与不存在的字段各被 422 拒绝、没有存下任何行;对照组按可排序字段保存成功。What changes
validateSortableFieldsdeclaresobjectin itsruntimeTypes(packages/lint/src/reference-integrity-suite.ts). ThevalidateReferenceIntegrityentry already dispatches onobjectwrites ([P0] Studio package publish accepts a danglinghighlightFieldsreference — the authoring gate never sees what the app builder produces #15254); the member axis decides which members judge that snapshot, and this member was the one list-view sibling The object write door still runs no field-existence rule for searchableFields or listViews — the same asymmetry #15254 closed one key over #15495 held back for its own adjudication. Its first rung walksobjects[].listViews.*.sort, so the object publish door (PUT /api/v1/meta/object/NAME; Studio, REST, MCP) now gives an object's own list view sort the verdictsos validate, theviewdoor and thepagedoor already give it:sort-field-unsortable(sortable: false, a virtualformula) andsort-field-unknown, botherror, refused422 INVALID_METADATA, nothing stored.highlightFieldsreference — the authoring gate never sees what the app builder produces #15254 / [finding] Both field-resolution gates for a list view (searchableFieldsandsort) are CLI-only — the reference-integrity suite dispatches at the runtime publish gate forflowalone, so a Studio/MCPviewwrite gets neither #9313 terms). The member resolves only againststack.objects, the collection every per-write snapshot carries, so it has no missing-collection false-positive channel; itsviews[]andpages[]rungs find nothing on an object snapshot. The gate's differential ([runtime/metadata] 作者时规则只存在于 CLI:Studio/REST/MCP 的运行时授权面是第四扇门,26 条规则一条不跑——#4409 修完后最大的敞口 #4463 D4) still never charges a stored sibling's violation to this write.c045c341, through the door's own shape:runRuntimeAuthoringRules, typeobject, every other corpus object as context): 122*.object.tsfiles underpackages/andexamples/, 127 objects, 45 of them carrying 102 built-in list views with 113 sort keys — 0 findings, precision 1.0. The same sweep's synthetic probe (a list view sorting by asortable: falsefield) drewsort-field-unsortablefrom the rule and nothing from the door: the defect, measured. The member note carries the population.authoring-rules.tsis not touched: the entry already listsobject.Tests
packages/lint/src/runtime-gate.object-writes.test.ts: the member-surface pin now listsvalidateSortableFieldsamong the members that declareobject(it used to assert the opposite and say this is where the adjudication has to be made); three refusals through the door's gate (sortable: false,formula, an unknown name), each one error atobjects.leave_request.listViews.inbox.sort[0]; CONTROL: the same list view sorting by a field with nosortablekey and by asortable: truefield publishes with the suite run.packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts, new top-leveldescribe(lint: the object publish door does not run validateSortableFields, so an object whose listViews sort a sortable:false field saves #30095), through the realsaveMetaItemobject publish route:sortable: falserefused422/INVALID_METADATA, onesort-field-unsortableissue aterrorat the sort key path,rulesRunnamesvalidateReferenceIntegrity, no active row; an unknown name refused the same way assort-field-unknown; CONTROL: the same object sorting by a sortable field saves one row.Acceptance notes
Metadata-protocol: noneis the claim's line, copied. Reading for the seat: nothing an author may write changes, becauseos validate/os build/os lintalready refused this sort; only the runtime door's accept set narrows, which the(narrowing)arm and the BREAKING banner carry. fix(lint)!: refuse a stored page sort naming an unknown field, on every page sort slot (#30093) #30270 declarednarrowedbecause it moved the CLI verdict too.?mode=draft) are not judged, unchanged ([P2] 运行时授权门扩到 object 写入 + 全量 runtime-safe 规则快照(#4463 P1 之后) #4716 D1).Verification
All readings on head
0e5a281c(basec045c341, the #30270 merge).fa9c0aa2and again onc045c341): through the samesaveMetaItemharness, an object whose list view sorts by asortable: falsefield saved (success: true, one active row), and so did one sorting bygone_field;validateReferenceIntegrityon the same body reportedsort-field-unsortableaterror(objects[0].listViews.inbox.sort[0]). The read half (400 INVALID_SORTat the list door forsortable: false) is pinned bypackages/rest/src/data-sort-field-sortable-flag-door.test.ts(field.sortable: false has no effect — the sortability projection still reports the field sortable, the data door sorts by it, and the list header and Sort picker offer it #29896).pnpm --filter @objectstack/lint test: Test Files 195 passed (195), Tests 8086 passed (8086).pnpm --filter @objectstack/lint typecheck: exit 0.pnpm --filter @objectstack/metadata-protocol test: Test Files 316 passed, 4 skipped (320); Tests 22434 passed, 26 skipped.pnpm --filter @objectstack/metadata-protocol typecheck: exit 0.pnpm lint: exit 0.pnpm --filter @objectstack/spec check:liveness: exit 0.node scripts/pm/dispatch-gates.mjs --ran: 58 derived, 58 run, 0 NOT-MEASURED, every exit code 0 (four dist-reading gates,check:type-check-debtand the teardown self-test re-run after a fullturbo run build --filter='!@objectstack/docs'and a deepening fetch; their first run was exit 3, prerequisite not met, not red).pnpm --filter @objectstack/dogfood testunder the verify lock, after building its closure; the title carries!): Test Files 420 passed, 3 skipped (423); Tests 3496 passed, 36 skipped (3532). VERDICT command-exit 0.scripts/ablation-replace.mjsreplaced the member's'object'with a marker type (ablate30095) inreference-integrity-suite.ts;@objectstack/lintrebuilt;ablation-dist-preflight.mjsfound the marker in all 4 built entry files. Result:runtime-gate.object-writes.test.ts4 failed / 37 passed (the member-surface pin and the three refusals), the door suite-t 300952 failed / 1 passed (both refusals red, the object saved; the control green). Restored by the tool (blob equals HEAD,git diff HEADempty), lint rebuilt, preflight--absentclean on all 20 built files, working tree clean, door suite 3/3 green again.Gate record (58 derived)
Generated by Claude Code