Skip to content

Commit 50169dc

Browse files
docs(qa): 18.0 sweep anchor round 20 — the area fixture recipes name the own-port boot by its port and file DB (#25043)
Refs #24579 Clause-②: no Round 20 of the 18.0 sweep's wave anchor (claim `6307282355`, PM loop round 35). It applies round 19's carried finding, PR #25027's out-of-scope finding as its ACCEPT `6306169987` and landing record `6306857223` carry it. Only checklist text changes: 11 strings in the area-level `fixtures` recipes of four area files, five recipes in all. No item changes, no top-level key other than those recipe strings moves, and there is no product code, test, pin, changeset text or `RUNNER.md` edit. - Base `d68aab6fde` (`origin/main` when the branch was cut). `origin/main` has since moved one commit to `dfe60e3a0c`, which touches only `packages/core` and a changeset, none of it cited by the ledger. - Head `60fccd21ef`, one commit. ## The recording rule, as read `docs/qa/platform-checklist/README.md` gives a recipe no revision or history of its own. The recipe shape ("Half 1 — the recipe") lists `$comment`, `title`, `why`, `provenance`, `app`, `requires`, `sequence`, `teardown` and `knownGaps`. `revision` and `history` are item fields: the Lifecycle section's "Change" rule ("edit the fields, bump `revision`, append a `history` entry") is about items. The validator's own comment says the same ("recipes carry no `revision`/`history` of their own", `scripts/check-platform-checklist.mjs`), and none of the five recipes on disk carries either key. So only the strings are edited here. No revision field is added, and no item's `revision` or `history` moves. ## What changed The respelling uses the voice rounds 17–19 landed: "an isolated boot (own port + file DB, …)" becomes "a boot on its own port and file DB (…)", matching `access-security`'s round-17 rows. "discard the isolated file DB … an isolated boot makes free" becomes "discard the run's own file DB … a boot on its own port and DB makes free", matching `platform-core.manifest-install-contract` `steps[9]`, round 17. Each parenthetical keeps the dogfood section-0 pointer as its file spelled it ("dogfood skill §0" or "dogfood §0"). Only the fragments below change; the rest of each string is byte-identical. | file | recipe | field | old → new | |:--|:--|:--|:--| | `attachments-storage.json` | `qa-scratch-authz` | `requires[2]` | `an isolated boot (own port + file DB, dogfood skill §0)` → `a boot on its own port and file DB (dogfood skill §0)` | | `attachments-storage.json` | `qa-scratch-authz` | `teardown` | `discard the isolated file DB, … the one an isolated boot makes free` → `discard the run's own file DB, … the one a boot on its own port and DB makes free` | | `attachments-storage.json` | `qa-media-constraints` | `requires[1]` | `an isolated boot (own port + file DB, dogfood skill §0)` → `a boot on its own port and file DB (dogfood skill §0)` | | `attachments-storage.json` | `qa-media-constraints` | `teardown` | `discard the isolated file DB, the cheaper path an isolated boot makes free` → `discard the run's own file DB, the cheaper path a boot on its own port and DB makes free` | | `automation.json` | `qa-flow-status-doors` | `requires[1]` | `an isolated boot (own port + file DB, dogfood §0)` → `a boot on its own port and file DB (dogfood §0)` | | `automation.json` | `qa-flow-status-doors` | `requires[2]` | `(RUNNER.md, the isolated-boot/OS_PORT standing fact)` → `(RUNNER.md, the own-port/OS_PORT connector standing fact)` | | `automation.json` | `qa-flow-status-doors` | `teardown` | `discard the isolated file DB, the cheaper path an isolated boot makes free` → `discard the run's own file DB, the cheaper path a boot on its own port and DB makes free` | | `records-forms.json` | `qa-feeds-disabled` | `requires[1]` | `an isolated boot (own port + file DB, dogfood skill §0)` → `a boot on its own port and file DB (dogfood skill §0)` | | `records-forms.json` | `qa-feeds-disabled` | `teardown` | `discard the isolated file DB, … the one an isolated boot makes free` → `discard the run's own file DB, … the one a boot on its own port and DB makes free` | | `search.json` | `qa-contributor-bound-member` | `requires[2]` | `an isolated boot (own port + file DB, dogfood §0)` → `a boot on its own port and file DB (dogfood §0)` | | `search.json` | `qa-contributor-bound-member` | `teardown` | `discard the isolated file DB — the cheaper path an isolated boot makes free` → `discard the run's own file DB — the cheaper path a boot on its own port and DB makes free` | `git diff --stat`: 4 files, 11 insertions, 11 deletions. **The re-pointed pointer (`qa-flow-status-doors.requires[2]`).** RUNNER.md's connector entry is now titled "A boot on its own non-3000 port breaks the showcase's self-pinging connectors unless you export `OS_PORT` …". The new pointer names it by words that title carries: own, port, `OS_PORT` and connector. "standing fact" is kept, because it is the section's own word: the entry sits under "Environment facts the runner should not re-derive", whose intro calls them "Standing facts about the stock showcase environment". The sibling item text `automation.json` already uses the same form ("RUNNER.md's connector self-URL standing fact"). ## `isolated` left in the four files' recipes Read over every string under each file's top-level `fixtures` block, the `$comment` annotations included, at the head: | file | recipe · field | text | sense | verdict | |:--|:--|:--|:--|:--| | all four | every recipe string | the word `isolated` | — | none left: 16 at the base, all inside the 11 strings above; 0 at the head | | `records-forms.json` | `qa-feeds-disabled` · `sequence[1].expect` | "a caller who can read and edit this parent isolates FEEDS_DISABLED from the sibling RECORD_NOT_ACCESSIBLE refusal" | the verb: tells one refusal apart from another | kept (names neither the boot nor the posture) | No posture text was in any of the five recipes, so none was touched. **Items citing a changed recipe string verbatim: none.** Every area file's items were searched for each old fragment. Three history rows carry the same phrasing: `access-security.rls-both-sides` and `access-security.record-share-grant-revoke` `history[6]`, and `platform-core.manifest-install-contract` `history[5]`. Each quotes its OWN item's old step text, not a recipe string, so nothing is reported under that rule. Outside `areas/`, `git grep` finds no file quoting any old fragment. ## How the edits were made and checked A one-off script (sha256 `52f33dacca5c…`, kept out of the tree) tokenizes each file to the byte span of every string value by JSON path. It edits only the 11 named spans and re-encodes each new value in the file's own style. It never re-serialises a file. Its assertions, all run in a dry run and again on the bytes re-read from disk after `--write`: - each span round-trips (decoding the span equals the parsed value, and re-encoding reproduces the span); - each phrase replacement hits exactly its expected count, and no edited string keeps `isolat`; - the new file parses, with the same set of string-value paths; - the new document equals the old one with only the 11 paths replaced: `items` equal, every other top-level key equal, every other recipe equal, and every other field of an edited recipe equal; - every byte outside the edited spans is identical, the head, the gaps and the tail included (trailing-newline state too); - each file's `isolat` count drops by exactly the named strings' hits (6, 4, 3, 3). The assertions were shown to fire first: three faults injected into the in-memory result (an item title edit, a whitespace-only change outside the spans, an edit to an unnamed recipe field) were each caught by the intended assertion. A separate per-file count against the base agrees: each old fragment goes from N to 0 and each new one from 0 to N, in the same files. ## Gates `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derives 13 commands on the 4 paths, against merge base `d68aab6fd` of `origin/main`. At head `60fccd21ef` each was run with its exit code captured before any pipe, and each exited 0: `node scripts/check-ci-filter-parity.mjs` · `node scripts/check-closing-keyword-parity.mjs` · `node scripts/check-closing-keyword-parity.mjs --self-test` · `node scripts/check-comment-mask-corpus.mjs` · `pnpm --filter @objectstack/lint run check:doc-formula-expressions` · `pnpm check:cross-package-test-inputs` · `pnpm check:doc-authoring` · `pnpm check:driver-memory-census` · `pnpm check:gitlink-declared` · `pnpm check:nul-bytes` · `pnpm check:platform-checklist` · `pnpm check:refd-timer-probe` · `pnpm check:watch-hint-literal` The first run of `check:doc-formula-expressions` refused with exit 3, a prerequisite: `@objectstack/formula` and `@objectstack/lint` were not built in this worktree. Both were built under the shared verify lock (`VERDICT command-exit 0`, a full turbo cache replay, held 1 s, waited 0 s), and the rerun exited 0. `--ran`, with an exit code on every line, reads "13 derived, 13 run, 0 NOT-MEASURED, 0 UNRUN", a derived zero. No per-PR CI job runs `pnpm check:platform-checklist`, so this local reading is its evidence. The base column was taken in this worktree at the base, before any edit: | reading | base `d68aab6fde` | head `60fccd21ef` | |:--|:--|:--| | exit | 0 | 0 | | items | 16 areas, 328 items (323 active, 1 planned) | 16 areas, 328 items (323 active, 1 planned) | | provisioning | 5 area recipes, 10 item references resolved (2 area-qualified), 5/5 recipes referenced | 5 area recipes, 10 item references resolved (2 area-qualified), 5/5 recipes referenced | | line citations | 0 survive across 21 swept documents | 0 survive across 21 swept documents | | symbol anchors | 979/989 against 434 cited sources, 10 on the named residual (#16898), 18 file floors held | 979/989 against 434 cited sources, 10 on the named residual (#16898), 18 file floors held | No anchor, citation or recipe key is added or removed. `main`'s one later commit touches no file the ledger cites. `git merge-tree --write-tree` exited 0 against each of: - `origin/main` `dfe60e3a0c`; - PR #25024's head `356172a1f9` (its only `docs/qa/` file is `FOLLOW-UPS.md`). None of these paths is routed to the `os-regen` merge driver (`merge: unspecified`). There is no ablation, because no tested behaviour changed. `skip-changeset` was re-measured. No `files[]` entry of the 73 non-private manifests (86 tracked `package.json` files) reaches outside its own package or names `docs/qa`, and the repo root is private. The two `docs/qa` mentions under `packages/` (`service-settings` `config-change-audit.ts`, and `packages/lint`'s gate script) are comments, not copies. A grep of the built dists on disk for the edited recipe keys finds none, with a positive control hit in `packages/spec/dist`. ## Acceptance notes - **`automation.flow-error-handling` `fixtures.requires[0]`** (an item, not on this round's surface) says `api.example.com` is "unroutable from the isolated env, so the failure is deterministic". That `isolated` means the network-isolated (no-egress) environment. It is a third sense: neither the own-port boot nor the tenancy posture. Noted, not filed; no carrier. - **`qa-contributor-bound-member.requires[2]`'s pointer** "(RUNNER.md's connector self-URL fact)" is left as it was. "connector" is a word of the entry's title and "self-URL" names its resolver, and the ruling named only `qa-flow-status-doors`'s pointer for re-pointing. --- _Generated by [Claude Code](https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent e939357 commit 50169dc

4 files changed

Lines changed: 11 additions & 11 deletions

File tree

‎docs/qa/platform-checklist/areas/attachments-storage.json‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"requires": [
1414
"an admin session that holds the `manage_metadata` capability — PUT /api/v1/meta/:type/:name is capability-gated per ADR-0066 D1 (#6603), so a bare authenticated session is NOT enough (packages/rest/src/rest-route-ledger.ts, the `PUT /api/v1/meta/:type/:name` row)",
1515
"system-context write access for the persona bindings (the sys_user_permission_set insert, exactly as showcase-permission-zoo.dogfood.test.ts does it — the same pattern access-security.json's items already use)",
16-
"an isolated boot (own port + file DB, dogfood skill §0) — this recipe authors metadata into the running app"
16+
"a boot on its own port and file DB (dogfood skill §0) — this recipe authors metadata into the running app"
1717
],
1818
"sequence": [
1919
{
@@ -126,7 +126,7 @@
126126
"source": "sys_user_permission_set insert in system context, mirroring showcase-permission-zoo.dogfood.test.ts — the binding shape access-security.json's permission-set items already replay. NOTE (ADR-0090 D5): every authenticated member ALSO holds the everyone baseline additively, so persona B's effective access is the UNION of its grants and that baseline — compute the union before calling a read 'invisible'."
127127
}
128128
],
129-
"teardown": "DELETE /api/v1/packages/com.objectstack.qa.attachments (client `packages.uninstall`, ledgered at rest-route-ledger.ts) — or simply discard the isolated file DB, which is the cheaper path and the one an isolated boot makes free.",
129+
"teardown": "DELETE /api/v1/packages/com.objectstack.qa.attachments (client `packages.uninstall`, ledgered at rest-route-ledger.ts) — or simply discard the run's own file DB, which is the cheaper path and the one a boot on its own port and DB makes free.",
130130
"knownGaps": [
131131
"The SDK helper `meta.saveItem(type, name, item)` does NOT send the `?package=` query — it PUTs the bare path (packages/client/src/index.ts). Steps 2-4 must therefore be issued as raw HTTP with the query string appended, or the scratch objects land outside the package and the teardown above will not take them with it.",
132132
"[CLOSED — the three set payloads are pinned in step 6's body, measured on main c91af8ed6 after QA run #23929 recorded their intent] earlier runs (#7635) provisioned the personas through a runtime permission-set/position binding whose exact body was never captured, so the recipe carried intent only. Replay step 6's body literally; if a save answers anything but 200, re-read the citation before assuming the recipe rotted"
@@ -139,7 +139,7 @@
139139
"app": "showcase",
140140
"requires": [
141141
"an admin session that holds the `manage_metadata` capability — same gate as qa-scratch-authz (PUT /api/v1/meta/:type/:name is capability-gated per ADR-0066 D1, packages/rest/src/rest-route-ledger.ts)",
142-
"an isolated boot (own port + file DB, dogfood skill §0) — this recipe authors metadata into the running app"
142+
"a boot on its own port and file DB (dogfood skill §0) — this recipe authors metadata into the running app"
143143
],
144144
"sequence": [
145145
{
@@ -157,7 +157,7 @@
157157
"source": "accept/maxSize are declared FieldSchema keys since ADR-0104 D3 wave 2 (packages/spec/src/data/field.zod.ts#shape — 'Offered to the file picker AND enforced on write'); authoring-call shape identical to qa-scratch-authz step 2 (packages/runtime/src/domains/meta.ts#handleMetadataRequest for ?package=); file-class field set is FILE_REFERENCE_TYPES = image/file/avatar/video/audio (packages/spec/src/data/field-value.zod.ts)"
158158
}
159159
],
160-
"teardown": "DELETE /api/v1/packages/com.objectstack.qa.media — or discard the isolated file DB, the cheaper path an isolated boot makes free.",
160+
"teardown": "DELETE /api/v1/packages/com.objectstack.qa.media — or discard the run's own file DB, the cheaper path a boot on its own port and DB makes free.",
161161
"knownGaps": [
162162
"Same SDK sharp edge as qa-scratch-authz: `meta.saveItem` drops `?package=` (packages/client/src/index.ts) — issue step 2 as raw HTTP or the object lands outside the package and the teardown misses it.",
163163
"Unlike qa-scratch-authz this recipe has NOT yet been proven by a live run — it is derived from the same authoring path the proven recipe uses plus the FieldSchema declaration. If step 2 4xxs on the constraint keys, re-read field.zod.ts before assuming the recipe rotted; a parse-time strip of accept/maxSize would itself be a finding (the pre-#4001 silent-strip class)."

‎docs/qa/platform-checklist/areas/automation.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
"app": "showcase",
1313
"requires": [
1414
"an admin session holding `manage_metadata` — PUT /api/v1/meta/:type/:name is capability-gated per ADR-0066 D1 (#6603), so a bare authenticated session is NOT enough",
15-
"an isolated boot (own port + file DB, dogfood §0) — this recipe authors metadata into the running app",
16-
"⚠️ export OS_PORT=<port> as well as passing -p <port>, or the showcase's self-pinging connectors dial 3000 and every unrelated flow run in the same boot fails `fetch failed` (RUNNER.md, the isolated-boot/OS_PORT standing fact)"
15+
"a boot on its own port and file DB (dogfood §0) — this recipe authors metadata into the running app",
16+
"⚠️ export OS_PORT=<port> as well as passing -p <port>, or the showcase's self-pinging connectors dial 3000 and every unrelated flow run in the same boot fails `fetch failed` (RUNNER.md, the own-port/OS_PORT connector standing fact)"
1717
],
1818
"sequence": [
1919
{
@@ -65,7 +65,7 @@
6565
"source": "packages/runtime/src/domains/automation.ts#flow (POST /:name/toggle → engine.toggleFlow); automation.flow-toggle-kill-switch names showcase_urgent_task_alert as the only type:'record_change' flow"
6666
}
6767
],
68-
"teardown": "POST /api/v1/automation/showcase_urgent_task_alert/toggle {\"enabled\": true} to undo step 4, then DELETE /api/v1/packages/com.objectstack.qa.automation (client `packages.uninstall`, ledgered at rest-route-ledger.ts) — or discard the isolated file DB, the cheaper path an isolated boot makes free. The toggle is NOT covered by discarding the DB if you reused a boot, so undo it explicitly.",
68+
"teardown": "POST /api/v1/automation/showcase_urgent_task_alert/toggle {\"enabled\": true} to undo step 4, then DELETE /api/v1/packages/com.objectstack.qa.automation (client `packages.uninstall`, ledgered at rest-route-ledger.ts) — or discard the run's own file DB, the cheaper path a boot on its own port and DB makes free. The toggle is NOT covered by discarding the DB if you reused a boot, so undo it explicitly.",
6969
"knownGaps": [
7070
"Same SDK sharp edge as qa-scratch-authz: `meta.saveItem(type, name, item)` does NOT send `?package=` (packages/client/src/index.ts) — issue steps 2 and 3 as raw HTTP with the query string appended, or the flows land outside the package and the teardown misses them.",
7171
"This recipe has NOT been proven by a live run. If step 2 or 3 4xxs on the flow body, re-read the cited schema line before assuming the recipe rotted — a publish-time refusal of a start-less flow would itself be a finding (it would mean the 422 row has moved from dispatch time to author time, which changes what the item is asserting)."

‎docs/qa/platform-checklist/areas/records-forms.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"app": "showcase",
1313
"requires": [
1414
"an admin session that holds the `manage_metadata` capability — PUT /api/v1/meta/:type/:name is capability-gated per ADR-0066 D1 (#6603), so a bare authenticated session is NOT enough (packages/rest/src/rest-route-ledger.ts, the `PUT /api/v1/meta/:type/:name` row)",
15-
"an isolated boot (own port + file DB, dogfood skill §0) — this recipe authors metadata into the running app",
15+
"a boot on its own port and file DB (dogfood skill §0) — this recipe authors metadata into the running app",
1616
"AuditPlugin active in the boot: it owns sys_comment AND registers the enable.feeds capability gate (packages/plugins/plugin-audit/src/audit-writers.ts). A boot without it accepts every comment and both probes go green for the wrong reason — confirm the gate is live before scoring either clause."
1717
],
1818
"sequence": [
@@ -53,7 +53,7 @@
5353
"source": "`enable.feeds` is the #2707 opt-out, default true (packages/spec/src/data/object.zod.ts#Record: 'Record comments/collaboration feed. Default on; explicit false hides the feed UI and rejects any write that makes a comment target this object (403 FEEDS_DISABLED) — a new comment and an update that re-threads an existing one alike'). `sharingModel` is a TOP-LEVEL object key, enum ['private','public_read','public_read_write','controlled_by_parent'] (packages/spec/src/data/object.zod.ts#sharingModel; ADR-0090 D4 — re-pointed #18104: query is not a key this schema declares, and sharingModel is the key this sentence is about). `?package=` is read as `query.package` and threaded to saveMetaItem as packageId (packages/runtime/src/domains/meta.ts)"
5454
}
5555
],
56-
"teardown": "DELETE /api/v1/packages/com.objectstack.qa.feeds (client `packages.uninstall`, ledgered at rest-route-ledger.ts) — or simply discard the isolated file DB, which is the cheaper path and the one an isolated boot makes free. Any throwaway qa_nofeeds record and any sys_comment row created against it go with the package.",
56+
"teardown": "DELETE /api/v1/packages/com.objectstack.qa.feeds (client `packages.uninstall`, ledgered at rest-route-ledger.ts) — or simply discard the run's own file DB, which is the cheaper path and the one a boot on its own port and DB makes free. Any throwaway qa_nofeeds record and any sys_comment row created against it go with the package.",
5757
"knownGaps": [
5858
"The recipe lands the OBJECT only. Each probe inserts its own throwaway qa_nofeeds record inline (it needs that record's id in the thread_id), exactly as attachments-storage's clause 5 does with qa_nofiles — no standing rows here.",
5959
"This recipe provisions the SERVER-side probe target. The `feeds:false must HIDE the panel` half of the negative is a console/objectui assertion: to score it, navigate to the qa_nofeeds record detail and confirm no discussion panel mounts and no sys_comment fetch is issued. If the console has no route for a scratch object in the running build, record that half blocked(fixture) and score the two API clauses — do not infer the UI half from the API refusal."

‎docs/qa/platform-checklist/areas/search.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"requires": [
1414
"a stock dev boot — the `contributor` position declares `showcase_contributor` in its `permissionSets` (examples/app-showcase/src/security/positions.ts), which the resolver reads by name (ADR-0131 D3/D4). ⛔ Do NOT hand-create a sys_position_permission_set row: no resolver reads it, so it proves nothing about the merge",
1515
"an admin session for the position binding: the admin's POST /api/v1/data/sys_user_position is the insert (sys_user_position is admin-writable system data, packages/plugins/plugin-security/src/objects/sys-user-position.object.ts managedBy 'system-data'; QA run #24574 bound the member this way) — the same pattern access-security.json's permission-set items already replay",
16-
"an isolated boot (own port + file DB, dogfood §0); export OS_PORT=<port> as well as passing -p (RUNNER.md's connector self-URL fact) so unrelated flow noise does not pollute the run",
16+
"a boot on its own port and file DB (dogfood §0); export OS_PORT=<port> as well as passing -p (RUNNER.md's connector self-URL fact) so unrelated flow noise does not pollute the run",
1717
"an admin session to INVITE the step-1 address before step 1: POST /api/v1/auth/organization/invite-member {\"email\": \"<the step-1 address>\", \"role\": \"member\"}. The stock showcase declares no auth.audience, so its posture is the invite_only default, which answers an uninvited sign-up 403 SELF_REGISTRATION_CLOSED; a pending, unexpired sys_invitation row for the address is what admits it (an admin POST /api/v1/auth/admin/create-user is the other door, and answers mustChangePassword:true)"
1818
],
1919
"sequence": [
@@ -49,7 +49,7 @@
4949
"source": "ContributorPermissionSet.objects.showcase_invoice.allowCreate === true (permission-sets.ts); the seeded owner emails hold no credential, so borrowing a seeded owner is not an option — this is why the own-row is CREATED"
5050
}
5151
],
52-
"teardown": "delete the sys_user_position row and the invoice created in step 5, or simply discard the isolated file DB — the cheaper path an isolated boot makes free. The signed-up principal is not otherwise cleaned up; use a unique per-run email so a leftover account never collides.",
52+
"teardown": "delete the sys_user_position row and the invoice created in step 5, or simply discard the run's own file DB — the cheaper path a boot on its own port and DB makes free. The signed-up principal is not otherwise cleaned up; use a unique per-run email so a leftover account never collides.",
5353
"knownGaps": [
5454
"⚠️ This recipe has consumers in TWO areas, and the validator resolves both (#10593, maintainer ruling 2026-08-22 — option A, area-qualified references). `provisioning.use` accepts either spelling: a bare key naming a recipe of the item's own area (search.rls-both-personas uses `qa-contributor-bound-member`), or `<area>:<recipe>` naming one another area owns — records-forms.crud-roundtrip clause 7 needs this same persona and opts in from records-forms.json as `search:qa-contributor-bound-member`. Both FAIL check:platform-checklist loudly if this recipe is renamed, moved, or removed, naming the item and what resolved to nothing; the cross-area pointer used to be knownGaps prose the tooling could not see, which is the drift the qualified spelling closes. ⛔ Replay it from here; do not fork a second copy into another area — this block is the one home, and that is what the qualifier buys.",
5555
"The persona is a subset reader of showcase_invoice ONLY. showcase_account is public_read_write and showcase_contributor grants plain allowRead on it with no RLS, so a contributor still reads every account row — an item needing an invisible SOURCE row must drive showcase_invoice, not showcase_account.",

0 commit comments

Comments
 (0)