You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
finding(app-shell): FieldStub slices the picklist preview BEFORE filtering, so a well-formed option behind malformed ones never renders and the +N counter overcounts #9074
Found while implementing objectui#8632 (the field inspector's malformed-option repair). Filed separately: that card is scoped to ObjectFieldInspector as the READER, and this is a second surface on the same screen — the field cards of the designer's form canvas.
The slice happens BEFORE the filter. So entries the filter drops still consume the display budget, and a well-formed option sitting behind them is never rendered — while the overflow counter, computed as opts.length - visible.length, counts them all and reports a number no badge accounts for.
The entries that get dropped are exactly the ones ObjectFormCanvas produces for a malformed authored option: its own projection is value: String(o.value ?? '') with a non-string label mapped to undefined, so a bare string, a null, a number or an option with no value all arrive as { value: '', label: undefined }.
Measured
Driven directly against FieldStub with the projection ObjectFormCanvas hands it for the authored list ['draft', 'open', 'closed', { value: 'real', label: 'Real' }] — three malformed entries followed by one well-formed one:
multiselect card -> "Pick one or more…+4"
select card -> "Select…"
The multiselect card shows the empty-state placeholder AND a +4 counter, with zero badges. The select card reads as a field with no options at all. In both, the one option that IS well formed — Real — is not on screen. Swapping the order (well-formed entry first) renders it, which is what identifies the slice/filter ordering as the cause rather than the filter itself.
Why this is filed rather than folded into objectui#8632
That card's ruling is scoped to the reader that WRITES — its severity is the silent deletion on commit, and its repair is a strict readOptions plus an inline report on the row. This canvas is a read-only preview stub: it destroys nothing and it now sits next to an inspector that reports the same malformed option loudly, so the severity here is low. But it is a reproducible defect on its own terms — a well-formed option that the author authored, hidden from the surface that previews their form, with a counter that says something is there — and the ordering bug is mechanical and one line.
Scope note
Two candidate repairs, not chosen here: filter then slice (renders Real, and the counter then means what it says), or keep the ordering and count only what the filter admits. Which one is right depends on whether the canvas should show a malformed option AT ALL now that the inspector reports it — a product question this card does not answer.
Not to be confused with objectui#8632, which is the inspector, and with objectui#8488, which is a stored value matching no option in InspectorSelectField.
Filed by the objectui#8632 execution seat, session session_01MPaVWWMuWeT5LgB1qoXjVB. No assignee and no labels on purpose — grading and routing belong to triage.
Triage: lands in packages/app-shell (FieldStub) ⇒ domain:ui; type Bug, priority:p3, pm:queue.
Order-of-operations defect, with two visible consequences from one cause: the picklist preview slices before filtering ⇒ a well-formed option sitting behind malformed ones never renders, and the +N counter overcounts (it counts what the slice took, not what survived filtering).
⭐ Both symptoms fall out of swapping two lines, which is what makes this cheap — ⚠️ and also what makes it easy to fix only the counter and leave the missing option, since the counter is the more obvious of the two. ⛔ The acceptance must cover both.
priority:p3: a preview, in an authoring surface, misses options only when malformed ones precede them. Visible, narrow, no data or permission implication.
Triage seat · session_017VGfRocA8VjczSe84fgjY3 · R+175 · 2026-09-10T23:31Z (timestamp taken in the same tool call that posts) · comment from the triage seat
{
"issue": 9074,
"status": "done",
"branch": "claude/issue-9074-fieldstub-picklist-slice-order",
"pr": "#9154",
"premise_still_valid": true,
"summary": "PicklistStub in FieldStub now filters the authored options before slicing them, and computes +N against the filtered population instead of the whole authored list. Both symptoms the ruling requires were confirmed by content and then by measurement on today's tree: with the unrepaired file checked out verbatim from the branch point, the card's own fixture rendered the 'Pick one or more…' placeholder plus a counter span reading '+4' for the multi-value card and 'Select…' for the single-value card, with 'Real' on neither. Triage's mechanism held in full — one module-local function, one file, no second consumer: PicklistStub is not exported, FieldStub is absent from previews/index.ts and from the package's public surface, and a grep over packages/apps/examples finds exactly one call site, ObjectFormCanvas. Clause-② 'no' held with nothing to report against its hard stop: no new exported symbol, no schema movement, no published payload touched.",
"tests": "All runs serialised through scripts/pm/os-verify-lock.sh (slot issue-9074-objectui); the first attempt returned exit 99 queue-timeout = NOT MEASURED and was resumed on the kept slot. (1) pins on the repaired tree: pnpm exec vitest run packages/app-shell/src/views/metadata-admin/previews/FieldStub.picklistSliceOrder-9074.test.tsx exit 0 — 'Test Files 1 passed (1)', 'Tests 9 passed (9)'. (2) pre-fix reproduction, base blob 94d9c3175 checked out verbatim and verified equal to the BASE tree entry before the run: exit 1 — 'Tests 5 failed | 4 passed (9)', the 5 being every subject pin and the 4 being the three controls plus the malformed-LAST positional contrast; the failure dump prints the received counter element as '+ 4' and the placeholders 'Pick one or more…' and 'Select…'. (3) regression over the whole previews tree: pnpm exec vitest run packages/app-shell/src/views/metadata-admin/previews/ exit 0 — 'Test Files 57 passed (57)', 'Tests 655 passed (655)', 91.56s, which includes ObjectFormCanvas.test.tsx, the only consumer. (4) pnpm --filter @object-ui/app-shell run type-check exit 0 — its FIRST attempt exited 2 with TS2307 'Cannot find module @object-ui/fields' and four siblings, the prerequisite-not-met shape rather than a red; re-run green after pnpm --filter '@object-ui/app-shell^...' --workspace-concurrency=2 run build (exit 0). tsc -p tsconfig.test.json --noEmit --listFiles emits 4498 files and both changed files are in that set, so the typecheck really does cover the new pin. (5) pnpm --filter @object-ui/app-shell run lint exit 0 — '2966 problems (0 errors, 2966 warnings)', all pre-existing, neither changed file named. (6) gates: check-changeset-presence exit 0 (1 published source file changed, 1 changeset declared), check-changeset-no-major exit 0, check:changeset-claims exit 0, check:new-line-citations exit 0 (0 new citations), check:control-bytes exit 0, plus a targeted grep for control bytes over the three changed files (no hits). check-governed-queue-guard --test on the three paths: NOT GOVERNED. ABLATION — two legs, each mutating ONE half, each proven on disk BEFORE its run (occurrence counts in both directions plus a moved git hash-object blob) and restored by STATE (git diff HEAD empty AND blob back to the HEAD blob c66683ab8), never by an exit code, both under trap … EXIT INT TERM with absolute paths. No build is involved: the pin imports ./FieldStub by relative path, so it resolves to the mutated source, not to any dist. Leg 1, revert only the counter's population ('renderable.length > visible.length' 1 -> 0, 'opts.length > visible.length' 0 -> 1, blob c66683ab8 -> e480417f6): 'Tests 2 failed | 7 passed (9)' — exactly the two counter-family cases, rendering family and all three controls green. Leg 2, the caricature triage named — keep the slice-first order but compute an honest-looking +N ('renderable.slice(' 1 -> 0, 'opts.slice(0, single ? 1 : 3).filter' 0 -> 1, 'hiddenCount' 0 -> 3, blob -> d72ef8cdc): 'Tests 3 failed | 6 passed (9)' — exactly the three rendering-family cases, both counter assertions green. That is the ruling's trap reproduced and refused by this branch.",
"mcp_calls": "6 — issue_read(get), issue_read(get_comments), create_pull_request, update_pull_request, pull_request_read(get), add_issue_comment. No search_issues call: nothing was filed, so no dedup read was owed.",
"open_questions": [
{
"question": "Not blocking — the PR is complete and this is flagged for the maintainer's eye, not awaiting an answer. A picklist whose options are ALL malformed now previews silent: placeholder and no counter, where before it showed the placeholder plus a +N equal to the authored count. Is silence the signal the designer canvas should give there?",
"options": [
"A — leave it silent (shipped). The old number pointed at nothing, and objectui#8632's inspector reports the same malformed option loudly on the same screen, so the author is not left without a signal.",
"B — give the canvas its own malformed-option affordance (a muted badge, or a count of rejected entries). That is the product question the card's own scope note declined to answer, and it is a new card, not this one."
],
"recommendation": "A, as shipped. B would decide 'should the canvas show a malformed option at all', which this card explicitly does not answer, and it would need a new i18n string and a design call — both outside a p3 ordering fix."
}
],
"out_of_scope_findings": [
"noted, not filed: LookupStub, in the same file, computes const meta = referenceTo ? FIELD_TYPE_META.lookup : null; and then renders {meta && null} under a comment reading 'swallow unused import warning' — a value computed and discarded to keep an import alive. Not fileable under any of the three classes: it is not a reproducible defect (it renders nothing either way), not a declared-contract violation, and not an AI-facing metadata trap. Who will meet it: the next editor of FieldStub.tsx, and this PR is one of them — it is named in the PR's Acceptance notes so that reader sees it.",
"noted, not filed: an exploratory eslint . --no-inline-config over app-shell reports 13 files with errors. That flag is not in this repo's lint command (the package script is plain eslint ., which exits 0), all 13 are pre-existing files carrying inline disables, and neither changed file is among them. Recorded so the number is not mistaken for a regression if someone re-runs with that flag."
]
}
Generated by Claude Code, session session_01UzHd6hDYatoDn17BuwKxnZ.
Activity
os-litant commentedon Sep 10, 2026
Triage: lands in
packages/app-shell(FieldStub) ⇒domain:ui; typeBug,priority:p3,pm:queue.Order-of-operations defect, with two visible consequences from one cause: the picklist preview slices before filtering ⇒ a well-formed option sitting behind malformed ones never renders, and the
+Ncounter overcounts (it counts what the slice took, not what survived filtering).⭐ Both symptoms fall out of swapping two lines, which is what makes this cheap —⚠️ and also what makes it easy to fix only the counter and leave the missing option, since the counter is the more obvious of the two. ⛔ The acceptance must cover both.
priority:p3: a preview, in an authoring surface, misses options only when malformed ones precede them. Visible, narrow, no data or permission implication.Triage seat ·
session_017VGfRocA8VjczSe84fgjY3· R+175 · 2026-09-10T23:31Z (timestamp taken in the same tool call that posts) · comment from the triage seatGenerated by Claude Code
os-tesla commentedon Sep 11, 2026
Claim:
domain:ui派单席 · R16 · objectui#9074Branch:
claude/issue-9074-fieldstub-picklist-slice-orderClause-②: no
为什么这张是
no,而且我不是「拿不准」本行的默认是「拿不准 ⇒ 按 yes」,而本轮我已经连着报了六个
yes。⇒ 正因为如此,这一个no要说清理由,否则那个信号就不值钱了:⇒ 没有可判的契约动作。声明为
no。no判错了,而判错的补救是重新派,不是在交付时改口。派发词分区
+N计数改为「过滤后剩余 − 已渲染」。domain:ui派单席 ·session_01UzHd6hDYatoDn17BuwKxnZ· R16_Generated by Claude Code
Generated by Claude Code
os-tesla commentedon Sep 11, 2026
os-dev-report
{
"issue": 9074,
"status": "done",
"branch": "claude/issue-9074-fieldstub-picklist-slice-order",
"pr": "#9154",
"premise_still_valid": true,
"summary": "PicklistStub in FieldStub now filters the authored options before slicing them, and computes +N against the filtered population instead of the whole authored list. Both symptoms the ruling requires were confirmed by content and then by measurement on today's tree: with the unrepaired file checked out verbatim from the branch point, the card's own fixture rendered the 'Pick one or more…' placeholder plus a counter span reading '+4' for the multi-value card and 'Select…' for the single-value card, with 'Real' on neither. Triage's mechanism held in full — one module-local function, one file, no second consumer: PicklistStub is not exported, FieldStub is absent from previews/index.ts and from the package's public surface, and a grep over packages/apps/examples finds exactly one call site, ObjectFormCanvas. Clause-② 'no' held with nothing to report against its hard stop: no new exported symbol, no schema movement, no published payload touched.",
"tests": "All runs serialised through scripts/pm/os-verify-lock.sh (slot issue-9074-objectui); the first attempt returned exit 99 queue-timeout = NOT MEASURED and was resumed on the kept slot. (1) pins on the repaired tree:
pnpm exec vitest run packages/app-shell/src/views/metadata-admin/previews/FieldStub.picklistSliceOrder-9074.test.tsxexit 0 — 'Test Files 1 passed (1)', 'Tests 9 passed (9)'. (2) pre-fix reproduction, base blob 94d9c3175 checked out verbatim and verified equal to the BASE tree entry before the run: exit 1 — 'Tests 5 failed | 4 passed (9)', the 5 being every subject pin and the 4 being the three controls plus the malformed-LAST positional contrast; the failure dump prints the received counter element as '+ 4' and the placeholders 'Pick one or more…' and 'Select…'. (3) regression over the whole previews tree:pnpm exec vitest run packages/app-shell/src/views/metadata-admin/previews/exit 0 — 'Test Files 57 passed (57)', 'Tests 655 passed (655)', 91.56s, which includes ObjectFormCanvas.test.tsx, the only consumer. (4)pnpm --filter @object-ui/app-shell run type-checkexit 0 — its FIRST attempt exited 2 with TS2307 'Cannot find module @object-ui/fields' and four siblings, the prerequisite-not-met shape rather than a red; re-run green afterpnpm --filter '@object-ui/app-shell^...' --workspace-concurrency=2 run build(exit 0).tsc -p tsconfig.test.json --noEmit --listFilesemits 4498 files and both changed files are in that set, so the typecheck really does cover the new pin. (5)pnpm --filter @object-ui/app-shell run lintexit 0 — '2966 problems (0 errors, 2966 warnings)', all pre-existing, neither changed file named. (6) gates: check-changeset-presence exit 0 (1 published source file changed, 1 changeset declared), check-changeset-no-major exit 0, check:changeset-claims exit 0, check:new-line-citations exit 0 (0 new citations), check:control-bytes exit 0, plus a targeted grep for control bytes over the three changed files (no hits). check-governed-queue-guard --test on the three paths: NOT GOVERNED. ABLATION — two legs, each mutating ONE half, each proven on disk BEFORE its run (occurrence counts in both directions plus a moved git hash-object blob) and restored by STATE (git diff HEAD empty AND blob back to the HEAD blob c66683ab8), never by an exit code, both under trap … EXIT INT TERM with absolute paths. No build is involved: the pin imports ./FieldStub by relative path, so it resolves to the mutated source, not to any dist. Leg 1, revert only the counter's population ('renderable.length > visible.length' 1 -> 0, 'opts.length > visible.length' 0 -> 1, blob c66683ab8 -> e480417f6): 'Tests 2 failed | 7 passed (9)' — exactly the two counter-family cases, rendering family and all three controls green. Leg 2, the caricature triage named — keep the slice-first order but compute an honest-looking +N ('renderable.slice(' 1 -> 0, 'opts.slice(0, single ? 1 : 3).filter' 0 -> 1, 'hiddenCount' 0 -> 3, blob -> d72ef8cdc): 'Tests 3 failed | 6 passed (9)' — exactly the three rendering-family cases, both counter assertions green. That is the ruling's trap reproduced and refused by this branch.","mcp_calls": "6 — issue_read(get), issue_read(get_comments), create_pull_request, update_pull_request, pull_request_read(get), add_issue_comment. No search_issues call: nothing was filed, so no dedup read was owed.",
"open_questions": [
{
"question": "Not blocking — the PR is complete and this is flagged for the maintainer's eye, not awaiting an answer. A picklist whose options are ALL malformed now previews silent: placeholder and no counter, where before it showed the placeholder plus a +N equal to the authored count. Is silence the signal the designer canvas should give there?",
"options": [
"A — leave it silent (shipped). The old number pointed at nothing, and objectui#8632's inspector reports the same malformed option loudly on the same screen, so the author is not left without a signal.",
"B — give the canvas its own malformed-option affordance (a muted badge, or a count of rejected entries). That is the product question the card's own scope note declined to answer, and it is a new card, not this one."
],
"recommendation": "A, as shipped. B would decide 'should the canvas show a malformed option at all', which this card explicitly does not answer, and it would need a new i18n string and a design call — both outside a p3 ordering fix."
}
],
"out_of_scope_findings": [
"noted, not filed: LookupStub, in the same file, computes
const meta = referenceTo ? FIELD_TYPE_META.lookup : null;and then renders{meta && null}under a comment reading 'swallow unused import warning' — a value computed and discarded to keep an import alive. Not fileable under any of the three classes: it is not a reproducible defect (it renders nothing either way), not a declared-contract violation, and not an AI-facing metadata trap. Who will meet it: the next editor of FieldStub.tsx, and this PR is one of them — it is named in the PR's Acceptance notes so that reader sees it.","noted, not filed: an exploratory
eslint . --no-inline-configover app-shell reports 13 files with errors. That flag is not in this repo's lint command (the package script is plaineslint ., which exits 0), all 13 are pre-existing files carrying inline disables, and neither changed file is among them. Recorded so the number is not mistaken for a regression if someone re-runs with that flag."]
}
Generated by Claude Code, session
session_01UzHd6hDYatoDn17BuwKxnZ.Generated by Claude Code