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 }}
Repository navigation
[finding] ListMapConfigSchema is strict and declares neither style nor mapStyle, while the objectui renderer reads schema.map?.style — a map style cannot be declared through the spec's list-view face at all #18406
Filed by the domain:spec execution seat (#6017), session_01KB5PFtxuy1x3dcR5gxudx6, 2026-09-16T09:3xZ, from the out_of_scope_findings of the #18305 round (PR #18403). ⛔ Not claimed, ⛔ not dispatched. Grading is triage's. ⛔ This seat did not run a dedupe search (per 「立卡者不查重,只附查重词」).
The defect
packages/spec/src/ui/view.zod.ts:1631 — ListMapConfigSchema is strict and declares neither style nor mapStyle.
objectui's renderer reads one of them: getMapConfig (plugin-map/src/ObjectMap.tsx:365 at the pinned sha 53ded82b) reads schema.map?.style, and objectui's own ObjectMapConfigSchemadeclares style.
An author cannot declare a map style through the spec's list-view face at all. And objectui#5017's dev warning prescribes map: { mapStyle } on a view — a key the spec also does not declare. So both spellings the ecosystem uses are refused by the one face that is supposed to be authoritative.
⚠️ This is the measured reason PR #18403 leaves object-map.map as z.unknown() rather than pointing it at ListMapConfigSchema: pointing at it would make the component row inherit a refusal the renderer contradicts. The negative is pinned in that PR's new tests, so the divergence is recorded rather than assumed.
⇒ Class (a): a reproducible defect with a named repro, on a published authoring face.
Ruling: batch #153 item 4 · letter 1 (declare style on ListMapConfigSchema, aligned with objectui's implementation and its own ObjectMapConfigSchema; retract object-map.map's z.unknown() in the same PR; the objectui dev warning that teaches mapStyle is corrected on the objectui side) · maintainer 「其他同意」 2026-09-18T03:59Z
Director seat, summon #24, session_01Wj1HUjzyeiBQ8atRf1ZhaL. Presented in detail with the recommendation 1; the maintainer agreed. Facts (this card; triage 5716375468; seat re-check on both mains): packages/spec/src/ui/view.zod.ts:1631ListMapConfigSchema is strict and declares neither style nor mapStyle; objectui's getMapConfig (plugin-map/src/ObjectMap.tsx:365 at the pin) reads schema.map?.style, and objectui's own ObjectMapConfigSchema declares style; objectui#5017's dev warning prescribes map: { mapStyle }, which nothing reads. ListMapConfigSchema.safeParse({ style: '…' }) → success: false. The cost already paid: PR #18403 (merged) left object-map.map as z.unknown() to avoid inheriting the refusal. Mapbox / MapLibre call the key style (a style URL) — one name, the industry's.
Ruling — 1
ListMapConfigSchema gains style: z.string().optional() with a describe naming it the map style URL; object-map.map in the component contract points at ListMapConfigSchema again (the z.unknown() retracted in the same PR, its negative pins inverted); generated artefacts regenerated.
objectui side (a sibling objectui card, domain:ui, filed by the director with this ruling): the objectui#5017 dev warning teaches style, ⛔ not mapStyle.
Published accept set widens by one key that the renderer already reads ⇒ Clause-②: yes; the spec lane's at-tier review; changeset @objectstack/spec minor.
⛔ 2 — a second spelling the renderer would have to learn; ⛔ 3 — an alias is a permanent obligation for a key nobody has written yet.
Four-facet reading: ① a map view's base style is standard configuration; ② one name, the industry's, declared where the renderer reads it; ③ today an author's AI can write the key neither way — after this it writes style and it works; ④ one key, no alias.
Claim: PM loop round 1
Session: session_019srGWGCBBCBHqcDoRZpQRh
Branch: claude/issue-18406-listmap-style-key
Worktree: objectstack-issue-18406
Domain: domain:spec
Seat: domain:spec#3 (the seat number this PM sits on; absent = seat 1)
File surface: packages/spec/src/ui/view.zod.ts (the ListMapConfigSchema block), packages/spec/src/ui/component.zod.ts (the object-map props block), the generated artefacts those two regenerate, their sibling tests, and one changeset (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: default judgment tier (opus) — this run's --tier output reads "no path-derived mandate: the surface hits none of the 3 declared glob(s)" and "floor sonnet · default opus · ceiling fable", plus "Clause ② SUSPECT surface — a hint, not a verdict" on both paths. Built at the default tier; the clause-② review is an ISOLATED at-tier (claude-fable-5-1) subagent, because this seat measured served claude-opus-5 and so may not self-review.
Clause-②: yes
Thread-read: 5724940537
Serial constraints cleared: PR #18638 (card #15811, draft, PARKED) is the ONE open PR touching either file — measured against the per-PR files endpoint for ALL 17 open PRs, not against a seat post. Same file, REGIONS DISJOINT: #18638's view.zod.ts hunks start at old lines 53 / 2241 / 2771 / 2978 and its component.zod.ts hunks at old lines 6 / 738 / 1591 / 1601 (12 changed lines each); ListMapConfigSchema sits at view.zod.ts:1754 and the object-map block at component.zod.ts:3186-3400 with its registration at :3735 — nearest hunk ~490 and ~1585 lines away. Nothing else in the lane is in flight on packages/spec/src/ui/**. No pin in this card asserts behaviour a sibling card is changing.
Seat note — the ruling is the authority for this card, and it is 9 minutes old at claim time.
Dispatching to implement ruling batch #153 item 4 letter 1 (comment 5724940537, maintainer 「其他同意」), read in full at claim time. ⛔ The three-way choice is CLOSED; the dev re-litigates nothing.
⚠️ One correction the dev must carry: both the card body and the ruling cite view.zod.ts:1631 for ListMapConfigSchema. On origin/main at 0b31d90fb3 it is at :1754. Line numbers get re-derived from the tree, never copied from the card.
Written 2026-09-18T04:09Z. The lane inventory and the all-open-PR file scan behind the serial line were read at 2026-09-18T04:07Z. Seat post: #18883.
os-dev-report
{
"issue": 18406,
"status": "done",
"branch": "claude/issue-18406-listmap-style-key",
"pr": "#18904",
"session": "session_019srGWGCBBCBHqcDoRZpQRh",
"premise_still_valid": true,
"summary": "Ruling batch #153 item 4 letter 1 implemented as specified. ListMapConfigSchema (packages/spec/src/ui/view.zod.ts:1754, NOT the :1631 the card and the ruling both cite) gains style: z.string().optional() with a describe naming it the map style URL; object-map's map prop (component.zod.ts:3272) stops being z.unknown() and points at ListMapConfigSchema again, and PR #18403's two negative pins (component.test.ts:3534-3540) are inverted. Not mapStyle, no alias. Generated artefacts regenerated by mechanism, never hand-edited; changeset @objectstack/spec minor with Clause-②: yes (widening). Card assignee was already set by the dispatch (os-elon-musk) and the newest Claim: comment 5725016686 names this branch, verified before the first write; no second claim posted.",
"gates": "107 families derived by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands from the REAL change set (8 paths incl. generated artefacts and tests) — not from the two paths named in the brief, whose derivation was ~71. All 107 RUN, each exit code captured before any pipe into a file; --ran FILE reconciles to 107 derived / 107 run / 0 NOT-MEASURED / 0 UNRUN, a DERIVED zero (every line carries a code, none is 3). Eight first returned a non-zero that was NOT a finding and are green after the prerequisite was met: 5 x PREREQUISITE NOT MET on build state (cleared by full pnpm build, 73/73 tasks), check:react-declaration-parity needed CI's MANIFEST value (re-run in CI's exact spelling, exit 0), and check-plugin-teardown-shape --self-test refused on the shallow clone for an unreachable fixture commit (cleared by a targeted git fetch origin 621a4876..., 48 cases pass). NOT read as clearance: 13 self-test-only families, 49 artifact-roster families, 11 wide-population families, 6 path-scheduled CI jobs. check:generated: all 15 artefacts up to date post-merge with a clean tree. Carrier reading: needs:contract-review is absent from BOTH carriers (card #18406 and PR #18904) and node scripts/pm/check-clause2-carriers.mjs --pair 18904 exits 4 (C3, never hung on either carrier) — reported as a reading only; the label is the seat's and this seat neither hung, cleared nor waited on it. PR labels: size/m (labeler's).",
"line_budget": "Skills line ratchet NOT APPLICABLE: 0 paths under skills/** or .claude/** in the diff (measured, git diff --name-only against the merge base). Diff size vs merge base 600b1e2: 8 files, +117/-24. Hand-written half: 5 files, +99/-23 (packages/spec/src + .changeset). Generated half: 3 files, +18/-1 (authorable-surface/ui.json +1 line, view.mdx +3, component.mdx +15/-1).",
"files_changed": [
"packages/spec/src/ui/view.zod.ts — style row added to ListMapConfigSchema after center; docblock strictness paragraph (:1746-1752) corrected ADDITIVELY (strictObject kept, rationale untouched)",
"packages/spec/src/ui/component.zod.ts — map door z.unknown() to ListMapConfigSchema.optional() (:3272); ListMapConfigSchema added to the ./view.zod import (line 4); VALUE-posture paragraph rewritten; flat-guidance docblock gains the minus style derivation and its reason. Registration at :3735 unchanged",
"packages/spec/src/ui/component.test.ts — the two #18403 negative pins inverted (:3534-3540) plus a THIRD assertion so they cannot pass against the z.unknown() they replaced (a styl typo must be refused AT map, key echoed); flat-key-set equality (:3507-3509) now derives by SUBTRACTION of style instead of hand-listing",
"packages/spec/src/ui/view.test.ts — documented-surface test carries eight keys and asserts the parse OUTPUT equals the input; new pin takes the card repro as its subject (style accepted alone; the node-level object form of style refused; styl and mapStyle still refused)",
"packages/spec/authorable-surface/ui.json — +1 line, ui/ListMapConfig:style. Written by pnpm --filter @objectstack/spec build. authorable-surface.base.json deliberately NOT touched",
"content/docs/references/ui/view.mdx — gen:docs",
"content/docs/references/ui/component.mdx — gen:docs; the object-map map row changes from any to the block shape and a nested-shape table appears",
".changeset/18406-listmap-config-style.md — @objectstack/spec minor, carries Clause-②: yes (widening)"
],
"tests": "All readings at 0af4dfc (= origin/claude/issue-18406-listmap-style-key; tree clean). pnpm --filter @objectstack/spec test: 488 files / 14128 tests pass. pnpm --filter @objectstack/spec typecheck: green incl. the test layer. Repo-wide pnpm lint (= eslint . --no-inline-config) run IN FULL rather than narrowed: exit 0, 6853 files inspected (counted from --format json), 0 errors, 0 warnings, 75s; for the record eslint.config.mjs:326-336 states with its own positive control that type-aware linting is never enabled for any file, so this diff could not move an untouched file's verdict. ABLATION (PLANT mode via scripts/ablation-replace.mjs, the style row renamed to styleAblated18406): on-disk proof anchor 1 to 0, marker 0 to 1, blob 1c83516951e3 to d256ada1f791; restore proved by blob == HEAD, git diff HEAD empty AND whole-tree git status --porcelain empty. Source leg RED as predicted: 4 of 782 tests fail and they are exactly the four this PR authors or modifies, 778 pass. Build leg is an independent third witness: gen:schema's authorable-key ratchet also reds and names ui/ListMapConfig:style as disappeared from the contract while the baseline still records it. Dist leg NOT MEASURED and declared so: the ablated build failed at gen:schema so no ablated dist ever existed, the type probe consequently read the PRE-mutation artefact and exited 0, and scripts/ablation-dist-preflight.mjs caught that false green by reporting the marker ABSENT from dist — that green is discarded, not recorded. CROSS-PACKAGE TYPE REVERSE VERIFICATION supplied separately from a temporary probe inside packages/lint resolving @objectstack/spec/ui through the package exports (the BUILT declarations): positive leg exit 0 (style assignable AND a ts-expect-error on an undeclared member inside map is USED, which only holds if the door really narrowed away from unknown); negative leg exit 2, both halves failing as required and each would have COMPILED against the pre-change declarations — TS2353 names bogus as absent from the block type and prints that type inline with its style member, TS2578 reports the stale expectation-of-refusal as unused. A cached declaration file cannot produce either error. Both probe files deleted; tree clean. Verify-lock readings for the lane baseline: waits 0s/5s/0s/4m05s/1m18s/0s, and the full pnpm build held the lock 4m56s.",
"deviations": [
"Ran dispatch-gates.mjs --commands WITHOUT explicit paths. The brief spells it with paths; the standing clause forbids feeding it a hand-made list and requires the script derive the change set from the merge base itself (which also picks up uncommitted and untracked paths). Declared, not silent — the derivation printed its own provenance line naming repo and commit, and --repo was asserted and held.",
"Commit trailer pair written MODEL-FREE (Claude-Session: + Co-authored-by: Claude), not the harness-suggested Co-Authored-By: Claude Opus 5. The pre-push hook refuses a model identifier in that pair; the push confirmed check:commit-card-trailers: 2 commit message(s) ... carry no card relation and no model identifier in the trailer pair. AGENTS.md names the harness form as a reporting-only exemption.",
"Shallow clone worked around by TARGETED single-commit fetches, not git fetch --unshallow: 621a4876... in this repo for check-plugin-teardown-shape's pinned fixture, and the objectui pin 53ded82b... in the sibling checkout for the measurements. Cheaper and it does not rewrite the shared object store wholesale.",
"Repo-wide pnpm lint run in full instead of the declared-narrowing form the standing clause permits. Beyond the minimum, not below it.",
"The docblock correction in view.zod.ts is PURELY ADDITIVE, per the dispatching seat's addendum: every pre-existing clause is kept byte-identical and the strictness rationale is untouched. One clause inside the paragraph I measured FALSE at the pin is therefore left standing and reported instead — see out_of_scope_findings item 1."
],
"mcp_calls": "0 — no MCP GitHub tool was called, read or write. Every GitHub interaction went through the REST proxy with curl.",
"api_writes": "2 REST writes, both inside budget: POST /repos/objectstack-ai/objectstack/pulls (draft PR #18904) and POST /repos//issues/18406/comments (this report). 0 label writes — needs:contract-review is the seat's and nothing else was owed. Plus 2 git pushes on the branch (the pre-edit empty-branch routing probe, then the two commits); no force-push, no push to main. Reads (not writes): the card, its comments, the PR read-back and its labels.",
"open_questions": [],
"out_of_scope_findings": [
"to file (3 classes, dedupe words: ObjectMapConfigSchema not strict · getMapConfig safeParse warn-only · extra key not dropped · ObjectMap.tsx:378 spread · map block undeclared key) — the clause so an extra key here would be dropped there in view.zod.ts's ListMapConfigSchema docblock (:1747-1748) is measurably FALSE at objectui pin 53ded82b, and it sits immediately beside the clause this PR corrects. Three readings: (1) ObjectMapConfigSchema is a plain z.object, NOT strict (packages/types/src/zod/objectql.zod.ts:562), so a safeParse of a block carrying an extra key SUCCEEDS and no warn is emitted; (2) getMapConfig uses that safeParse result only to decide whether to console.warn (ObjectMap.tsx:373-376), never as the value; (3) ObjectMap.tsx:378 returns a spread of the AUTHORED block, so the extra key is carried through, not dropped. So an undeclared key inside map is neither flagged nor dropped by the renderer — the opposite of the claim. Filing class is the seat's to judge and this seat did not judge it: it is a false MECHANISM claim in a docblock rather than a runtime defect, so it may or may not reach class (a); it does not on its own make an AI write metadata the runtime rejects or silently drops, so this seat does not read it as class (c). Left untouched per the addendum — the ruling's facts reach the style key and objectui's read of it, and do not reach this. Filed in objectstack, where the docblock lives.",
"noted, not filed: the spec docblock's citation of content/docs/plugins/plugin-map.mdx does NOT exist in this repo — it is objectui's path, and the whole parenthetical is scoped to objectui. Verified present at the pin (and it documents style at :131, which is why it strengthens the ruling rather than weakening the citation). No finding; recorded only so the next reader does not re-derive it. Successor: the next seat touching this docblock.",
"noted, not filed: the two lint field-reference tables that enumerate map-block keys (packages/lint/src/validate-list-view-field-refs.ts:435-443 POSITIONS, validate-field-consumers.ts:236-247 BEHAVIOUR_SEGMENTS) are allowlists of FIELD-NAMING keys with no mechanical parity gate against the schema shape, so style correctly needs no row in either. Checked so the reviewer does not have to; the liveness ledger likewise drills only to list.map, so no per-key row is owed. Successor: none — this is a negative result recorded to close the question."
]
}
ACCEPT — PR #18904, with the clause-② review record below. domain:spec seat 3, session_019srGWGCBBCBHqcDoRZpQRh, R1.
Clause-② review record — isolated, at-tier, adopted VERBATIM
⛔ This seat did not grade clause ②. It measured its own served model as claude-opus-5, belowCONTRACT_REVIEW_TIER (claude-fable-5-1, read from scripts/pm/dispatch-gates.mjs:11899), so the verdict was taken by an isolated subagent fed only the card, the ruling and the PR. Its verdict block, quoted verbatim and ⛔ not rewritten:
CLAUSE-2-REVIEW: PASS
WIDENING-SCOPE: one optional key, `ui/ListMapConfig:style` (`z.string().optional()`), on the strict `ListMapConfigSchema`; everything else in the diff narrows (`object-map.map`: `z.unknown()` → `ListMapConfigSchema.optional()`) or is generated/test/changeset
BEYOND-RULING: none — no `mapStyle`, no alias, `strictObject` and its options untouched, type matches objectui's own `style: z.string().optional()` at pin 53ded82b, no refinement removed
FLOOR-TOUCHED: none — no CI/workflow, package.json, dependency, threshold, skipped test, or security/permission surface; one changeset `@objectstack/spec` minor; single-revert reversible
Judged head: 0af4dfc76e.
⭐ Tier attestation — the reviewer reported unobservable, and it was RIGHT to
The reviewer declined to attest its own tier, for a measured reason: get_session inside a mode:subagent run reports the dispatching session, not the subagent — it proved this by reading the block twice ~5 minutes apart and finding the usage counters frozen across roughly a dozen of its own API turns. ⇒ an honest unobservable rather than a guess, which is the correct behaviour: a guessed attestation would have silently voided the very compensating control the review exists to be.
The seat resolved it from outside, which is where it is resolvable. Per the established method — 「档位证据取子代理自身 transcript 的逐请求 harness model 盖章;⛔ get_session 在 mode:subagent 里量的是派发会话,不作数」 — this seat grepped the reviewing round's own transcript:
reading
value
assistant turns carrying a per-request model stamp
100
of those stamped claude-fable-5-1
100
of those stamped off-tier
0
The 17 claude-opus-5 occurrences elsewhere in that transcript are the reviewer quoting the parent session's get_session output while explaining why it distrusted it — ⛔ not its own turn stamps. ⇒ the review ran AT tier, 100/100. The verdict is adopted.
⇒ Generalisable, and recorded for the lane: a subagent cannot self-attest its tier, but the dispatching seat can verify it from the transcript. An unobservable from the reviewer is therefore not a failed control — it is the control working, with the last step belonging to the seat.
Seat-side checklist (the part that IS this seat's)
PR form: draft ✓ · base main ✓ · Fixes #18406 first body line ✓ · Clause-②: yes (widening) line-initial ✓ · head on the claimed branch ✓. Scope 8 files, +117/−24. mcp_calls: 0, no deny-roster tool named ⇒ no reject trigger. api_writes: 2, inside budget. Path surface: no governed path (nothing under docs/adr/**, .claude/**, skills/**, AGENTS.md, CLAUDE.md) ⇒ ordinary landing path. No content/docs/releases/ path ⇒ the release-owned guardrail is respected; the docs-drift advisory naming v17/17-1.mdx was checked and needs no action — that page enumerates the key set v17.1 shipped, and a later additive key does not falsify a point-in-time release record.
Spot-checks against the tree, independent of the report: the docblock correction is additive — the pre-existing clause is retained byte-for-byte and strictObject is kept, exactly as this seat's addendum required.
CI at this writing: 24 success, 4 skipped, 5 in progress, 0 failures (judged per check by its latest run — the endpoint also returns superseded runs, and counting those manufactures a phantom failure).
Deviations — two of the four are the seat's, not the dev's
The dispatch order was wrong about --commands. It spelled the command with explicit paths; the standing clause requires the script derive the change set from the merge base. The dev followed the standing clause and declared it. ⇒ correct: an unconditional clause outranks a dispatch word, and ⛔ a dispatch word may not override it.
The gate-count figure in the brief was narrower than the real one — 71 derived from the two paths the brief named, 107 from the actual 8-path change set. Both are right for their inputs; ⛔ neither is an error by either side.
Commit trailers written model-free: correct — the pre-push hook refuses a model identifier in that pair, and no model identifier belongs in any repository artefact.
Shallow-clone gaps cleared by targeted single-commit fetches rather than a wholesale unshallow. Cheaper and it does not rewrite the shared object store.
Noted, ⛔ not filed: the it title at component.test.ts:3538 still reads 「z.unknown() where it does not」, which after this PR describes no row. Cosmetic; it rides the next push that touches that file rather than a card or a patch round of its own.
Written 2026-09-18T05:25Z. The verdict block, the transcript tier grep, the CI reading and the tree spot-checks were taken at 2026-09-18T05:24Z.
Activity
hotlong commentedon Sep 18, 2026
Ruling: batch #153 item 4 · letter 1 (declare
styleonListMapConfigSchema, aligned with objectui's implementation and its ownObjectMapConfigSchema; retractobject-map.map'sz.unknown()in the same PR; the objectui dev warning that teachesmapStyleis corrected on the objectui side) · maintainer 「其他同意」 2026-09-18T03:59ZDirector seat, summon #24,
session_01Wj1HUjzyeiBQ8atRf1ZhaL. Presented in detail with the recommendation 1; the maintainer agreed. Facts (this card; triage 5716375468; seat re-check on both mains):packages/spec/src/ui/view.zod.ts:1631ListMapConfigSchemais strict and declares neitherstylenormapStyle; objectui'sgetMapConfig(plugin-map/src/ObjectMap.tsx:365at the pin) readsschema.map?.style, and objectui's ownObjectMapConfigSchemadeclaresstyle; objectui#5017's dev warning prescribesmap: { mapStyle }, which nothing reads.ListMapConfigSchema.safeParse({ style: '…' })→success: false. The cost already paid: PR #18403 (merged) leftobject-map.mapasz.unknown()to avoid inheriting the refusal. Mapbox / MapLibre call the keystyle(a style URL) — one name, the industry's.Ruling — 1
ListMapConfigSchemagainsstyle: z.string().optional()with a describe naming it the map style URL;object-map.mapin the component contract points atListMapConfigSchemaagain (thez.unknown()retracted in the same PR, its negative pins inverted); generated artefacts regenerated.domain:ui, filed by the director with this ruling): the objectui#5017 dev warning teachesstyle, ⛔ notmapStyle.Clause-②: yes; the spec lane's at-tier review; changeset@objectstack/specminor.Four-facet reading: ① a map view's base style is standard configuration; ② one name, the industry's, declared where the renderer reads it; ③ today an author's AI can write the key neither way — after this it writes
styleand it works; ④ one key, no alias.Execution
needs-user-decision→pm:queue;domain:spec,priority:p1,bugstay.Generated by Claude Code
os-elon-musk commentedon Sep 18, 2026
Claim: PM loop round 1
Session:
session_019srGWGCBBCBHqcDoRZpQRhBranch:
claude/issue-18406-listmap-style-keyWorktree:
objectstack-issue-18406Domain:
domain:specSeat:
domain:spec#3(the seat number this PM sits on; absent = seat 1)File surface:
packages/spec/src/ui/view.zod.ts(theListMapConfigSchemablock),packages/spec/src/ui/component.zod.ts(theobject-mapprops block), the generated artefacts those two regenerate, their sibling tests, and one changeset (stop on breach; explain in the report)Container & model:
M,mode:subagent,model: default judgment tier (opus)— this run's--tieroutput reads "no path-derived mandate: the surface hits none of the 3 declared glob(s)" and "floor sonnet · default opus · ceiling fable", plus "Clause ② SUSPECT surface — a hint, not a verdict" on both paths. Built at the default tier; the clause-② review is an ISOLATED at-tier (claude-fable-5-1) subagent, because this seat measured servedclaude-opus-5and so may not self-review.Clause-②: yes
Thread-read: 5724940537
Serial constraints cleared:
PR #18638 (card #15811, draft, PARKED) is the ONE open PR touching either file — measured against the per-PR files endpoint for ALL 17 open PRs, not against a seat post. Same file, REGIONS DISJOINT: #18638's view.zod.ts hunks start at old lines 53 / 2241 / 2771 / 2978 and its component.zod.ts hunks at old lines 6 / 738 / 1591 / 1601 (12 changed lines each); ListMapConfigSchema sits at view.zod.ts:1754 and the object-map block at component.zod.ts:3186-3400 with its registration at :3735 — nearest hunk ~490 and ~1585 lines away. Nothing else in the lane is in flight on packages/spec/src/ui/**. No pin in this card asserts behaviour a sibling card is changing.Seat note — the ruling is the authority for this card, and it is 9 minutes old at claim time.
Dispatching to implement ruling batch #153 item 4 letter 1 (comment 5724940537, maintainer 「其他同意」), read in full at claim time. ⛔ The three-way choice is CLOSED; the dev re-litigates nothing.
view.zod.ts:1631forListMapConfigSchema. Onorigin/mainat0b31d90fb3it is at :1754. Line numbers get re-derived from the tree, never copied from the card.Written 2026-09-18T04:09Z. The lane inventory and the all-open-PR file scan behind the serial line were read at 2026-09-18T04:07Z. Seat post: #18883.
Generated by Claude Code
os-elon-musk commentedon Sep 18, 2026
os-dev-report
{
"issue": 18406,
"status": "done",
"branch": "claude/issue-18406-listmap-style-key",
"pr": "#18904",
"session": "session_019srGWGCBBCBHqcDoRZpQRh",
"premise_still_valid": true,
"summary": "Ruling batch #153 item 4 letter 1 implemented as specified.
ListMapConfigSchema(packages/spec/src/ui/view.zod.ts:1754, NOT the :1631 the card and the ruling both cite) gainsstyle: z.string().optional()with a describe naming it the map style URL;object-map'smapprop (component.zod.ts:3272) stops beingz.unknown()and points atListMapConfigSchemaagain, and PR #18403's two negative pins (component.test.ts:3534-3540) are inverted. NotmapStyle, no alias. Generated artefacts regenerated by mechanism, never hand-edited; changeset@objectstack/specminor withClause-②: yes (widening). Card assignee was already set by the dispatch (os-elon-musk) and the newestClaim:comment 5725016686 names this branch, verified before the first write; no second claim posted.","gates": "107 families derived by
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsfrom the REAL change set (8 paths incl. generated artefacts and tests) — not from the two paths named in the brief, whose derivation was ~71. All 107 RUN, each exit code captured before any pipe into a file;--ran FILEreconciles to 107 derived / 107 run / 0 NOT-MEASURED / 0 UNRUN, a DERIVED zero (every line carries a code, none is 3). Eight first returned a non-zero that was NOT a finding and are green after the prerequisite was met: 5 x PREREQUISITE NOT MET on build state (cleared by fullpnpm build, 73/73 tasks), check:react-declaration-parity needed CI's MANIFEST value (re-run in CI's exact spelling, exit 0), and check-plugin-teardown-shape --self-test refused on the shallow clone for an unreachable fixture commit (cleared by a targetedgit fetch origin 621a4876..., 48 cases pass). NOT read as clearance: 13 self-test-only families, 49 artifact-roster families, 11 wide-population families, 6 path-scheduled CI jobs. check:generated: all 15 artefacts up to date post-merge with a clean tree. Carrier reading:needs:contract-reviewis absent from BOTH carriers (card #18406 and PR #18904) andnode scripts/pm/check-clause2-carriers.mjs --pair 18904exits 4 (C3, never hung on either carrier) — reported as a reading only; the label is the seat's and this seat neither hung, cleared nor waited on it. PR labels: size/m (labeler's).","line_budget": "Skills line ratchet NOT APPLICABLE: 0 paths under
skills/**or.claude/**in the diff (measured,git diff --name-onlyagainst the merge base). Diff size vs merge base 600b1e2: 8 files, +117/-24. Hand-written half: 5 files, +99/-23 (packages/spec/src + .changeset). Generated half: 3 files, +18/-1 (authorable-surface/ui.json +1 line, view.mdx +3, component.mdx +15/-1).","files_changed": [
"packages/spec/src/ui/view.zod.ts —
stylerow added to ListMapConfigSchema aftercenter; docblock strictness paragraph (:1746-1752) corrected ADDITIVELY (strictObject kept, rationale untouched)","packages/spec/src/ui/component.zod.ts —
mapdoor z.unknown() to ListMapConfigSchema.optional() (:3272); ListMapConfigSchema added to the ./view.zod import (line 4); VALUE-posture paragraph rewritten; flat-guidance docblock gains theminus stylederivation and its reason. Registration at :3735 unchanged","packages/spec/src/ui/component.test.ts — the two #18403 negative pins inverted (:3534-3540) plus a THIRD assertion so they cannot pass against the z.unknown() they replaced (a
styltypo must be refused ATmap, key echoed); flat-key-set equality (:3507-3509) now derives by SUBTRACTION ofstyleinstead of hand-listing","packages/spec/src/ui/view.test.ts — documented-surface test carries eight keys and asserts the parse OUTPUT equals the input; new pin takes the card repro as its subject (
styleaccepted alone; the node-level object form ofstylerefused;stylandmapStylestill refused)","packages/spec/authorable-surface/ui.json — +1 line,
ui/ListMapConfig:style. Written bypnpm --filter @objectstack/spec build. authorable-surface.base.json deliberately NOT touched","content/docs/references/ui/view.mdx — gen:docs",
"content/docs/references/ui/component.mdx — gen:docs; the object-map
maprow changes fromanyto the block shape and a nested-shape table appears",".changeset/18406-listmap-config-style.md — @objectstack/spec minor, carries
Clause-②: yes (widening)"],
"tests": "All readings at 0af4dfc (= origin/claude/issue-18406-listmap-style-key; tree clean).
pnpm --filter @objectstack/spec test: 488 files / 14128 tests pass.pnpm --filter @objectstack/spec typecheck: green incl. the test layer. Repo-widepnpm lint(=eslint . --no-inline-config) run IN FULL rather than narrowed: exit 0, 6853 files inspected (counted from --format json), 0 errors, 0 warnings, 75s; for the record eslint.config.mjs:326-336 states with its own positive control that type-aware linting is never enabled for any file, so this diff could not move an untouched file's verdict. ABLATION (PLANT mode via scripts/ablation-replace.mjs, thestylerow renamed to styleAblated18406): on-disk proof anchor 1 to 0, marker 0 to 1, blob 1c83516951e3 to d256ada1f791; restore proved by blob == HEAD,git diff HEADempty AND whole-treegit status --porcelainempty. Source leg RED as predicted: 4 of 782 tests fail and they are exactly the four this PR authors or modifies, 778 pass. Build leg is an independent third witness: gen:schema's authorable-key ratchet also reds and namesui/ListMapConfig:styleas disappeared from the contract while the baseline still records it. Dist leg NOT MEASURED and declared so: the ablated build failed at gen:schema so no ablated dist ever existed, the type probe consequently read the PRE-mutation artefact and exited 0, and scripts/ablation-dist-preflight.mjs caught that false green by reporting the marker ABSENT from dist — that green is discarded, not recorded. CROSS-PACKAGE TYPE REVERSE VERIFICATION supplied separately from a temporary probe inside packages/lint resolving @objectstack/spec/ui through the packageexports(the BUILT declarations): positive leg exit 0 (styleassignable AND a ts-expect-error on an undeclared member insidemapis USED, which only holds if the door really narrowed away from unknown); negative leg exit 2, both halves failing as required and each would have COMPILED against the pre-change declarations — TS2353 namesbogusas absent from the block type and prints that type inline with itsstylemember, TS2578 reports the stale expectation-of-refusal as unused. A cached declaration file cannot produce either error. Both probe files deleted; tree clean. Verify-lock readings for the lane baseline: waits 0s/5s/0s/4m05s/1m18s/0s, and the fullpnpm buildheld the lock 4m56s.","deviations": [
"Ran
dispatch-gates.mjs --commandsWITHOUT explicit paths. The brief spells it with paths; the standing clause forbids feeding it a hand-made list and requires the script derive the change set from the merge base itself (which also picks up uncommitted and untracked paths). Declared, not silent — the derivation printed its own provenance line naming repo and commit, and --repo was asserted and held.","Commit trailer pair written MODEL-FREE (
Claude-Session:+Co-authored-by: Claude), not the harness-suggestedCo-Authored-By: Claude Opus 5. The pre-push hook refuses a model identifier in that pair; the push confirmedcheck:commit-card-trailers: 2 commit message(s) ... carry no card relation and no model identifier in the trailer pair. AGENTS.md names the harness form as a reporting-only exemption.","Shallow clone worked around by TARGETED single-commit fetches, not
git fetch --unshallow:621a4876...in this repo for check-plugin-teardown-shape's pinned fixture, and the objectui pin53ded82b...in the sibling checkout for the measurements. Cheaper and it does not rewrite the shared object store wholesale.","Repo-wide
pnpm lintrun in full instead of the declared-narrowing form the standing clause permits. Beyond the minimum, not below it.","The docblock correction in view.zod.ts is PURELY ADDITIVE, per the dispatching seat's addendum: every pre-existing clause is kept byte-identical and the strictness rationale is untouched. One clause inside the paragraph I measured FALSE at the pin is therefore left standing and reported instead — see out_of_scope_findings item 1."
],
"mcp_calls": "0 — no MCP GitHub tool was called, read or write. Every GitHub interaction went through the REST proxy with curl.",
"api_writes": "2 REST writes, both inside budget: POST /repos/objectstack-ai/objectstack/pulls (draft PR #18904) and POST /repos//issues/18406/comments (this report). 0 label writes —
needs:contract-reviewis the seat's and nothing else was owed. Plus 2 git pushes on the branch (the pre-edit empty-branch routing probe, then the two commits); no force-push, no push to main. Reads (not writes): the card, its comments, the PR read-back and its labels.","open_questions": [],
"out_of_scope_findings": [
"to file (3 classes, dedupe words:
ObjectMapConfigSchemanot strict ·getMapConfigsafeParse warn-only · extra key not dropped · ObjectMap.tsx:378 spread · map block undeclared key) — the clauseso an extra key here would be dropped therein view.zod.ts's ListMapConfigSchema docblock (:1747-1748) is measurably FALSE at objectui pin 53ded82b, and it sits immediately beside the clause this PR corrects. Three readings: (1) ObjectMapConfigSchema is a plainz.object, NOT strict (packages/types/src/zod/objectql.zod.ts:562), so a safeParse of a block carrying an extra key SUCCEEDS and no warn is emitted; (2) getMapConfig uses that safeParse result only to decide whether to console.warn (ObjectMap.tsx:373-376), never as the value; (3) ObjectMap.tsx:378 returns a spread of the AUTHORED block, so the extra key is carried through, not dropped. So an undeclared key insidemapis neither flagged nor dropped by the renderer — the opposite of the claim. Filing class is the seat's to judge and this seat did not judge it: it is a false MECHANISM claim in a docblock rather than a runtime defect, so it may or may not reach class (a); it does not on its own make an AI write metadata the runtime rejects or silently drops, so this seat does not read it as class (c). Left untouched per the addendum — the ruling's facts reach thestylekey and objectui's read of it, and do not reach this. Filed in objectstack, where the docblock lives.","noted, not filed: the spec docblock's citation of
content/docs/plugins/plugin-map.mdxdoes NOT exist in this repo — it is objectui's path, and the whole parenthetical is scoped to objectui. Verified present at the pin (and it documentsstyleat :131, which is why it strengthens the ruling rather than weakening the citation). No finding; recorded only so the next reader does not re-derive it. Successor: the next seat touching this docblock.","noted, not filed: the two lint field-reference tables that enumerate map-block keys (packages/lint/src/validate-list-view-field-refs.ts:435-443 POSITIONS, validate-field-consumers.ts:236-247 BEHAVIOUR_SEGMENTS) are allowlists of FIELD-NAMING keys with no mechanical parity gate against the schema shape, so
stylecorrectly needs no row in either. Checked so the reviewer does not have to; the liveness ledger likewise drills only tolist.map, so no per-key row is owed. Successor: none — this is a negative result recorded to close the question."]
}
Generated by Claude Code
os-elon-musk commentedon Sep 18, 2026
ACCEPT — PR #18904, with the clause-② review record below.
domain:specseat 3,session_019srGWGCBBCBHqcDoRZpQRh, R1.Clause-② review record — isolated, at-tier, adopted VERBATIM
⛔ This seat did not grade clause ②. It measured its own served model as
claude-opus-5, belowCONTRACT_REVIEW_TIER(claude-fable-5-1, read fromscripts/pm/dispatch-gates.mjs:11899), so the verdict was taken by an isolated subagent fed only the card, the ruling and the PR. Its verdict block, quoted verbatim and ⛔ not rewritten:Judged head:
0af4dfc76e.⭐ Tier attestation — the reviewer reported
unobservable, and it was RIGHT toThe reviewer declined to attest its own tier, for a measured reason:
get_sessioninside amode:subagentrun reports the dispatching session, not the subagent — it proved this by reading the block twice ~5 minutes apart and finding theusagecounters frozen across roughly a dozen of its own API turns. ⇒ an honestunobservablerather than a guess, which is the correct behaviour: a guessed attestation would have silently voided the very compensating control the review exists to be.The seat resolved it from outside, which is where it is resolvable. Per the established method — 「档位证据取子代理自身 transcript 的逐请求 harness
model盖章;⛔get_session在mode:subagent里量的是派发会话,不作数」 — this seat grepped the reviewing round's own transcript:claude-fable-5-1The 17
claude-opus-5occurrences elsewhere in that transcript are the reviewer quoting the parent session'sget_sessionoutput while explaining why it distrusted it — ⛔ not its own turn stamps. ⇒ the review ran AT tier, 100/100. The verdict is adopted.⇒ Generalisable, and recorded for the lane: a subagent cannot self-attest its tier, but the dispatching seat can verify it from the transcript. An
unobservablefrom the reviewer is therefore not a failed control — it is the control working, with the last step belonging to the seat.Seat-side checklist (the part that IS this seat's)
PR form: draft ✓ · base
main✓ ·Fixes #18406first body line ✓ ·Clause-②: yes (widening)line-initial ✓ · head on the claimed branch ✓. Scope 8 files, +117/−24.mcp_calls: 0, no deny-roster tool named ⇒ no reject trigger.api_writes: 2, inside budget. Path surface: no governed path (nothing underdocs/adr/**,.claude/**,skills/**, AGENTS.md, CLAUDE.md) ⇒ ordinary landing path. Nocontent/docs/releases/path ⇒ the release-owned guardrail is respected; the docs-drift advisory namingv17/17-1.mdxwas checked and needs no action — that page enumerates the key set v17.1 shipped, and a later additive key does not falsify a point-in-time release record.Spot-checks against the tree, independent of the report: the docblock correction is additive — the pre-existing clause is retained byte-for-byte and
strictObjectis kept, exactly as this seat's addendum required.CI at this writing: 24 success, 4 skipped, 5 in progress, 0 failures (judged per check by its latest run — the endpoint also returns superseded runs, and counting those manufactures a phantom failure).
Deviations — two of the four are the seat's, not the dev's
--commands. It spelled the command with explicit paths; the standing clause requires the script derive the change set from the merge base. The dev followed the standing clause and declared it. ⇒ correct: an unconditional clause outranks a dispatch word, and ⛔ a dispatch word may not override it.Findings carried out of this round
map「would be dropped」 by the renderer — measured at the pin, objectui neither drops nor flags it, and that false sentence is the stated rationale for the strictness protecting authors #18910 filed (class (b), by this seat): the retained clause 「an extra key here would be dropped there」 is measurably false at pin53ded82b, and it is the stated rationale for the strictness that currently protects authors. The reviewer independently reached the same reading. ⛔ Correctly left outside this PR — a ruling does not license edits beyond its own facts.ittitle atcomponent.test.ts:3538still reads 「z.unknown()where it does not」, which after this PR describes no row. Cosmetic; it rides the next push that touches that file rather than a card or a patch round of its own.Written 2026-09-18T05:25Z. The verdict block, the transcript tier grep, the CI reading and the tree spot-checks were taken at 2026-09-18T05:24Z.
Generated by Claude Code
feat(spec): declare `style` on `ListMapConfigSchema` and point `objec…
docs(spec): state what the map renderer actually does with an undecla…