Skip to content

feat(spec): user:profile is explicitly not author-placeable — refused by name at the schema door (#14159) - #15112

Merged
zhuangjianguo merged 3 commits into
mainfrom
claude/issue-14159-user-profile-not-placeable
Sep 4, 2026
Merged

feat(spec): user:profile is explicitly not author-placeable — refused by name at the schema door (#14159)#15112
zhuangjianguo merged 3 commits into
mainfrom
claude/issue-14159-user-profile-not-placeable

Conversation

@claude

@claude claude Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixes #14159
Clause ②: yes — path limb: packages/spec/src/** (the SUSPECT surface dispatch-gates --tier names; no path-derived mandate); content limb yes: accept-set narrowing — an authored user:profile element type is refused at the schema door, where it parsed clean before.

Dispatched by the domain:spec PM seat (session session_0174WZTU6XcFcS7g2kykC53i, seat post #6017), mode:subagent. Draft on purpose — needs:contract-review is hung on this PR and on the card; ⛔ never flipped to ready by this seat.

The ruling (director seat 2026-09-01, batch #26, maintainer verbatim 「同意」 — comment 5494656898 on #14159, quoted untranslated where it is the operative criterion)

「1. B:spec 与 validate 明示 user:profile 不可被作者放置 —— 编写期响亮拒绝(reference-diagnostics 家族),失败落在作者面前而不是用户面前的红面板; 2. 渲染器不建:零测量拉动 … 3. PALETTE_EXCLUSIONS 条目不动; 4. 裁决理由入册:用户档案是 shell chrome(头像菜单),主流产品无一把它做成页面可放置组件 —— B 是对结构事实的诚实声明,不是能力欠账; 5. 路由:落点 spec + validate ⇒ 本仓 domain:spec 排队;条款②(明示拒绝 = accept-set 收窄)⇒ 契约复审档」

What changed

One prescription string, three doors, no driftRETIRED_PAGE_COMPONENT_TYPES (packages/spec/src/ui/page.zod.ts, retired type → prescription) is the single source:

  1. PageComponentType loses user:profile, and its own error map consults the table keyed on issue.input — only a value that used to be legal gets the retirement prescription (code: 'invalid_value'); a stranger keeps zod's enum message. This is the enum-VALUE-narrowing spelling the file already uses for record:chatter position (CHATTER_POSITION_RETIRED) and the master-detail form type (MASTER_DETAIL_FORM_TYPE_RETIRED).
  2. PageComponentSchema.type gains a check against the same table. This is the one new mechanism, and it is contained in packages/spec/src/ui: type is z.union([PageComponentType, z.string()]), and the open string arm admits every string the enum refuses, so the enum's error map alone cannot reach an author through the page door — the gap the element:filter / element:form retirements recorded in their docblocks as "a node-level refusal is not expressible here". With the check, an authored user:profile node is refused at its own path with code: 'custom', params.retiredComponentType: 'user:profile', and the prescription as the message. Every string the table does not name keeps parsing; stored documents keep loading; the component-type-unknown rule keeps its namespace claim.
  3. ComponentPropsMap['user:profile'] stays a row (so the SDUI 组件 props 没有解析闸门:PageComponent.properties 是开放 record,ComponentPropsMap 的 29 个站点从不被 parse(#4001 批 17 的 no gate 判定) #5068 props gate, check-yaml-examples and the type vocabulary keep recognising the name instead of skipping it as an unregistered custom string — the element:filter argument) and becomes retiredComponentProps('user:profile'): z.never carrying the same prescription, refusing every bag including {} — the retiredKey channel one grain wider (expected: 'never' / code: 'invalid_type'). The helper throws at module load if the table has no entry for the type, so the row and the door cannot drift apart.

The empty-props docblock loses the member (packages/spec/src/ui/component.zod.ts). content/docs/ui/pages.mdx (hand-written) says the truth on the Utility line; the generated content/docs/references/ui/page.mdx, api-surface/ui.json and export-origins/ui.json follow the schema via check:generated --fix (second run exits 0). check:strictness-ledger asked for no entry (the row is z.never, not an object site).

Measured first, as asked: the repo retires a component type two ways — element grain (element:filter / element:form: enum value dropped, row kept with every key a retiredKey tombstone, bare node still parses) and enum-value narrowing (a ReadonlyMap of retired value → prescription on the enum's error map). Neither reaches an author through PageComponentSchema.type, so the node-level check is the smallest addition that makes the ruling's "refused by name, at the author" true; it reuses the family's table shape rather than inventing a tombstone table.

validate measurement — one defect, one door, no lint rule

ObjectStackDefinitionSchema.pages is z.array(PageSchema) (stack.zod.ts), so the schema-door refusal surfaces at os validate step 2, before the authoring rules run. Measured through the source CLI (tsx packages/cli/bin/run-dev.js validate) on a fixture stack carrying one region node and one slot node (both user:profile), exit 1:

  pages:
    ✗ pages.0.regions.0.components.1.type
      custom: `user:profile` is not a page-placeable element — it is shell chrome (the signed-in user's avatar menu, which the app shell renders itself on every page), no renderer for it exists anywhere by ruling, and there is nothing to put in its place: delete the component node and let the shell render the profile. …
    ✗ pages.1.slots.header
      invalid_union: Invalid input
        ✗ pages.1.slots.header.type: `user:profile` is not a page-placeable element — …
  2 validation error(s) total

--json carries the same issues under errors (the slot one nested inside the slot union's invalid_union.errors, paths relative to the union — a property of Page.slots' z.union([PageComponentSchema, z.array(PageComponentSchema)]), not of this retirement; the text face renders the nested line with the absolute path). Control in the same run: the identical fixture with global:search in both positions exits 0, Validation passed. So validate neither swallows nor generalises the located message, and packages/lint/src/validate-component-props.ts is untouched — the claim comment declared it conditionally and the condition did not hold.

Verification record — at the final head bf4716f2

Every exit captured before any pipe (cmd > log 2>&1; EXIT=$?); verdict lines quoted from the gates' own output.

step result
pnpm --filter @objectstack/spec build (under os-verify-lock.sh) VERDICT command-exit 0 · DTS ⚡️ Build success · check-dts-emitted: 34/34
spec pins: vitest run --maxWorkers=2 src/ui/component.test.ts src/ui/component-type-vocabulary.test.ts src/ui/page.test.ts Test Files 3 passed (3) · Tests 335 passed (335) · VERDICT command-exit 0
pnpm --filter @objectstack/spec typecheck (tsc + scripts + test layer) exit 0 · check:test-typecheck: OK — 54 file(s) / 261 error(s) / 145 pinned signature(s) held (no debt moved)
pnpm --filter @objectstack/spec check:generated after --fix ✓ All 15 generated artifacts are up to date. (api-surface, export-origins, docs were the stale three)
downstream @objectstack/lint: vitest run --maxWorkers=2 + pnpm typecheck (under the lock) Test Files 94 passed (94) · Tests 2905 passed (2905) · VERDICT command-exit 0
eslint (--no-inline-config) over the four edited TypeScript files exit 0, no findings — a targeted run, not the repo-wide pnpm lint (that one is CI's; type-aware linting is not enabled, so this diff moves no untouched file's verdict)
node scripts/check-adr-0087-registration.mjs --base 29db3cd2 ✓ 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition
node scripts/check-changeset-no-major.mjs --base 29db3cd2 ✓ This diff introduces no major bump.
node scripts/check-system-context-census.mjs (after the last edit, no --fix needed) OK — 106 elevation read sites in 20 packages across 45 files, all anchored
pnpm check:nul-bytes OK (scanned 8215 text file(s) … no raw ASCII control bytes)
pnpm check:doc-authoring ✓ 14685 customer-facing string(s) across 723 spec sources clean — no internal issue-id references (see deviation 1 below — it went red on the first spelling)
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths; 91 families derived from the merge base) run at bf4716f2 86 of 91 exit 0

NOT MEASURED locally, each by the gate's own words, all CI-owned: check-test-completeness.mjs (exit 3: "grades a saved turbo run test log, and no log was named … record this gate as NOT MEASURED"); check:react-declaration-parity (exit 1: "MANIFEST is not set … This gate did NOT run" — objectui's sdui.manifest.json, an on-demand pin-bump gate by ruling); check:skill-examples (the skills+docs and spec-TSDoc surfaces ran; the client-SDK surface refused because packages/client-react/dist is unbuilt here); check:dual-build-cjs-loads and check:type-check-debt (exit 3 PREREQUISITE NOT MET: they read every package's dist / built type entry points, and this worktree built only spec, formula, sdui-parser, lint, metadata-core).

Shipped apps: definePage() is PageSchema.parse(), so importing every *.page.ts under examples/** (21 modules: app-showcase, app-crm) through the freshly built @objectstack/spec proves none authors user:profile under the new schema — page modules: 21 · imported clean: 21 · failed/authoring user:profile: 0, with a positive control in the same run (definePage on a user:profile node throws the prescription: true). os validate through the source CLI: app-crm and app-todo exit 0 ✓ Validation passed; app-showcase and app-multi-package could not load their configs here (they import @objectstack/connector-* / @objectstack/types dist this worktree did not build) — NOT MEASURED via the CLI, covered for pages by the module proof, and git grep user:profile finds zero authored nodes in examples/** or packages/** sources at the base.

Reverse verification — one leg, from the committed state

Mutation: both schema files restored to the base commit 29db3cd2 in the worktree only (git restore --source=BASE --worktree), landing proven by content (RETIRED_PAGE_COMPONENT_TYPES occurrences: page.zod.ts 6 → 0, component.zod.ts 4 → 0; the enum line and the emptyProps row back). Same three test files under the lock: 6 failed, 329 passed — the four refusal pins in the #14159 describe (row, PageComponentSchema, PageSchema, PageComponentType) and the two vocabulary pins (user back in the reserved namespaces; the known-through-row pin) went red; the positive controls, the preservation pin and the open-arm pin stayed green. Restore: git checkout HEAD -- both paths under a trap, proven by git diff HEAD --stat empty, git status --porcelain empty, and git hash-object equal to git rev-parse HEAD:path for both files (page.zod.ts 0f6e88ee…, component.zod.ts 14d8bb44… at the then-head; the final commit re-touched page.zod.ts only for deviation 1). Direction observed: red, as expected.

Changeset — @objectstack/spec minor, and why

Deviations and notes for the contract review

  1. The prescription names no issue id. The dispatch asked the first sentence to say "by ruling (objectstack#14159, objectui#7135)". check:doc-authoring refuses citation-shaped tokens in text printed at the customer (maintainer ruling 2026-08-12, 「处理 issue 时犯的错应该总结成经验,保留 issue id没有意义」) and went red on exactly those three tokens, so the customer-facing string says "by ruling" and carries the ADR ids (ADR-0078, ADR-0049); the issue anchors live in the adjacent source comment and the enum docblock. The pin asserts the first sentence, ADR-0049, and (negative) no #NNNN.
  2. packages/spec/src/ui/component-type-vocabulary.ts is not edited (outside the declared surface). Its docblock says the row set is "exactly" the string-arm registrations plus element:filter / element:form; user:profile now joins that set, so the sentence is one member short. Report line, not an edit; [finding] bare element:filter / element:form nodes still validate clean, and retired component types are offered as typo suggestions — the node-level refusal #14159 built could close both #15110 carries it.
  3. user: is no longer a reserved namespaceuser:profile was its only enum member, so RESERVED_COMPONENT_TYPE_NAMESPACES (derived) drops it and the component-type-unknown rule no longer claims user:* strings. Pinned consciously in component-type-vocabulary.test.ts; the only string refused is the retired name itself, and the open-arm pin says so.
  4. The format-type.test.ts PAGE_COMPONENT literal (a formatter fixture that copies the enum as it was) still lists user:profile; it is not the spec's list and is not compared to the live enum, so it is left alone.
  5. Slot-mounted nodes arrive at the CLI as invalid_union with the prescription nested (rendered with the absolute path by formatZodIssue, formatZodError 把 union 分支的拒绝信息压成 "Invalid input" —— #4001 策展的散文在 CLI 路径上到不了作者 #4971 / os validate / os build 用的是 CLI 自己的 formatZodErrors,它同样把 union 分支的处方裁掉 —— #4971 修的不是这条路径 #5341) — pre-existing behaviour of the slot union for every refusal, pinned as such.

Out of scope

⛔ Untouched, per the ruling and the dispatch: objectui (PALETTE_EXCLUSIONS stays — point 3; objectui#7135 closes on B through its own lane), every other member of PageComponentType / ComponentPropsMap, content/docs/releases, skills. No renderer, no placeholder, no scaffold.

🤖 Generated with Claude Code

https://claude.ai/code/session_0174WZTU6XcFcS7g2kykC53i


Generated by Claude Code

… by name at the schema door (#14159)

Ruling B (director seat 2026-09-01, maintainer verbatim 「同意」): a user
profile is shell chrome (the avatar menu), no renderer is built, and an
authored user:profile node is refused at the parse with a located
prescription instead of drawing the unknown-type panel in front of a user.

- page.zod.ts: RETIRED_PAGE_COMPONENT_TYPES (retired type -> prescription),
  consulted by PageComponentType's own error map and by a check on
  PageComponentSchema.type so the open string arm cannot re-admit the name
- component.zod.ts: the ComponentPropsMap row stays and refuses every bag
  (z.never, the retiredKey channel at element grain)
- pins: code + path + first sentence at each door, controls, preservation
- generated artifacts regenerated; content/docs/ui/pages.mdx says the truth
- changeset: @objectstack/spec minor (launch-window convention), ADR-0087
  not-required (no-migration-prescription), the #7596 disposition

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0174WZTU6XcFcS7g2kykC53i
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 6 documentable anchor(s). ⚠️ 2 changed file(s) yielded no anchor (packages/spec/api-surface/ui.json, packages/spec/export-origins/ui.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

6 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/api/error-catalog.mdx (via invalid_type (literal, a string literal on a changed line))
  • content/docs/api/error-handling-server.mdx (via invalid_type (literal, a string literal on a changed line))
  • content/docs/deployment/cli.mdx (via invalid_type (literal, a string literal on a changed line))
  • content/docs/protocol/objectui/concept.mdx (via invalid_type (literal, a string literal on a changed line))
  • content/docs/protocol/objectui/layout-dsl.mdx (via ComponentPropsMap (symbol, a top-level const object), PageComponentSchema (symbol, a top-level const))
  • content/docs/ui/pages.mdx (via PageComponentType (symbol, a top-level const object))

2 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx (via PageComponentSchema (symbol, a top-level const))
  • content/docs/releases/v17.mdx (via ComponentPropsMap (symbol, a top-level const object), invalid_type (literal, a string literal on a changed line))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 2 changed file(s) yielded no anchor (packages/spec/api-surface/ui.json, packages/spec/export-origins/ui.json) — pages documenting those are invisible to this run
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 35e94c96b8a4f6f3f8bbfbf898342b7d84076d02packageMentionDocs.

Which tree this was computed on

This run read content/docs from 9c4c385505b5dd168a675838e772195826c090c8 — the merge of head bf4716f283b410d95464e0bc20f6742080b9df08 into base 35e94c96b8a4f6f3f8bbfbf898342b7d84076d02, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 9c4c385505b5dd168a675838e772195826c090c8 && git checkout 9c4c385505b5dd168a675838e772195826c090c8
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 35e94c96b8a4f6f3f8bbfbf898342b7d84076d02 bf4716f283b410d95464e0bc20f6742080b9df08 && git checkout -B drift-repro 35e94c96b8a4f6f3f8bbfbf898342b7d84076d02 && git merge --no-ff bf4716f283b410d95464e0bc20f6742080b9df08

node scripts/docs-audit/affected-docs.mjs --json 35e94c96b8a4f6f3f8bbfbf898342b7d84076d02

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 35e94c96b8a4f6f3f8bbfbf898342b7d84076d02 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:ui tests tooling labels Sep 3, 2026
@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Contract review (Clause ②) — PASS · ACCEPT

Reviewer of record: the domain:spec PM seat, session session_0174WZTU6XcFcS7g2kykC53i (seat post #6017). Tier fuse: get_session read at 2026-09-03T23:55Z — both model fields equal CONTRACT_REVIEW_TIER. Gate: check-clause2-carriers.mjs --pair 15112 exit 0 at 23:55Z (the Clause-②: declaration is in the dev's own claim comment 5533095001; both carriers were hung). Report comment 5533656899 (23:54Z) read against GitHub, not against its own prose.

Head and window

  • Report head bf4716f2 = PR head.sha at 23:55Z — every reading below is on that commit. Trial merge onto origin/main 369da918 (23:55Z): clean. Governed test: 0 of 9 changed files on a governed surface.
  • CI on bf4716f2 at 23:59Z: 35 checks, 14 success, 5 skipped, 16 running, 0 red — not yet all-green; landing waits (readings below).

The narrowing, verified in the diff

  • What is refused, where, with what issue: an authored user:profile node at PageComponentSchema.typecode: 'custom', path: ['type'], params.retiredComponentType: 'user:profile', message = the one prescription in RETIRED_PAGE_COMPONENT_TYPES (packages/spec/src/ui/page.zod.ts); the enum's own error map (invalid_value, keyed on issue.input, so a stranger such as user:avatar keeps zod's message); ComponentPropsMap['user:profile'] = z.never carrying the same string (invalid_type / expected: 'never', refuses {} too). The helper throws at module load for a type the map does not name — the row and the door cannot drift.
  • What stays accepted, pinned: global:search / global:notifications at all three doors; app:launcher / nav:menu / nav:breadcrumb unchanged incl. their unknown-key refusal; the open string arm (custom.widget, mcp:connect-agent, object-grid, user:avatar) still parses. The user: namespace leaves RESERVED_COMPONENT_TYPE_NAMESPACES consciously (pinned in component-type-vocabulary.test.ts); isKnownComponentType('user:profile') stays true through the kept row.
  • Refusal pins carry code + path + the first sentence plus the negative #NNNN pin and ADR-0049 — not a bare toThrow(). The SDUI 组件 props 没有解析闸门:PageComponent.properties 是开放 record,ComponentPropsMap 的 29 个站点从不被 parse(#4001 批 17 的 no gate 判定) #5068 open-bag gate gains one skip for def.type === 'never' — closed by construction, the positive control parses the row.
  • Load order (checked on origin/main, 23:58Z): this PR adds the component.zod.ts → page.zod.ts import. Base page.zod.ts imports no component.zod.ts, and nothing in its import closure does (the only hit is a test file); the ui/index.ts barrel exports page.zod (line 40) before component.zod (line 42), so retiredComponentProps('user:profile') runs after the map is initialised under ESM — consistent with the report's build, 335 green pins, source-CLI validate and the 21-module examples import all passing. The CJS load is CI's Build Core job (check:dual-build-cjs-loads), NOT MEASURED locally by the report's own words — pinned as a landing reading below.
  • Consumers on origin/main (23:54Z): zero user:profile in objectstack outside packages/spec and content/docs; the only hand-written page naming the value is content/docs/ui/pages.mdx:185 — edited to say the truth. The generated baselines the changeset lists (json-schema.manifest/, authorable-surface/, liveness/, docs/) carry zero hits for the value, so "the stale three" (api-surface, export-origins, reference page) is the complete regeneration set. Nit, not a patch round: the changeset sentence "generated baselines/docs follow the schema (authorable-surface/, json-schema.manifest/, …)" is true as "consistent", not as "regenerated" — two of the four named directories are unchanged.
  • Docs-drift advisory (bot comment on this PR): six hand-written pages listed by symbol; five of them name invalid_type / ComponentPropsMap / PageComponentSchema generically and never the value (grep 23:54Z); the sixth is pages.mdx, edited. The two release pages are read-only and untouched — no content/docs/releases/ in the file list.

Report checklist

  • Reverse verification: one leg from the committed state, both schema files restored to base 29db3cd2 in the worktree only, landing proven by content (map occurrences 6→0 / 4→0); 6 red / 329 green on the three pinned files; restore proven by git diff HEAD --stat empty and git hash-object = HEAD:path for both files. Direction red, as expected. Accepted.
  • validate measurement: source CLI exit 1 with the located issue at pages.0.regions.0.components.1.type (custom) and the slot case nested under the slot union's invalid_union (a property of Page.slots, pre-existing and pinned as such); control with global:search exits 0. No lint rule needed; packages/lint untouched, the claim's conditional file declared and not taken. Accepted.
  • Gate union at bf4716f2: 86 of 91 families exit 0; the five NOT MEASURED are stated by the gates' own words (saved-turbo-log grader, objectui manifest parity, client-SDK skill examples, dual-build CJS loads, type-check debt — all CI-owned). check:doc-authoring went red on the first spelling (three issue ids in the customer-facing prescription) and green after — deviation 1 is the maintainer's 2026-08-12 rule applied, and the pin asserts the negative.
  • Changeset: @objectstack/spec is published (private: false), so a changeset is required and present — minor with the **BREAKING** banner under the post-cut lockstep convention (the element:filter / element:form retirements shipped under 17.1.0 minor; the two 17.0.0 precedents were major because that release was the major); check-changeset-no-major green; ADR-0087 disposition not-required (no-migration-prescription), the [spec] FieldReferenceSchema is declared in the $between endpoints but NO backend resolves a $field inside a list #7596 disposition one surface over. Accepted as filed.
  • Scope: 9 files, all inside the claim's declared surface plus the generated followers, the changeset and the two docs pages; no content/docs/releases/ edits; no unrelated files. objectui, PALETTE_EXCLUSIONS, every other enum / row member: untouched, per the ruling's point 3.
  • Closing keyword, two reads (23:57Z): first line Fixes #14159; the body scan finds no other closing keyword beside a card number (#15110 appears as "filed as" / "not addressed here"; "closes on B" carries no number). Fixes is correct — this card is the objectstack half in full; objectui#7135 is pm:blocked with Blocked-by: objectstack-ai/objectstack#14159 and unlocks in its own lane.
  • MCP-call accounting: 0 — REST and git throughout; the dedup read (236 finding issues, three pages) is a GitHub read by nature, not a git-answerable one.
  • Head pinning: the report's git rev-parse --short HEAD (bf4716f2) equals the PR head — the local gate readings are live, not dead-tree.

Seat ruling on the report's open question (open to the maintainer's veto)

A — keep as landed. A stored page row carrying a user:profile node is refused at rehydration with the prescription; no D2 conversion. Reasons: the element-filter-removed docblock already rules node deletion out of a mechanical conversion (a layout decision, not a rewrite); the row declared zero keys, so there is no old shape to rewrite; the measured population is zero (examples, packages, docs, stored metadata; Studio's palette excluded the type since objectui 5e8965c). B stays available additively as a follow-up registry entry if a real row ever surfaces.

Out-of-scope group (sweep criterion: doors the new node-level refusal could also close, and readers that still advertise retired names)

Landing

At all-green on bf4716f2 — including Build Core (the CJS-load reading), Lint & Repo Gates, the three Type Check jobs and Temporal Conformance (live PG + MySQL): provenance → ready → squash auto-merge → added_to_merge_queue. On MERGED: strip pm:dispatched from #14159, probe page.zod.ts / component.zod.ts on origin/main, landing note on the card, notification on objectui#7135 with the consumer-side facts above, and the component.zod.ts / page.zod.ts / component.test.ts reservation is released.

needs:contract-review is cleared on this PR and on #14159 in this stroke (read-modify-write, both read back). If the head moves after this clear, the gate's C3 reading re-hangs it and the delta is reviewed before it is cleared again.


Generated by Claude Code

@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Landing provenancedomain:spec PM seat, session session_0174WZTU6XcFcS7g2kykC53i (seat post #6017). Contract review (Clause ②) PASS · ACCEPT: comment 5533702051 (2026-09-04T00:00Z); needs:contract-review cleared on both carriers 00:01Z.

Landing window readings, all on head bf4716f2 at 2026-09-04T00:11Z:

  • CI: 41 checks — 34 success, 7 skipped, 0 red, 0 running; the required floor (Lint & Repo Gates, Type Check · workspace / · consumer gates / · debt ledger, Check Changeset, Temporal Conformance (live PG + MySQL)) all success on this head; Build Core success — the CJS-load reading (check:dual-build-cjs-loads) the review named as a landing reading is in; legacy status Vercel success.
  • Trial merge onto origin/main 35e94c96: clean.
  • check-clause2-carriers.mjs --pair 15112: exit 0 (head unchanged since the clear — no C3). Governed surface: 0 of 9 changed files. No content/docs/releases/ edits.
  • Closing keyword, two reads: first line Fixes #14159; the body is byte-identical to the one reviewed at 23:57Z and carries no other closing keyword beside a card number.

Sequence: ready → squash auto-merge → added_to_merge_queue. On MERGED: strip pm:dispatched from #14159, probe page.zod.ts / component.zod.ts on origin/main, landing note on the card, notification on objectui#7135 with the consumer-side facts from the review.


Generated by Claude Code

@zhuangjianguo
zhuangjianguo marked this pull request as ready for review September 4, 2026 00:11
@zhuangjianguo
zhuangjianguo added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 97a2263 Sep 4, 2026
43 checks passed
@zhuangjianguo
zhuangjianguo deleted the claude/issue-14159-user-profile-not-placeable branch September 4, 2026 00:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:ui size/m tests tooling

Projects

None yet

2 participants