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.
Maintainer ruling (2026-08-18, live PM chat with the triage seat, session session_01EUZUjvnLsqwHVkXkTv8TKQ; verbatim: 「其他接受你的建议」, applying the triage recommendation delivered for this card).
Ruled: B, limited to the map block.ObjectMapConfigSchema goes .strict(), diagnosed through the existing safeParse → console.warn channel (warn, not reject — the channel the surrounding code already uses). Two conditions of the ruling:
Pre-measure before landing: sweep existing app metadata (examples + real apps reachable in-repo) for extra keys inside map blocks; the change lands only with that measurement quiet (zero or knowingly-accepted findings) attached to the PR.
⛔ No generalization in this card: the "all component sub-block schemas go closed" rule is a separate decision card, to be filed WITH the map-block's post-landing data (warn volume, real catches) — not assumed here.
Promoted to pm:queue. #5155 (BaseSchema index signature / top-level keys) remains its own card, untouched by this ruling.
Mislabel report from the repo:objectui execution seat (session session_01RV6yuVCxymHYE16PL9vQkE) — ⛔ reporting only, no label changed. Routing/grading is the triage seat's to produce (objectstack#6015).
The state machine and this card disagree. It is labelled pm:queue + enhancement, i.e. dispatchable. But its title is [Decision], and its content is a proposal about the shape of a published contract — whether ObjectMapConfigSchema should be .strict(). That is a contract-shape question on the manual floor, not a fix with a named landing point.
Why this matters more than a cosmetic label slip: an execution seat is required to trust labels and to treat every unassigned pm:queue card as fair game. Under the current labels, any seat scanning this lane is entitled to claim this card and dispatch a dev at it — and the dev would be implementing a contract decision nobody has ruled on. needs-user-decision is the only label that stops that, and it is absent. I skipped it on the strength of its content, but the next seat may not read the body before claiming.
Suggested disposition (yours to make, not mine):needs-user-decision with the four-facet block, or — if triage judges it inside the adjudication lane — an explicit ruling comment plus auto-adjudicated, the way #5190 was handled this morning. Either produces a card an execution seat can act on correctly. What it should not stay is silently dispatchable.
Noted in the seat post's queue snapshot so it is not lost if this session ends.
Claim: PM loop round 4 — domain:ui execution seat 2
Session: session_014mXUNuFomfj24w7s1pZzhN
Branch: claude/issue-5157-map-config-strict
Worktree: objectui-issue-5157
Domain: domain:ui
Seat: domain:ui#2
File surface: packages/types/src/zod/objectql.zod.ts (ObjectMapConfigSchema region only: .strict()); the existing safeParse → console.warn read in packages/plugin-map/src/ObjectMap.tsx only if its message has to name the refused key; tests beside them; the pre-measure the ruling requires (examples and in-repo apps, with extra keys inside map blocks) attached to the PR; one .changeset/5157-…md (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: opus — dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」; executes ruling 5328158731 (B, limited to the map block)
Clause-②: yes
Thread-read: 5328750768
Serial constraints cleared: the objectql.zod.ts predecessor PR objectui#10477 (objectui#10327) merged ae98f1d44. Open-PR file lists read 2026-09-25T05:21Z: no open PR touches objectql.zod.ts or plugin-map/src/ObjectMap.tsx. This seat's in-flight objectui#10392 fold edits plugin-map/src/index.tsx, a different file. Live pm:dispatched claims of seats 1, 3 and 4 name neither file. The mislabel report 5328750768 came after the ruling 5328158731 (same day), and the ruling stands.
Clause-②: yes — a published schema's accept set narrows: unknown keys in a map block stop parsing clean. Per the ruling the diagnostic channel is the existing safeParse → console.warn (warn, not reject). The dev measures whether the same schema also reaches a validate-face refusal through ObjectMapSchema.map, and stops and reports if it does.
{
"issue": 5157,
"status": "needs_decision",
"branch": "claude/issue-5157-map-config-strict",
"pr": null,
"session": "session_014mXUNuFomfj24w7s1pZzhN (mode:subagent, the dispatching PM session)",
"premise_still_valid": true,
"summary": "Stopped at dispatch hypothesis H2, as the order directs: `.strict()` on `ObjectMapConfigSchema` reaches a hard refusal on the validate face. `ObjectMapSchema.map` is `ObjectMapConfigSchema.optional()`, so `safeValidateSchema` (`AnyComponentSchema`, the function `objectui validate` and `objectui check` call) returns success=true for a map block with a misspelled key at BASE and success=false with the mutation. Everything else measured quiet. The ruling-condition-1 sweep found 20 `map` blocks that use only declared keys: 18 in objectui examples/apps/content and 2 in objectstack examples. The existing warn already names the refused key, so ObjectMap.tsx needs no change under either option. The card premise holds: at BASE the misspelled key parses clean on every tolerant face and the runtime prints no warn. No code, PR, changeset or label was written. The only artefact is the empty branch at BASE, pushed as the claim landing marker.",
"tests": "BASE = cc139d820fdeade7dcf5931f7430dfb5c31f2f2a (objectui origin/main when the worktree was made). No diff exists, so no gate family was run. NOT MEASURED: typecheck, unit tests, check-changeset-presence, check:new-line-citations, check:control-bytes; reason: needs_decision stop at H2 before implementation. || H1 holds at BASE (cited by symbol): `export const ObjectMapConfigSchema = z.object({...})` has no `.strict()`. ObjectMap.tsx `getMapConfig` runs `ObjectMapConfigSchema.safeParse(config)` and then `console.warn('[ObjectMap] Invalid map configuration:', result.error.format())`. `FLAT_MAP_CONFIG_KEYS` is derived from `.shape`, and `.shape` is unchanged under `.strict()`: the probe measured the same 8 keys, latitudeField,longitudeField,locationField,titleField,descriptionField,zoom,center,style. Both `authoredEverything` pins exist, in ListView.mapFlatten.test.tsx and ObjectView.mapFlatten.test.tsx. || H2 probe (tsx over the worktree source; documents: clean = object-map with map {latitudeField,longitudeField}; typo = map {latitudeFieId,longitudeField}; child = div whose children hold the typo node). BASE: block typo success=true; safeValidateSchema clean success=true; safeValidateSchema typo success=true; safeValidateSchema child success=true; StrictAnyComponentSchema typo success=false, unrecognized_keys keys [latitudeFieId] at path [map]. || H2 probe with the mutation `}).strict();` on the ObjectMapConfigSchema closer. The write landed on disk: catchall def type read as never, and the anchor-marker grep counted 1. Results: block typo success=false (unrecognized_keys [latitudeFieId]); safeValidateSchema clean success=true; safeValidateSchema typo success=false (unrecognized_keys [latitudeFieId] at path [map]); safeValidateSchema child success=false (invalid_union at path [children], message Invalid input). The restore used `git checkout HEAD --` under a trap. It was proven three ways: git diff HEAD = 0 bytes, marker grep = 0, and git hash-object matching the HEAD blob. || H4 probe, same mutation and the same restore proof: `result.error.format()` on the typo block = {\"_errors\":[\"Unrecognized key: \\\"latitudeFieId\\\"\"]}. The existing warn therefore names the refused key. At BASE the typo parses success=true and no warn fires, which is the card symptom. || Spec cross-read, @objectstack/spec 17.4.0 as resolved from packages/types: `ListViewSchema.map` is an object with catchall never and 7 keys (the objectui set minus style). `safeParse({locationField, latitudeFieId})` returns success=false, unrecognized_keys [latitudeFieId]. The same logical block authored on a view is therefore already refused by the spec. || H3 sweep. Population is enumerated with git ls-tree at the ref, and content is read with git show from the same ref. The script is a one-time instrument kept in the seat scratchpad, not in the repo. Every hit is reconciled against a raw grep for a map key. (1) objectui BASE examples+apps+content: 967 files, 17 brace-literal map blocks plus 1 variable-bound block (plugin-map.mdx, TypeScript Support section, `mapConfig` with 6 declared keys), 0 undeclared keys. The 17 are content/docs/fields/location.mdx x1, content/docs/plugins/plugin-map.mdx x13, and examples/schema-catalog plugin-map JSON x3 (event-venue-finder, real-time-delivery-tracking, store-locator-map). The other raw-grep hits are package names, type annotations and test helpers. (2) objectstack origin/main aa04ea2 examples+apps: 284 files. There are 2 real map config blocks, both {titleField, locationField}: app-showcase task.view.ts on the view named map, and test task-map-marker-title.test.ts. The 2 other hits are false positives: a view whose key is `map`, and a translations label map. (3) objectui BASE packages/ plus console and catalog tests: 96 brace blocks. No object-map fixture authors an undeclared key inside `map`. The only `bogusKey` is in ListView.mapViewLevelConfig.test.tsx, on the ListView flatten path, which never parses ObjectMapConfigSchema. The remaining EXTRA rows are unrelated `map` configs (flow nodes, recipient maps) or spreads of declared keys. Verdict: measurement quiet, 0 findings. || Door census, by git grep of the symbol in non-test source at BASE. Four sites use `ObjectMapConfigSchema`. (i) `ObjectMapSchema.map` flows through ObjectQLComponentSchema and AnyComponentSchema into safeValidateSchema/validateSchema, reaching packages/cli validate.ts and check.ts (check uses it as a recogniser, and a refused file moves to its UNVALIDATED_CANDIDATE bucket), plus every SchemaNodeSchema child slot. (ii) The ObjectMap.tsx getMapConfig warn, reached only when a `map` key is present on the node; the ListView/ObjectView flatteners emit flat keys and no `map` key. (iii) ObjectMap.tsx FLAT_MAP_CONFIG_KEYS, which reads shape only. (iv) StrictAnyComponentSchema, which already refuses and has no non-test consumer at BASE. ListViewSchema in objectql.zod.ts does not reference ObjectMapConfigSchema. packages/core validateSchema (SchemaRenderer dev validation) imports no zod face.",
"mcp_calls": "0 — none",
"api_writes": "1 — POST /repos/objectstack-ai/objectui/issues/5157/comments (this os-dev-report, via scripts/pm/post-stamped.mjs). The git push of the empty branch is not REST. Reads: GET /repos/objectstack-ai/objectui/issues/5157 and GET .../issues/5157/comments?per_page=100.",
"deviations": [
"Stopped at H2 per the order: no PR, no PR-assignee label-write, no changeset, no code. The write budget used is 1 of 4 (the report comment), plus the empty-branch git push.",
"The role file was read at objectstack origin/main aa04ea2, not a4ca69a: origin/main had moved. `git diff a4ca69a origin/main -- .claude/agents/os-dev.md` is empty, so the text is the same.",
"The sweep ran wider than the order named (examples/apps/content). It also covered objectstack origin/main examples+apps and objectui packages/ fixtures. These are reported separately so the named scope stays readable on its own.",
"The worktree objectui-issue-5157 had no changes. It is removed after this report, and the branch stays on the remote at BASE for the claim."
],
"open_questions": [
{
"question": "Does ruling 5328158731 (B, map block only, \"warn, not reject\") cover the validate-face refusal that `ObjectMapConfigSchema.strict()` brings with it? `ObjectMapSchema.map` IS `ObjectMapConfigSchema.optional()`. Closing the schema therefore also makes `safeValidateSchema`, and `objectui validate` / `objectui check` with it, refuse a map block with a misspelled key. Measured: BASE success=true, strict success=false, unrecognized_keys [latitudeFieId] at [map]; a nested document fails with invalid_union at [children]. The runtime channel stays a warn under both options: ObjectMap still renders and warns.",
"options": [
"A — strict everywhere: `.strict()` on ObjectMapConfigSchema itself. The runtime warns and renders as before; the validate face refuses at authoring time. [Business need] The sweep found 20 of 20 existing map blocks clean, so A newly refuses 0 measured documents. The symptom is real and measured: at BASE a typo leaves an empty map with no diagnostic. validate/check is the only authoring-time check that untyped metadata passes through. [Long-term] A keeps the one-schema property objectui#5018 lifted the schema for (declared face = runtime check = validate face). It matches the spec's own view-level block (spec 17.4.0 ListViewSchema.map, catchall never) and the objectui#5250 strict twin, which already refuses. Precedent for strict sub-blocks on the tolerant face: DashboardWidgetSchema (objectui#6002) and CalendarDayRangeSchema (objectui#10304). [Anti-AI-error] Strongest: a loud refusal at validate/publish that names the key. [Startup focus] Smallest diff: one `.strict()`, the pins, and a minor changeset that states the narrowing. No new gate, no second schema, no transition window needed, since measured breakage is 0. Costs: (1) at the validate face A goes beyond the literal \"warn, not reject\", so it needs the maintainer's explicit yes; (2) bare safeValidateSchema reports a nested document as a generic invalid_union at children (NOT MEASURED: how the CLI arm-selection diagnostics render it).",
"B — strict on the runtime warn path only. The node `map` member keeps the tolerant schema, and ObjectMap.tsx parses the block with a strict variant, for example `ObjectMapConfigSchema.strict()`. [Business need] B gives the same runtime catch (the warn names the key, as measured) but only on nodes that directly author a `map` block. The view flatten path never reaches it. `objectui validate` keeps printing valid for a misspelled block. [Long-term] B re-creates two accept sets for one declared block (declared tolerant, runtime strict), which is the drift shape objectui#5018 removed. It is also transitional: once the objectui#5250 devx half wires validate to StrictAnyComponentSchema, validate refuses the same typo anyway. [Anti-AI-error] Weaker: AI-authored metadata is judged at validate/check, which stays silent; a dev-console warn never reaches a publish pipeline. [Startup focus] Slightly more code: a second parse spelling in plugin-map, plus a pin that the node face stays tolerant. B is literally compliant with \"warn, not reject\"."
],
"recommendation": "A, for the maintainer to confirm (not chosen or implemented here, per the order). All four axes point the same way: 0 measured documents would be refused; one schema, matching the spec's own strict view-level block and the strict twin; a loud authoring-time refusal is what protects untyped AI metadata, and a runtime warn does not; and A is the smallest change with no new gate. Choose B only if \"warn, not reject\" is meant to bind the validate face as well as the runtime."
}
],
"out_of_scope_findings": [
"Not class a/b/c: a stale code comment in ObjectMap.tsx `warnOnTopLevelStyleUrl` says `@objectstack/spec` list-view schemas \"declare no `map` block at all\". Measured on spec 17.4.0: ListViewSchema declares `map`, a strict 7-key object. Noted, not filed. carrier: the implementation round of this same claim, if it touches ObjectMap.tsx; otherwise no carrier (承接者:无), acceptance notes only."
]
}
维护者速读 · decision box: does "warn, not reject" bind the validate face too? · domain:ui seat 2 · 2026-09-28T11:0xZ
session_014mXUNuFomfj24w7s1pZzhN. The claim 5827254568 stopped at needs_decision before any code (dev report 5827348034). The seat left the card at pm:dispatched from 2026-09-25 and never routed it. This comment routes it now: release to needs-user-decision. The claim is spent.
The question. Ruling 5328158731 (B, the map block only) makes ObjectMapConfigSchema.strict(), diagnosed through the existing safeParse → console.warn channel ("warn, not reject"). But ObjectMapSchema.mapisObjectMapConfigSchema.optional(). So closing the schema also makes safeValidateSchema, and with it objectui validate / objectui check, refuse a map block with a misspelled key. Does the ruling cover that refusal?
Measured (dev report):
At the base, success=true. Strict gives success=false, unrecognized_keys [latitudeFieId] at [map].
At runtime, ObjectMap still renders and warns under both options.
The pre-measure sweep the ruling requires found 20 of 20 existing map blocks clean, so 0 documents would be newly refused.
ObjectMapConfigSchema is still tolerant on main today.
Options, on the four axes:
A (recommended)..strict() on ObjectMapConfigSchema itself. The runtime warns and renders as before, and validate / check refuse the typo at authoring time.
Business need: the symptom is real and measured. At the base, a typo leaves an empty map with no diagnostic. The sweep shows A newly refuses 0 of the 20 existing blocks.
Long-term: it keeps the one-schema property objectui#5018 set up (declared face = runtime check = validate face). It matches the spec's strict view-level map block and the objectui#5250 strict twin. Strict sub-blocks on the tolerant face have precedent in objectui#6002 and objectui#10304.
AI-error: the strongest option. It is a loud refusal at validate / publish that names the key, which is where untyped AI-authored metadata is judged.
Startup focus: the smallest diff: one .strict(), pins and a minor changeset. No new gate, and no transition window, because measured breakage is 0.
Against: at the validate face it goes past the literal "warn, not reject", so it needs an explicit yes. A nested document fails as a generic invalid_union at children. How the CLI renders that was not measured.
B. Strict on the runtime warn path only. ObjectMap.tsx parses with a strict variant, and the node's map member stays tolerant.
Business need: the same runtime catch, but only on nodes that author a map block directly. objectui validate keeps printing valid for a misspelled block.
Long-term: two accept sets for one declared block, the drift shape objectui#5018 removed. It is also transitional: once objectui#5250's devx half wires validate to StrictAnyComponentSchema, validate refuses the typo anyway.
AI-error: weaker. Validate / check stay silent, and a dev-console warning never reaches a publish pipeline.
Startup focus: slightly more code: a second parse in plugin-map and a pin that the node face stays tolerant. It is literally "warn, not reject".
After the decision: the next dispatch re-claims the card. The ruling's "no generalization in this card" condition stands under either option.
domain:ui seat 2 · decision box and release · 2026-09-28T11:0xZ
Decision-box entry check by the triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-09-28T12:06Z. ⛔ Not a claim; labels are untouched (needs-user-decision stays).
Prior rulings on this card: 5328158731 (Ruled: B, limited to the map block; .strict() diagnosed through safeParse → console.warn, "warn, not reject"). What changed since: the dev measured that ObjectMapSchema.mapisObjectMapConfigSchema.optional(). Closing that schema therefore also makes safeValidateSchema, and with it objectui validate / check, refuse a misspelled key, which is a face the ruling's "warn, not reject" did not address. The question is only whether the ruling covers that refusal. ⛔ The ruling's scope, the map block only, is not reopened.
Entry check.
The 维护者速读 is present (5868608591).
The four-facet block is present.
The ruling's pre-measure is reported: 20 of 20 map blocks are clean.
The only thing missing was the line above. The seat's question paragraph already states the change, so triage completed the line from that measured text instead of bouncing the card back through pm:retriage for one line.
Ruling: batch #238 item 2 · letter A · maintainer 「同意」 2026-09-28T13:48Z
Director seat (objectstack#12708, summon #30 续 2, session_01AsCNgFBs8HCjwhyHQsFbx3). Provenance: maintainer, live PM chat with the director seat, 2026-09-28, replying 「同意」 to batch #238 as presented — this card item 2, recommendation A, fallback B, the full four-axis body in chat.
Ruled: A..strict() goes on ObjectMapConfigSchema itself (packages/types/src/zod/objectql.zod.ts), per ruling 5328158731 (B, the map block only), and the refusal that produces on the validate face is COVERED: because ObjectMapSchema.map is ObjectMapConfigSchema.optional() (objectql.zod.ts:1954), safeValidateSchema — and with it objectui validate / objectui check — refuses a map block with an unknown key at authoring time, while the runtime ObjectMap keeps rendering and warning through the existing safeParse → console.warn channel. 「Warn, not reject」 in the earlier ruling described the runtime channel; it does not bind the validate face. B (a strict variant on the runtime warn path only, the node's map member left tolerant) is not taken.
Real use: the symptom is measured, not assumed — a typo renders an empty 「坐标无效」 map with no diagnostic. The pre-measure sweep the earlier ruling required (dev report 5827348034, H3) found 20 of 20 existing map blocks using declared keys only (objectui examples / apps / content 18, objectstack examples 2): 0 documents newly refused.
AI-safety: untyped AI-authored metadata is judged at validate / publish; a loud refusal there that names the key is the only diagnostic that reaches it, and a dev-console warning never reaches a publish pipeline. Mainstream config validators (JSON Schema additionalProperties: false, ESLint config validation, Next.js unknown-key warnings) speak at authoring time.
Startup scope: the smallest diff — one .strict(), pins, a minor changeset; no new gate, no transition window (measured breakage 0).
Execution parameters (ruled in the same stroke):
This card → pm:queue; domain:ui, priority:p2 stay; the next dispatch re-claims it and executes A. The claim 5827254568 is spent.
Change: ObjectMapConfigSchema closes with .strict(). FLAT_MAP_CONFIG_KEYS (derived from .shape) is unchanged (8 keys, measured). packages/plugin-map/src/ObjectMap.tsx needs no change: the existing warn already names the refused key (Unrecognized key: "latitudeFieId", measured H4).
Pins, both sides: (i) runtime — a map block with an unknown key still renders and warns, and the warn names the key; (ii) validate face — safeValidateSchema refuses the same block with unrecognized_keys at path [map] and the clean block passes; (iii) the sweep's 20 existing blocks parse clean under strict (a fixture pin, so the sweep's result is held rather than remembered).
Nested documents: a nested typo fails as invalid_union at [children]. The dev measures how objectui validate / check render that refusal and records it in the PR; if the rendered message does not name the key, that is a follow-up card, not this one.
Clause-②: yes (a published schema's accept set narrows); @object-ui/types changeset minor.
Standing condition kept: no generalisation to other component sub-blocks in this card.
State: needs-user-decision → pm:queue; domain:ui, priority:p2 stay; the Ruled line goes on the body in the same stroke.
Claim: PM loop round 16 (serial) — domain:ui execution seat 2
Session: session_014mXUNuFomfj24w7s1pZzhN
Branch: claude/issue-5157-map-config-strict-a
Worktree: objectui-issue-5157
Domain: domain:ui
Seat: domain:ui#2
Ruling-ref: 5328158731 (B, the map block only) and 5871202958 (batch #238 item 2, letter A, maintainer 「同意」 2026-09-28T13:48Z)
File surface, per the execution parameters of 5871202958:
packages/types/src/zod/objectql.zod.ts: ObjectMapConfigSchema closes with .strict(). FLAT_MAP_CONFIG_KEYS stays at 8 keys. packages/plugin-map/src/ObjectMap.tsx is unchanged (its warn already names the key).
Pins on both faces: (i) runtime, where a map block with an unknown key still renders and the warn names the key; (ii) validate face, where safeValidateSchema refuses it with unrecognized_keys at [map] and a clean block passes; (iii) the sweep's 20 existing blocks parse clean under strict, held as a fixture.
The nested-document refusal (invalid_union at [children]): the rendered objectui validate / check message is measured and recorded in the PR. If it does not name the key, that is a follow-up card.
A '@object-ui/types': minor changeset that states the narrowing.
⛔ No generalisation to other component sub-blocks (the standing condition).
Container & model: S, mode:subagent, model: opus (default judgment tier)
Clause-②: yes
Why yes: a published schema's accept set narrows (ruled so). The PR carries needs:contract-review.
Thread-read: 5871202958
Serial constraints cleared:
Dispatch is serial, and this is the one card in development. PR objectui#10983 (objectui#10963) is in the merge queue, and PR objectui#10989 (objectui#10951) is in a base-merge landing chore. Neither counts.
I read the open-PR file lists at 2026-09-28T14:3xZ, at objectui origin/main40c076fc2d. None touches objectql.zod.ts's ObjectMapConfigSchema region or plugin-map.
The claim 5827254568 is spent (per 5871202958), and its empty branch claude/issue-5157-map-config-strict is not reused.
If another seat claims at the same time, the earliest live claim wins and this seat yields.
{
"issue": 5157,
"status": "done",
"branch": "claude/issue-5157-map-config-strict-a",
"pr": "https://github.com/objectstack-ai/objectui/pull/10997",
"session": "session_014mXUNuFomfj24w7s1pZzhN (mode:subagent, the dispatching PM session)",
"premise_still_valid": true,
"summary": "Implemented ruling A. `ObjectMapConfigSchema` now closes with `.strict()`, so `safeValidateSchema` and `objectui validate` refuse an undeclared `map` key with `unrecognized_keys` at `map`, naming it, while `ObjectMap` still renders and warns with the key named; `.shape` keeps its 8 keys and ObjectMap.tsx is unchanged. The re-derived sweep found 20 of 20 existing map blocks clean (18 objectui, 2 objectstack), and it is held as a fixture pin. The CLI names the key at both depths (the nested case as arm sub-line 1.6 of 10 under an `invalid_union` at `children`), so no follow-up card is needed. PR #10997 is draft, assigned to os-elon-musk, with a `'@object-ui/types': minor` changeset. The earliest live Claim at start was 5872032029 (5827254568 spent per 5871202958), and the card assignee os-elon-musk was already set.",
"tests": "HEAD d68b1086ed. BASE 40c076fc2ddbc418c833a2be607b975fde77a9cb. All test runs went through os-verify-lock.sh; verdict lines quoted. || (1) `pnpm exec vitest run --maxWorkers=2 packages/types/ packages/cli/` + the 31 outside test files that read ObjectMapConfigSchema / ObjectMapSchema / FLAT_MAP_CONFIG_KEYS or author an object-map (from git grep) + `examples/schema-catalog/test/`: `Test Files 358 passed (358)`, `Tests 9311 passed (9311)`, `VERDICT command-exit 0`. (2) `pnpm exec vitest run --maxWorkers=2 packages/plugin-map/` + the new types pin: `Test Files 34 passed (34)`, `Tests 243 passed (243)`, `VERDICT command-exit 0`. (3) type-check of @object-ui/types, @object-ui/plugin-map and @object-ui/cli (all three echoed), `VERDICT command-exit 0`, after building the `@object-ui/plugin-map^...` closure. `--listFilesOnly` on each package's tsconfig.test.json lists the new test file (1 hit each). || ABLATION (red on base, green on head). Tool: objectstack origin/main `scripts/ablation-replace.mjs`, copied to the scratchpad, WRAP mode. Anchor `}).strict();` x1 to x0, replacement `});` x23 to x24, blob 7ef2545fa19c to 4d0b11cad207. Restore: blob == HEAD 7ef2545fa19c and `git diff HEAD` empty. Resolution: the root vitest alias maps `@object-ui/types/zod` to packages/types/src/zod/index.zod.ts, so no dist is involved. Mutated run: `Tests 5 failed / 46 passed (51)`. Red: the 4 (ii) rows (safeValidateSchema typo, ObjectMapSchema typo, ObjectMapConfigSchema typo, nested typo), plus the (i) warn row `expected 0 to be greater than 0`. Green: the (ii) clean control, the 2 shape rows, the 40 (iii) sweep rows, the (i) render row, and the (i) no-warn control. Head: `Tests 51 passed (51)`. || CLI measurement on built dist. HEAD: `objectui validate` on the root typo exits 1, `1. Unrecognized key: \"latitudeFieId\" / Path: map / Code: unrecognized_keys`. The nested typo exits 1, `1. Invalid input / Path: children / Code: invalid_union`, with sub-line `1.6 [arm 1/6] Unrecognized key: \"latitudeFieId\" / Path: children → 0 → map / Code: unrecognized_keys` among 10 sub-lines. The clean node exits 0 valid. `objectui check` exits 0 and lists only the root typo file under `did not validate`, then `✓ All checks passed`. BASE (types rebuilt with `.strict()` ablated; dist preflight read the ObjectMapConfigSchema closer as `});`): validate exits 0 valid on all three files; check exits 0 with no list. Types dist rebuilt after the restore, and the closer reads `}).strict();`. || Gates at HEAD d68b1086ed: check-changeset-presence `✅ 3 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)`; check-changeset-no-major `✅ No changeset declares a major bump`; check-changeset-overwrite `✅`; check:changeset-claims exit 0 (22 pending changesets name touched files; the 7 mentioning map, strip or tolerance were re-read, none is falsified); check:pending-changeset-literals `✅`; check:new-line-citations `VERDICT new-cross-file-line-citations: 0 new citation(s)`; check:control-bytes `✅ OK`, plus a self-grep of the changed files for control bytes with 0 hits; check:spec-symbols `✅`; check-doc-links `Links are valid across 17 scan roots`; check:doc-fences, check:doc-types, check-prompt-component-keys, check:test-path-roots, check:vi-mock-specifiers all `✅`; check-governed-queue-guard --test on the 7 paths `✅ NOT GOVERNED`. ESLint (narrowed, --no-inline-config --format json) on the 3 changed TS files: 0 errors, 0 warnings on the new files, 1 pre-existing warning in objectql.zod.ts; no type-aware linting is configured, so the diff cannot move another file's verdict; the repo-wide lint is CI's. Eager closure: the console vite build guard printed `[plugin assert-types-zod-stays-lazy] ... none in the eager closure`, and `pnpm check:eager-closure` printed `✅ Console eager closure is 3103.9 KB gzipped ... (budget: 3104.5 KB, headroom: 0.6 KB)`, equal to the dispatch's reading, so the delta is 0.0 KB. `git merge-tree --write-tree origin/main HEAD` against fresh origin/main f667c1df97 exits 0. NOT MEASURED: check:doc-snippets / check:doc-examples; reason: they need every package built, and this diff adds no code fence and changes no TS declaration. CI: in_progress, not awaited.",
"mcp_calls": "0 — none",
"api_writes": "3 — all via the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches, run conclusion success, as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls, draft, PR #10997, relay run 36441807972; (2) label-write --assign os-elon-musk → POST /repos/objectstack-ai/objectui/issues/10997/assignees, relay run 36441947624, read-back MATCHES (labels untouched: documentation, package: types, plugin, tests from labeler); (3) this os-dev-report via post-stamped.mjs → POST /repos/objectstack-ai/objectui/issues/5157/comments. Not REST: 4 git pushes (empty branch, then 3 commits). Reads: GET issues/5157, issues/5157/comments, pulls?head=…, pulls/10997.",
"files_changed": [
"packages/types/src/zod/objectql.zod.ts",
"packages/types/src/__tests__/object-map-config-strict-5157.test.ts",
"packages/plugin-map/src/ObjectMap.strictConfigWarn-5157.test.tsx",
".changeset/5157-object-map-config-strict.md",
"packages/plugin-map/README.md",
"content/docs/plugins/plugin-map.mdx",
"packages/types/README.md"
],
"deviations": [
"Order said pin (i) is green on base. Measured, only its render half is green on base. The warn half is red on base, because the tolerant schema never fails the safeParse, so nothing is warned. That silence is the card's symptom. The pin asserts the ruled head behaviour (renders AND warns naming the key), and the ablation shows the split.",
"Order said FLAT_MAP_CONFIG_KEYS stays at 8 keys. `.shape` has 8 keys. FLAT_MAP_CONFIG_KEYS (module-private, `.shape` minus `style`) has 7, before and after. The pin asserts the 8-key `.shape` list.",
"During the base-CLI measurement, the script's EXIT trap restore failed with `not inside a git repository`. ablation-replace.mjs resolves the repo root from process.cwd(), and the script had cd'd into the scratchpad. I caught it in that step's log and restored by hand in the next command with `ablation-replace.mjs --restore` from the repo root: blob == HEAD 7ef2545fa19c, `git diff HEAD` empty, `git status` clean. Then I rebuilt types dist, and the closer reads `}).strict();`. No commit or test ran on the mutated tree. The pin ablation itself ran in WRAP mode, and its own restore passed.",
"The write tools and the ablation tool ran from objectstack origin/main 3cf6449389. The write tools ran from a detached worktree at /home/user/objectstack-pm-5157, removed after this report. The ablation tool was copied into the scratchpad. The reason: the shared objectstack checkout's HEAD 5581d3000f differs from origin/main in scripts/pm/post-stamped.mjs, dispatch-gates.mjs and three others, and objectui has no ablation tool.",
"dispatch-gates.mjs is objectstack-only, so the objectui gate families were derived by hand from package.json and .github/workflows. Added beyond the order's list: check-changeset-overwrite, check:doc-fences, check:doc-types, check-prompt-component-keys, check:test-path-roots, check:vi-mock-specifiers, the governed-surface test, and a narrowed ESLint run.",
"Docs item 5: no sentence anywhere said the map block tolerated unknown keys or that validate accepted them. The types README said the whole rendering face, every named mirror included, is tolerant, so it now names the map block as closed. Per AGENTS #2, a one-paragraph closure note was also added to the plugin-map README and plugin-map.mdx.",
"The eager closure was measured with a head console build only, with no base build. The reading equals the dispatch's quoted 3103.9 KB, and types-zod is outside the closure by the build's own guard.",
"The PR title keeps `feat(types)!`: check-changeset-no-major reads only changeset front matter, not the title, and the bump is minor."
],
"open_questions": [],
"out_of_scope_findings": [
"Not class a/b/c (a comment): the ObjectMap.tsx `warnOnTopLevelStyleUrl` docblock says @objectstack/spec list-view schemas \"declare no `map` block at all\". Measured on spec 17.4.0: ListViewSchema declares `map`, and safeParse of a view with map {locationField, latitudeFieId} gives unrecognized_keys [latitudeFieId] at [map]. carrier: 承接者:无 — noted in the PR's Acceptance notes, not filed.",
"Not class a/b/c (by design, advisory): `objectui check` admits a file whose root carries a structural key (children, className, …) without validating it. So a map typo in such a file, nested or at the root, never reaches check; only a root object-map with no structural key lands in its `did not validate` list. The command's own description sends the verdict to `objectui validate`. carrier: 承接者:无 — Acceptance notes only.",
"Not class a/b/c (readability): the nested refusal names the key as sub-line 1.6 of 10 under a generic invalid_union at children; the other nine lines are non-candidate arms. The key IS named, so the ruling's follow-up condition is not met. carrier: 承接者:无 — Acceptance notes only.",
"Siblings with the same shape (standing condition, not touched, not measured): the object-calendar `calendar` block (spec-derived, `.passthrough()`), plus plain z.object config schemas such as SortConfigSchema, DrillDownConfigSchema and ReportExportConfigSchema. Listed in Acceptance notes for the separate generalisation decision."
]
}
ObjectMapConfigSchema closes with .strict(). objectui validate refuses an undeclared map key and names it: at map on a root node, and in the arm detail under invalid_union at children when nested. ObjectMap does not throw: it warns and names the key. .shape is unchanged, and so is ObjectMap.tsx
sweep
20 of 20 existing map blocks are clean (18 objectui, 2 objectstack, one of them on a named view), held as a fixture. Measured breakage: 0
review
contract review 5873208537FAIL (the ledger entry for CI's shard 1/8, and three wording defects), then fix round 1 (bf4797f85f, d5c28d4da2), then the in-seat delta record PASS (posted with this landing)
changesets
'@object-ui/types': minor, Clause-②: yes: a published schema's accept set narrows, following the objectui#6002 / #10304 precedent
follow-up
objectui check never names the refused key, and skips nested typos. One card, filed after landing
CI
head d5c28d4da2: every check final and green before ready. Eager closure +0
Activity
os-support-ai commentedon Aug 18, 2026
Maintainer ruling (2026-08-18, live PM chat with the triage seat, session
session_01EUZUjvnLsqwHVkXkTv8TKQ; verbatim: 「其他接受你的建议」, applying the triage recommendation delivered for this card).Ruled: B, limited to the
mapblock.ObjectMapConfigSchemagoes.strict(), diagnosed through the existingsafeParse→console.warnchannel (warn, not reject — the channel the surrounding code already uses). Two conditions of the ruling:mapblocks; the change lands only with that measurement quiet (zero or knowingly-accepted findings) attached to the PR.Promoted to
pm:queue. #5155 (BaseSchema index signature / top-level keys) remains its own card, untouched by this ruling.Generated by Claude Code
os-support-ai commentedon Aug 18, 2026
Mislabel report from the
repo:objectuiexecution seat (sessionsession_01RV6yuVCxymHYE16PL9vQkE) — ⛔ reporting only, no label changed. Routing/grading is the triage seat's to produce (objectstack#6015).The state machine and this card disagree. It is labelled
pm:queue+enhancement, i.e. dispatchable. But its title is[Decision], and its content is a proposal about the shape of a published contract — whetherObjectMapConfigSchemashould be.strict(). That is a contract-shape question on the manual floor, not a fix with a named landing point.Why this matters more than a cosmetic label slip: an execution seat is required to trust labels and to treat every unassigned
pm:queuecard as fair game. Under the current labels, any seat scanning this lane is entitled to claim this card and dispatch a dev at it — and the dev would be implementing a contract decision nobody has ruled on.needs-user-decisionis the only label that stops that, and it is absent. I skipped it on the strength of its content, but the next seat may not read the body before claiming.Suggested disposition (yours to make, not mine):
needs-user-decisionwith the four-facet block, or — if triage judges it inside the adjudication lane — an explicit ruling comment plusauto-adjudicated, the way #5190 was handled this morning. Either produces a card an execution seat can act on correctly. What it should not stay is silently dispatchable.Noted in the seat post's queue snapshot so it is not lost if this session ends.
Generated by Claude Code
ci(stale): correct the action SHA the job has never once resolved (ob…
objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 4 —
domain:uiexecution seat 2Session:
session_014mXUNuFomfj24w7s1pZzhNBranch:
claude/issue-5157-map-config-strictWorktree:
objectui-issue-5157Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/types/src/zod/objectql.zod.ts(ObjectMapConfigSchemaregion only:.strict()); the existingsafeParse→console.warnread inpackages/plugin-map/src/ObjectMap.tsxonly if its message has to name the refused key; tests beside them; the pre-measure the ruling requires (examples and in-repo apps, with extra keys insidemapblocks) attached to the PR; one.changeset/5157-…md(stop on breach; explain in the report)Container & model:
S,mode:subagent,model: opus—dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」; executes ruling5328158731(B, limited to themapblock)Clause-②: yes
Thread-read: 5328750768
Serial constraints cleared: the
objectql.zod.tspredecessor PR objectui#10477 (objectui#10327) mergedae98f1d44. Open-PR file lists read 2026-09-25T05:21Z: no open PR touchesobjectql.zod.tsorplugin-map/src/ObjectMap.tsx. This seat's in-flight objectui#10392 fold editsplugin-map/src/index.tsx, a different file. Livepm:dispatchedclaims of seats 1, 3 and 4 name neither file. The mislabel report5328750768came after the ruling5328158731(same day), and the ruling stands.Clause-②: yes— a published schema's accept set narrows: unknown keys in amapblock stop parsing clean. Per the ruling the diagnostic channel is the existingsafeParse→console.warn(warn, not reject). The dev measures whether the same schema also reaches a validate-face refusal throughObjectMapSchema.map, and stops and reports if it does.Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
os-dev-report
{ "issue": 5157, "status": "needs_decision", "branch": "claude/issue-5157-map-config-strict", "pr": null, "session": "session_014mXUNuFomfj24w7s1pZzhN (mode:subagent, the dispatching PM session)", "premise_still_valid": true, "summary": "Stopped at dispatch hypothesis H2, as the order directs: `.strict()` on `ObjectMapConfigSchema` reaches a hard refusal on the validate face. `ObjectMapSchema.map` is `ObjectMapConfigSchema.optional()`, so `safeValidateSchema` (`AnyComponentSchema`, the function `objectui validate` and `objectui check` call) returns success=true for a map block with a misspelled key at BASE and success=false with the mutation. Everything else measured quiet. The ruling-condition-1 sweep found 20 `map` blocks that use only declared keys: 18 in objectui examples/apps/content and 2 in objectstack examples. The existing warn already names the refused key, so ObjectMap.tsx needs no change under either option. The card premise holds: at BASE the misspelled key parses clean on every tolerant face and the runtime prints no warn. No code, PR, changeset or label was written. The only artefact is the empty branch at BASE, pushed as the claim landing marker.", "tests": "BASE = cc139d820fdeade7dcf5931f7430dfb5c31f2f2a (objectui origin/main when the worktree was made). No diff exists, so no gate family was run. NOT MEASURED: typecheck, unit tests, check-changeset-presence, check:new-line-citations, check:control-bytes; reason: needs_decision stop at H2 before implementation. || H1 holds at BASE (cited by symbol): `export const ObjectMapConfigSchema = z.object({...})` has no `.strict()`. ObjectMap.tsx `getMapConfig` runs `ObjectMapConfigSchema.safeParse(config)` and then `console.warn('[ObjectMap] Invalid map configuration:', result.error.format())`. `FLAT_MAP_CONFIG_KEYS` is derived from `.shape`, and `.shape` is unchanged under `.strict()`: the probe measured the same 8 keys, latitudeField,longitudeField,locationField,titleField,descriptionField,zoom,center,style. Both `authoredEverything` pins exist, in ListView.mapFlatten.test.tsx and ObjectView.mapFlatten.test.tsx. || H2 probe (tsx over the worktree source; documents: clean = object-map with map {latitudeField,longitudeField}; typo = map {latitudeFieId,longitudeField}; child = div whose children hold the typo node). BASE: block typo success=true; safeValidateSchema clean success=true; safeValidateSchema typo success=true; safeValidateSchema child success=true; StrictAnyComponentSchema typo success=false, unrecognized_keys keys [latitudeFieId] at path [map]. || H2 probe with the mutation `}).strict();` on the ObjectMapConfigSchema closer. The write landed on disk: catchall def type read as never, and the anchor-marker grep counted 1. Results: block typo success=false (unrecognized_keys [latitudeFieId]); safeValidateSchema clean success=true; safeValidateSchema typo success=false (unrecognized_keys [latitudeFieId] at path [map]); safeValidateSchema child success=false (invalid_union at path [children], message Invalid input). The restore used `git checkout HEAD --` under a trap. It was proven three ways: git diff HEAD = 0 bytes, marker grep = 0, and git hash-object matching the HEAD blob. || H4 probe, same mutation and the same restore proof: `result.error.format()` on the typo block = {\"_errors\":[\"Unrecognized key: \\\"latitudeFieId\\\"\"]}. The existing warn therefore names the refused key. At BASE the typo parses success=true and no warn fires, which is the card symptom. || Spec cross-read, @objectstack/spec 17.4.0 as resolved from packages/types: `ListViewSchema.map` is an object with catchall never and 7 keys (the objectui set minus style). `safeParse({locationField, latitudeFieId})` returns success=false, unrecognized_keys [latitudeFieId]. The same logical block authored on a view is therefore already refused by the spec. || H3 sweep. Population is enumerated with git ls-tree at the ref, and content is read with git show from the same ref. The script is a one-time instrument kept in the seat scratchpad, not in the repo. Every hit is reconciled against a raw grep for a map key. (1) objectui BASE examples+apps+content: 967 files, 17 brace-literal map blocks plus 1 variable-bound block (plugin-map.mdx, TypeScript Support section, `mapConfig` with 6 declared keys), 0 undeclared keys. The 17 are content/docs/fields/location.mdx x1, content/docs/plugins/plugin-map.mdx x13, and examples/schema-catalog plugin-map JSON x3 (event-venue-finder, real-time-delivery-tracking, store-locator-map). The other raw-grep hits are package names, type annotations and test helpers. (2) objectstack origin/main aa04ea2 examples+apps: 284 files. There are 2 real map config blocks, both {titleField, locationField}: app-showcase task.view.ts on the view named map, and test task-map-marker-title.test.ts. The 2 other hits are false positives: a view whose key is `map`, and a translations label map. (3) objectui BASE packages/ plus console and catalog tests: 96 brace blocks. No object-map fixture authors an undeclared key inside `map`. The only `bogusKey` is in ListView.mapViewLevelConfig.test.tsx, on the ListView flatten path, which never parses ObjectMapConfigSchema. The remaining EXTRA rows are unrelated `map` configs (flow nodes, recipient maps) or spreads of declared keys. Verdict: measurement quiet, 0 findings. || Door census, by git grep of the symbol in non-test source at BASE. Four sites use `ObjectMapConfigSchema`. (i) `ObjectMapSchema.map` flows through ObjectQLComponentSchema and AnyComponentSchema into safeValidateSchema/validateSchema, reaching packages/cli validate.ts and check.ts (check uses it as a recogniser, and a refused file moves to its UNVALIDATED_CANDIDATE bucket), plus every SchemaNodeSchema child slot. (ii) The ObjectMap.tsx getMapConfig warn, reached only when a `map` key is present on the node; the ListView/ObjectView flatteners emit flat keys and no `map` key. (iii) ObjectMap.tsx FLAT_MAP_CONFIG_KEYS, which reads shape only. (iv) StrictAnyComponentSchema, which already refuses and has no non-test consumer at BASE. ListViewSchema in objectql.zod.ts does not reference ObjectMapConfigSchema. packages/core validateSchema (SchemaRenderer dev validation) imports no zod face.", "mcp_calls": "0 — none", "api_writes": "1 — POST /repos/objectstack-ai/objectui/issues/5157/comments (this os-dev-report, via scripts/pm/post-stamped.mjs). The git push of the empty branch is not REST. Reads: GET /repos/objectstack-ai/objectui/issues/5157 and GET .../issues/5157/comments?per_page=100.", "deviations": [ "Stopped at H2 per the order: no PR, no PR-assignee label-write, no changeset, no code. The write budget used is 1 of 4 (the report comment), plus the empty-branch git push.", "The role file was read at objectstack origin/main aa04ea2, not a4ca69a: origin/main had moved. `git diff a4ca69a origin/main -- .claude/agents/os-dev.md` is empty, so the text is the same.", "The sweep ran wider than the order named (examples/apps/content). It also covered objectstack origin/main examples+apps and objectui packages/ fixtures. These are reported separately so the named scope stays readable on its own.", "The worktree objectui-issue-5157 had no changes. It is removed after this report, and the branch stays on the remote at BASE for the claim." ], "open_questions": [ { "question": "Does ruling 5328158731 (B, map block only, \"warn, not reject\") cover the validate-face refusal that `ObjectMapConfigSchema.strict()` brings with it? `ObjectMapSchema.map` IS `ObjectMapConfigSchema.optional()`. Closing the schema therefore also makes `safeValidateSchema`, and `objectui validate` / `objectui check` with it, refuse a map block with a misspelled key. Measured: BASE success=true, strict success=false, unrecognized_keys [latitudeFieId] at [map]; a nested document fails with invalid_union at [children]. The runtime channel stays a warn under both options: ObjectMap still renders and warns.", "options": [ "A — strict everywhere: `.strict()` on ObjectMapConfigSchema itself. The runtime warns and renders as before; the validate face refuses at authoring time. [Business need] The sweep found 20 of 20 existing map blocks clean, so A newly refuses 0 measured documents. The symptom is real and measured: at BASE a typo leaves an empty map with no diagnostic. validate/check is the only authoring-time check that untyped metadata passes through. [Long-term] A keeps the one-schema property objectui#5018 lifted the schema for (declared face = runtime check = validate face). It matches the spec's own view-level block (spec 17.4.0 ListViewSchema.map, catchall never) and the objectui#5250 strict twin, which already refuses. Precedent for strict sub-blocks on the tolerant face: DashboardWidgetSchema (objectui#6002) and CalendarDayRangeSchema (objectui#10304). [Anti-AI-error] Strongest: a loud refusal at validate/publish that names the key. [Startup focus] Smallest diff: one `.strict()`, the pins, and a minor changeset that states the narrowing. No new gate, no second schema, no transition window needed, since measured breakage is 0. Costs: (1) at the validate face A goes beyond the literal \"warn, not reject\", so it needs the maintainer's explicit yes; (2) bare safeValidateSchema reports a nested document as a generic invalid_union at children (NOT MEASURED: how the CLI arm-selection diagnostics render it).", "B — strict on the runtime warn path only. The node `map` member keeps the tolerant schema, and ObjectMap.tsx parses the block with a strict variant, for example `ObjectMapConfigSchema.strict()`. [Business need] B gives the same runtime catch (the warn names the key, as measured) but only on nodes that directly author a `map` block. The view flatten path never reaches it. `objectui validate` keeps printing valid for a misspelled block. [Long-term] B re-creates two accept sets for one declared block (declared tolerant, runtime strict), which is the drift shape objectui#5018 removed. It is also transitional: once the objectui#5250 devx half wires validate to StrictAnyComponentSchema, validate refuses the same typo anyway. [Anti-AI-error] Weaker: AI-authored metadata is judged at validate/check, which stays silent; a dev-console warn never reaches a publish pipeline. [Startup focus] Slightly more code: a second parse spelling in plugin-map, plus a pin that the node face stays tolerant. B is literally compliant with \"warn, not reject\"." ], "recommendation": "A, for the maintainer to confirm (not chosen or implemented here, per the order). All four axes point the same way: 0 measured documents would be refused; one schema, matching the spec's own strict view-level block and the strict twin; a loud authoring-time refusal is what protects untyped AI metadata, and a runtime warn does not; and A is the smallest change with no new gate. Choose B only if \"warn, not reject\" is meant to bind the validate face as well as the runtime." } ], "out_of_scope_findings": [ "Not class a/b/c: a stale code comment in ObjectMap.tsx `warnOnTopLevelStyleUrl` says `@objectstack/spec` list-view schemas \"declare no `map` block at all\". Measured on spec 17.4.0: ListViewSchema declares `map`, a strict 7-key object. Noted, not filed. carrier: the implementation round of this same claim, if it touches ObjectMap.tsx; otherwise no carrier (承接者:无), acceptance notes only." ] }Generated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
维护者速读 · decision box: does "warn, not reject" bind the validate face too? ·
domain:uiseat 2 · 2026-09-28T11:0xZsession_014mXUNuFomfj24w7s1pZzhN. The claim5827254568stopped atneeds_decisionbefore any code (dev report5827348034). The seat left the card atpm:dispatchedfrom 2026-09-25 and never routed it. This comment routes it now: release toneeds-user-decision. The claim is spent.The question. Ruling
5328158731(B, themapblock only) makesObjectMapConfigSchema.strict(), diagnosed through the existingsafeParse→console.warnchannel ("warn, not reject"). ButObjectMapSchema.mapisObjectMapConfigSchema.optional(). So closing the schema also makessafeValidateSchema, and with itobjectui validate/objectui check, refuse a map block with a misspelled key. Does the ruling cover that refusal?Measured (dev report):
success=true. Strict givessuccess=false,unrecognized_keys [latitudeFieId]at[map].ObjectMapstill renders and warns under both options.ObjectMapConfigSchemais still tolerant onmaintoday.Options, on the four axes:
.strict()onObjectMapConfigSchemaitself. The runtime warns and renders as before, and validate / check refuse the typo at authoring time.mapblock and the objectui#5250 strict twin. Strict sub-blocks on the tolerant face have precedent in objectui#6002 and objectui#10304..strict(), pins and a minor changeset. No new gate, and no transition window, because measured breakage is 0.invalid_unionatchildren. How the CLI renders that was not measured.ObjectMap.tsxparses with a strict variant, and the node'smapmember stays tolerant.mapblock directly.objectui validatekeeps printing valid for a misspelled block.StrictAnyComponentSchema, validate refuses the typo anyway.After the decision: the next dispatch re-claims the card. The ruling's "no generalization in this card" condition stands under either option.
domain:uiseat 2 · decision box and release · 2026-09-28T11:0xZ1 remaining item
objectstack-fleet commentedon Sep 28, 2026
Decision-box entry check by the triage seat ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-28T12:06Z. ⛔ Not a claim; labels are untouched (needs-user-decisionstays).Prior rulings on this card:
5328158731(Ruled: B, limited to themapblock;.strict()diagnosed throughsafeParse→console.warn, "warn, not reject"). What changed since: the dev measured thatObjectMapSchema.mapisObjectMapConfigSchema.optional(). Closing that schema therefore also makessafeValidateSchema, and with itobjectui validate/check, refuse a misspelled key, which is a face the ruling's "warn, not reject" did not address. The question is only whether the ruling covers that refusal. ⛔ The ruling's scope, themapblock only, is not reopened.Entry check.
5868608591).pm:retriagefor one line.objectstack-fleet commentedon Sep 28, 2026
Ruling: batch #238 item 2 · letter A · maintainer 「同意」 2026-09-28T13:48Z
Director seat (objectstack#12708, summon #30 续 2,
session_01AsCNgFBs8HCjwhyHQsFbx3). Provenance: maintainer, live PM chat with the director seat, 2026-09-28, replying 「同意」 to batch #238 as presented — this card item 2, recommendation A, fallback B, the full four-axis body in chat.Ruled: A.
.strict()goes onObjectMapConfigSchemaitself (packages/types/src/zod/objectql.zod.ts), per ruling5328158731(B, themapblock only), and the refusal that produces on the validate face is COVERED: becauseObjectMapSchema.mapisObjectMapConfigSchema.optional()(objectql.zod.ts:1954),safeValidateSchema— and with itobjectui validate/objectui check— refuses amapblock with an unknown key at authoring time, while the runtimeObjectMapkeeps rendering and warning through the existingsafeParse→console.warnchannel. 「Warn, not reject」 in the earlier ruling described the runtime channel; it does not bind the validate face. B (a strict variant on the runtime warn path only, the node'smapmember left tolerant) is not taken.Readings that decided it:
mapblock (@objectstack/spec17.4.0ListViewSchema.map, catchallnever, refuseslatitudeFieIdtoday) and the objectui#5250 strict twin; strict sub-blocks on the tolerant face have precedent (objectui#6002, objectui#10304). B re-creates two accept sets for one declared block, the drift shapeObjectMapSchema(types)声明的键几乎与 ObjectMap 实际读的键无交集:map块整体未建模,组件 props 类型写的是ObjectGridSchema,每处 map 读取都走as any#5018 removed, and is transitional anyway: once finding: JSON doc snippets are checked by nothing — the ts/tsx gate cannot see them, andBaseSchema.passthrough()makesobjectui validateaccept arbitrary undeclared keys #5250's devx half wires validate toStrictAnyComponentSchema, validate refuses the typo regardless.5827348034, H3) found 20 of 20 existingmapblocks using declared keys only (objectui examples / apps / content 18, objectstack examples 2): 0 documents newly refused.additionalProperties: false, ESLint config validation, Next.js unknown-key warnings) speak at authoring time..strict(), pins, aminorchangeset; no new gate, no transition window (measured breakage 0).Execution parameters (ruled in the same stroke):
pm:queue;domain:ui,priority:p2stay; the next dispatch re-claims it and executes A. The claim5827254568is spent.ObjectMapConfigSchemacloses with.strict().FLAT_MAP_CONFIG_KEYS(derived from.shape) is unchanged (8 keys, measured).packages/plugin-map/src/ObjectMap.tsxneeds no change: the existing warn already names the refused key (Unrecognized key: "latitudeFieId", measured H4).mapblock with an unknown key still renders and warns, and the warn names the key; (ii) validate face —safeValidateSchemarefuses the same block withunrecognized_keysat path[map]and the clean block passes; (iii) the sweep's 20 existing blocks parse clean under strict (a fixture pin, so the sweep's result is held rather than remembered).invalid_unionat[children]. The dev measures howobjectui validate/checkrender that refusal and records it in the PR; if the rendered message does not name the key, that is a follow-up card, not this one.Clause-②: yes(a published schema's accept set narrows);@object-ui/typeschangesetminor.State:
needs-user-decision→pm:queue;domain:ui,priority:p2stay; the Ruled line goes on the body in the same stroke.objectstack-fleet commentedon Sep 28, 2026
Claim: PM loop round 16 (serial) —
domain:uiexecution seat 2Session:
session_014mXUNuFomfj24w7s1pZzhNBranch:
claude/issue-5157-map-config-strict-aWorktree:
objectui-issue-5157Domain:
domain:uiSeat:
domain:ui#2Ruling-ref:
5328158731(B, themapblock only) and5871202958(batch #238 item 2, letter A, maintainer 「同意」 2026-09-28T13:48Z)File surface, per the execution parameters of
5871202958:packages/types/src/zod/objectql.zod.ts:ObjectMapConfigSchemacloses with.strict().FLAT_MAP_CONFIG_KEYSstays at 8 keys.packages/plugin-map/src/ObjectMap.tsxis unchanged (its warn already names the key).mapblock with an unknown key still renders and the warn names the key; (ii) validate face, wheresafeValidateSchemarefuses it withunrecognized_keysat[map]and a clean block passes; (iii) the sweep's 20 existing blocks parse clean under strict, held as a fixture.invalid_unionat[children]): the renderedobjectui validate/checkmessage is measured and recorded in the PR. If it does not name the key, that is a follow-up card.'@object-ui/types': minorchangeset that states the narrowing.Container & model:
S,mode:subagent,model: opus(default judgment tier)Clause-②: yes
Why yes: a published schema's accept set narrows (ruled so). The PR carries
needs:contract-review.Thread-read: 5871202958
Serial constraints cleared:
origin/main40c076fc2d. None touchesobjectql.zod.ts'sObjectMapConfigSchemaregion orplugin-map.5827254568is spent (per5871202958), and its empty branchclaude/issue-5157-map-config-strictis not reused.objectstack-fleet commentedon Sep 28, 2026
os-dev-report
{ "issue": 5157, "status": "done", "branch": "claude/issue-5157-map-config-strict-a", "pr": "https://github.com/objectstack-ai/objectui/pull/10997", "session": "session_014mXUNuFomfj24w7s1pZzhN (mode:subagent, the dispatching PM session)", "premise_still_valid": true, "summary": "Implemented ruling A. `ObjectMapConfigSchema` now closes with `.strict()`, so `safeValidateSchema` and `objectui validate` refuse an undeclared `map` key with `unrecognized_keys` at `map`, naming it, while `ObjectMap` still renders and warns with the key named; `.shape` keeps its 8 keys and ObjectMap.tsx is unchanged. The re-derived sweep found 20 of 20 existing map blocks clean (18 objectui, 2 objectstack), and it is held as a fixture pin. The CLI names the key at both depths (the nested case as arm sub-line 1.6 of 10 under an `invalid_union` at `children`), so no follow-up card is needed. PR #10997 is draft, assigned to os-elon-musk, with a `'@object-ui/types': minor` changeset. The earliest live Claim at start was 5872032029 (5827254568 spent per 5871202958), and the card assignee os-elon-musk was already set.", "tests": "HEAD d68b1086ed. BASE 40c076fc2ddbc418c833a2be607b975fde77a9cb. All test runs went through os-verify-lock.sh; verdict lines quoted. || (1) `pnpm exec vitest run --maxWorkers=2 packages/types/ packages/cli/` + the 31 outside test files that read ObjectMapConfigSchema / ObjectMapSchema / FLAT_MAP_CONFIG_KEYS or author an object-map (from git grep) + `examples/schema-catalog/test/`: `Test Files 358 passed (358)`, `Tests 9311 passed (9311)`, `VERDICT command-exit 0`. (2) `pnpm exec vitest run --maxWorkers=2 packages/plugin-map/` + the new types pin: `Test Files 34 passed (34)`, `Tests 243 passed (243)`, `VERDICT command-exit 0`. (3) type-check of @object-ui/types, @object-ui/plugin-map and @object-ui/cli (all three echoed), `VERDICT command-exit 0`, after building the `@object-ui/plugin-map^...` closure. `--listFilesOnly` on each package's tsconfig.test.json lists the new test file (1 hit each). || ABLATION (red on base, green on head). Tool: objectstack origin/main `scripts/ablation-replace.mjs`, copied to the scratchpad, WRAP mode. Anchor `}).strict();` x1 to x0, replacement `});` x23 to x24, blob 7ef2545fa19c to 4d0b11cad207. Restore: blob == HEAD 7ef2545fa19c and `git diff HEAD` empty. Resolution: the root vitest alias maps `@object-ui/types/zod` to packages/types/src/zod/index.zod.ts, so no dist is involved. Mutated run: `Tests 5 failed / 46 passed (51)`. Red: the 4 (ii) rows (safeValidateSchema typo, ObjectMapSchema typo, ObjectMapConfigSchema typo, nested typo), plus the (i) warn row `expected 0 to be greater than 0`. Green: the (ii) clean control, the 2 shape rows, the 40 (iii) sweep rows, the (i) render row, and the (i) no-warn control. Head: `Tests 51 passed (51)`. || CLI measurement on built dist. HEAD: `objectui validate` on the root typo exits 1, `1. Unrecognized key: \"latitudeFieId\" / Path: map / Code: unrecognized_keys`. The nested typo exits 1, `1. Invalid input / Path: children / Code: invalid_union`, with sub-line `1.6 [arm 1/6] Unrecognized key: \"latitudeFieId\" / Path: children → 0 → map / Code: unrecognized_keys` among 10 sub-lines. The clean node exits 0 valid. `objectui check` exits 0 and lists only the root typo file under `did not validate`, then `✓ All checks passed`. BASE (types rebuilt with `.strict()` ablated; dist preflight read the ObjectMapConfigSchema closer as `});`): validate exits 0 valid on all three files; check exits 0 with no list. Types dist rebuilt after the restore, and the closer reads `}).strict();`. || Gates at HEAD d68b1086ed: check-changeset-presence `✅ 3 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)`; check-changeset-no-major `✅ No changeset declares a major bump`; check-changeset-overwrite `✅`; check:changeset-claims exit 0 (22 pending changesets name touched files; the 7 mentioning map, strip or tolerance were re-read, none is falsified); check:pending-changeset-literals `✅`; check:new-line-citations `VERDICT new-cross-file-line-citations: 0 new citation(s)`; check:control-bytes `✅ OK`, plus a self-grep of the changed files for control bytes with 0 hits; check:spec-symbols `✅`; check-doc-links `Links are valid across 17 scan roots`; check:doc-fences, check:doc-types, check-prompt-component-keys, check:test-path-roots, check:vi-mock-specifiers all `✅`; check-governed-queue-guard --test on the 7 paths `✅ NOT GOVERNED`. ESLint (narrowed, --no-inline-config --format json) on the 3 changed TS files: 0 errors, 0 warnings on the new files, 1 pre-existing warning in objectql.zod.ts; no type-aware linting is configured, so the diff cannot move another file's verdict; the repo-wide lint is CI's. Eager closure: the console vite build guard printed `[plugin assert-types-zod-stays-lazy] ... none in the eager closure`, and `pnpm check:eager-closure` printed `✅ Console eager closure is 3103.9 KB gzipped ... (budget: 3104.5 KB, headroom: 0.6 KB)`, equal to the dispatch's reading, so the delta is 0.0 KB. `git merge-tree --write-tree origin/main HEAD` against fresh origin/main f667c1df97 exits 0. NOT MEASURED: check:doc-snippets / check:doc-examples; reason: they need every package built, and this diff adds no code fence and changes no TS declaration. CI: in_progress, not awaited.", "mcp_calls": "0 — none", "api_writes": "3 — all via the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches, run conclusion success, as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls, draft, PR #10997, relay run 36441807972; (2) label-write --assign os-elon-musk → POST /repos/objectstack-ai/objectui/issues/10997/assignees, relay run 36441947624, read-back MATCHES (labels untouched: documentation, package: types, plugin, tests from labeler); (3) this os-dev-report via post-stamped.mjs → POST /repos/objectstack-ai/objectui/issues/5157/comments. Not REST: 4 git pushes (empty branch, then 3 commits). Reads: GET issues/5157, issues/5157/comments, pulls?head=…, pulls/10997.", "files_changed": [ "packages/types/src/zod/objectql.zod.ts", "packages/types/src/__tests__/object-map-config-strict-5157.test.ts", "packages/plugin-map/src/ObjectMap.strictConfigWarn-5157.test.tsx", ".changeset/5157-object-map-config-strict.md", "packages/plugin-map/README.md", "content/docs/plugins/plugin-map.mdx", "packages/types/README.md" ], "deviations": [ "Order said pin (i) is green on base. Measured, only its render half is green on base. The warn half is red on base, because the tolerant schema never fails the safeParse, so nothing is warned. That silence is the card's symptom. The pin asserts the ruled head behaviour (renders AND warns naming the key), and the ablation shows the split.", "Order said FLAT_MAP_CONFIG_KEYS stays at 8 keys. `.shape` has 8 keys. FLAT_MAP_CONFIG_KEYS (module-private, `.shape` minus `style`) has 7, before and after. The pin asserts the 8-key `.shape` list.", "During the base-CLI measurement, the script's EXIT trap restore failed with `not inside a git repository`. ablation-replace.mjs resolves the repo root from process.cwd(), and the script had cd'd into the scratchpad. I caught it in that step's log and restored by hand in the next command with `ablation-replace.mjs --restore` from the repo root: blob == HEAD 7ef2545fa19c, `git diff HEAD` empty, `git status` clean. Then I rebuilt types dist, and the closer reads `}).strict();`. No commit or test ran on the mutated tree. The pin ablation itself ran in WRAP mode, and its own restore passed.", "The write tools and the ablation tool ran from objectstack origin/main 3cf6449389. The write tools ran from a detached worktree at /home/user/objectstack-pm-5157, removed after this report. The ablation tool was copied into the scratchpad. The reason: the shared objectstack checkout's HEAD 5581d3000f differs from origin/main in scripts/pm/post-stamped.mjs, dispatch-gates.mjs and three others, and objectui has no ablation tool.", "dispatch-gates.mjs is objectstack-only, so the objectui gate families were derived by hand from package.json and .github/workflows. Added beyond the order's list: check-changeset-overwrite, check:doc-fences, check:doc-types, check-prompt-component-keys, check:test-path-roots, check:vi-mock-specifiers, the governed-surface test, and a narrowed ESLint run.", "Docs item 5: no sentence anywhere said the map block tolerated unknown keys or that validate accepted them. The types README said the whole rendering face, every named mirror included, is tolerant, so it now names the map block as closed. Per AGENTS #2, a one-paragraph closure note was also added to the plugin-map README and plugin-map.mdx.", "The eager closure was measured with a head console build only, with no base build. The reading equals the dispatch's quoted 3103.9 KB, and types-zod is outside the closure by the build's own guard.", "The PR title keeps `feat(types)!`: check-changeset-no-major reads only changeset front matter, not the title, and the bump is minor." ], "open_questions": [], "out_of_scope_findings": [ "Not class a/b/c (a comment): the ObjectMap.tsx `warnOnTopLevelStyleUrl` docblock says @objectstack/spec list-view schemas \"declare no `map` block at all\". Measured on spec 17.4.0: ListViewSchema declares `map`, and safeParse of a view with map {locationField, latitudeFieId} gives unrecognized_keys [latitudeFieId] at [map]. carrier: 承接者:无 — noted in the PR's Acceptance notes, not filed.", "Not class a/b/c (by design, advisory): `objectui check` admits a file whose root carries a structural key (children, className, …) without validating it. So a map typo in such a file, nested or at the root, never reaches check; only a root object-map with no structural key lands in its `did not validate` list. The command's own description sends the verdict to `objectui validate`. carrier: 承接者:无 — Acceptance notes only.", "Not class a/b/c (readability): the nested refusal names the key as sub-line 1.6 of 10 under a generic invalid_union at children; the other nine lines are non-candidate arms. The key IS named, so the ruling's follow-up condition is not met. carrier: 承接者:无 — Acceptance notes only.", "Siblings with the same shape (standing condition, not touched, not measured): the object-calendar `calendar` block (spec-derived, `.passthrough()`), plus plain z.object config schemas such as SortConfigSchema, DrillDownConfigSchema and ReportExportConfigSchema. Listed in Acceptance notes for the separate generalisation decision." ] }Generated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
✅ ACCEPT: PR objectui#10997 (
Fixes) atd5c28d4da2; ready and auto-merge follow this ACCEPTdomain:uiseat #2,session_014mXUNuFomfj24w7s1pZzhN. I checked this against the diff and CI, not against the reports' own account.5872032029.5328158731and5871202958(A).os-dev-reporton this card, plus the fix-round reports relayed in-session.ObjectMapConfigSchemacloses with.strict().objectui validaterefuses an undeclaredmapkey and names it: atmapon a root node, and in the arm detail underinvalid_unionatchildrenwhen nested.ObjectMapdoes not throw: it warns and names the key..shapeis unchanged, and so isObjectMap.tsxmapblocks are clean (18 objectui, 2 objectstack, one of them on a named view), held as a fixture. Measured breakage: 05873208537FAIL (the ledger entry for CI's shard 1/8, and three wording defects), then fix round 1 (bf4797f85f,d5c28d4da2), then the in-seat delta record PASS (posted with this landing)'@object-ui/types': minor,Clause-②: yes: a published schema's accept set narrows, following the objectui#6002 / #10304 precedentobjectui checknever names the refused key, and skips nested typos. One card, filed after landingd5c28d4da2: every check final and green before ready. Eager closure +0Fixes #5157feat(types)!: ObjectMapConfigSchema is strict, so objectui validate r…