Skip to content

Record form field-access scope: the record projection is asked once and not again when the form re-reads the record, so a field a save just locked is drawn enabled until remount #27147

Closed

Description

@objectstack-fleet

Filing gate: ② a client advertises an edit that the gate refuses, in a window PR #27137 opens. Contract review 6463995320 on PR #27137 (#26594 PR 2), flag 1. Filed by domain:spec seat 3 · os-support-ai · session session_01WGufzgbJhFoXYsLSe5WSPP. ⛔ Not a claim. No grade: triage sets the lane and the grade (the ui lane is suggested).

What happens. RecordFieldAccessScope (ui/packages/permissions/src/RecordFieldAccessScope.tsx, from PR #27137) asks the record projection once per (object, record id): its effect depends on [!!parent, nested, key] only. The forms it wraps re-read the record in place: useRecordInvalidation moves recordRefetch on a bus change while the form is pristine, and replays a held refetch on recordSaved() after the form's own save (ModalFormBody, SimpleObjectForm). When that re-read moves the row into the state a field permission when names, the earlier editable stands, so the form draws the newly locked field enabled and the server refuses the save. This is the opposite polarity of #26594's symptom, and it did not exist under the row-blind lock.

Where it shows. A form that stays mounted and filled after a save: an SDUI view:form, or ScreenView's form with no onSuccess. Also a pristine dialog whose record the bus re-reads after a same-tab write. The console's own paths close or navigate on success (AppContent keys the dialog by record id; RecordFormPage passes handleSuccess), so the window is narrow there. The server stays the boundary: nothing is written that the gate refuses.

Expected. The scope re-asks when the record is re-read, for example by taking the form's recordRefetch nonce or the loaded record snapshot into its key, or by clearing the held answer on recordSaved() so the row-blind lock stands until the new answer lands. Pin it with one more leg in recordFieldAccess-26594.test.tsx: save a draft into approved on a mounted form, and the conditioned field is locked after the re-read.

Dedupe. search_issues on this repo (open): "stale projection refetch record form editable" returned nothing; "RecordFieldAccessScope OR "field-access" OR "row-blind"" returned #26594 (the source), #27075 (ADR note) and #27138 (row write scope), none on this window. New.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 · 2026-10-28T08:37Z
    Session: session_01WGufzgbJhFoXYsLSe5WSPP
    Account: os-support-ai
    Branch: claude/project-thread-dyw8uu (the #26594 card thread; this card is fixed in that PR, #27137 round 2, head 6ad9e982)
    Worktree: objectstack-issue-26594
    Domain: domain:spec
    Seat: domain:spec#3
    Ruling-ref: 6457467702 (letter B on #26594: the server's record projection, never a client when evaluator); this card is the stale-answer window that PR's scope opened (contract review 6463995320, flag 1)
    File surface: ui/packages/permissions/src/RecordFieldAccessScope.tsx, ui/packages/plugin-form/src/recordFieldAccess.tsx, their two 26594 test files, the @object-ui/permissions and @object-ui/plugin-form changesets — all inside #27137's existing surface (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: TIER_DEFAULT — --tier: no path-derived mandate (ui fix folded into #27137; its CONTRACT_REVIEW_TIER round-2 review covers it), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the #26594 card thread, folded into PR #27137 so the window lands closed with the scope that opens it
    Thread-read: 6463995320
    Premise: holds on PR #27137 head 90f1ea4d: the scope's effect depends on [!!parent, nested, key] only, while the wrapped form re-reads the record in place (useRecordInvalidation)
    Serial constraints cleared: only #27137 touches these files

  2. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #27137 comment 6464763665

  3. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Triage: lane domain:ui · p2 · area:access · 2026-10-28T09:02Z

    ⛔ Not a claim.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed (folded into PR #27137, round 2) · domain:spec seat 3 · os-support-ai · 2026-10-28T09:11Z

    reading value
    PR #27137 (PR 2) merged through the queue at 2026-10-28T09:09Z, merge commit 6866e2e7c5
    origin/main 6866e2e7 contains both merge commits (git merge-base --is-ancestor)

    Delivered (ruling B, 6457467702): the console's edit dialog, edit page and drawer form now read the record-scoped field projection. A when-conditioned lock disables a field only on rows the condition names. The projection is asked again when the form re-reads the record (#27147). Until the answer lands, and when there is none, the row-blind lock stands. The client never evaluates when.

    Follow-ups, each filed on its own card: #27146 (record detail page inline edit still row-blind), #27138 (the dialog never asks whether the row itself is writable), #27075 (ADR-0066 note, Tier H). pm:dispatched is removed here and on #27147.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:uipriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions