docs(permissions): compile the permissions README's 7 blocks and drop its ledger entry - #8025
Merged
Merged
Conversation
… its ledger entry `packages/permissions/README.md` leaves `UNGATED_DOCS` in `scripts/check-doc-snippet-types.mjs` and all 7 of its ts/tsx blocks now compile against the built types. The gate file's only change is the two lines of that one entry — removals only, inside the object literal. All 18 measured diagnostics were semantic (zero parse, zero bound). Seven of them were real drift between the page and the SHIPPED dist types of the same package rather than fragment shape: `PermissionProvider` taught `roles` as bare strings, `permissions` as an object map and omitted the required `userRoles`; `PermissionGuard` taught a `resource` prop and a JSX-valued `fallback`; `usePermissions().can` was documented with the action first and the object second; `useFieldPermissions` was called with two arguments and destructured for `isVisible` / `isEditable`; `evaluatePermission` was given `resource` with no `object`, `userRoles` or `user`; `createPermissionStore().check` was documented action-first and annotated as returning a boolean. Each is corrected in the README to the package's own dist type, per the card's standing ruling. The remaining blocks gained real self-imports and `declare const` placeholders typed to the shipped surface, with bare JSX bound to a name and not re-indented. No `packages/**` source touched, no public type widened, no lenient alias added, no gate loosened, and no new fragment marker: declared fragments stay at 158. Part of objectui#5174 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Batch 19 (PR #8017, packages/collaboration/README.md) and objectui#7692 (PR #8016) landed while this batch was measuring. The two UNGATED_DOCS removals are different lines of the same object literal, so the merge is clean; every gate, test, probe and reading is re-run on the merged head. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contributor
|
Standing-down note — Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #5174 — batch 20 of the
UNGATED_DOCSburn-down.packages/permissions/README.mdleaves the ledger and all 7 of its ts/tsxblocks now compile against the built types. The gate file's only change is the
two lines of that one entry.
Notation, read this first
This repository has measured that GitHub's body sanitizer deletes tag-shaped
fragments even inside backticks and fenced blocks, which is how a before/after
table can render as though nothing changed. So generic parameters and JSX
elements are spelled out in words below — "an array of RoleDefinition", "the
PermissionGuard element" — rather than in their real angle-bracket form. The
README itself carries the real spellings; this page does not.
Batch 19 (PR #8017) and objectui#7692 (PR #8016) both merged while this batch
was measuring.
origin/mainmoved fromeeda78ato4bb33d7a4, soorigin/mainwas merged into this branch (merge commit742bd5078) and everygate, test, probe, census and reading reported below was re-run on the merged
head after a second forced rebuild. The merge was clean: batch 19's removal and
this one are two line deletions in the same object literal, on different lines,
for different documents.
No open pull request touches
packages/permissions/README.md. All 8 open PRs'file lists were read in full and their counts reconciled against each PR's own
changed_files— including PR #5400 (changeset-release/main), whose 1048-filelist was paged to exhaustion because the REST files endpoint pages at 100 and a
truncated list renders as a confident absence. The only two hits anywhere near
this diff are PR #8017 on the gate file (batch 19, since landed) and PR #5400 on
packages/permissions/CHANGELOG.mdandpackage.json— neither is thisREADME.
Live E2E (informational)is red on every branch today for an upstream reason(objectui#7990 / objectstack#16186), not because of this diff.
Ledger arithmetic
4bb33d7a4742bd5078UNGATED_DOCSentriescheck:readme-exports)Both rows were MEASURED, not computed: the base row is a real
pnpm check:doc-snippetsrun with both changed files checked out atorigin/mainbytes (on-disk hashes proven equal to theorigin/mainblobs) andrestored afterwards under a trap.
Programmatic diff of the two
UNGATED_DOCSobjects — both imported as OBJECTS,never diffed as text: removed =
['packages/permissions/README.md'],added =
[], reason-changed =[], key order preserved for survivors = true,survivors = 18 at the pre-merge pair and 17 at the post-merge one.
git diff --numstaton the gate file is exactly0 2. On the branch:permissions entries 0,
packages/NAME/README.mdentries 16 (from 17),control
'packages/auth/README.md'1.The strictness region — the
Fence scanningbanner line to EOF, 1178 lines onboth sides — hashes to
f46b5662ba336f026bca3a0003e0b7979789d48d0291fa5760be7d23c8ed0160onorigin/mainand on the branch. Re-measured here rather than inherited, on boththe pre-merge pair and the post-merge one; it is the value batches 15 to 19
recorded, as it must be with nothing landing in the region since.
Census and the rung that decided
Re-taken on this branch's base through the gate's exported
analyze()/compileSnippets()over every non-excluded ledger candidate — first on theoriginal base
eeda78a(19 entries, 15 candidates), then again on thepost-merge base
4bb33d7a4(18 entries, 15 candidates). Both runs give thesame table and the same pick. The three rung-1 contenders were additionally
re-measured one at a time, each in its own program, so the pick does not rest on
a single combined run.
Rung 1 (larger measured debt: blocks, then diagnostics) DECIDES OUTRIGHT this
time: permissions ties on blocks with types and layout and is far ahead of both
on diagnostics. Rung 2 was never reached.
Permissions' 18: TS2304x11 TS2322x4 TS2345x1 TS2353x1 TS2552x1 — zero parse
failures, zero bound failures, all 18 semantic.
The dispatch's assumption A1 is CONFIRMED on both bases: permissions is
alone on rung 1. One correction to the b19 census it was derived from, reported
rather than smoothed: permissions reads 5 distinct codes here, not 4, and
packages/layout/README.mdreads 2 diagnostics, not 3 — layout's third is aBOUND failure (a specifier that resolves only through the root manifest), which
is counted as a refusal rather than a diagnostic by this census. Neither moves
the pick, and rung 2 is not reached either way. The TS2304 / TS2552 split inside
permissions' 12 undefined-name diagnostics also moves with which other documents
share the program (11 + 1 in the combined run, 8 + 4 in the isolated one) — the
total is 18 in every run, which is what the rungs read.
Exclusions re-verified against GitHub on this base, not inherited: the root
README.mdis not apackages/NAME/README.md;packages/auth/README.mdisheld by open draft PR #7685 (67 paths, read again here);
packages/collaboration/README.mdwas batch 19's and has now landed, so it isout of the ledger entirely rather than merely reserved;
packages/plugin-chatbot/README.mdis deferred by an earlier ruling on thecard.
A4 is CONFIRMED: the gate reads README bytes from the working tree and
compiles against BUILT types, so the forced package build came first, twice —
once on
eeda78aand again after the merge.What the 18 diagnostics were, and what each repair did
SEVEN of them were real drift — the README taught an API this package has
never shipped — and the rest were continuation-fragment shape. Every
replacement was checked against
packages/permissions/dist/*.d.tsafter theforced build.
rolesgiven bare strings where the prop takes an array ofRoleDefinition;permissionsgiven an object map keyed by object name where the prop takes an array ofObjectPermissionConfig; the requireduserRolesprop absent; the PermissionGuard element given aresourceprop the component does not declare and a JSX-valuedfallback; andcan('delete', 'orders')— action firstRoleDefinitionandObjectPermissionConfigvalues built in the block,userRolessupplied, the guard writtenobject="orders" action="create" fallback="custom"with the node moved tofallbackContent, andcan('orders', 'delete')— the declared(object, action)orderPermissionProvider,permissionMapandAppdeclare constplaceholders typed to the shipped surface, a localApp, and the element bound to a name with no re-indentationusePermissions; doc lie underneath it:can('update', 'orders')is the reverse of the declared arity(object, action);cannotis now exercised rather than only destructuredisVisible/isEditable, neither of which the hook returnscanRead/canWritepredicates it really returns, withisVisible/isEditablederived from them so the reader's mental model survivesPermissionGuardandDeleteButtonboth undefined, plus the sameresource/ JSX-fallbacklie as the Quick StartDeleteButton,object/fallback="custom"/fallbackContent, and the element bound to a name with no re-indentationresourcekey the params type does not declare, noobject, nouserRoles, nouser(all three required), androlesas bare stringscreatePermissionStoreandpermissionConfig; doc lie in the trailing comment:store.check(...)was annotated// true | falseand called action-firstcheck('orders', 'read')— the declared(object, action)— and the comment corrected to thePermissionCheckResultit really returnsEvery one of these seven contradictions is between the README and the SHIPPED
type of the same package, so each is corrected in the README, per this card's
standing ruling. One contradiction between two SHIPPED surfaces was found and
is NOT decided here:
PermissionGuardConfigin@object-ui/typesispublished authoring surface with zero consumers whose
fallbackunion carries aredirectmember the shippedPermissionGuardcannot honour — filed asobjectui#8024, unassigned, exactly as batch 18 filed objectui#8008.
No
packages/**source touched, no public type widened, no lenient alias added,no gate loosened, and no new fragment marker — declared fragments stay at
158, so all 7 blocks earn their coverage by COMPILING.
Probes — one base measurement and seven probes, each predicted in writing first
Predictions were written to the scratchpad (
5174-b20-PREDICTIONS.md, md5d1f65b78872f0f3357c8647b2b249d85) at commit9a6529d80with a clean tree,before any leg ran. Every mutation is proven on disk by occurrence counts of
BOTH the injected and the deleted text plus
git hash-objectagainst the HEADblob; every restore is
git checkout HEAD -- ABSOLUTE_PATH, never a barecheckout, proven by an empty
git diff HEAD; every leg runs under atrapwithabsolute paths. No rebuild is owed on any leg, and that was reasoned rather than
assumed: the gate reads the mutated bytes straight from the working tree and no
leg touches
dist/. All eight legs were run twice — once before the merge andagain on the merged head — with identical results; the numbers below are the
merged-head run.
209 covered … 18 ungated,693 — 535 to compile,535 of 535 judged, 0 failed209 covered (107 …), 18 ungated,693 — 535 to compile,535 of 535 judged, 0 failed. The entry is what suppressed the verification. The restored gate file hashed byte-identical to theorigin/mainblobroleDefinitionsfrom an array ofRoleDefinitionto an array ofnumber, aimed BY LINE so the two sibling blocks keep their own declarations542 of 542 judged, 1 failed,README.md:97:23 TS2322: Type 'number[]' is not assignable to type 'RoleDefinition[]'— exactly one, siblings greenPermissionGuardNope)check:readme-exportscontrol green first, then exit 1 with 1 fabricated478 real, 0 wrong-path, 0 fabricated; mutated exit 1,477 real, 0 wrong-path, 1 fabricated, namingpackages/permissions/README.md:147can('orders', 'delete')tocan('delete', 'orders')1 failed,README.md:66:22 TS2345: Argument of type '"orders"' is not assignable to parameter of type …fallback1 failed,README.md:154:52 TS2322: Type 'Element' is not assignable to type '"custom" | "hide" | "disable" | undefined'useFieldPermissions('orders', 'discount')1 failed,README.md:131:63 TS2554: Expected 1 arguments, but got 2P5, P6 and P7 exist because seven of this diff's repairs are corrections of the
documented API rather than fragment plumbing: they show the gate reds on each
lie individually, so the repair is load-bearing and not cosmetic.
Gates — all at
742bd5078, clean tree, nothing pushed afterExit codes captured by redirect-then-capture, never read through a pipe; each row
quotes the gate's own verdict line.
pnpm check:doc-snippetsScanned 227 document(s): 210 covered (108 of them hold a ts/tsx block), 17 ungated·Covered blocks: 700 — 542 to compile, 158 declared fragment(s)·542 of 542 block(s) judged, 0 failed·Every covered documentation snippet compiles against the built types.pnpm check:doc-fencesevery TypeScript block in 227 document(s) is fenced ts/tsx/typescriptpnpm check:readme-exports478 of them self-imports judged (478 real, 0 wrong-path, 0 fabricated)pnpm check:doc-typesEvery documented component type is registered.node scripts/check-doc-links.mjsLinks are valid across 17 scan roots.pnpm check:doc-example-readersOK 80 documented symbol(s), 3947 call site(s)pnpm check:control-bytesOK (scanned 6446 tracked text file(s); skipped 85 binary); plus a manual C0/DEL scan of both changed paths withgrep -naP, no hitnode scripts/check-node-esm-load.mjs --force-buildProvenance leg: 37 of 37 gradable entries were built by this tree.(its threeERR_UNKNOWN_FILE_EXTENSIONlines are the gate's own by-design entries)pnpm type-check:scriptsnode scripts/check-changeset-presence.mjsno changeset is owed(2 files changed, 0 of them published source of a released package)check-governed-queue-guard.mjs --test(both paths)NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matchedcheck-node-esm-load.mjsfailed once at the merged head and the failure isreported rather than smoothed, because it is exactly the hazard the dispatch
named: run without
--force-build, the gate's own internal build replayedanother worktree's cached artifacts over this tree's
dist/(
22 of 37 entries REFUSED … foreign, each naming/home/user/objectui-issue-7834), and the gate said so and exited 1 rather thangrading someone else's output. Re-run with
--force-buildit is green at 37 of37, and every reading in this PR was then taken again on that force-built
dist/— the gate union above, the tests below and all eight probe legs. Nogate was weakened; the flag the gate's own message prescribes was used.
The build came first and was FORCED, both before the merge and again after it:
turbo run build --filter=./packages/* --concurrency=2 --force,39 successful, 0 cached(3m20s and 2m49s). Forced because turbo shares one cache across everyworktree of a checkout and
check-node-esm-load's provenance leg refusesartifacts a different tree produced.
Tests:
pnpm exec vitest runover every test file that reads either changedpath, derived with
git grep -lon both paths and not guessed — 16 files,re-derived after the merge and byte-identical to the pre-merge derivation,
Test Files 16 passed (16) / Tests 597 passed (597). That set includesscripts/__tests__/check-doc-snippet-types.test.ts, which this diff's own editedscript owes, and
scripts/__tests__/doc-version-claims.test.ts, which names thisREADME path and which a docs-only diff would otherwise reach only inside the
merge-group build. Owning package:
pnpm exec vitest run packages/permissions/—Test Files 8 passed (8) / Tests 85 passed (85);pnpm --filter @object-ui/permissions type-checkexit 0,its output echoing
tsc --noEmit && tsc -p tsconfig.test.jsonso the testtsconfig really is included.
Lint, as a declared narrowing with its three evidence items:
pnpm linthere is
turbo run lintper package, so the repository-wide sweep is CI's run.The narrowed run over exactly this diff is
pnpm exec eslint --no-inline-config --format jsonon both paths — 2 entries,0 errors; eslint's own answer for the README is
File ignored because no matching configuration was supplied, so the real lint surface of this diff isthe one
.mjsat 0 errors / 0 warnings. (1) The population eslint wouldotherwise judge is 4356 files by its own count. (2) That run exits 1 with 93
errors and 12145 warnings, all of them in files this diff does not touch and all
pre-existing on the base — reported rather than smoothed, so nobody reads the
narrowed green as a statement about the repository. (3)
eslint.config.jsdeclares no
project/projectService/parserOptions.project(grep count0), so type-aware linting is off and this diff cannot move the verdict on any
untouched file.
Readers of the changed paths
Derived with
git grep -lfor the README path and for the package name overscripts/andpackages/, re-derived on the merged head, then run — notassumed.
scripts/check-doc-snippet-types.mjs— the gate itself, which now COMPILESthis page instead of excusing it (P1 proves the entry was what suppressed it).
scripts/check-doc-fence-languages.mjs(check:doc-fences) — reads everyfence in this README; green at the final commit over 227 documents.
scripts/check-readme-exports.mjs— reads this README's self-imports; provenlive by P4. This diff ADDS self-imports (465 to 478 across the repository), so
it hands that gate more to check than it had — and that is why the seven doc
lies survived every gate until now: six of the seven blocks imported nothing at
all, so readme-exports had no name to judge and doc-snippets was excused by the
ledger entry.
scripts/__tests__/doc-version-claims.test.ts— the only test file naming thisREADME path (A3 re-derived and confirmed); green inside the 16-file run, and no
version literal on this page moved.
git grep -lfor the path across the tree returnsdoc-version-claims.test.tsalone, and
packages/permissions/src/__tests__/holds no README-reading suite(its 8 files are exercised in the owning-package run anyway).
could contradict:
git grepforPermissionGuardConfig,redirectPathandfallbackComponentoverpackages,apps,examples,scripts,content,docs,skillsande2e(excludingdist/) returns declarations and barrelsonly — which is the finding filed as objectui#8024, not a reader this diff
breaks.
This PR is a DRAFT and stays a draft: this seat does not flip ready, does not
enable auto-merge, and touches no labels or assignee.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Generated by Claude Code