Skip to content

Every record-detail open costs two separate /api/v1/security/explain round trips, where the grid's sibling hook batches #8014

Description

@baozhoutao

Filed unassigned by the domain:devx @ objectui execution seat while converting batch 2 of objectui#7307 (PR #8013). No domain:*, type or grade set — triage's to produce. This is an OBSERVATION, not a defect report: nothing is broken, no assertion is wrong, and objectui#7307 needed none of it. It is recorded because it was measured rather than guessed, and the measurement is cheap to lose.

What was measured

A stack probe on the network-escape guard's attribution point, run over the four batch-2 files, attributed every escaped request. packages/plugin-detail/src/DetailView.tsx calls useRecordEditable twice:

DetailView.tsx:290   const canEditRecord   = useRecordEditable(..., 'edit' ...)
DetailView.tsx:296   const canDeleteRecord = useRecordEditable(..., 'delete' ...)

Each call owns its own effect and its own verdictCache key, so each issues its own POST /api/v1/security/explain. Counted in the guard's attribution lines before the fix, the ratio is exactly 2 requests per drawer open in every one of the four files (3 opens gave 6 lines, 6 opens gave 12, 2 opens gave 4, 2 opens gave 4).

Why it is worth writing down

The route already supports the batched form. packages/plugin-grid/src/hooks/useRecordCrudVerdicts.ts posts recordIds and reads decision.records, one request for a whole page of rows; useRecordEditable posts a single recordId and reads decision.record.visible, one request per operation. So the detail header pays two serial round trips for two verdicts on the SAME record, on a route whose batched shape exists and is exercised elsewhere in this repo.

Both hooks fail open and both memoise, so the user-visible cost is limited to the first open of each record: two requests instead of one, and two chances for a slow or refused verdict rather than one.

What this is NOT

  • Not a correctness problem. Both verdicts are read independently and both are correct.
  • Not caused by, and not fixed by, objectui#7307's doubles — the double answers both shapes, so the conversion is neutral to whatever is decided here.
  • Not the same finding as objectui#7996, which is about a landed double answering a key that neither hook reads. This one is about the product code's request shape, not about a test's stub.

Whether the two-operation lookup should fold into one batched request (a operations array, or the existing recordIds form used twice-in-one) is a design question for whoever owns the explain contract; it may well be deliberate, since the two verdicts have different cache lifetimes.

Duplicate check before filing: a semantic search over this repo's issues for this shape returned only closed cards (objectui#6332, objectui#4296, objectui#4302), none of which covers the request count; a control query in the same session returned objectui#7307 and objectui#7765, so the empty read is a real read and not a broken search.

Refs: objectui#7307 (the burn-down that measured it) · PR #8013 (batch 2) · objectui#7996 (the sibling finding, different subject).

Attribution, in prose because an issue body's footer block does not survive creation: generated by Claude Code, session session_01MM7kaS4dPpYHV5BsMyu4tQ.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions