Repository navigation
feat(spec): ObjectSchema.attachedOnRead declares per-caller read attachments, and the shared validator judges record.BLOCK.LEAF against them - #22425
Conversation
…chments Claude-Session: https://claude.ai/code/session_01DhTqaEHqPVSVnAkjG3jywn Co-authored-by: Claude <noreply@anthropic.com>
…; pins + ledger row Claude-Session: https://claude.ai/code/session_01DhTqaEHqPVSVnAkjG3jywn Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhTqaEHqPVSVnAkjG3jywn Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhTqaEHqPVSVnAkjG3jywn Co-authored-by: Claude <noreply@anthropic.com>
…ed-world pins; type the unknown-field leaf params Seat order 6074312931 widens the surface by the five measured files: the ADR-0106 FLS position row, the object form ledger's root omit row, the two composeStacks collection-list pins, and the unknown-field block/leaves params with their codes pin. Formula changeset to minor; the liveness note names the declaring package's conformance test as the leaf types' reader. Claude-Session: https://claude.ai/code/session_01DhTqaEHqPVSVnAkjG3jywn Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 4 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 140 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 ffbbac7facbdd55f961e89d7f9811a1b5d8459bc && git checkout ffbbac7facbdd55f961e89d7f9811a1b5d8459bc
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2b61f2d9d6f8f7cc7f6b9f5f9772b8bc8fb0ea5d a5104d85433bdf7511d561694ebb0910750c488d && git checkout -B drift-repro 2b61f2d9d6f8f7cc7f6b9f5f9772b8bc8fb0ea5d && git merge --no-ff a5104d85433bdf7511d561694ebb0910750c488d
node scripts/docs-audit/affected-docs.mjs --json 2b61f2d9d6f8f7cc7f6b9f5f9772b8bc8fb0ea5d
|
Contract reviewServed-tier: Reviewer seat One line: FAIL on this head. The required ① Derived judgmentsAccept-set changes in
Public-surface changes in the three other packages:
Reach of reader 1, measured at the head — right for the card's surface, and short of the text's claim in two places: the field-existence set is The gate verdict this record turns on. ② Semver levelPackages whose published files move:
Clause-②: ③ Boundary flagsRound-1
Round-2 Dev flags (PR body and report
Reviewer's flags:
Check-runs on the head at this reading:
Remedy, one round: (1) Implemented-by: VERDICT: FAIL |
…in; name the build validator as the reader The served object schema gains attachedOnRead, so CARD_PROPERTY_COUNTS.object moves 44 to 45 with the docblock sentence its precedents carry. The describe text, docblock, ledger note and changesets now name the shared build validator (lint over formula) as the reader, and record that the injected-column collision is out of reach of object.zod.ts. Claude-Session: https://claude.ai/code/session_01DhTqaEHqPVSVnAkjG3jywn Co-authored-by: Claude <noreply@anthropic.com>
…d describe Claude-Session: https://claude.ai/code/session_01DhTqaEHqPVSVnAkjG3jywn Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Reviewer seat One line: PASS on this head. The sixth closed-world pin is visited, the reader wording is narrowed to the one door delivered, every check-run on the head is completed and none is red, and an independent inventory finds no seventh pin. One landing precondition, not a contract defect: ① Derived judgmentsThis head differs from Judged new on this head:
Reach of reader 1. Unchanged from the FAIL record: lint's ② Semver levelPackages whose published files move:
Clause-②: ③ Boundary flagsThe seat order Round-1 Dev flags (PR body and reports
Reviewer's flags:
Check-runs on the head at this reading — 42, every one
Implemented-by: VERDICT: PASS |
…tached-on-read # Conflicts: # packages/lint/src/validate-expressions.test.ts
… validator as its reader Claude-Session: https://claude.ai/code/session_01DhTqaEHqPVSVnAkjG3jywn Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Reviewer seat One line: PASS on the contract. This head is the PASS head ① Derived judgmentsThe PR's own delta, before and after the merge round — unchanged apart from F4. Right. The added and removed lines of the diff against the merge base, over the 22 PR files, are 764 at The one conflict, the #5017 Coexistence in F4. Right. A test-only string in The merged tree's generated artifacts. Right.
The gate verdicts this record reads. ② Semver levelUnchanged from the PASS head: the two changesets are byte-identical at
Clause-②: ③ Boundary flagsDev flags this round (report
Earlier flags, each re-read on this head: F1 carried (the MCP expression tool and the automation flow-registration resolver build Reviewer's flags:
Check-runs on the head at this reading — 42, every one
Implemented-by: VERDICT: PASS |
Contract reviewServed-tier: Reviewer seat One line: PASS on this head. It is the PASS head ① Derived judgmentsThe PR's own delta, before and after the merge round — unchanged. Right. The diff from the merge base over the PR's files is 22 files, +753 / −11, at Coexistence with #22315 in The merged tree's generated artifacts. Right. The gate verdicts this record reads. ② Semver levelUnchanged from the two PASS heads: the two changesets are inside the unchanged delta and byte-identical. Packages whose published files move:
Clause-②: ③ Boundary flagsDev flags this round (report
Earlier flags, each re-read on this head: F1 carried (the MCP expression tool and the automation flow-registration resolver build Reviewer's flags:
Check-runs on the head at this reading — 42, every one
Implemented-by: VERDICT: PASS |
Fixes #22386
Clause-②: yes (widening: a new optional
ObjectSchemakey)The spec half of #22211's ruling A (
6070963704), built under the claim6073245703as amended by the seat order6074312931. #22387 follows: the plugin-approvals declaration ofvieweronsys_approval_requestand its conformance test. That card is blocked on this PR, and it is the one that finishes #22211; this PR leaves #22211 open, and its 8 shippedrecord.viewer.*predicates stay refused until #22387 declares the block.What changes
ObjectSchema.attachedOnRead(packages/spec/src/data/object.zod.ts, besidefields). An optional map from block name to that block's leaves, each naming its value type:attachedOnRead: { viewer: { can_act: 'boolean', can_override: 'boolean', is_submitter: 'boolean' } }. These are the blocks a service attaches to each row it serves, computed per caller and never stored.number | text | boolean | date, taken fromFieldType(the fourField.returnTypevalue types).superRefine, so no new check node reaches the JSON Schema projection.git grep -c attachedOnReadat the head finds it only inpackages/spec(the schema, its pins, the ledger row, the generated surface),packages/lint/src/validate-expressions*.ts,packages/formula/src/{validate,expression-refusal}*.ts,packages/metadata-core/src/object-schema-fls-references.ts(classifiedkeep), the generated reference docs and the changesets.@objectstack/lintbuildFieldIndexadds each declared block name to the field-existence set, and both call sites that pass the field index hand the shared validator the block's leaves.@objectstack/formulacheckFieldExistencejudges the SECOND segment ofrecord.BLOCK.LEAF(andprevious.) against the declared leaves, through the new optionalExprSchemaHint.attachedOnRead, under the EXISTINGunknown-fieldcode. No new rule id, no new refusal code, nothing keyed onviewer.fieldis the dotted path as written,suggestionthe nearest declared leaf, and the new optionalblock+leavesparams carry the declared leaves, present together exactly when the message names them:unknown field `viewer.can_actt` on `approval` (the read attachment `viewer` declares `can_act`, `is_submitter`) — did you mean `viewer.can_act`?RECORD_REF_REis untouched (the second segment is read by a separate sticky regex), and the judgement runs only for a declared block, so an object without the key takes exactly today's path.sys_approval_requestdeclares its per-callerviewerblock underattachedOnRead, with a conformance test againstattachViewers(#22211 ruling A, plugin-approvals half) #22387's conformance test, which pins the keysattachViewersemits and the runtime type of each value against the declaration (seat order6074312931, recorded on plugin-approvals:sys_approval_requestdeclares its per-callerviewerblock underattachedOnRead, with a conformance test againstattachViewers(#22211 ruling A, plugin-approvals half) #22387 as6074324160). The liveness row says so.6074312931, Q1): the ADR-0106 D1 FLS positionattachedOnRead: keep; the object form ledger's rootomitrow (the ruling says no form reads it); the composeStacks collection lists in the two pins, plus one row pinning that two stacks declaring differentattachedOnReadfor one object are refused underobjectConflict: 'merge'. Nostack.zod.tschange: the composition derives the set from the shape walk.liveness/object.jsongrades the keyliveon an authoring consumer (theaction.executionprecedent), withproducer,evidenceScopeandverifiedAt. Generated by the repo's generators only:authorable-surface/data.json(build),liveness/state-counts/object.md(gen:liveness-counts),content/docs/references/**(gen:docs).@objectstack/specminor (carries the Clause-② line);@objectstack/formulaminor (additive public members);@objectstack/lintand@objectstack/metadata-corepatch.Merge round at
a5104d854After the contract review at
e19c1e349(PASS6077844912;Test Core (6/6)was red only on #22415's timing-drift grade, whichmainreverted in #22435),origin/mainwas merged twice throughos-regen-merge.sh, never rebased, with no conflict:da159f74e, brought the revert;2b61f2d9d, brought feat(spec)!: flow text slots read the {{ }} delimiter, refusing a single-brace token with its hole spelling (#22110) #22315, this card's named serial predecessor onvalidate-expressions.ts.The PR's delta is unchanged:
git diff origin/main...HEADis 22 files, +753 / −11, line for line.Measured at
a5104d854, afterpnpm install --frozen-lockfileand a full build (73 / 73):Merge round at
e19c1e349After the contract review PASS
6076679507ata0545b853,origin/main05c7c3fa3was merged throughos-regen-merge.sh, never rebased.??别名读法(#5009 建议 3 的核对结果) #5017PLUMBINGhunk invalidate-expressions.test.ts. Both sides are kept: lint/objectql: a select option'svisibleWhenreadingcurrent_user.roles(gone since ADR-0090 D3) or a computed key passes both doors and faults open at the server — the EvalUser-member level of the #22157 / #22274 family #22394's five names, thenattachedOnReadIndex.validate-expressions.tsauto-merged.whynow names the shared build validator.e19c1e349:visibleWhenreadingcurrent_user.roles(gone since ADR-0090 D3) or a computed key passes both doors and faults open at the server — the EvalUser-member level of the #22157 / #22274 family #22394's 13 included);metadata-protocolandmetadata-coreare as below; the merge did not touch them.Measured at
a0545b853The patch round after the contract review
6075426209(FAIL on the sixth closed-world pin) mergedmainat3054516efcleanly throughos-regen-merge.sh. All runs went throughos-verify-lock(eachVERDICT command-exit 0; shared-box seconds), after themetadata-protocol,lintandmetadata-coreclosures were built:@objectstack/metadata-protocolprotocol.meta-types-degenerate-derivation.test.tspasses.@objectstack/specunit (--project local)@objectstack/lint@objectstack/formula@objectstack/metadata-coreTypecheck exits 0 for
metadata-protocolandspecata0545b853.lint,formulaandmetadata-coreexited 0 at4ba858882, and their sources are unchanged since.Gates.
dispatch-gates --commandsata0545b853derived 111 commands: the previous 110 pluscheck:durability-log-level. All 111 exited 0 on the first pass, after a fullturbo run build.--ranreconciles 111 derived, 111 run, 0 NOT-MEASURED, 0 UNRUN.The closed-world inventory of
ObjectSchema's top-level keys, searched before the push. Every list or count found is visited:metadata-coreOBJECT_REFERENCE_POSITIONS;composeStackspins;metadata-protocolCARD_PROPERTY_COUNTS.object(44 → 45, this round);validate-expressions.test.ts's validate-expressions / validate-security-posture 也有同形的 spec 不声明键的??别名读法(#5009 建议 3 的核对结果) #5017 read surfaces;Derived sets needed no edit: the
composeStacksshape walk,ObjectSchema.create()'s known keys, and the object form, where the key is an omit row.Ablation: the misspelt-leaf pin bites.
node scripts/ablation-replace.mjsonpackages/formula/src/validate.ts, anchorif (leaves.includes(leaf)) return;replaced byreturn;plus a marker:f7e24675toac2f0590;validate-attached-on-read.test.ts: 3 failed, 6 passed. The misspelt-leaf, no-near-leaf andprevious-root pins went red; the accept and control pins stayed green, which is the expected direction;f7e24675,git diff HEADempty, marker count 0; the restored run passed 9/9.The ablation ran at
37711ce70. The file's blob at4ba858882is the samef7e24675. Formula's tests import./validatefrom source, so the ablation has no dist leg.Acceptance notes
sys_approval_requestdeclares its per-callerviewerblock underattachedOnRead, with a conformance test againstattachViewers(#22211 ruling A, plugin-approvals half) #22387 (contract review6075426209, F1).packages/mcp's expression tool andservice-automation's flow-registration resolver build their ownrecord.*field sets fromfields. The wording here names only the shared build validator. plugin-approvals:sys_approval_requestdeclares its per-callerviewerblock underattachedOnRead, with a conformance test againstattachViewers(#22211 ruling A, plugin-approvals half) #22387 threads the key into both, or shows that they are unreachable (6075461181).object.zod.tscannot reach those names:resolveInjectedSystemColumnsimports from./object.zod, which would make a cycle, and its column constants are module-private. Widening the refusal needs those constants exported belowobject.zod.ts. Carrier: none; the docblock records it.ObjectExtensionSchemacannot carry the key (F3). That is consistent with an in-code declaration beside the service that attaches the block.sys_approval_requestdeclares its per-callerviewerblock underattachedOnRead, with a conformance test againstattachViewers(#22211 ruling A, plugin-approvals half) #22387 (noted, not filed). This is the boundary of the ruling's literal "field-existence set". A declared block resolves at every surface the lint field index serves on that object: validation rules, hooks, field formulas, flow conditions. Yet only rows the declaring service serves carry the block. No producer writes such a predicate today, so this reaches nothing and is not a card. The field-formula pin in this PR covers the refusal half only.validate-predicate-path-refs.ts:55–:63(Publish-time validation of predicate path references — a spec-delivered predicate naming a nonexistent path should fail at authoring, not evaluate to a guess at render (#6936 companion) #7010) scopes itself to thedata.*layer and leavesrecord.*to the sibling rules. Judging there would be a new rule id, so the judgement lives in formula'scheckFieldExistence, the existingunknown-fieldsite.attachedOnRead.attachViewers/attachDecisionProgress/attachFlowSteps), and "OnRead" follows the spec'senforceOnRead.readAttachmentswould read as file attachments, and "virtual" or "computed" would read as fields.record.viewer['x']), a method call on a block, and a third segment are not judged. Each is a missed catch, never a false refusal.origin/mainwas merged twice throughscripts/pm/os-regen-merge.sh, never rebased. fix(lint)!: os build and the object save door refuse a select option's visibleWhen that reads an unbound ctx/os member (#22274) #22392 (lint: a select option'svisibleWhenreading a member the option check never binds (os.org.id,os.env,ctx.locale) passesos buildand the save door, and the server's option gate then faults open #22274) landed onvalidate-expressions.tsin between; its three symbols are verified present at the head.Generated by Claude Code