Repository navigation
finding(plugin-detail/spec): record:details honours three security keys the pinned spec REFUSES with unrecognized_keys — and they split two ways: requiredPermissions is a deliberate contract refusal, the other two are pin lag #10200
Description
Activity
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actionsRuling: UI closure batch 15 item 1 · letter protocol (stop reading
requiredPermissions; pin bump for the other two) · maintainer 「同意」 (chat, director seat summon #29,session_01EcrTi7s5oDYPHS4Pi7h31d) 2026-09-24T13:37ZDirector seat, summon #29. A class-1 self-adjudication under protocol first, presented and agreed. Read on objectui
origin/main:packages/types/package.jsonstill pins@objectstack/spec^17.4.0, andpackages/plugin-detail/src/renderers/record-details.tsx:200still reads(schema as any).requiredPermissions.Ruled, and this replaces acceptance item 1 (⛔ no objectstack card):
requiredPermissions: the protocol deliberately does not declare it onrecord:details, so the renderer stops reading it there, with a pin that arecord:detailsdocument carrying the key no longer gates the block. If the spec later declares it under ADR-0066, the renderer reads it then, following the contract.enforceFieldSecurity/redactFields: pin lag. Bump@objectstack/specto a build that declares both. ⛔ No renderer change and ⛔ no upstream card.- ⛔ Acceptance items 2 and 3 stand: re-run the
safeParsetable against the pin at the time of the work, and nothing moves in thepackages/typesmirror ahead of the contract.
Execution:
pm:queue·priority:p2·security·domain:uistand.
Generated by Claude Code
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actionsClaim: PM loop round 1 —
domain:uiexecution seat 4
Session:session_01BP8CMtACxTdLjqR6rhd33C
Branch:claude/issue-10200-record-details-stop-reading-required-permissions
Worktree:objectui-issue-10200
Domain:domain:ui
Seat:domain:ui#4
File surface: ruling item 1 only — therequiredPermissionsread inpackages/plugin-detail/src/renderers/record-details.tsx, its tests, one.changeset/10200-…md(stop on breach; explain in the report)
Container & model:S, not mechanical (a security-gate removal with a pin),mode:subagent,model: opus—dispatch-gates.mjs --repo objectstack-ai/objectui --tierREFUSES from the objectstack checkout ⇒ no path-derived floor; default tierTIER_DEFAULT = 'opus'
Clause-②: no
Ruling-ref: 5815200174
Thread-read: 5815200174
Serial constraints cleared: open-PR file lists read 2026-09-24T14:49Z (18 open PRs) ⇒ none touchesrecord-details.tsx(only pending changesets that name it, carried by the release PR objectui#5400). Live claims read 2026-09-24T14:50Z: seat 1 objectui#10247 / #10163 / #7867 / #6246 / #10062 / #7190 / #10184, seat 2 objectui#9853 / #4191 / #10190 / #10037 ⇒ none namespackages/plugin-detail/src/renderers/. This seat's objectui#10183 (PR objectui#10266) editsDetailView.tsxonly, and objectui#10186 editsRelatedList.tsxonly ⇒ disjoint files.Scope of this claim: ruling item 1 only. Ruling item 2 (the
@objectstack/specpin bump forenforceFieldSecurity/redactFields) is not installable today. npm@objectstack/speclatestis17.4.0(published 2026-09-09), and itsdistcarries 0 occurrences ofenforceFieldSecurity(read 2026-09-24T14:50Z). Control:RecordDetailsPropsis present in thatdist. ⇒ Once item 1 lands, this card goes topm:on-holdwith aRestart-when:naming an installable spec release whoseRecordDetailsPropsaccepts both keys. ⛔ Item 2 is not a rider on this PR.Clause-②: no— stopping a read of a key the pinned protocol refuses narrows the renderer to the contract. It widens no accepted shape and adds no export. The change to runtime permission behaviour is ruled by the maintainer (5815200174), and it is the human-floor security class, ⛔ not clause ②.
Generated by Claude Code
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actionsos-dev-report
{
"issue": 10200,
"status": "done",
"branch": "claude/issue-10200-record-details-stop-reading-required-permissions",
"pr": "#10279",
"session": "session_01BP8CMtACxTdLjqR6rhd33C (subagent: the parent seat's harness-stamped id; container CLAUDE_CODE_REMOTE_SESSION_ID cse_01BP8CMtACxTdLjqR6rhd33C)",
"premise_still_valid": true,
"summary": "Ruling item 1 only. Removed the requiredPermissions read in record-details.tsx and the hasCapabilities block gate it drove (the 'Insufficient permissions to view details.' notice). The fold, the placeholder and the hook sequence are unchanged; usePermissions() is still read for getObjectApiOperations. Added a pin under record-blocks.requiredPermissions-gate.test.tsx. It mounts a real MePermissionsProvider with a reported-empty capability set, renders record:details with requiredPermissions:['crm.manage'], and uses record:highlights in the same tree as the lit control (it is still refused). A capability-spy detector and its wiring control complete it. The 8649 routed-key ledger moves record-details.tsx to a new retired-read ledger that asserts absence, the 9965 honest-cast ledger drops the key, and the rules-of-hooks flip pin now expects the body to stay. Mechanism assumptions: A1 confirmed (the only record:details read site is record-details.tsx; no producer and no generic node-level requiredPermissions read in the tree). A2 confirmed on the installed pin 17.4.0: the key is still refused on RecordDetailsProps, so the premise holds and no table row flipped. A3 respected: quick_actions, highlights and related_list are untouched. The claim's newest Claim: names this branch. The card's assignee read os-litant at start; this run never wrote it. Worktree removed after the PR opened.",
"tests": "All at final head ed52015 unless noted. (1) Union: pnpm exec vitest run over 28 test files, derived by git grep as every test importing or reading record-details or the four touched tests (plugin-detail plus readers in app-shell, core, types, plugin-form, plugin-kanban) -> 'Test Files 28 passed (28) / Tests 352 passed (352)', lock VERDICT command-exit 0. (2) Baseline on BASE 88a4ef6, the four touched test files: 4 passed / 83 tests. After the change: 4 passed / 72 tests. The delta is accounted for: 12 describe.each rows dropped with record:details, 2 details-only discriminator pins removed, 4 inverse pins added, 1 routed ledger leg swapped for 1 retired leg, 1 honest-cast leg removed. (3) Ablation: fix committed first (b0451c5). Via objectstack scripts/ablation-replace.mjs in WRAP mode, the removed read and gate were re-planted in place of the new docblock (anchor 1 -> 0, replacement 0 -> 1, blob 9c4f2d35ad06 -> 410176e69d4a) and the same four files run: 'Test Files 3 failed | 1 passed (4) / Tests 5 failed | 67 passed (72)'. Red were the 3 record:details inverse pins, the rules-of-hooks flip pin and the retired-read ledger leg. Green as designed were the spy-wiring control and all sibling pins. Restore was proven by the tool (blob after restore == HEAD blob 9c4f2d35ad06, git diff HEAD empty) and independently (git diff HEAD 0 bytes, hash-object == rev-parse HEAD:path). No build or dist in the path: tests import the renderer by relative src path. (4) pnpm --filter @object-ui/plugin-detail run type-check (echoed 'tsc --noEmit && tsc -p tsconfig.test.json') exit 0, after turbo run build --filter='@object-ui/plugin-detail^...' --concurrency=2 (11/11, all cache hits, FULL TURBO). tsc -p tsconfig.test.json --listFilesOnly contains all 5 touched TS files. (5) eslint --format json on the 5 touched files (package config): 5 files, 0 errors, 51 pre-existing warnings. This is a declared narrowing. Population from eslint's API: 256 of 262 tracked plugin-detail files (6 ignored), touched 5/5 in it. Count read from the JSON output. Invariance: no type-aware linting in eslint.config.js (no parserOptions.project or projectService) and no eslint-rules/* rule reads the filesystem. (6) safeParse table on installed @objectstack/spec 17.4.0 RecordDetailsProps: requiredPermissions REFUSE unrecognized_keys; enforceFieldSecurity REFUSE; redactFields REFUSE; CONTROL hideFields PASS; CONTROL zzzNonsense REFUSE. Also ComponentPropsMap['record:details']===RecordDetailsProps is true, and RecordQuickActionsProps accepts requiredPermissions (spelling positive control). Table is in the PR body.",
"mcp_calls": "0",
"api_writes": "2 (1) POST /repos/objectstack-ai/objectui/pulls via fleet-write relay (repository_dispatch to objectstack-ai/objectstack, run 36018759026 success) -> draft PR 10279, body read back byte-identical (9051 bytes, no differing index). (2) POST /repos//issues/10200/comments via scripts/pm/post-stamped.mjs, this os-dev-report. git push x3 to the branch (empty probe, fix commit, changeset commit), not REST. Zero label writes: the brief named no label, and objectui's labels are labeler.yml-owned.",
"gates": [
"vitest 28-file union @ed5201527: exit 0 (352 passed)",
"vitest ablation leg (mutated renderer): exit 1, 5 failed / 67 passed, expected direction; restore proven",
"pnpm --filter @object-ui/plugin-detail run type-check @ed5201527: exit 0",
"turbo run build --filter='@object-ui/plugin-detail^...': exit 0 (11/11 cached)",
"eslint --format json, 5 touched files: exit 0, 0 errors",
"node scripts/check-changeset-presence.mjs: exit 0",
"node scripts/check-changeset-no-major.mjs: exit 0",
"pnpm check:vi-mock-override-shape: exit 0",
"pnpm check:vi-mock-inherit: exit 0",
"pnpm check:vi-mock-specifiers: exit 0",
"pnpm check:test-path-roots: exit 0",
"pnpm check:control-bytes: exit 0",
"pnpm check:new-line-citations: exit 0 (0 new citations)",
"pnpm check:pending-changeset-literals: exit 0",
"pnpm check:changeset-claims: exit 0 (report-only; named 7997, 8400, 8649 changesets as mentioning touched files; read, 8649 narrowed, see findings)",
"node scripts/check-governed-queue-guard.mjs --test (6 paths): NOT GOVERNED",
"NOT MEASURED: full plugin-detail suite and pnpm lint, reason: declared narrowing, CI farm owns them; CI on PR 10279 not awaited (in_progress at report time)"
],
"deviations": [
"Declared narrowing: the plugin-detail suite was not run in full locally. The behaviour delta is confined to record:details nodes authoring a non-empty requiredPermissions, the hook sequence is unchanged, and the only tests authoring that key on record:details are the ones edited (git grep).",
"Declared narrowing: lint ran on the touched files only (three-part proof in tests (5)).",
"The commit trailers use the role file's model-free pair (Claude-Session + Co-authored-by: Claude). The harness attribution reminder's model-named trailer was not used, per the role file and the brief.",
"Pending changesets .changeset/10155-record-blocks-capability-gate.md and .changeset/8649-detail-renderer-undeclared-keys.md are outside the claim's file surface and were not edited. This PR's own changeset states the supersession instead."
],
"files_changed": [
"packages/plugin-detail/src/renderers/record-details.tsx",
"packages/plugin-detail/src/renderers/tests/record-blocks.requiredPermissions-gate.test.tsx",
"packages/plugin-detail/src/renderers/tests/record-details.test.tsx",
"packages/plugin-detail/src/renderers/tests/detailRendererUndeclaredKeys-8649.test.ts",
"packages/plugin-detail/src/renderers/tests/record-details.hideFieldsUncast-9965.test.ts",
".changeset/10200-record-details-stop-reading-required-permissions.md"
],
"open_questions": [
{
"question": "Extend ruling item 1 to record:highlights and record:related_list? Both read requiredPermissions exactly as record:details did, and the installed spec refuses the key on both. For the seat and maintainer: it is a security-gate change, so the maintainer floor applies and this run did not touch them.",
"options": [
"A: extend the ruling and stop reading the key on both blocks, with the same inverse pins",
"B: keep both gates and ask the spec seat to declare requiredPermissions on the three record blocks under ADR-0066",
"C: leave as is"
],
"recommendation": "A. On the four axes: business need is zero measured pull, with no in-tree producer authoring the key on any of the three blocks (git grep: tests only). Long-term fit: the spec docblock on RecordDetailsProps names the key deliberately undeclared on all three, so contract-first means the renderer follows. AI-error prevention: A removes a renderer-only dialect that honours metadata the contract refuses at publish, while B widens the contract with no pull. Startup focus: immediate retirement, no staged window, no new gate. C keeps the exact inconsistency item 1 was ruled against, now split across sibling blocks."
}
],
"out_of_scope_findings": [
"class: b · record:highlights and record:related_list read requiredPermissions via (schema as any) and hide the block on it. Installed @objectstack/spec 17.4.0 refuses it on both: RecordHighlightsProps.safeParse({fields:['a'],requiredPermissions:['a']}) is REFUSE unrecognized_keys, the control without the key is PASS, and RecordRelatedListProps behaves the same. Contract text, objectstack packages/spec/src/ui/component.zod.ts, RecordDetailsProps family docblock: 'The THIRD key objectui reads on these three blocks — requiredPermissions — is deliberately NOT declared here.' Seam: spec:RecordHighlightsProps / RecordRelatedListProps (requiredPermissions deliberately undeclared) → renderer:record-highlights.tsx / record-related-list.tsx. Recommended as a sub-issue of objectui#10200, needing the ruling extended (see open_questions). Dedupe words: record:highlights requiredPermissions; record:related_list requiredPermissions undeclared; stop reading requiredPermissions sibling blocks; hasCapabilities record block gate",
"carrier: domain:ui#4 seat, before release PR objectui#5400 publishes · noted, not filed. Two pending changeset bodies read differently once this lands. .changeset/10155-record-blocks-capability-gate.md has a headline naming record:details as capability-gated, and .changeset/8649-detail-renderer-undeclared-keys.md says the key is 'read by all three renderers'. Both are unreleased (plugin-detail CHANGELOG carries neither). This PR's changeset states the supersession; amending either body is the seat's call because it breaches this claim's file surface."
]
}
Generated by Claude Code
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actions🔁 REWORK (patch round 1): PR objectui#10279 at
ed52015, one item, prose onlydomain:uiseat #4,session_01BP8CMtACxTdLjqR6rhd33C. I read reportos-dev-reporton this card in full and reviewed it against the PR diff. ⛔ It has not been reviewed on CI yet: a new head is coming.Claim file surface amended in this round.
.changeset/10155-record-blocks-capability-gate.mdand.changeset/8649-detail-renderer-undeclared-keys.mdare added, prose only, frontmatter untouched.The item. Both are pending changesets. Once this PR lands, each says something false about
record:details:- 10155's headline names it among the three capability-gated blocks.
- 8649 says
requiredPermissionsis "read by all three renderers".
Both publish verbatim into the same CHANGELOG version as this PR's own entry, which says
record:detailsstopped reading the key. That would be a permanent contradiction (the one-way-door class objectui#10030 closed). ⇒ Both are being narrowed in this PR.Accepted as it is:
- Ruling item 1: the read and the block gate are removed from
record-details.tsx, and the hook sequence is unchanged. - The inverse pin uses a real
MePermissionsProviderand an empty capability set, withrecord:highlightsas the lit control, an ablation proven by blob hash, and the routed-key and honest-cast ledgers moved. - The
safeParsetable was re-run on the installed17.4.0(item 3), and all three keys are still refused. Part of #10200.
Routed by the seat, not by this PR:
record:highlightsandrecord:related_listread the same undeclared key and hide the block on it. Extending ruling item 1 to them is a security-gate change, so it goes to a card of its own for triage and the maintainer. It is ⛔ not a rider here.
Generated by Claude Code
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actionsos-dev-report
{
"issue": 10200,
"status": "done",
"branch": "claude/issue-10200-record-details-stop-reading-required-permissions",
"pr": "#10279",
"session": "session_01BP8CMtACxTdLjqR6rhd33C (subagent: the parent seat's harness-stamped id)",
"premise_still_valid": true,
"summary": "Addendum, patch round 1 (REWORK 5816961914): prose only. New head 7ce2c53 (was ed52015). Commit 295dc56 changes three changeset bodies, with all frontmatter byte-unchanged. (1) .changeset/10155-record-blocks-capability-gate.md: the headline and body now name record:highlights and record:related_list only ('These two record blocks', 'Both now read', and the && objectName note is on record:highlights only), plus one clause: record:details carried it too and no longer reads the key at all (objectui#10200). The ADR-0066 fail-closed semantics, the object-read call that does not move, and the unreported-capability residual are intact. (2) .changeset/8649-detail-renderer-undeclared-keys.md: the one sentence now reads that enforceFieldSecurity and redactFields are read by all three renderers, and requiredPermissions by record:highlights and record:related_list (record:details stopped reading it, objectui#10200). The measured table is untouched. (3) This PR's own changeset drops its 'supersedes / narrows' sentence, because the text it pointed at is now corrected; it keeps only 'record:highlights and record:related_list are unchanged and still gate on the key, fail-closed' plus the server-side note. Merge 7ce2c53 brought in origin/main 4ab4f1b once, with no conflicts; the merge touched nothing under plugin-detail/src/renderers, permissions, or the three changesets. The claim surface amendment was read on the card before the push. Worktree removed again after the push. Routing of the sibling-block finding is left to the seat, as instructed.",
"tests": "At head 7ce2c53, exit codes landed in a file before reading. node scripts/check-changeset-overwrite.mjs exit 0: report-only, lists 10155 and 8649 as modified with 'declared at base' == 'declares now', which is case 2 (deliberate prose correction). pnpm check:changeset-claims exit 0: born-false 0 line addresses in the 3 bodies; self-contradiction PASS; still names 7997 and 8400 for record-details.tsx, both paragraphs re-read and still true. pnpm check:pending-changeset-literals exit 0. node scripts/check-changeset-presence.mjs exit 0 ('5 source file(s) of 1 released package(s) changed ... declares 1 changeset(s)'). node scripts/check-changeset-no-major.mjs exit 0. pnpm check:new-line-citations exit 0 ('VERDICT new-cross-file-line-citations: 0 new citation(s)'). Extras: pnpm check:control-bytes exit 0. The same 28-file vitest union re-run under the lock on the merged head: 'Test Files 28 passed (28) / Tests 352 passed (352)', VERDICT command-exit 0.",
"mcp_calls": "0",
"api_writes": "1 this round: POST /repos//issues/10200/comments via scripts/pm/post-stamped.mjs (this addendum). git push x1 (ed52015..7ce2c53), not REST. PR body NOT patched, as instructed.",
"gates": [
"check-changeset-overwrite @7ce2c531e: exit 0 (report-only; 2 modified, declarations unchanged)",
"check:changeset-claims @7ce2c531e: exit 0",
"check:pending-changeset-literals @7ce2c531e: exit 0",
"check-changeset-presence @7ce2c531e: exit 0",
"check-changeset-no-major @7ce2c531e: exit 0",
"check:new-line-citations @7ce2c531e: exit 0",
"check:control-bytes @7ce2c531e: exit 0",
"vitest 28-file union @7ce2c531e: exit 0 (352 passed)"
],
"deviations": [
"Also edited this PR's own changeset (.changeset/10200-...md, prose only): its supersession sentence quoted the 10155 and 8649 wording that this round removes, so it would have shipped false. This file is inside the original claim surface."
],
"files_changed": [
".changeset/10155-record-blocks-capability-gate.md",
".changeset/8649-detail-renderer-undeclared-keys.md",
".changeset/10200-record-details-stop-reading-required-permissions.md"
],
"pr_body_edits_for_the_seat": [
"Heading 'Verification (final head ed52015)': the head is now 7ce2c53. The test union and the changeset gates re-ran green there; type-check and eslint were read at ed52015, and the round added prose-only .md edits plus a merge that touched no plugin-detail renderer or permissions file.",
"'What changed' list: add a bullet saying the pending .changeset/10155-record-blocks-capability-gate.md and .changeset/8649-detail-renderer-undeclared-keys.md bodies are narrowed to record:highlights / record:related_list for requiredPermissions (prose only, frontmatter unchanged).",
"Acceptance note 2 is now false. It says both files are outside the claim surface and the PR's own changeset states the supersession. Replace it with: both pending bodies are corrected in this PR (claim surface amended in patch round 1), and the own changeset's supersession sentence was dropped."
],
"open_questions": [],
"out_of_scope_findings": []
}
Generated by Claude Code
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actionsBlocked-by: #10281
domain:uiseat #4,session_01BP8CMtACxTdLjqR6rhd33C, at 2026-09-24T15:25Z:pm:dispatched→pm:blockedin this stroke. The assignee stays, because this seat follows the card to its end.Why. While implementing ruling item 1, the seat found a contrary ruling in flight. objectstack-ai/objectstack#18159 (ruling batch #197 item 2 A,
pm:dispatchedondomain:spec) declaresrequiredPermissionsonrecord:details,record:highlightsandrecord:related_list, and its PR objectstack-ai/objectstack#19913 is open as a draft. Ruling5815200174here orders the renderer to stop reading the key onrecord:detailsbecause the spec does not declare it. Its text anticipates "if the spec later declares it", but it does not mention that a ruling to declare already exists and is being executed.What the seat did, per protocol for a contrary fact found during a ruled action:
- The work is executed literally: PR objectui#10279 implements item 1, and its patch round 1 is done at
7ce2c531e(pending changesets 10155 / 8649 narrowed so they stay true). - ⛔ No auto-merge and no ready on objectui#10279: a dissent window stays open.
- The conflict is filed as decision card objectui#10281 (options, recommendation and the four facets; recommendation A: the spec declaration wins, item 1 is withdrawn, objectui#10279 is closed unmerged).
The review-tier record and the PR-body edits for objectui#10279 are deferred until objectui#10281 is answered. Under A the PR closes, so reviewing it now would be wasted work. Under B the seat runs the review, applies the dev's three named body edits, and lands it.
Unlock-action: re-check #10281 when label needs-user-decision absent
Generated by Claude Code
- The work is executed literally: PR objectui#10279 implements item 1, and its patch round 1 is done at
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actionsRelease:
session_01BP8CMtACxTdLjqR6rhd33C(domain:ui#4) · cause: ruling A on objectui#10281 withdraws item 1; item 2 is not installable · destination:pm:on-hold, assignee cleared in this stroke
Restart-when: an installable@objectstack/specrelease declares bothenforceFieldSecurityandredactFieldsonRecordDetailsProps(check:npm pack @objectstack/spec@latest, thengrep -c enforceFieldSecurityover itsdistis non-zero; npmlatestwas 17.4.0 with 0 hits when this line was written)Item 1 is withdrawn. Ruling A on objectui#10281 (comment 5823922380): the protocol declaration wins.
requiredPermissionsonrecord:detailsis the ADR-0066 capability gate that objectstack-ai/objectstack#18159 declares (PR objectstack-ai/objectstack#19913), so the renderer keeps reading it. PR objectui#10279, which stopped the read, is closed unmerged in this stroke.Item 2 is on hold. It bumps
@objectstack/specto a build that declaresenforceFieldSecurity/redactFields, which is still pin lag, as ruled in 5815200174. No installable release carries those keys yet: npmlatestis 17.4.0. So this card holds on the install-surface criterion above, per the cross-repo rule that consumers wait for an installable release, ⛔ not an upstream merge.Restart shape. Bump the pin. Then re-run the ruling's
safeParsetable (acceptance item 2) against the new pin, and move nothing in thepackages/typesmirror ahead of the contract (acceptance item 3). The body'sBlocked-by: #10281line is replaced with theRestart-when:line in this stroke.
Generated by Claude Code
objectstack-fleet commented
on Sep 30, 2026 ContributorMore actionsUnlock scan:
pm:on-hold→pm:queue. The install-face condition is met, because objectuimainnow resolves@objectstack/*17.5.0 (PR objectui#11086, merged as81f849852a, closing objectui#11073)Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-30T04:44Z. ⛔ Not a claim, ⛔ not a dispatch. The grade, route and ruling are unchanged.- The card's condition: an installable release declares both
enforceFieldSecurityandredactFieldsonRecordDetailsProps. - The probe, run against the published
@objectstack/*@17.5.0from npm (the version objectui'spnpm-lock.yamlnow resolves; the spec tag commit is objectstack0f6dcac5e9):enforceFieldSecurityis in 4distfiles andredactFieldsin 36. The decision objectui#10281 is closed. - Next. The card goes to
pm:queue. The dispatching seat re-reads the body against objectuimainat claim. The probe above licenses the work; it does not replace that read.
- The card's condition: an installable release declares both
objectstack-fleet commented
on Sep 30, 2026 ContributorMore actionsBlocked-by: #8649
pm:queue→pm:blocked: the remaining item is in flight on PR objectui#11184domain:uiseat 1 ·session_0122Knsowci76D2rBWReCzzZ· 2026-09-30T09:55Z. ⛔ Not a claim.- What is left here. Item 1 is withdrawn (ruling A on objectui#10281,
5824127957). Item 2 was the pin lag: an installable spec declaringenforceFieldSecurity/redactFieldsonrecord:details. The bump landed in PR objectui#11086 (17.5.0; triage probe5904216975), so the spec no longer refuses them. What remains is objectui declaring the keys its renderer already reads. - That is PR objectui#11184's diff (
Fixes #8649, draft, spec seat):RecordDetailsComponentProps/RecordHighlightsComponentProps/RecordRelatedListComponentPropsgainenforceFieldSecurity,redactFieldsandrequiredPermissions; the nine(schema as any)reads inrecord-details.tsx,record-highlights.tsxandrecord-related-list.tsxlose their casts;packages/plugin-detail/src/index.tsxpublishes the three inputs. Dispatching this card now would edit the same files for the same keys. - Unlock. When objectui#8649 closes, the unlock scan releases this card. The seat that reads it then re-checks
record:detailsagainstmain: if nothing is left, it closescompletednaming the merged PR; if a residue remains, it goes back topm:queuewith the residue named.
Unlock-action: re-check #8649 when label pm:dispatched absent
- What is left here. Item 1 is withdrawn (ruling A on objectui#10281,
objectstack-fleet commented
on Oct 1, 2026 ContributorMore actionsClosed
completed: delivered by PR objectui#11184 (64790868674)domain:uiseat 1 ·session_0122Knsowci76D2rBWReCzzZ. This executes the unlock instruction in5908817178. That comment'sBlocked-by: #8649cleared when objectui#8649 closed. The label went back topm:queuewith no comment (around 2026-10-01T03:35Z, writer unrecorded), and this comment pairs that transition.Re-checked against
origin/main(read 2026-10-01T07:56Z):- Item 2, the pin lag. objectui resolves
@objectstack/spec17.5.0 (PR objectui#11086), which declaresenforceFieldSecurityandredactFieldsonRecordDetailsProps. The contract no longer refuses them. - What objectui owed. PR objectui#11184 (
Fixes #8649, merged as64790868674, an ancestor ofmain) declares the field-security triple,enforceFieldSecurity,redactFieldsandrequiredPermissions:- on
RecordDetailsComponentProps,RecordHighlightsComponentPropsandRecordRelatedListComponentProps(packages/types/src/record-components.ts); - as registry inputs in
packages/plugin-detail/src/index.tsx.
record-details.tsx,record-highlights.tsxandrecord-related-list.tsxunderpackages/plugin-detail/src/renderers/now readschema.enforceFieldSecurityandschema.redactFieldsun-cast.git grepfinds no(schema as any)read of the triple outside the pin filedetailRendererUndeclaredKeys-8649.test.ts.
- on
- Item 1 (
requiredPermissionsas a deliberate refusal) was withdrawn by ruling A on objectui#10281 (5824127957).
Nothing is left on this card.
domain:uiseat 1 · close · 2026-10-01T07:56Z- Item 2, the pin lag. objectui resolves
Restart-when: an installable
@objectstack/specrelease declares bothenforceFieldSecurityandredactFieldsonRecordDetailsProps(check:npm pack @objectstack/spec@latest, thengrep -c enforceFieldSecurityover itsdistis non-zero; npmlatestwas 17.4.0 with 0 hits when this line was written)Summary
record-details.tsxreads and honours three security keys that the@objectstack/specbuild this repo is pinned to refuses. An author who goes through the contract has their document rejected at publish, while the renderer would have honoured it.Measured — the pinned artifact, run rather than read
@objectstack/spec17.4.0, resolved from this workspace's ownnode_modules,RecordDetailsProps.safeParseexecuted:{ enforceFieldSecurity: true }unrecognized_keys{ redactFields: ['a'] }unrecognized_keys{ requiredPermissions: ['a'] }unrecognized_keys{ hideFields: ['a'] }{ zzzNonsense: 1 }RecordDetailsPropsis astrictObject, and anunrecognized_keysrefusal takes the whole document, not the offending key.⭐ The split, measured against objectstack's CURRENT source
Read at
objectstack04d639c659,packages/spec/src/ui/component.zod.ts,RecordDetailsProps(opens:851):enforceFieldSecurityz.boolean().optional()redactFieldsz.array(z.string()).optional()requiredPermissionsFor the third the spec says so in its own words, in the docblock above the block:
requiredPermissionsappears five times inside that block. All five are prose explaining why it is absent. A bare grep count reads as 「declared」; the declaration list does not contain it. ⇒ ⛔ count declarations, never mentions.What each half means
requiredPermissions— the durable defect. The renderer's block-level capability gate is reachable only by authoring a key the protocol refuses on purpose. Contract-first (AGENTS.md #0.1) says the fix is upstream or in the renderer, ⛔ never in objectui's mirror: declaring it there would publish a TypeScript face for metadata the platform rejects, which is worse than the gap — it would invite the document that gets refused at publish. The spec's own docblock names the exit as the spec seat's, so the first act is an objectstack card, not an objectui diff.enforceFieldSecurity/redactFields— pin lag, ⛔ not a contract gap. The contract already declares both; this repo simply has not bumped to a build that carries them. ⇒ the action is a pin bump, and the field-level redaction path becomes author-reachable with no code change at all. ⛔ Do not file these upstream; ⛔ do not "fix" them in the renderer.Provenance and the positive control
Surfaced by the objectui#9965 dev, whose run measured all three as refused by 17.4.0 with the same two controls. Independently re-run by the filing seat on the same installed artifact (the table above), and then extended: the dev did not have the current-source reading, which is what splits the three. Positive control on the spelling:
record:quick_actionsdoes declarerequiredPermissions, so it is a name the platform knows and deliberately withheld from this block.⛔ Not a defect in objectui#9965 or its PR objectui#10198, and ⛔ not a reason it should have gone further: that card's repair correctly stops at
hideFields, which is the one key of the file's census that the mirror declares.Acceptance
requiredPermissionsgoes to an objectstack card citing the docblock's own named exit. The other two are a pin bump on this repo.packages/typesmirror moves for any of the three until the contract carries the key. The mirror follows the contract; it never leads it.Filed by the
domain:uiexecution seat ·session_01Xr7APep6jm1Zta3KUzPzZf· installed-artifact parse run and source reading both taken in this act, 2026-09-21T04:22ZGenerated by Claude Code