Repository navigation
docs(comments): re-scope the #8959 CBP residue note to what #9138 actually closed - #14132
Conversation
…ually closed The paragraph at the `controlled_by_parent` stand-down site said the #8772 ramp had "two code legs and neither has landed yet". #9138 (Direction 2) merged on 2026-08-17, so that sentence is false. Correcting it rather than deleting it: #9138 narrows exactly ONE of the three residue shapes, and only on the builder path. The note now states, measured: - `master_detail` with no `required` is no longer newly authorable through `ObjectSchema.create()` (`forceCbpMasterDetailRequired` forces `required: true` and refuses an explicit `required: false`), but survives on the raw `.parse()`/`.safeParse()` path #9138 deliberately left untouched. - `required: true` + `readonly` and `required: true` + `system` are STILL newly authorable through `create()` itself -- the force returns early on `required === true` and never inspects `readonly`/`system`, and on an omitted `required` it mints those two shapes. - The lint leg (#9139) has not landed: still open, `pm:on-hold`, held for v18; predicate still `def.required !== true` at `severity: 'warning'`, so the two flagged shapes draw no finding at any severity. Comments only -- the non-comment diff is empty (TypeScript `removeComments` text + scanner token stream both identical), with a reverse control proving the comparator reports non-empty on a one-token code change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZC5rNQj3WEet5HAmmAkMs
📓 Docs Drift Check1 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 — 14 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 f617e60f0418fe7b3929a1266af8019763f94946 && git checkout f617e60f0418fe7b3929a1266af8019763f94946
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 9e1b2de73ef5d7ce5f3f665612a12731d3608725 1d1263f26ac406d8fe8dbacabebb560d852995a3 && git checkout -B drift-repro 9e1b2de73ef5d7ce5f3f665612a12731d3608725 && git merge --no-ff 1d1263f26ac406d8fe8dbacabebb560d852995a3
node scripts/docs-audit/affected-docs.mjs --json 9e1b2de73ef5d7ce5f3f665612a12731d3608725 |
Fixes #13722
Comments only, one paragraph, one file. Final commit
1d1263f26.The false sentence
packages/plugins/plugin-security/src/security-plugin.ts— the[#8959]paragraph at thecontrolled_by_parentstand-down site inassertControlledByParentWrite— said the #8772 ramp has "two code legs and neither has landed yet", and that #9138 "is dispatchable now but not yet merged".Located by symbol and text, never by line number: the card cites
:6351-6367, and after #14049 (09e4b0ece) landed upstream in the same file the paragraph is at:6484-6500. Anchored on the literal stringneither has landed yet.Falsified before rewriting — and the card's suggested rewrite did not survive intact
Read directly from the API rather than from the card's paraphrase:
2026-08-17, PR #9206pm:on-hold,target:v18The card then proposed re-scoping the residue claim "to the raw
.parse()path". Measured against today's code, that would have replaced one false sentence with another. It is true for one of the three residue shapes and false for the other two.forceCbpMasterDetailRequired(packages/spec/src/data/object.zod.ts) returns early onrequired === trueand never inspectsreadonly/system. So the two provenance-flagged shapes are still newly authorable throughObjectSchema.create()itself — not merely through raw parse. Measured by running the builtdistof@objectstack/specand@objectstack/lint:Every zero above is a reading, not an absence:
master-detail-requiredfinding, and in the same lint call two other rules do fire — so the linter is live on that object and the zero is about the predicate, which is stilldef.required !== trueatseverity: 'warning'.safeParserefuses an alias key, so M6/M7'ssuccess=trueis a decision and not a comparator that always says yes.sharingModel: 'private'are not forced and not refused, so the force is CBP-scoped rather than unconditional.M5 / M5b are the sharpest reading: the force mints the two flagged shapes. A
readonlyorsystemmaster reference authored withrequiredomitted comes out ofcreate()asrequired: trueplus the flag — which is exactly a shapevalidateRecordskips (if (def.system || def.readonly) continue;), leaving the security gate the sole refusal. That matchesomissionRefusedByValidation's own predicate,def?.type === 'master_detail' && !!def?.required && !def?.readonly && !def?.system.The rewritten paragraph states all of that, plus the parts of the old text that re-measured true (#8772 ruled; #9139 held for v18;
mainstill 17.x —packages/specis17.2.0).The non-comment diff is empty — with a live comparator
Both versions transpiled with
removeComments: trueand compared two independent ways (output text andts.createScannertoken stream), plus two controls:Exit code captured before any pipe:
node noncomment-diff.cjs ... ; echo "EXIT=$?"gave0. An earlier run exited 9 because control 2's anchor matched 0 times — reported as NOT RUN, not as a pass; the anchor was fixed and the control then actually ran.Gates
Re-derived from the actual diff with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no path arguments — the script took the change set from the merge base itself), both output sections read whole. 21 matched families plus 2 convention-triggered i18n families. All run at1d1263f26:check:comment-mask-adoption,check:doc-authoring,check:keyed-text-bounds,check:system-context-census(whose declared population is literally this file),check:tenant-audit-census,check:published-files,check:test-source-alias,check:type-source-resolution,check:nul-bytes, andcheck:i18n-stale-fill.pnpm check:i18nfirst exited 1 with its own verdict line readingPREREQUISITE NOT MET — the workspace CLI is not built/ "Nothing was checked". Not recorded as a red: the named build closure was run and the gate then passed, reportingplugins/plugin-security in sync (7 bundle(s))andOK (9 package(s)).check-test-completeness— grades a savedturbo run testlog; the gate's own text says to record the local reading as NOT MEASURED. CI supplies the log.check:dual-build-cjs-loads— needs a fullpnpm build; still reports missingdist/for ~73 packages after the i18n closure. CI runs it.Beyond the family:
pnpm lint(eslint . --no-inline-config) run repo-wide in the foreground, exit 0, 5623 files linted, 0 findings — and this PR's file is confirmed present in that population aterrors=0 warnings=0, so the zero is a measurement rather than a file eslint never opened.pnpm --filter @objectstack/plugin-security typecheckexit 0 (it runstsconfig.test.jsontoo).@objectstack/plugin-securityvitest: 94 files / 1764 tests passed.No changeset: comments-only, publishes nothing. Same disposition as #14049, the reference PR for this shape, which carried
skip-changesetfor a diff that included this same file.Out of scope, filed not fixed
#14130 — the adjacent
[#9137]freeze note citesrecord-validator.ts:993 / :1003for the provenance skip; both anchors have rotted (the guard is at:1037/:1047, and:993/:1003land on unrelated docblock prose while still being in range). Filed unassigned rather than folded in, because #13722's ruling fences this card to the one paragraph. Same class as #13556, different carrier.The repo-wide sweep of similar stale comments is not addressed here; that surface belongs to #14046, which stays open.
Generated by Claude Code