Repository navigation
spec: RecordChatterProps.position declares a vocabulary no read point compares — sidebar/inline/drawer vs the renderer's bottom/right/left — and its collapsible default inverts the renderer's #8762
Description
Activity
Triage: lands in
packages/spec/src/ui/component.zod.ts(RecordChatterProps) —domain:spec, the semantic lane, because every candidate fix moves the accept face. Typed Bug: the row declares a vocabulary nothing reads, which is declared-≠-enforced on a published contract, not a new capability.State:
needs-user-decision. Reasoning below, including the half that does not need a ruling.Why not straight to
pm:queue— the boundary test, appliedThe card is two defects sharing a schema object, and they grade differently:
- The two
.default()s (position: 'sidebar',collapsible: true) — already ruled. spec:record:reference_railhas no ComponentPropsMap row — an entryfilterparses, typechecks, validates, ships, and silently does nothing #8691 settled the principle for this exact family (renderer fallbacks stay the renderer's facts; the spec row does not mint a value the renderer contradicts) and spec:record:alert/record:quick_actions/record:historyhave no ComponentPropsMap row — same silent no-op mechanism #8691 closed for the rail #8744 is applying it to three neighbouring rows right now. Inheriting a sibling ruling together with its reason is the default here, and the reason transfers cleanly: a materializedsidebaron every parsed node is the same silent no-op the mother card closed. No new decision needed for this half. - The vocabulary (
sidebar/inline/drawervsbottom/right/left) — not covered by that ruling. spec:record:reference_railhas no ComponentPropsMap row — an entryfilterparses, typechecks, validates, ships, and silently does nothing #8691/spec:record:alert/record:quick_actions/record:historyhave no ComponentPropsMap row — same silent no-op mechanism #8691 closed for the rail #8744 were about missing rows and defaults, never about two enums that disagree. Converging them narrows a published enum on a GA contract (ADR-0087 conversion) or changes renderer behaviour on stored metadata. Either direction is a public-contract shape change, which is maintainer floor regardless of how confident the analysis is.
So one ruling on the vocabulary releases the whole card, defaults included.
Four-facet card face
- Platform long-term coherence — the only outcome to avoid is a mapping layer; that is special-case growth papering over two contracts. One vocabulary, and the loser's spellings get an ADR-0087 conversion. Note
drawerhas no renderer counterpart at all, so convergence toward the renderer is also a removal question, not a pure rename. - Measured business pull — today the authoring path is broken in both directions: the schema's own default (
sidebar) renders inline, and the value that actually docks the panel (right) is spec-invalid and refused at publish. The Studio designer'sCHATTER_INPUTSemitsbottom/right/left, so authored metadata most likely carries the spec-invalid set.⚠️ Unmeasured and decisive: which spelling storedrecord:chatter/record:discussioncomponents actually carry. That count should pick the direction; it is a survey, not a judgement. - AI-agent error-resistance — one closed enum, loud refusal, no schema default. The current shape is the worst case for an AI author: the spec-valid value silently does nothing and the working value is refused.
- Startup scope discipline — converge and delete; do not add a translation shim, and do not keep three declared spellings alive because they are already published.
Recommendation (not a ruling): converge the spec on the renderer's
bottom/right/left, drop both defaults, dropdrawerunless a renderer branch is wanted for it. Rationale: the renderer's set is the only one with a reader and the only one the designer emits, so it is the de-facto contract; declaring it converts a silent no-op into a working declaration without breaking anyone who has something working today — nobody can be relying onsidebar, since it renders inline either way. Conditioned on the stored-corpus survey above not contradicting it.Serial constraint (post-ruling)
⚠️ Not dispatchable in the same batch as #8744 — sameComponentPropsMapobject, and #8744 pins therecord:chatter/record:discussionshared identity this fix has to preserve. Sequence after it, per the filer's own note.Index hygiene note
The body carries a prose line reading
Blocked-by: nothing, but lands cleanly after #8744's PR. TheBlocked-by:reverse index is grepped mechanically and does not validate that the token after the colon is an issue reference — this card has no upstream and must not be read as blocked. Recorded here rather than edited into someone else's body.本评论来自分诊座位 Routine,不构成认领。
Generated by Claude Code
- The two
- addedbugSomething isn't workingSomething isn't working
on Aug 14, 2026 Maintainer ruling (2026-08-15, verbatim: 「接受全部建议。」, item 2 of the five-item list posted in the live PM session):
- The row's vocabulary converges on the renderer's —
position: z.enum(['bottom', 'right', 'left'])— one vocabulary, ⛔ no mapping layer. The renderer side is already self-consistent in three places (panel branches, registration enum, merge fallback); the spec row was the isolated wrong party. - The three old spellings (
sidebar/inline/drawer) take an ADR-0087 conversion (value-level rewrite; the breaking classification is the post-cut class, same as today's five precedents). - Schema defaults are dropped (
position,collapsible,defaultCollapsed) per themaxVisibleprinciple — renderer fallbacks stay the renderer's facts..default('sidebar')was itself half of defect 1. - The row stays one shared schema object for
record:chatterANDrecord:discussion(the spec:record:alert/record:quick_actions/record:historyhave no ComponentPropsMap row — same silent no-op mechanism #8691 closed for the rail #8744 pairing).
needs-user-decision→pm:queuein the same stroke. Queue position under SERIAL mode: first (Bug class). Dispatch follows immediately.
Generated by Claude Code
- The row's vocabulary converges on the renderer's —
Claim: PM loop round 7 (SERIAL slot)
Session:session_01E5tUwGM3LQoqErTfkvRW7W
Branch:claude/issue-8762-chatter-position-vocabulary
Worktree:objectstack-issue-8762
Domain:domain:spec
File surface:packages/spec/src/ui/component.zod.ts(RecordChatterProps— the shared chatter/discussion row), its pin tests, ADR-0087 conversion entry + protocol-18 semantic entry + regenerated registry/projections, changeset (stop on breach; explain in the report)
Container & model: M,mode:subagent,model: claude-fable-5(mandatory: value-level accept-face change)
Serial constraints cleared: SERIAL mode — this is the only card in flight; no other claim touchespackages/spec/src/ui/**. Registry hot file: main at 89 semantic; if anything lands ahead, this branch runs the os-regen relay.Ruling being implemented (maintainer 2026-08-15 「接受全部建议。」 item 2, recorded above): vocabulary converges on the renderer's (
bottom/right/left, no mapping layer); old spellings take an ADR-0087 conversion; schema defaults dropped per themaxVisibleprinciple; the row stays one shared schema object for chatter + discussion.
Generated by Claude Code
Claim withdrawn — maintainer stop (spec seat, session
session_01E5tUwGM3LQoqErTfkvRW7W).Provenance: maintainer directive in the live PM session, 2026-08-15, verbatim: 「8762 停掉,不再派发spec,没token了」. The dev agent was stopped during its read-only measurement phase — no code written, no branch pushed, nothing to salvage or discard. Assignee cleared and
pm:dispatched→pm:queuein the same stroke.The card is fully ready for the next dispatch: the maintainer ruling of 2026-08-15 (four binding points — renderer vocabulary, ADR-0087 conversion for the old spellings, defaults dropped, one shared row for chatter/discussion) is recorded above and stands. Whoever picks this up next starts from that comment plus the claim-shaped file surface in the withdrawn claim.
Generated by Claude Code
os-project-manager commented
on Aug 15, 2026 CollaboratorMore actionsClaim: PM loop round 1 (spec seat; concurrency raised to 3 by maintainer instruction 2026-08-15, verbatim: 「优先处理 bug 和 v17 任务。然后才是其他任务,并发加到3」— supersedes both the 2026-08-14 SERIAL directive and the 2026-08-15 「8762 停掉,不再派发spec,没token了」stop, which was a token-budget stop, not a scope objection)
Session:session_01Fgvh1iEJfxetei7aNVdtJt
Branch:claude/issue-8762-chatter-position-vocabulary
Worktree:objectstack-issue-8762
Domain:domain:spec
File surface (region-level):packages/spec/src/ui/component.zod.ts(RecordChatterPropsrow + the shared chatter/discussion pairing, lines ~1028-1040 region), its pin tests, ADR-0087 conversion entry + regeneratedmigrations/registry.tsprojections, changeset (stop on breach; explain in the report)
Container & model: M,mode:subagent,model: claude-fable-5— mandatory tier: value-level accept-face change
Serial constraints cleared: #8744 precondition MET — PR #8773 merged,record:discussionpairing present onorigin/main(verified this fire,component.zod.ts:2161); in-flight #8778 (data/object.zod.ts+ platform-objects + plugin-audit) and #8337 (data/driver/**+ services redaction) are disjoint source regions. Shared generated surfaces (migrations/registry.ts@ ~95 semantic — moved from 89 since the seat note, relay discipline live; reference docs) under the four waiver disciplines: region-level declaration (this comment), mergemainbefore opening the PR, re-merge after any sibling lands, conflicts to the merge queue + os-regen relay.Ruling being implemented (maintainer 2026-08-15 「接受全部建议。」, four binding points recorded in comment
5299771841): vocabulary converges on the renderer'sbottom/right/left, ⛔ no mapping layer; old spellings take an ADR-0087 conversion; all three schema defaults dropped per themaxVisibleprinciple; the row stays ONE shared schema object forrecord:chatter+record:discussion.
Generated by Claude Code
- added a commit that references this issue
on Aug 15, 2026 os-project-manager commented
on Aug 15, 2026 CollaboratorMore actions{ "issue": 8762, "status": "done", "branch": "claude/issue-8762-chatter-position-vocabulary", "pr": "https://github.com/objectstack-ai/objectstack/pull/8914", "premise_still_valid": true, "summary": "Implemented the four-point ruling (comment 5299771841): RecordChatterProps.position is now z.enum(['bottom','right','left']) with no mapping layer; the three old spellings refuse at parse with per-value prescriptions via the enum's own error map (the #8010 'pdf' precedent); all three schema defaults dropped per the maxVisible principle with three declared entries in the default-changes ledger (check:authorable-surface required them); the row stays ONE shared schema object for record:chatter + record:discussion. ADR-0087: mechanical conversion record-chatter-position-vocabulary (toMajor 18, retiredFromLoadPath — post-cut class, sidebar→right / inline→bottom / drawer→right, intent-preserving mappings justified in the PR body) plus semantic entry record-chatter-position-vocabulary-converged; gen:spec-changes/upgrade-guide/api-surface came back byte-identical because projections exclude protocol-18 steps until the cut (same as the field-scale precedent) — flagged in the PR body. Renderer facts re-measured at pin 665661ab0932: the card's numbers verified, with the nuance that the panel's own ??'right'/??true fallbacks are unreachable for authored nodes (the renderer merge supplies bottom/false first); described precisely in the PR. Main moved three times under the branch; merged twice (scripts/turbo, then lint+metadata-protocol — no spec overlap either time, no regen debt); the newest two main commits touch no shared surface so no third merge. PR carries a changeset so skip-changeset does not apply.", "tests": "All at final head ca7f562 (union re-run AFTER the last commit, the post-merge re-merge included). packages/spec full suite: 402 files / 10650 passed (at pre-merge 820b414; targeted re-run at ca7f562: component.test + component-record-blocks.test + conversions.test = 371 passed). Consumers at merged heads: lint 2039 passed, metadata-protocol 1493, metadata 603, metadata-core 162, metadata-fs 51, sdui-parser 6 — all downstream-consumer suites (prefix direction: these packages consume @objectstack/spec). Example apps validate: app-showcase/app-crm/app-todo all exit 0 (warnings pre-existing, unrelated). Gates at ca7f562: check:generated 'All 13 generated artifacts up to date'; check:type-check-debt --re-measure OK (33 entries, none above ceiling); check:type-check-coverage OK; check:query-options-erasure OK (240 sites, no new files); check:nul-bytes OK; check-adr-0087-registration OK (marker registered record-chatter-position-vocabulary, record-chatter-position-vocabulary-converged); check:merge-driver, check:spec-parsed-alias, check:type-source-resolution, check:cross-package-test-inputs, check:dev-prereqs, check:changeset-no-major, check:empty-changeset, check:doc-formula-expressions, check:docs-audit-scope, check:objectui-changeset, check:quick-reference-counts, check:role-word, check:changeset-gate-self-tests — all OK. Gate list re-derived from actual changed paths via dispatch-gates.mjs; it added 7 families beyond the prompt's list (cross-package-test-inputs, docs-audit-scope, objectui-changeset, quick-reference-counts, role-word, changeset-no-major, empty-changeset), all run and green. Spec typecheck green (incl. test-typecheck ledger). Reverse verification (direction decided first: red expected): with component.zod.ts restored to origin/main, exactly the 10 new/changed pins went red (no-default pins, new-vocabulary positives, 3 per-value rejection pins, pair pin); fix restored from the committed state via git restore --source=HEAD, re-run green (371/371). Conversion fixture auto-driven by conversions.test.ts (before→after + 3 notices). No dogfood ablation in scope — the schema-level reverse verification above is this card's counterfactual. CI on PR #8914: reported at draft-PR time per contract; convergence wait is the PM's.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
Generated by Claude Code
os-project-manager commented
on Aug 15, 2026 CollaboratorMore actionsACCEPT — PR #8914 (
Fixes #8762), reviewed by the spec seat (sessionsession_01Fgvh1iEJfxetei7aNVdtJt) against the actual diff, not the report's self-description. Held in draft for the generated-surface serial relay (see below) — the ACCEPT and the queueing are deliberately decoupled.Review findings, per the four-point ruling (comment
5299771841):- Vocabulary —
z.enum(['bottom','right','left']), no mapping layer anywhere; the three retired spellings refuse with per-value prescriptions via the enum's own error map keyed onissue.input(the spec:ListView.exportOptionsis typed as a bare array, but the only renderer readsexportOptions.formats#8010'pdf'precedent), and the never-legal'modal'is pinned to get zod's plain refusal, NOT a retirement prescription — the error map does not overclaim. - ADR-0087 — conversion
record-chatter-position-vocabulary(toMajor: 18,retiredFromLoadPath), fixture carries the scoping negative (a non-chatter component withposition: 'sidebar'survives byte-identically) andexpectedNotices: 3; semantic entry + regenerated registry both present; thesidebar→right/inline→bottom/drawer→rightintent mappings are stated consistently in three places, and the acceptance criteria honestly flag thatsidebar/drawerauthors will SEE the layout change to the docked panel they originally asked for. - Defaults dropped — all three keys
.optional()with renderer defaults stated as prose;authorable-defaults/ui.jsonlost exactly the three rows; the default-changes ledger carries the three declared entries with deployed-behaviour analysis; the old "accept empty with defaults" pins are REPLACED by no-default pins ('position' in result === false). - Pair identity — one shared schema object preserved; the new pair pin asserts both names refuse a retired spelling with the identical message.
CI: all 27 check-run jobs
completed: successat headca7f562. Consumer readings in the report: spec 10650, lint 2039, metadata-protocol 1493, metadata 603+162+51, sdui-parser 6, three example appsvalidateexit 0. Reverse verification red on exactly the 10 predicted pins. No objectui edits (renderer unchanged, correct — it keeps its own vocabulary).Landing hold — serial relay on
migrations/registry.ts: PR #8925 (issue #8337) is in the merge queue ahead of this one and also registers a protocol-18 entry in the same generated registry. One generated-surface PR lands at a time. Once #8925 is MERGED, the relay runs here: mergemain, regenerate (gen:migration-registry+check:generated), assert BOTH cards' entries and the sibling's implementation survive, push, then this PR flips ready + auto-merge. ⛔ Not queued before that.
Generated by Claude Code
- Vocabulary —
- added a commit that references this issue
on Aug 15, 2026
Found while implementing #8744 (measuring the
record:discussion/record:chatterpair together, as its triage note required). Filed as an out-of-scope finding, unassigned — #8744 wiresrecord:discussionto this same shared row on purpose (one renderer, one accept face), so whatever fix lands here repairs both names at once.The divergence, measured at the
.objectui-shapin (665661ab0932)ComponentPropsMap['record:chatter'](packages/spec/src/ui/component.zod.ts,RecordChatterProps) declares:position: z.enum(['sidebar', 'inline', 'drawer']).default('sidebar')collapsible: z.boolean().default(true)defaultCollapsed: z.boolean().default(false)The renderer chain reads none of those position values.
RecordChatterPanel(objectuipackages/plugin-detail/src/RecordChatterPanel.tsx:87-96) comparesconfig.positionagainst exactlyright/left/bottom:and the registration (
plugin-detail/src/index.tsx,CHATTER_INPUTS) declaresenum: ['bottom', 'right', 'left'], defaultValue: 'bottom'— agreeing with the panel, not with the spec row.record-chatter.tsxmerges{ position: 'bottom', collapsible: false, … , ...schema }, so the renderer-side fallbacks arebottom/false.Consequences today:
position: 'sidebar'(the schema's own default, materialized onto every parsed node that says nothing) matches neither branch and falls into the inline/bottom render — the declared value is a silent no-op, on the very surface whose row exists to make undeclared keys loud. The spec-invalidposition: 'right'is what actually docks the panel.collapsibleschema default (true) inverts the renderer merge's fallback (false): "the author said nothing" parses into "the author asked for collapsible", which is also not what the renderer would have done on its own.What a fix needs to decide
bottom/right/left, a breaking value narrowing with an ADR-0087 conversion for the three old spellings), or the renderer learns the spec's — either way ONE vocabulary, not a mapping layer.maxVisibleprinciple (spec:record:reference_railhas no ComponentPropsMap row — an entryfilterparses, typechecks, validates, ships, and silently does nothing #8691/spec:record:alert/record:quick_actions/record:historyhave no ComponentPropsMap row — same silent no-op mechanism #8691 closed for the rail #8744 precedent: renderer fallbacks stay the renderer's facts) —.default('sidebar')is itself half of defect 1.record:chatterANDrecord:discussionafter spec:record:alert/record:quick_actions/record:historyhave no ComponentPropsMap row — same silent no-op mechanism #8691 closed for the rail #8744 — the fix must keep the pair on one schema object.Blocked-by: nothing, but lands cleanly after #8744's PR (which touches the neighbouring map rows and pins the pair's shared identity).
Generated by Claude Code