Repository navigation
Commit 7525045
fix(plugin-detail,plugin-gantt,plugin-grid,plugin-form,app-shell): leg A of the write census reads the affordance-to-grant map (objectui#12082) (#12132)
Part of #12082 (leg A of the write-census backlog; the backlog freeze
and leg B stay on the card)
Clause-②: no
`domain:ui` seat 2 dispatch, claim `6106206228`, implementation session
`session_01TYgwmFK1q4KJ6Qq2WRLzsD` (subagent mode: the seat's id). The
card stays open: this round converts leg A only, per the claim's
sequencing call.
## What lands
Ten `unmapped` entries of the write census (`WRITE_SITES` in
`packages/plugin-form/src/affordanceGrantMap-12082.test.tsx`) become
`mapped`, each read where its affordance is offered. **No row is added
to `AFFORDANCE_GRANTS`**: every site reuses the row of the same verb on
the same object, and the row comments now name the new affordances. So
`@object-ui/core` is `patch` (comment-only source change).
| Census entry (site) | Row | Read in | How a closed row withholds it |
|---|---|---|---|
| calendar, kanban, gantt `renderRecordOverlay` update (3) |
`recordEdit` | `plugin-detail` `RecordDetailPanel` | no inline-edit
session: `canEdit`, `inlineEdit` and the save bar all see no handler |
| gantt `handleTaskUpdateDefault` (bar drag / resize / progress,
in-place title) | `rowEdit` | `plugin-gantt` `ObjectGantt` |
`onTaskUpdate` withheld from `GanttView` |
| gantt `persistDependencies` (link create / delete) | `rowEdit` |
`ObjectGantt` | `onDependencyCreate` / `onDependencyDelete` withheld |
| gantt `confirmDelete` (row Delete) | `rowDelete` | `ObjectGantt` |
`onTaskDelete` withheld |
| grid `useBulkExecutor` per-row / undo / retry update (3) | `rowEdit` |
`plugin-grid` `ObjectGrid` | a `bulkActionDefs` `update` def is filtered
from the bar, as a `delete` def already was on `rowDelete`; no dialog,
so no undo or retry |
| `MasterDetailForm` `sendBatch` | `relatedNew` / `relatedRowDelete` on
the child (+ the form rows for the header) | `MasterDetailForm` (+
`fieldWriteGate`) | the line grid's `allowAdd` / `allowDelete` |
The riders triage placed with leg A:
- **Line items, `childSchema`:** `LineItemsPanel` hands the child schema
it already loads (for the save's sanitize) to `relatedNew` /
`relatedRowDelete`, so the child's own policy (`managedBy`,
`userActions`) is read, as `RelatedRecordActionsBridge` does.
- **`ExcelImportBar`:** reads `listImport` of the picked object; Import
is disabled when the row is closed, and picking another object asks
again.
`GanttView.tsx`, `useBulkExecutor.ts`, `resolveBulkActions.ts`,
`BulkActionDialog.tsx` and the three overlay hosts are not edited: each
affordance is already drawn from handler or def presence, so the gate
sits where the handler is handed over.
## Measured on main first
Each runtime pin was written against BASE source and is the defect
direction when red. Recorded run (restore-trapped script, commit
`9e3748a`): the seven source files checked out at BASE `29b99490` blobs
(7/7 hashes equal on disk, each fix anchor counted 0), then the six
runtime pins and the census:
`Test Files 7 failed (7)` · `Tests 28 failed | 73 passed (101)`; restore
proven: `7/7 blobs == HEAD (9e3748a), git diff HEAD empty`.
| Pin | red on BASE | what was red | stayed green on BASE (controls) |
|---|---|---|---|
| `plugin-detail` `RecordDetailPanel.editGrant-12082` | 4 / 9 |
create-only and read-only shapes (with an `editable: true` field entry),
an operation set without `update`, `userActions.edit: false` |
edit-only, full, fail-open, the plain read-only shape (see H6) |
| `plugin-gantt` `ObjectGantt.writeGrant-12082` | 7 / 11 | every shape
lacking update or delete, the operation set, the policy | edit-only
update, full, fail-open |
| `plugin-grid` `bulkUpdateGrant-12082` | 4 / 7 | create-only,
read-only, the operation set, the policy | edit-only, full, fail-open |
| `plugin-form` `MasterDetailForm.lineGrant-12082` | 6 / 11 | edit form:
create-only (remove), edit-only, read-only; create form: edit-only,
read-only (entry row present); the operation set | full, create-only
create form, fail-open, the H4 measurement |
| `plugin-form` `LineItemsPanel.lineGrant-12082` | 1 / 8 | the
child-policy rider | the round-1 cases, the rider's control |
| `app-shell` `ExcelImportBar.importGrant-12082` | 4 / 7 | edit-only,
read-only, the operation set, the picked-object case | create-only,
full, fail-open |
| census `affordanceGrantMap-12082` | 2 / 48 | "every mapped site names
rows … read by one of the files it names" (16 problems), the overlay
one-seam pin | the rest |
### The PM's hypotheses, as measured
- **H1 holds.** All three hosts reach the overlay's inline edit through
`RecordDetailPanel`'s `onFieldSave`, and `recordEdit` is the row the
record page reads for the same in-place edit. The grid and tree overlays
hand no `onFieldSave` (read-only by design) and are unchanged.
- **H6, overlay, partly already closed.** Since objectui#12117 each
field asks the row's field question, so the plain read-only shape (no
field entry, `allowEdit: false`) was already withheld on BASE (the
CONTROL case is green on BASE). The site still reproduced through the
three object-level layers the field question does not ask: a permission
set naming a field `editable: true` under an object grant without
`allowEdit`, an effective operation set without `update`, and an object
policy closing edit. Those are what the `recordEdit` read closes.
- **H2:** the gantt needs no internal prop: `GanttView` already draws
every edit affordance (drag, resize, progress, in-place title, link
handles, the Delete item, undo, auto-schedule) from handler presence.
Reused `rowEdit` / `rowDelete` rather than adding gantt rows (Zone 3:
reuse where verb and object match).
- **H3:** the gate sits in `ObjectGrid` where `bulkActionDefs` are
resolved, reading the `rowEditVerdict` already computed there.
objectui#12119 had landed before this branch's base (`29b99490`), so
both intents are in the file. Undo and retry are only reachable from the
dialog of a def the bar drew, so they inherit the verdict.
- **H4, measured.** A create form's batch is `buildMasterDetailBatch`:
the parent create plus one create per line, never a delete. The MEASURED
case adds two lines, removes one, saves, and reads `[sales_order:create,
sales_order_line:create]` with the kept line's value. So remove asks
`relatedRowDelete` on an edit form only; on a create form it stays open
for a create-only caller.
- **H5:** the census keys one site for two mounts, so a new `HOST_GATED`
list holds every console mount of `ImportWizard` (a JSX element of that
name, found by the same TypeScript walk) to the site's `readBy`, and the
existing mapped-site check holds each named file to reading the row.
Ablation A1 below.
### Ablation A1 (the mount census can fail)
`scripts/ablation-replace.mjs` (objectstack) WRAP mode at `9e3748a`,
prediction written first: drop `EXCEL_IMPORT_BAR` from the import wizard
entry's `readBy` → the mount census alone goes red naming
`ExcelImportBar.tsx`. Observed: anchor 1 → 0, blob moved; `Tests 1
failed | 47 passed (48)`, the one failure
"packages/app-shell/src/console/ai/ExcelImportBar.tsx mounts
ImportWizard but is not named by …"; restored `blob == HEAD
(47a5b15)`, `git diff HEAD` empty. As predicted.
## Tests and gates
Runtime pins + census + the re-judged `rowCrudEffectiveOps` fixture at
merged head `5d006eb` (main `0df67f23` merged, see below): `Test Files 8
passed (8)` · `Tests 121 passed (121)`.
At `9e3748a` (before the merge of main): dependency closure built
(`turbo` `Tasks: 28 successful, 28 total`); `pnpm --filter
@object-ui/PKG type-check` for `core`, `plugin-detail`, `plugin-gantt`,
`plugin-grid`, `plugin-form`, `app-shell`: each echoed its own
`type-check` script, exit 0, 0 `error TS` (each package's
`tsconfig.test.json` includes `src/**/*.test.tsx`, so the new pins are
compiled). eslint on the 15 touched `.ts`/`.tsx`: 0 errors, and every
modified file's warning count is equal at BASE and head (JSON counts);
the three new test files carry 2 `no-explicit-any` warnings each.
At `5d006eb`, all exit 0: `check-changeset-presence` (15 source files of
6 released packages, 1 changeset), `check:changeset-claims`,
`check:pending-changeset-literals`, `check-changeset-no-major`,
`check-changeset-overwrite`, `check:new-line-citations` (0 new),
`check:control-bytes`, `check:test-path-roots`,
`check:vi-mock-specifiers` / `-inherit` / `-override-shape`,
`check:phantom-deps`, `check:self-import`, `check:esm-specifiers`,
`check:unreferenced-sources`, `check:handler-key-reads`,
`check:i18n-keys`, `check:doc-fences`, `check:doc-types`,
`check:doc-example-ids`.
Final readings, from the dev's report (`6107630689`), amended into this
body by the seat:
- At `b85ebdf` (the final head, `main` `10713937` merged): the
dependency closure built (`turbo` `Tasks: 29 successful, 29 total`);
`type-check` for `core`, `plugin-detail`, `plugin-gantt`, `plugin-grid`,
`plugin-form` and `app-shell`, each exit 0 with 0 `error TS`; `vitest`
over `packages/plugin-grid/`, every leg-A pin, the census,
`createFormGrant-12082`, `masterDetailDetailsMembers-8071` and the two
repo-wide ratchets: `Test Files 211 passed (211)`, `Tests 2046 passed
(2046)`.
- At `5d006eb` (`main` `0df67f23` merged): `packages/core/`,
`packages/plugin-detail/` and `packages/plugin-gantt/`: `Test Files 549
passed | 2 skipped (551)`, `Tests 7168 passed | 149 skipped`.
`packages/plugin-form/`: 173 of 174 files passed; the 2 failures were
`masterDetailDetailsMembers-8071`, re-judged in `cbbc04e` (see below)
and green at `cbbc04e` and `b85ebdf`. `packages/app-shell/src/console/`,
`scripts/__tests__/` and the column-identity ratchet: `Test Files 313
passed | 2 skipped (315)`.
- Not re-run locally after the second merge of `main` (`10713937`, which
touches `app-shell`, `i18n`, `types` and `plugin-grid`): the `core`,
`plugin-detail`, `plugin-gantt`, `plugin-form` and `app-shell` console
suites. `plugin-grid` was re-run; CI runs the rest.
NOT MEASURED, with reasons: `check:doc-examples` / `check:doc-snippets`
(prerequisite: every package built; the docs edits are prose only, no
code block added or changed); `check:eager-closure` (needs a base and a
head Console build, not run; the source delta is a few conditionals plus
comments across seven modules, left to the Bundle Analysis workflow).
## Merge of main
objectui#12089 (the objectui#7611 epic) landed while this round ran;
`main` `0df67f23` is merged. It added two `unmapped` Setup entries
(`PositionHoldersSection` add / remove, not the three the claim
expected); both are kept byte-for-byte, beside the existing leg-B
entries. The census on the merged tree: 13 `unmapped` entries left, all
leg B (feed 5, Setup 4, dashboard designer 1, related list 3).
A second merge, `main` `10713937`, followed: objectui#12123 also edits
`ObjectGrid.tsx` and `content/docs/plugins/plugin-grid.mdx`. It merged
clean, and both intents are kept.
## Files beyond the claim's surface
- `packages/plugin-grid/src/__tests__/rowCrudEffectiveOps.test.tsx`: its
"drops a bulkActionDefs entry whose operation is delete" case used an
`update` def as the control that stays under a read-only operation set;
that set now withholds the update def too, so the fixture's set became
`['get', 'list', 'update']` (the control still stays, the delete still
drops).
-
`packages/plugin-form/src/__tests__/masterDetailDetailsMembers-8071.test.tsx`:
it pins the exact key set the block hands the grid. `allowAdd` and
`allowDelete`, the map's verdicts, now join it, so the set grows from
six keys to eight (`cbbc04e`). The authored `allowAdd: false` still
reaches nothing.
- `packages/core/README.md`, `packages/plugin-detail/README.md`,
`content/docs/plugins/plugin-form.mdx`, `plugin-gantt.mdx`,
`plugin-grid.mdx` (objectui AGENTS.md #2).
## Acceptance notes
Noted, not filed (no measured reach at a public door, or a pre-existing
limit):
- The gantt's drag and the grid's bulk update read the row's object
verdict only. Neither applies the row's per-record `userActions`
predicates (`visibleWhen` / `disabledWhen`), and neither asks the field
question of the fields it writes (dates, progress, the dependencies
field, the patch keys). The calendar reschedule and the kanban move have
the same two limits (round-1 note). An `editable: false` field is still
refused only by the server.
- `ExcelImportBar` reads `listImport` with the default bucket (it has
not read the target's schema when it offers Import), and its target
fields come from its own `normalizeFields`, not `importTargetFields`, so
they do not ask the field question the list's Import asks.
- `MasterDetailForm`'s line rows read the child's default bucket: a
fully configured entry loads no child schema into render state (the
sanitize cache is a ref by design, objectui#1581).
- On an edit form, `allowDelete` is whole-grid, so a caller without the
child delete grant cannot remove a just-added, unsaved line either (the
same `GridField` limit round 1 noted for `LineItemsPanel`).
- `HOST_GATED` is hand-written: a host-gated write component that is not
listed there is not seen by the mount census.
- A `value`-provider gantt that also names an `objectName` asks that
object's grant, as the calendar and kanban rows do.
## Overlap with in-flight work
- objectui#12089: landed and merged in (above).
- objectui#12119: landed before this branch's base; `ObjectGrid.tsx`
carries both.
- objectui#12123: landed; merged in with `main` `10713937` (above).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01TYgwmFK1q4KJ6Qq2WRLzsD)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 1071393 commit 7525045
22 files changed
Lines changed: 1146 additions & 68 deletions
File tree
- .changeset
- content/docs/plugins
- packages
- app-shell/src/console/ai
- __tests__
- core
- src/utils
- plugin-detail
- src
- __tests__
- plugin-form/src
- __tests__
- plugin-gantt/src
- plugin-grid/src
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
474 | 474 | | |
475 | 475 | | |
476 | 476 | | |
477 | | - | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
478 | 485 | | |
479 | 486 | | |
480 | 487 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
39 | 47 | | |
40 | 48 | | |
41 | 49 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
608 | 608 | | |
609 | 609 | | |
610 | 610 | | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
611 | 620 | | |
612 | 621 | | |
613 | 622 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
15 | 20 | | |
16 | 21 | | |
17 | 22 | | |
| |||
27 | 32 | | |
28 | 33 | | |
29 | 34 | | |
| 35 | + | |
| 36 | + | |
30 | 37 | | |
31 | 38 | | |
32 | 39 | | |
| |||
133 | 140 | | |
134 | 141 | | |
135 | 142 | | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
136 | 154 | | |
137 | 155 | | |
138 | 156 | | |
| |||
162 | 180 | | |
163 | 181 | | |
164 | 182 | | |
165 | | - | |
| 183 | + | |
166 | 184 | | |
167 | 185 | | |
168 | 186 | | |
| |||
215 | 233 | | |
216 | 234 | | |
217 | 235 | | |
218 | | - | |
| 236 | + | |
219 | 237 | | |
220 | 238 | | |
221 | 239 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
224 | 224 | | |
225 | 225 | | |
226 | 226 | | |
227 | | - | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
228 | 232 | | |
229 | 233 | | |
230 | | - | |
| 234 | + | |
| 235 | + | |
231 | 236 | | |
232 | 237 | | |
233 | 238 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
133 | 133 | | |
134 | 134 | | |
135 | 135 | | |
136 | | - | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
137 | 139 | | |
138 | 140 | | |
139 | 141 | | |
| |||
143 | 145 | | |
144 | 146 | | |
145 | 147 | | |
146 | | - | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
147 | 154 | | |
148 | 155 | | |
149 | 156 | | |
150 | 157 | | |
151 | 158 | | |
152 | 159 | | |
153 | 160 | | |
154 | | - | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
155 | 167 | | |
156 | | - | |
| 168 | + | |
157 | 169 | | |
158 | 170 | | |
159 | 171 | | |
160 | 172 | | |
161 | 173 | | |
162 | | - | |
163 | | - | |
| 174 | + | |
| 175 | + | |
164 | 176 | | |
165 | 177 | | |
166 | 178 | | |
167 | 179 | | |
168 | 180 | | |
169 | 181 | | |
170 | | - | |
| 182 | + | |
| 183 | + | |
171 | 184 | | |
172 | 185 | | |
173 | 186 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
363 | 363 | | |
364 | 364 | | |
365 | 365 | | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
366 | 375 | | |
367 | 376 | | |
368 | 377 | | |
| |||
0 commit comments