Uh oh!
There was an error while loading. Please reload this page.
Determine the #13419 name-folds are a fixture collision, and warn loudly on ungoverned same-name grants - #13724
Conversation
📓 Docs Drift CheckThis PR changes 1 package(s): 4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
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 5e864f73d5fa1dc5e47f14d856647c98dbf08cbb && git checkout 5e864f73d5fa1dc5e47f14d856647c98dbf08cbb
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin cc837dbfec53401c03b2d89071c8b4bee1e5ac97 f0408bad1c3c0e20a1d6d5e2e908d9b477fa7658 && git checkout -B drift-repro cc837dbfec53401c03b2d89071c8b4bee1e5ac97 && git merge --no-ff f0408bad1c3c0e20a1d6d5e2e908d9b477fa7658
node scripts/docs-audit/affected-docs.mjs --json cc837dbfec53401c03b2d89071c8b4bee1e5ac97
|
Uh oh!
There was an error while loading. Please reload this page.
Part of #13419 — slice 2 of the 2026-08-31 ruling: 执行要点 2's determination, and 执行要点 3's warning half.
⛔ Deliberately not a closing keyword. 执行要点 2's out-of-repo half and all of 要点 3's fold deletion are unstarted; merging this must close nothing.
Step 1 — the determination: the two name-folds are a fixture collision, not grants
Slice 1's census reports exactly two name-fold dependencies, both
cross_scope. Their position half is declared byexamples/app-crm/src/security/sales-positions.ts; their permission-set half comes from the vendoredpackages/metadata/src/__fixtures__/hotcrm-17.1-built-permissions.artifact.json.The determination is based on load paths, never on file location — "it lives under
__fixtures__/" is a hint, not evidence.packages/ examples/ apps/ scripts/ tools/ .github/for the basename, the repo-relative fixtures directory, and the glob shape (__fixtures__on the same line ashotcrmor.artifact): 4 references, 2 test + 2 declared instrument, 0 loaderpackages/metadata/src/plugin-artifact-forward-conversion.test.ts, classified TEST. A zero from a walk that visited nothing is refusedpackages/runtime/src/, confirmed on disk (210 bytes, 1 named reference). Gate exited 1 naming that file. Probe removed; gate back to 0loader; a bare glob sweep matches;__fixtures__andhotcrmon separate lines does notsales_rep/sales_manager; app-crm still declares positions of both names. Either moving reddens the gate rather than passing quietly⇒ Nothing composes that artifact into a deployment. The two "dependencies" are a collision between an example app's position names and a test fixture's permission-set names — not grants any deployment holds. Materialising junction rows for them would mint two authorizations nothing intends, which is the opposite of what the ruling protects. 执行要点 2's in-repo materialisation worklist is empty, and
scripts/check-position-name-fold-loaders.mjs(wired intolint.yml) keeps it empty on purpose: wire the artifact into a real composition and CI reddens, instead of two live grants appearing with nothing said.The measured / NOT MEASURED boundary
Measured: every in-repo load path for the vendored artifact, across the six scanned roots, for all three spellings a loader can use (literal path, directory, glob).
NOT MEASURED — unchanged from slice 1, and this slice adds nothing to either side:
Step 2 — 执行要点 3's warning half
A permission set granted only because a position of the same name resolved by name, with no junction row, now emits a
position_name_fold_grantwarning. 要点 5 names this as the permitted shape: 「任何行为差异只能表现为拒绝/告警,永不静默改变解析结果」.The predicate reports position
Pwhen a set namedPresolved,Pwas not already requested through the governed channel (junction row or direct assignment — both arrive as set names incontext.permissions), andPis not a baseline name in force regardless of the fold.sales_manageris junction-bound (tocrm_sales_user) and folds onto its own same-name set anyway; a predicate asking "is this position bound to anything?" would report neither real fold while looking complete.Both directions pinned, from the census's own classification
sales_rep,sales_manager.everyone → member_defaultincluded), and the 7 inert positions the census prints under a heading saying so —platform_admin,org_owner,org_admin,org_member,guest,finance,legal. Plusorg_adminagainst the real setorganization_admin(a near-miss, one underscore away), the baseline case, and the pair once 执行要点 2 materialises it.A false positive on a built-in identity is this slice's most expensive failure mode, so it is pinned rather than assumed. Three ablations, each direction predicted first, each mutation confirmed on disk and each restore proven byte-identical to the HEAD blob:
organization_adminnear-miss, and all 11 non-fold junction bindingsA fourth attempt silently missed its anchor; the disk-landing guard voided that reading rather than reporting a green from an unmutated tree.
⛔ Boundaries held
const requested = [...positions, ...explicitPermissionSets];(relocated tosecurity-plugin.ts:4687by this diff's own insertions; located by symbol, never by line number).resolve-authz-context.tsis not touched — 0 files in the diff.Verification
Union re-run at final head
f0408bad1, on the tree that ships.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(re-derived after the docs page entered the diff, which added 20 families the first derivation did not name). 77 green, 0 red, 2 NOT MEASURED.check-test-completeness(grades a saved turbo test log CI supplies).check:dual-build-cjs-loadsandcheck:i18nandcheck:type-check-debteach hit a build prerequisite first; all three were cleared by building the closure each names and then ran green.pnpm lint— full repoeslint . --no-inline-config, green. No narrowing claimed.@objectstack/plugin-security:typecheckgreen, and--listFilesconfirms both edited files are really in the tsc program (1 hit each) — the check is a measurement, not a vacuous green. Full suite 93 files / 1722 tests passed.check-system-context-census(pure anchor line rot from the insertion; repaired with its own documented--fix),check:doc-authoring(a tracker id in a runtime string — stripped to an adjacent comment, per the 2026-08-12 ruling), andcheck:engine-double-contract(a new pinned double — removed instead, the stub never neededfindOne, so no ledger row was added).REFUSE-WIDEverdicts are recorded with measured precision (packages 5562/5625, examples 240/243, apps 36/40, scripts 295/298 — the population is not a subset of each root, it is the root).Tier
Dispatched not clause ②, and the actual diff agrees: no path touches
packages/spec/src/**, no governed surface, and the content limb does not fire — no accept/reject result changes and no published symbol is added (the event constant is deliberately not exported).Changeset:
@objectstack/plugin-securitypatch — a new operator-visible warning. Thescripts/,.github/andcontent/docs/halves publish nothing from any package.Session: https://claude.ai/code/session_016ZC5rNQj3WEet5HAmmAkMs
Generated by Claude Code