Skip to content

list-view: the spec's new ComponentPropsMap row judges list-view — measure its 38 unpublished spec keys against ListViewBlock, publish the ones it honours, and strike the OWED rows objectui#12971 books #13047

Closed

Description

@objectstack-fleet

Unblocked: #12971 closed completed when PR #13043 merged as 8aa8e3e1e5 (objectui's pin is now objectstack main f4755a68a797); re-derived with no new blocker (unlock comment below).

Filing gate: an owner card under an existing ruling. objectui#11111 decision 3 = B (ruling 5902351047, maintainer 「11111 同意」) says: when a pin bump surfaces keys the spec newly judges, the bump books every difference to an owner card, and the owner card declares them. This is that owner card for list-view, surfaced by objectui#12971 (PR #13043). Filed by domain:ui seat 1 (session_0188TsgPV8kQXfuRuKmkj2ks). ⛔ Not a claim.

Measured (objectui#12971's dev report, PR #13043)

  • objectstack#22444 (194a42d1f7) adds a list-view row to the spec's ComponentPropsMap, so registry-inputs-spec-parity now judges list-view.
  • The registry's list-view publishes 6 inputs: data, type, columns, filter, sort, options.
  • 38 live spec keys are unpublished (among them name, label, searchableFields, pagination, kanban, calendar, rowActions, emptyState), and 6 member pins are owed: list-view.data, columns, filter, sort, options, dataSource.
  • PR chore(deps): build @objectstack/* from objectstack main 2ec6827962 and follow its contract (objectui#12971) #13043 books each difference as OWED to this card, with an expiry. ⛔ It declares nothing.

Done when

  1. Each of the 38 keys is measured against ListViewBlock / ListView: does the renderer honour it, with a test that draws it, or not?
  2. Each honoured key is published in list-view's inputs. A key the renderer does not honour stays unpublished, and is named with that reason, or carded as a renderer gap.
  3. The 6 member pins are written.
  4. Every OWED row PR chore(deps): build @objectstack/* from objectstack main 2ec6827962 and follow its contract (objectui#12971) #13043 booked for list-view is struck, and the parity caps are restored.
  5. ⛔ No key is published without a measured renderer (decision 3 = B, and objectui#11536's shape).

Generated by Claude Code

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobs
    on Oct 19, 2026
  2. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p1 (target:v18 kept) · domain:ui · area:api · pm:blocked (on #12971) · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-19T12:56Z

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlock: pm:blocked → pm:queue · domain:ui seat 1 · session_0188TsgPV8kQXfuRuKmkj2ks · 2026-10-19T14:36Z

    ⛔ Not a claim.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 14 (priority:p1, target:v18)
    Session: session_01XVp19E1MYUTFM3dnkwz8gB
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-13047-list-view-spec-inputs
    Worktree: objectui-issue-13047
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/plugin-list/src/index.tsx (the list-view registration's inputs), packages/plugin-list/src/ListViewBlock.tsx / ListView.tsx (read to measure; edited only where a key is honoured but needs a drawing test), apps/console/src/__tests__/registry-inputs-spec-parity.test.ts (strike the list-view OWED rows, restore the caps, write the 6 member pins), tests beside them, and one .changeset/13047-list-view-spec-inputs.md (@object-ui/plugin-list minor). ⛔ No key published without a measured renderer (objectui#11111 decision 3 = B). A renderer gap is carded, not built here. Stop on breach; explain in the report.
    Container & model: M, mode:subagent, model: opus (default tier; dispatch-gates --tier over this surface reads no path-derived mandate; the Clause-② contract review runs at the review tier)
    Clause-②: yes (list-view publishes the spec keys its renderer is measured to honour)
    Responsibility: n/a — not a defect card (the owner card under objectui#11111 decision 3 = B for PR #13043's list-view OWED rows)
    Thread-read: 6269812594
    Serial constraints cleared: objectui#12932 landed as c219165 (its serial predecessor on the parity test). No open objectui PR touches plugin-list's registration.
    Claimed at: 2026-10-19T17:36Z


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 13047,
    "status": "done",
    "branch": "claude/issue-13047-list-view-spec-inputs",
    "pr": "#13072",
    "session": "session_01XVp19E1MYUTFM3dnkwz8gB",
    "premise_still_valid": true,
    "summary": "Measured all 38 unpublished keys of the spec's list-view row on a page node. Each key was authored in properties and rendered through the real SchemaRenderer and the real list-view registration, with a control per row and every fixture parsed by the spec row first. 33 keys are honoured and are now published in one shared LIST_VIEW_INPUTS list, used by both list-view and the view:list alias. The other 5 are recorded in the parity gate as unpublished by measurement: name and requiredPermissions are read by nothing on a page node; sharing and addRecord each draw a button that does nothing there; filterableFields is read as the Filter panel's field list, not as the userFilters.fields shorthand the row declares. The OWED rows are struck: 38 unpublished plus 6 member pins. Caps restored: unpublishedKeys 0, memberPins 0, per-owner total 0, MEMBER_PIN_EXEMPTION_CEILING 0. 33 list-view member pins are registered, the 6 booked ones among them. One honest limit: child views are stand-ins, the package convention, because the view packages are not dependencies of plugin-list. So grid and per-kind keys are measured at the node ListView hands the drawing view. appearance.allowedVisualizations is inert on a page node because no view switcher is drawn there. It is published with the key, since showDescription acts, and the description says so.",
    "tests": "All at 215edf5, through os-verify-lock with --maxWorkers=1. New ListViewBlock.specInputs-13047.test.tsx: 49 passed. registry-inputs-spec-parity.test.ts: 260 passed. plugin-list family, the 12 files importing the registration: 130 passed. Console registry/manifest family, 8 files: 443 passed. app-shell block-config/page-blocks, 3 files: 68 passed. sdui-parser, 3 files: 130 passed. type-check exit 0 for plugin-list (tsc + tsconfig.test.json; --listFilesOnly counts the new test as 1) and for console, each after a turbo build of its dependency closure. eslint --no-inline-config on the 3 changed source files: 0 errors and 3 pre-existing warnings. Lint narrowing proof: (1) the population is read from eslint itself, isPathIgnored=false for all 3 files under the one root eslint.config.js; (2) --format json reports 3 files; (3) the root config enables no type-aware linting, so the change cannot move a verdict on an untouched file. Ablation: ablation-replace.mjs deleted allowPrinting's input line (anchor 1 to 0, blob 2ed1ea1932b1 to 780b8c1b9265). The parity file went red on exactly 1 test: 'list-view publishes every top-level key its spec props schema declares', expected [ 'allowPrinting' ] to deeply equal []. Restore was proved by blob hash: hash-object = HEAD blob = 2ed1ea1932b1, and git diff HEAD is empty. The console alias resolves plugin-list to src, so no build was needed.",
    "mcp_calls": "0",
    "api_writes": "2 relay writes. (1) fleet-write dispatch pr_create (POST /repos/objectstack-ai/objectui/pulls draft, then POST /repos//issues/13072/assignees); read-back: body identical (7154 bytes), assignee baozhoutao. (2) post-stamped os-dev-report comment, POST /repos//issues/13047/comments. Plus 2 branch pushes (git, not REST). 0 label writes: the dispatch named none, and objectui labels are path-driven.",
    "gates": {
    "vitest ListViewBlock.specInputs-13047 (new)": 0,
    "vitest registry-inputs-spec-parity": 0,
    "vitest plugin-list family (12 files)": 0,
    "vitest console family (8 files)": 0,
    "vitest app-shell family (3 files)": 0,
    "vitest sdui-parser family (3 files)": 0,
    "type-check @object-ui/plugin-list": 0,
    "type-check @object-ui/console": 0,
    "eslint changed files": 0,
    "check:phantom-deps": 0,
    "check:self-import": 0,
    "check:unreferenced-sources": 0,
    "check:doc-example-readers": 0,
    "check:handler-key-reads": 0,
    "check:side-effects-array": 0,
    "check:element-data-source-declaration": 0,
    "check:spec-symbols": 0,
    "check:action-forward-parity": 0,
    "check:designer-field-key-parity": 0,
    "check:icon-record-names": 0,
    "check:i18n-keys": 0,
    "check:i18n-drift": 0,
    "check:i18n-designer-parity": 0,
    "check:control-bytes": 0,
    "check-hand-rolled-comment-mask.mjs": 0,
    "check-changeset-fixed.mjs": 0,
    "check-changeset-presence.mjs": 0,
    "check:spec-floors": "1 (no-artifact: needs a whole-workspace build; recorded, not fixed, as the dispatch said)",
    "full packages/plugin-list and apps/console dirs": "NOT MEASURED: declared to CI (the dispatch says no whole-package-directory runs)",
    "pnpm lint (repo-wide)": "NOT MEASURED: CI-owned; narrowed run above"
    },
    "files_changed": [
    ".changeset/13047-list-view-spec-inputs.md",
    "apps/console/src/tests/registry-inputs-spec-parity.test.ts",
    "packages/plugin-list/src/tests/ListViewBlock.specInputs-13047.test.tsx",
    "packages/plugin-list/src/index.tsx"
    ],
    "line_budget": "n/a (no skills/** or governed surface touched)",
    "deviations": [
    "The dispatch contradicts itself on package dirs. Gates says to run each touched package's dir under the lock; Lock says no whole-package-directory runs and to declare them to CI. I followed Lock and declared plugin-list and console to CI.",
    "The view:list alias registration in the same file now publishes the same list. It is the same renderer, and its comment said 'same spelling and same reason as list-view'. Both registrations were already in index.tsx, the claimed surface."
    ],
    "open_questions": [
    {
    "question": "filterableFields: the spec row declares it as the 'legacy shorthand for userFilters.fields' (quick filters). The renderer draws no quick-filter bar from it and reads it as the Filter panel's field whitelist. Which meaning stands?",
    "options": [
    "A: amend the spec description to the Filter-panel whitelist the renderer reads, then publish the key.",
    "B: make the renderer honour it as userFilters.fields shorthand, then publish it. That is a second spelling of userFilters.fields.",
    "C: retire filterableFields in the spec (ADR-0049, ADR-0087 conversion), with no window. The Filter-panel whitelist, if wanted, gets its own declared key."
    ],
    "recommendation": "C, on the four axes. Business need: no measured author or producer of it was found in this card (not measured further). Long-term: the spec itself calls it legacy. AI-error: two meanings for one key is the trap 'declared means enforced' exists to stop. Startup focus: an alias is retired at once, not staged. A is the fallback if the maintainer wants the whitelist kept."
    }
    ],
    "out_of_scope_findings": [
    "renderer gap (dispatch: card for the seat) · requiredPermissions on a page list-view node: the record blocks gate on it (insufficient-permissions notice) and ListViewBlock/ListView read nothing, so a capability nobody holds still draws and queries the list · reach: page list-view node through SchemaRenderer, measured in ListViewBlock.specInputs-13047.test.tsx · Seam: spec:ListViewSchema.requiredPermissions → renderer:ListViewBlock (consumer: none on the page path) · dedupe words: list-view requiredPermissions gate, page list-view capability, ADR-0066 list-view block",
    "renderer gap (dispatch: card for the seat) · addRecord on a page list-view node: the Add button calls the host prop onAddRecord, which a page node never receives, so the click does nothing · reach: page list-view node through SchemaRenderer, measured (click changes nothing, no create) · Seam: spec:ListViewSchema.addRecord → renderer:ListView add-record-button (props.onAddRecord) · dedupe words: list-view addRecord page, onAddRecord host, add record button no-op",
    "class: b · reach: page list-view node through SchemaRenderer, measured: filterableFields ['stage'] draws no quick-filter bar · the spec says 'Legacy shorthand for userFilters.fields'; ListView reads it as the Filter panel whitelist (filterFields memo) · Seam: spec:ListViewSchema.filterableFields → renderer:ListView filterFields · see open_questions[0] · dedupe words: filterableFields userFilters shorthand, filter panel whitelist, list-view filterableFields",
    "carrier: 承接者:无 · sharing.type draws a Share button with no onClick wherever ListView renders (object list page included). It was measured inert on a page node only; the console object-list door was not measured. Noted in the PR Acceptance notes, not filed.",
    "carrier: 承接者:无 · appearance.allowedVisualizations is inert on a page list-view node: the switcher is gated on the host prop showViewSwitcher, which no row key sets. Published with the key (showDescription acts), and the description says so. Noted, not filed."
    ]
    }

  6. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Contract review

    Served-tier: CONTRACT_REVIEW_TIER
    Head-sha: 215edf59d57f8922c8fad4e9f9c705f44dd4e25e
    Local-runs: none

    Inputs read: card #13047 body and all 4 comments (triage, unlock, claim, os-dev-report), PR #13072 body, its 4-file list, the full net diff against main (1460 lines, read end to end), and the 35 check-runs on the head. No build, no test, no checkout.

    Check-runs on the head at review time. Completed success: Lint, Build Docs, Build & E2E, Test (dist pins), Bundle Analysis, Live E2E (informational), Changeset Declaration, Changeset Claim Re-read, Changeset Fixed Group Check, Changeset Bump Policy, Changeset Overwrite Report, Governed Surface Queue Guard, Line Citation Gate, label. Skipped: dependabot, Test (coverage), Test (coverage shard). Still in_progress: all 16 Test shards, Type Check, Repo Gates. So the derived gate families that would run registry-inputs-spec-parity.test.ts and the new ListViewBlock.specInputs-13047.test.tsx have NOT reported yet; the only evidence for them is the dev's local claim (260 and 49 passed, with the allowPrinting ablation reddening exactly one parity test). This record does not wait on them.

    ① Derived judgments

    Accept-set / public-surface changes the diff implies

    1. list-view registration inputs: 6 to 39 entries (the 6 kept, 33 added) via one shared LIST_VIEW_INPUTS, cloned per registration. Right as a widening: every added name is a key of the spec's list-view ComponentPropsMap row (the fixture guard node() parses each authored bag through ComponentPropsMap['list-view'].safeParse, and its CONTROL proves an undeclared key is refused). No reader, prop, export or type is added; nothing changes at render time.
    2. view:list alias (the register('list', ...) with namespace: 'view') publishes the same LIST_VIEW_INPUTS. Right: same renderer (ListViewRenderer), same page spelling; the old comment already said "same spelling and same reason as list-view". Publishing a narrower list on the alias would have been the wrong state.
    3. The 5 unpublished keys (name, requiredPermissions, sharing, addRecord, filterableFields) moved from OWED rows to UNPUBLISHED_EXEMPTIONS entries each starting Unpublished by measurement (objectui#13047): with the measured reason and what the renderer does instead. Right in substance; each has a measuring test in the last describe block (name with a full equality control on query, DOM text and handed grid node; sharing and addRecord with a click that changes nothing and no create; filterableFields with both the no-quick-filter-bar assertion and the Filter-panel-whitelist reading). Whether the string form matches the map header's documented "by measurement" bar is only visible in the unchanged part of the parity file, which the in-progress Repo Gates / Test shards judge, not this record.
    4. Caps: unpublishedKeys 38 to 0, memberPins 6 to 0, per-owner objectui#13047 44 to 0, MEMBER_PIN_EXEMPTION_CEILING 6 to 0. Honest: the caps count entries whose reason starts with OWED_PREFIX (OWED TO ); the five by-measurement entries do not carry it, so 0 is the ledger's own arithmetic, not a relabelling. The OWED_TO / owedEntries helpers are deleted with their last callers and the comment says a future bump writes them back. owedIdsOf and objectui11111OwnerOf are kept.
    5. MEMBER_PINS gains exactly 33 list-view.* entries (counted in the diff): the 6 booked (data, columns, filter, sort, options in the new file; dataSource in the pre-existing ListView.elementDataSource.test.tsx) plus one for every structured key published (label/description string-or-object, the 8 kind blocks, the grid's array/object keys, appearance, emptyState, exportOptions, grouping, navigation, pagination, rowColor, selection, userActions, userFilters). The pins are real in the sense that each names a measurement that exists as a test in the diff. ⚠ The diff does not show the new file being added to the parity gate's lazy ?raw loader list ("Every test file a member pin can live in"); either that list is glob-driven or the dev's 260-pass run already covers it. Not determinable from the inputs; the in-progress shards decide it.
    6. Changeset @object-ui/plugin-list minor: see ②.

    Is every one of the 33 published keys backed by a test that authors it on a page node, renders through the real registration and SchemaRenderer, and shows it acting with a control?

    Tallied against the 49 it( rows: all 33 keys have a row (12 toolbar/chrome, 13 grid, 8 kind blocks; data/columns/filter/sort/options rows cover the booked pins). Every row mounts through SchemaRendererProvider + SchemaRenderer with the node in { type: 'list-view', properties } form and the real ../index import. Rows with a true absent-key control: description, appearance.showDescription, userActions, compactToolbar, allowPrinting, showRecordCount, emptyState, userFilters, exportOptions, label, pagination, searchableFields, data (value provider queries nothing), filter, resizable, selection, rowHeight, grouping (two rows), rowColor, hiddenFields, fieldOrder, rowActions, bulkActions, bulkActionDefs, conditionalFormatting, inlineEdit, navigation, kanban (its CONTROL row), calendar, gantt, gallery, timeline, map, tree. Rows without an absent-key control but whose asserted value cannot arise from anything but the authored key: columns (BASE's amount must vanish from $select), sort (amount desc, name asc), chart (task_metrics). Those three are acceptable as proofs of honour.

    One row proves acceptance, not honour: options. The row authors options: { kanban: { groupByField: 'stage', columns: ['name'] } } and asserts the handed object-kanban node has groupBy === 'stage'. stage is the fixture's only select field. The package's own kanban CONTROL row (type: 'kanban' with no block) says the list "lanes the board on a field the list derives" and asserts only groupBy !== 'owner', which is exactly why the kanban row uses owner. The options row did not take that precaution: if the derived default is the first select field, the assertion passes with options ignored entirely, and nothing in the file excludes that. The options pin registered in MEMBER_PINS ("lanes the board the same way the top-level kanban block does") therefore rests on a test that cannot fail for the reason it claims to guard. options was already published before this PR, so no key is newly published on it, but the pin is one of the six the bump booked to this card (Done-when #3) and it is written as a measurement it is not. Fix is one value: author groupByField: 'owner' (or any non-select field) in the options row so the existing CONTROL distinguishes it, or add an explicit control asserting the bare node's derived groupBy differs from the authored one.

    appearance.allowedVisualizations. The published key is appearance; the renderer is measured to honour its showDescription member (control: description drawn without, hidden with false). allowedVisualizations is measured inert on a page node (an authored kanban still draws under allowedVisualizations: ['grid'], no grid node handed), and the inertness is stated in the registration description, the changeset, the pin text and the test header rather than hidden. Decision 3 = B is a key-level rule ("no key is published without a measured renderer"); the key has one. Acceptable, with the sub-key called out here so the seat can decide whether it wants a spec-side note (the spec row describes a member a page node cannot act on) rather than only an objectui description. Not a FAIL ground.

    Stand-in boundary. Child views are replaced by stand-ins recording props.schema and props.data, because plugin-grid, plugin-kanban etc. are not dependencies of plugin-list. For the grid's row keys and the kind blocks the measurement is the hand-off to the node of the view that draws it. Sound as a measurement of what ListView honours (the page-path translation, e.g. bulkActions to batchActions, kanban.groupByField to groupBy, kanban.columns to cardFields, gallery.coverField into the nested gallery config, timeline.startDateField both flat and nested), provided the drawing side is pinned in the child's package; each such pin text names that pin (object-grid.rowActions, object-grid.bulkActionDefs, object-grid.conditionalFormatting, object-grid.rowColor, object-grid.bulkActions). Whether those object-grid.* pins exist by those names is in the unchanged part of the parity file and is not verified here. One consequence to note: a key that reaches the grid node but which the grid then drops would still read as honoured in this file; that is the accepted shape of the package convention, not a defect of this PR.

    The 5 unpublished keys are each held out with a measured reason, in the form the PR, the test header and the registration comment all agree on; requiredPermissions and addRecord are additionally named as renderer gaps for the seat to card. Right.

    Alias publishes the identical cloned list. Right.

    Caps and the 33 pins: honest and real, with the one options pin weakness above and the loader-list question deferred to the in-progress shards.

    Minor, non-blocking: several descriptions assert members the file does not measure (userActions "hideFields and rowColor are off unless true", label "the title of the compact list in a narrow page region", description "a map with no usable entry draws nothing"). They are descriptions of the spec shape, not pins, and the pin texts name only what is measured; noted so the seat does not read them as measured.

    ② Semver level

    .changeset/13047-list-view-spec-inputs.md declares @object-ui/plugin-list minor. The diff widens a published surface (the registration's inputs, read by the page compile and the parity gate) with 33 additive entries and changes nothing at render time: an additive public-surface widening is minor under AGENTS.md (features and even objectui-internal breaking changes are minor; major is reserved for the objectstack cross-major sync and is mechanically refused by check-changeset-no-major.mjs). apps/console is in the fixed group and its changed file is a test, so no second changeset is owed under check-changeset-presence.mjs. Changeset Declaration, Bump Policy, Fixed Group Check, Claim Re-read and Overwrite Report all success on the head. The changeset body carries no model identifier. minor is right. Clause-②: yes is right: the PR publishes a contract (the spec keys list-view is measured to honour) and the review tier was served.

    ③ Boundary flags

    Dev deviations:

    • "The dispatch contradicts itself on package dirs; followed Lock and declared plugin-list and console to CI." Answered: the full-directory runs are exactly what the in-progress Test shards are; nothing for this record to re-run (read-only), and the declaration is honest in the report's gates.
    • "The view:list alias now publishes the same list." Answered, right (① item 2); same file, same renderer, inside the claimed surface.

    Dev open_questions[0] (filterableFields: spec says legacy shorthand of userFilters.fields, renderer reads it as the Filter panel whitelist; A amend spec, B make renderer honour shorthand, C retire): escalated to the seat, not answered here. It is a spec-versus-renderer contract decision outside this card's surface (A and C are objectstack spec changes; B is a second spelling of userFilters.fields). The PR's state is correct under every option: the key stays unpublished with its reason recorded, and no code path changes. Reviewer's view for the seat: C (retire under ADR-0049, with the whitelist re-declared under its own key if wanted) matches "declared means enforced" best; A is the cheap fallback. Whichever lands, the UNPUBLISHED_EXEMPTIONS entry must be struck in that act.

    Dev out_of_scope_findings: the requiredPermissions and addRecord renderer gaps are for the seat to card (not built here, per the dispatch, and rightly so under decision 3 = B); sharing on the console object-list door is unmeasured and noted, not filed; appearance.allowedVisualizations handled in ① above. Nothing further to escalate.

    Reviewer's own flags:

    • options pin (① above): the one correction this record requires before the head can PASS.
    • The loader-list registration of ListViewBlock.specInputs-13047.test.tsx in the parity gate is not visible in the diff; the in-progress shards will say whether the 260 local passes hold on CI. If they go green, that flag closes by itself.
    • Test shards, Type Check and Repo Gates were in_progress at review time; the seat should re-read the check-runs before adopting any PASS on this head.

    Implemented-by: claude/issue-13047-list-view-spec-inputs
    Reviewed-by: session_01XVp19E1MYUTFM3dnkwz8gB

    VERDICT: FAIL

    Narrow: one test value. The options row in ListViewBlock.specInputs-13047.test.tsx must author a groupByField the list cannot derive on its own (as the kanban row already does with owner), or carry its own control, so the list-view.options member pin is a measurement rather than a coincidence. Everything else in the diff reads right; a re-render on the fixed head with the shards reported should PASS.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 13047,
    "status": "done",
    "branch": "claude/issue-13047-list-view-spec-inputs",
    "pr": "#13072",
    "session": "session_01XVp19E1MYUTFM3dnkwz8gB",
    "premise_still_valid": true,
    "summary": "Patch round on the contract review (FAIL, narrow). Head is now dea7d35, after merging origin/main (5024915). The options row now authors options.kanban.groupByField: 'owner' and columns: ['name'], against an in-row CONTROL: a bare kanban node lanes on the derived stage, asserted as not owner. The row reads the bag, not the default. The list-view.options member pin text says so. The label, description and userActions descriptions are trimmed to what the file measures. label: the export file name and the record-detail heading; the compact-title claim is dropped. description: the empty-map claim is dropped. userActions: false takes a control off and unnamed controls stay; the defaults claim is dropped. Everything else is as in the first report: 33 keys published, 5 unpublished by measurement, OWED rows struck, caps at 0. Filed by the seat: objectstack-ai/objectstack#24640 (filterableFields) and objectui#13074 (requiredPermissions/addRecord/sharing).",
    "tests": "At dea7d35, through os-verify-lock with --maxWorkers=1. ListViewBlock.specInputs-13047.test.tsx plus registry-inputs-spec-parity.test.ts: 2 files, 309 passed (49 + 260). plugin-list type-check (tsc + tsconfig.test.json) exit 0 after a turbo closure build. check:control-bytes 0. eslint --no-inline-config on the 3 changed files: 0 errors, 3 pre-existing warnings. Options ablation: ablation-replace.mjs replaced the authored node with a bare one (anchor 1 to 0, blob b276e1a971af to 1e24b85d83a6). The row went red, alone: expected 'stage' to be 'owner' (1 failed, 48 passed). Restore was proved by blob hash: hash-object = HEAD blob = b276e1a971af, and git diff HEAD is empty. Pin-file reachability: the parity gate's lazy ?raw glob already covers packages//src/**/.test.tsx. The gate's own check, every registered member pin points at a collected test file that names its block and key, is green in the 260, so no listing is needed. First-round results (families, console type-check, the allowPrinting ablation) stand at 215edf5. They were not re-run on the merge with main: NOT MEASURED, reason: the patch touches only the test row and three description strings.",
    "mcp_calls": "0",
    "api_writes": "Round 2: 1 relay write, the post-stamped os-dev-report comment (POST /repos//issues/13047/comments), plus 1 branch push. Round 1 total: 2 relay writes (pr_create with assignee; report comment 6274855151) and 2 pushes.",
    "gates": {
    "vitest ListViewBlock.specInputs-13047 + registry-inputs-spec-parity (dea7d35)": 0,
    "type-check @object-ui/plugin-list (dea7d35)": 0,
    "eslint changed files (dea7d35)": 0,
    "check:control-bytes (dea7d35)": 0,
    "options ablation": "red as required, restored (blob proof)",
    "round-1 gates": "see first report (215edf5); not re-run after merge with main"
    },
    "files_changed": [
    ".changeset/13047-list-view-spec-inputs.md",
    "apps/console/src/tests/registry-inputs-spec-parity.test.ts",
    "packages/plugin-list/src/tests/ListViewBlock.specInputs-13047.test.tsx",
    "packages/plugin-list/src/index.tsx"
    ],
    "line_budget": "n/a (no skills/** or governed surface touched)",
    "deviations": [
    "The dispatch contradicts itself on package dirs. Gates says to run each touched package's dir under the lock; Lock says no whole-package-directory runs and to declare them to CI. I followed Lock and declared plugin-list and console to CI.",
    "The view:list alias registration in the same file now publishes the same list. It is the same renderer, and its comment said 'same spelling and same reason as list-view'. Both registrations were already in index.tsx, the claimed surface.",
    "Round 2 merged origin/main into the branch (merge commit 5024915, no conflicts), as the coordinator directed. Families and console type-check were not re-run on the merged tree; that is declared to CI."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "filed by the seat: objectstack-ai/objectstack#24640 (filterableFields meaning), objectui#13074 (requiredPermissions / addRecord / sharing on a page list-view)",
    "carrier: 承接者:无 · appearance.allowedVisualizations is inert on a page node; documented in its description. Noted, not filed."
    ]
    }

  8. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Contract review

    Served-tier: CONTRACT_REVIEW_TIER
    Head-sha: dea7d3582701a2ba8b22bd015cd457510dd7aee0
    Local-runs: none

    Re-review after contract review FAIL 6275010079 at 215edf59d5. Inputs read: card #13047 body and all 6 comments (triage, unlock, claim, both os-dev-reports, the prior record), PR #13072 body, its 4-file list, the full net diff against main at this head (1471 lines, read end to end), the 3-commit list, the head commit's own patch (3 files, +18/-7), the parity file at this head for the ?raw loader section (lines 4680-4760 and the pin-file test at 6165, read for question 5 only), and the 35 check-runs on the head. No build, no test, no checkout.

    Check-runs on the head at review time. Completed success: Lint, Build Docs, Build & E2E, Test (dist pins), Bundle Analysis, Live E2E (informational), Changeset Declaration, Changeset Claim Re-read, Changeset Fixed Group Check, Changeset Bump Policy, Changeset Overwrite Report, Governed Surface Queue Guard, Line Citation Gate, label. Skipped: dependabot, Test (coverage), Test (coverage shard). Still in_progress: all 16 Test shards, Type Check, Repo Gates. The same families were in progress at the prior review, so the derived gate families that run registry-inputs-spec-parity.test.ts and ListViewBlock.specInputs-13047.test.tsx have not reported on either head; the evidence for them is the dev's two local runs (260 + 49 at 215edf59d5; 260 + 49 again at this head, with the options ablation red alone). This record does not wait on them.

    ① Derived judgments

    Scope of the change between 215edf59d5 and this head (brief question 2). The head commit dea7d3582701 touches exactly three files, 25 lines: (a) the options row of the new test file (+14/-3); (b) the list-view.options pin text in MEMBER_PINS (+1/-1); (c) three description strings in LIST_VIEW_INPUTS (label, description, userActions, +3/-3). The middle commit 5024915d15 is the merge of origin/main and carries nothing of the branch's own. The changeset, the UNPUBLISHED_EXEMPTIONS entries, the caps, the alias registration, the other 32 pin texts and the other 46 test rows are byte-identical to what the prior record read. Nothing beyond the dev's report is in the diff. Right.

    The corrected options row (brief question 1). The row now mounts a bare { type: 'kanban' } node first, waits for load, reads the handed object-kanban node's groupBy and asserts it is not 'owner'; then mounts { type: 'kanban', options: { kanban: { groupByField: 'owner', columns: ['name'] } } } and asserts groupBy === 'owner' and cardFields equals ['name']. owner is a text field in the fixture, not the select field the list derives a lane from, so the positive assertion can only be satisfied by the bag being read. The dev's ablation (bag replaced by a bare node) is reported as expected 'stage' to be 'owner', 1 failed / 48 passed, which is both the red the prior record asked for and a measurement that the derived default is stage. The list-view.options pin now says exactly this (authored owner, control lanes elsewhere, "the row reads the bag and not the default"). The pin is now a measurement. The prior record's one FAIL ground is closed. One non-blocking note: the in-row control reads lastHanded('object-kanban')?.groupBy with optional chaining, so if the bare node handed nothing the control would pass vacuously (undefined is not 'owner'); the existing package CONTROL row at the kanban block has the same shape, and the positive arm plus the ablation carry the proof, so this does not weaken the pin.

    The three trimmed descriptions (brief question 3).

    • label: "names the exported file and heads the record-detail overlay." The label row measures the export file name (string arm and zh-CN map arm, with a no-label control); the navigation row measures the drawer dialog's text containing the label. The dropped "title of the compact list in a narrow page region" claim was unmeasured. Truthful, and now only what is measured.
    • description: the "a map with no usable entry draws nothing" claim is dropped; what remains (info control's accessible name, string or locale map, hidden by appearance.showDescription: false) is each measured in the first three toolbar rows. Truthful.
    • userActions: "a control set to false ... is taken off the toolbar, and the controls it does not name stay." The row measures sort: false removing the Sort trigger while the Filter trigger stays, with an absent-key control. The dropped member list and the "hideFields and rowColor are off unless true" default claim were unmeasured. Truthful. The description now names the spec's UserActionsConfig as the shape, which is the row the fixture guard parses, so it stays a correct pointer to the member contract.

    Loader reachability (brief question 5). The parity gate's PIN_SOURCES is import.meta.glob over ../../../../packages/*/src/**/*.test.ts, .../*.test.tsx and the console's own tests, lazy ?raw; repoPathOfGlobKey maps each key to the repo-relative spelling the pins use, and memberPinProblem fails a pin whose file is outside the glob, is not a *.test.ts(x), or does not name the block and the key (word-boundaried). packages/plugin-list/src/__tests__/ListViewBlock.specInputs-13047.test.tsx matches the second pattern, is a collected test file, names list-view and every pinned key (each key is the subject of an it( row). The dataSource pin points at the pre-existing ListView.elementDataSource.test.tsx under the same glob. The dev's claim is right; no listing edit is needed, and the prior record's open flag on this closes. The test every registered member pin points at a collected test file that names its block and key (line 6165) is the gate that would otherwise red it, inside the 260 the dev reports green.

    Prior PASS findings at this head (brief question 4). The prior record's items 1-6 (the 33-key widening of inputs, the view:list alias sharing LIST_VIEW_INPUTS, the five by-measurement UNPUBLISHED_EXEMPTIONS entries, the caps at 0 by the ledger's own arithmetic, the 33 real MEMBER_PINS entries, the changeset) are unchanged in the diff and stand. The stand-in boundary, the appearance.allowedVisualizations handling, and the five unpublished keys are also unchanged and stand. The merge of main brought no change to the four files the PR touches (the net diff against main is the same shape the prior record read, plus the 25-line patch). Nothing in the prior record's PASS findings changes at this head.

    ② Semver level

    Unchanged from the prior record and still right: .changeset/13047-list-view-spec-inputs.md declares @object-ui/plugin-list minor for an additive widening of a published surface with no render-time change; apps/console is in the fixed group and its changed file is a test, so no second changeset is owed. This head's patch changes test text and three description strings, which moves no semver level. Changeset Declaration, Bump Policy, Fixed Group Check, Claim Re-read and Overwrite Report are all success on this head. minor is right. Clause-②: yes is right (the PR publishes a contract and the review tier was served).

    ③ Boundary flags

    Dev deviations (second report):

    • Package dirs declared to CI rather than run under the lock: answered as before; the in-progress Test shards are that run.
    • view:list alias publishes the same list: answered, right (prior record ① item 2, unchanged).
    • Round 2 merged origin/main (5024915d15, no conflicts) and did not re-run the families or the console type-check on the merged tree, declared to CI: answered. The patch touches one test row and three strings, so the round-1 family results are not moved by the branch's own change; whether main moved them is what the in-progress shards and Type Check decide, and this record is read-only.

    Dev open_questions: empty in the second report. The first report's filterableFields question (A/B/C) has been filed by the seat as objectstack-ai/objectstack#24640, which is the escalation the prior record asked for; the key stays unpublished with its reason recorded, so this PR is correct under every option.

    Dev out_of_scope_findings: requiredPermissions / addRecord / sharing renderer gaps filed as objectui#13074; appearance.allowedVisualizations inertness documented in its description, noted not filed. Nothing further to escalate.

    Prior record's reviewer flags, re-read at this head:

    • options pin: closed (① above).
    • Loader reachability of the new pin file: closed (① above, read off the parity file at this head).
    • Shards, Type Check and Repo Gates in progress: still open, same families as before. The seat should re-read the check-runs on dea7d3582701 before adopting; a red there is CI's finding, not a contract finding, and nothing in the diff predicts one.

    Implemented-by: claude/issue-13047-list-view-spec-inputs
    Reviewed-by: session_01XVp19E1MYUTFM3dnkwz8gB

    VERDICT: PASS

    Scoped to this re-review: the one FAIL ground of 6275010079 is fixed by a real control and a real ablation, the diff since 215edf59d5 is exactly the three edits reported, the trimmed descriptions say only what the file measures, the new pin file is inside the parity gate's glob, and every PASS finding of the prior record stands unchanged. Test shards, Type Check and Repo Gates were in_progress at review time.


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT · objectui#13047 · PR #13072 · domain:ui#2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-19T19:19Z

    PR #13072 at head dea7d35 (Fixes #13047, Clause-②: yes). Reviewed against:

    • the claim 6273333677;

    • the unlock 6269812594;

    • the dev reports 6274855151 / 6275155308;

    • contract review FAIL 6275010079 at 215edf5 (one ground: the options pin could not tell honoured from ignored), then re-review PASS 6275239964 at this head.

    • Premise: holds. PR chore(deps): build @objectstack/* from objectstack main 2ec6827962 and follow its contract (objectui#12971) #13043 booked 38 unpublished list-view spec keys and 6 member pins to this card as OWED, under objectui#11111 decision 3 = B.

    • Diff read by the seat:

      • Each of the 38 keys was authored on a page list-view node and rendered through the real registration and SchemaRenderer, with every fixture parsed by the spec row first.
      • 33 keys are measured as honoured and published in one shared LIST_VIEW_INPUTS, also used by the view:list alias.
      • 5 stay unpublished by measurement, with their reasons recorded: name and requiredPermissions are read by nothing; sharing and addRecord draw a button that does nothing on a page node; filterableFields is read as the Filter-panel whitelist, not as the declared userFilters.fields shorthand.
      • The OWED rows are struck and the caps restored to 0 by the ledger's own arithmetic. 33 member pins are registered, including the 6 booked.
    • Changeset: @object-ui/plugin-list minor.

    • Correction round: the options row now authors groupByField: 'owner', a field the list cannot derive, against an in-row bare-node control. Ablation: a bare node, and the row goes red alone. Three registration descriptions are trimmed to what is measured.

    • Local gates: the new file 49 and the parity test 260 (309 at this head); the plugin-list family 130; the console registry/manifest family 443; type-check plugin-list and console exit 0; eslint 0 errors; the battery and changeset checks all 0. The allowPrinting ablation reddens exactly one parity test.

    • Filed from this card's measurement:

    • Acceptance notes (not filed): appearance.allowedVisualizations is inert on a page node (no view switcher is drawn there). It is published with its acting sibling showDescription, and its description says so.

    • Commits: model-free trailers. The PR went through the fleet-write relay.

    • CI at head: 36/36 check-runs success or skipped on dea7d35 (filter=latest), mergeable_state clean.

    Verdict: ACCEPT. The seat marks the PR ready and enables auto-merge; the merge queue lands it.


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · objectui#13047 · PR #13072 · domain:ui#2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-19T19:34Z


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p1target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions