Skip to content

feat(spec)!: marketplace:installed-list is retired — refused by name at the schema door; the separate Installed Apps view it drew was retired - #24255

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-24230-marketplace-installed-list-retired
Oct 18, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-24230-marketplace-installed-list-retired

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #24230

Clause-②: no (narrowing)

Retires the page component type marketplace:installed-list, refused by name through RETIRED_PAGE_COMPONENT_TYPES. This executes ruling B on #23892 (record 6216295104, item 2: "the separate Installed Apps view retires once the filtered view serves its actions"), within triage grade 6243387750 and release 6245014494. objectstack-ai/objectui#12926 (merged 35244b6379) deleted the type's one renderer. Its one producer, @objectstack/cloud-connection's marketplace_installed page, had already left MARKETPLACE_INSTALLED_UI_BUNDLE (#23933). The shape follows the record:json retirement (PR #24170, 030a7b83e) surface for surface, with the differences listed below.

Dev session: session_01SovhHbD8dAQGDyEGHRoSUx (cloud dispatch from the domain:spec#1 seat, claim 6245064045).

Accept set, before → after, at each door

door before (cbfa5e4335) after (this head)
PageComponentSchema.type (node) accepts { type: 'marketplace:installed-list' } through the open string arm refuses: code: 'custom', path: ['type'], params.retiredComponentType: 'marketplace:installed-list', message = the prescription. Bare, {}-bag and keyed alike
PageSchema (what os validate and save parse) accepts the node refuses at regions[i].components[j].type, one issue per node
ComponentPropsMap['marketplace:installed-list'] (props gate, check-yaml-examples, vocabulary) strict empty emptyProps(...): {} passes, any key refused row kept as retiredComponentProps(...) (z.never): every bag refused, {} included, invalid_type at [] with the prescription
lint component-type-unknown silent (open-arm plugin namespace) error at …type; message = the prescription's head, hint = its "Delete the …" sentence (193 chars, under the one-line 200 cap)
lint component-props-* component-props-unknown-key on a keyed bag, silent on {} component-props-invalid error at …properties for every bag
typo suggester candidate no longer a candidate (out of KNOWN_COMPONENT_TYPE_CANDIDATES, derived from the map)
print pages PRINT_REFUSED_PAGE_COMPONENT_TYPES row row removed: a retired type is refused at the parse before any print rule reads it (the map's own docblock rule)
PageComponentType enum never a member unchanged: nothing to remove
exports none of its own (emptyProps mints no def) unchanged

The open string arm stays open, the marketplace: namespace included (marketplace:installed-list-v2 still parses; pinned). Everything else is byte-identical.

The prescription is one string at all doors. Its fix sentence names the route the console uses: "Delete the marketplace:installed-list component node; to link to that view, add a component navigation item with componentRef: 'developer:packages' and params: { source: 'marketplace' }." That is the spelling MARKETPLACE_INSTALLED_UI_BUNDLE's own "Installed Apps" entry uses, and it validates against app.zod.ts's component navigation item. It carries no tracker number (check:doc-authoring).

Where this differs from the record:json precedent

surface record:json here
enum value removed from PageComponentType n/a, never a member. The map entry is therefore the only parse door. Without it, the retired name would fall back to the open arm and parse in silence (pinned)
row retiredComponentProps same, and here the kept row is the only thing that keeps the name KNOWN (pinned in component-type-vocabulary.test.ts)
props def / retired-defs entry RecordJsonProps deleted, retired-defs/18.ui__RecordJsonProps.ts none: emptyProps exports nothing, so no def leaves the published set (H4 measured: check:generated moved only content/docs/references/ui/page.mdx)
D3 entry and step-18 fragment ui-record-json-retired ui-marketplace-installed-list-retired, inserted at its sorted id, order: 102 (max 101 + 1)
sibling D3 entries none ui-cloud-connection-widgets-unknown-keys-refused amended, ui-mcp-connect-agent-unknown-keys-refused one clause (decision below)
whole-bag census component-record-related-list-parent-23134.test.ts gained record:json gains marketplace:installed-list
lint pins validate-record-json-23745.test.ts flipped validate-component-types.test.ts: the accept row is removed (the map-driven flags %s case now covers it); validate-component-props.test.ts: the keyed-bag and {} cases flipped into one whole-bag refusal pin
tree-scoped absence walk new, in vitest.repo-tests.json same, in the new pin file, registered in vitest.repo-tests.json
Clause-② no (narrowing) (shipped in one prerelease only) no (narrowing) too: the type shipped in stable 17.3.0, which decides the ADR-0087 disposition and the FROM → TO text, not the value. The diff widens nothing, and yes (narrowing) would claim a widening (contract review 6245719006 ②)

The two semantic/18.* entries: amended, not superseded

Measured: both entries are in the same major-18 step as the new retirement entry, so an upgrader replaying 17 → 18 reads all three. ui-cloud-connection-widgets-unknown-keys-refused's acceptanceCriteria said "Every cloud-connection:panel / marketplace:installed-list node authors an empty bag and validates clean". After this PR that sentence is false for the second type, and it contradicts the retirement entry. Its id is referenced by shipped CHANGELOG text and by packages/cli/test/migrate-meta-engine-guidance.test.ts's guidance census. So the entry is amended in place: id kept, surface, replacement and acceptanceCriteria narrowed to cloud-connection:panel, and reason names the retired sibling and the new entry. Superseding it (new id, old entry deleted or left stale) would either drop a referenced id or leave contradictory text in one step. ui-mcp-connect-agent-unknown-keys-refused only named the row historically, as the precedent for its own row. One clause now says that row was since retired by name. No guidance changes.

H2 / H3 / stop conditions, measured

  • H1 (premise): true on origin/main cbfa5e4335 (the dispatch read af284b05e5): the row (component.zod.ts), the docblocks, the print row (page.zod.ts) and the lint accept pins were all present.
  • H2 (producers): no stored-row producer. The MARKETPLACE_INSTALLED_UI_BUNDLE carries no pages. Outside the spec and tests, the string survives in CHANGELOGs, content/docs/releases/v17/17-3.mdx (release-owned, untouched), packages/spec/liveness/page.json (a historical read-point note at an older objectui sha, untouched), a doc comment in packages/cloud-connection/src/canonical-expression-envelopes.test.ts (hold-off, untouched) and the CLI fixture below. So no D2 conversion is registered.
  • CLI fixture: packages/cli/test/platform-page-i18n-parity.test.ts's SAMPLE_PAGE does not parse the page (no PageSchema read in the file), so it did not fail. It did author a { type: 'marketplace:installed-list' } node inside the new absence walk's radius, so its body block is now element:divider. The gate reads only the header copy. 27/27 pass.
  • H3 (Console Pin Gate): git grep at the objectui pin 5e15928b46: the type appears only as a string registration (InstalledListWidget.tsx), a CLI known-types string list, tests, and the parity test's UNJUDGED_SPEC_BLOCKS entry. There is no typed read of ComponentPropsMap['marketplace:installed-list'] in non-test source. The row's KEY is kept, so keyof typeof ComponentPropsMap and the parity partition's key set are unchanged. Removing the key cannot break the pinned build because the key is not removed. The parity entry's "EMPTY SPEC SHAPE" text becomes "RETIRED UPSTREAM" in objectui's own pin bump, per the card.

Ablation (fix committed first, scripts/ablation-replace.mjs, restored by blob)

The subject resolves by relative import (./page.zod, ./component.zod) to src, so no dist rebuild is involved.

  • Mutation: the map key renamed to marketplace:installed-list-ABLATED (held), and the row turned back into emptyProps('marketplace:installed-list'). On-disk counts: 1 and 1.
  • Result: retirement pin 4 failed / 6 passed (the map, the row, PageComponentSchema, PageSchema); vocabulary pins 2 failed / 20 passed.
  • Restore: both files back to their HEAD blobs (9146237b28f7, 0365abe5e2cf) by hash, and git diff HEAD is empty.

Gates (local, head fc6245ba2)

  • spec build exit 0. check:generated: ✓ All 14 generated artifacts are up to date (only gen:docs moved: content/docs/references/ui/page.mdx, 2 lines, the regenerated .describe()).
  • spec test (vitest --project local): 693 files, 692 passed and 1 failed: the whole-bag census in component-record-related-list-parent-23134.test.ts, which this PR then updated; that file re-run 17/17. 21001 tests passed, 1 todo. spec test:repo scoped to the new repo-project file: 10/10. spec typecheck exit 0, check:test-typecheck: OK.
  • lint: closure built, test 143 files, 6820 passed, 5 skipped; typecheck exit 0.
  • cli unit: test/platform-page-i18n-parity.test.ts 27/27.
  • check-platform-checklist --changed-from origin/main: OK, 0 anchors lost.
  • dispatch-gates --commands: 111 commands, each run with its exit code captured before any pipe. 107 exited 0; check:skill-examples exited 3 (PREREQUISITE NOT MET: client-react dist built without DTS by this run's own CLI closure build) and was re-run green after a DTS build (262 examples). NOT MEASURED, declared to CI:
    • check:dts-closure (exit 1, missing .d.ts in 58 packages that this run built with OS_SKIP_DTS=1 for the CLI unit test; the diff touches no build config);
    • check:dual-build-cjs-loads (exit 3, PREREQUISITE NOT MET: needs a whole-repo build);
    • check-plugin-teardown-shape.mjs --self-test (exit 3: its fixture needs an unshallow clone; checker-health only).
  • Changeset gates, re-run on head 603c1a10c after patch round 1 (report 6245768083), exit codes captured before any pipe. check-adr-0087-registration, exit 0: "✓ check-adr-0087-registration: 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition." and "[BREAKING+bang+clause-②-narrowing] registered ui-marketplace-installed-list-retired (new here: ui-marketplace-installed-list-retired)". check-changeset-no-major with this body as the --event payload, exit 0: "✓ This diff introduces no major bump." and "✓ LEVEL AXIS: this PR declares clause-② no (narrowing), and no package whose published source (src/**, a packed bin target, or a repo file its build copies in) it moves is graded patch." Both carriers, this body and the changeset, read Clause-②: no (narrowing) at line start (contract review 6245719006 ②).

Acceptance notes

  • packages/spec/liveness/page.json's regions note still cites the widget's read point at an older objectui sha. It is historical evidence and was not edited here (ledger edits carry their own verifiedAt discipline).
  • objectui's registry-inputs-spec-parity.test.ts entry and packages/cli/src/utils/known-schema-types.ts (objectui) list the string. Both are objectui's pin-bump follow-up, per the card. .objectui-sha is not moved.
  • packages/cloud-connection (hold-off) is untouched; its doc comment already records the page retirement.
  • content/docs/releases/ and every CHANGELOG.md are untouched.

Generated by Claude Code

…at the schema door, the separate Installed Apps view it drew was retired

Claude-Session: https://claude.ai/code/session_01SovhHbD8dAQGDyEGHRoSUx
Co-authored-by: Claude <noreply@anthropic.com>
… census for the retired marketplace:installed-list

Claude-Session: https://claude.ai/code/session_01SovhHbD8dAQGDyEGHRoSUx
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 5 documentable anchor(s). ⚠️ 3 changed file(s) yielded no anchor (packages/spec/src/migrations/registry.ts.template, packages/spec/src/ui/component-type-vocabulary.ts, packages/spec/vitest.repo-tests.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

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

  • content/docs/deployment/validating-metadata.mdx (via ComponentPropsMap (symbol, a top-level const object))
  • content/docs/protocol/objectui/layout-dsl.mdx (via ComponentPropsMap (symbol, a top-level const object), PageComponentSchema (symbol, a top-level const))

⛔ 6 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/17-1.mdx (via ComponentPropsMap (symbol, a top-level const object))
  • content/docs/releases/v17/17-3.mdx (via ComponentPropsMap (symbol, a top-level const object))
  • content/docs/releases/v17/17-4.mdx (via ComponentPropsMap (symbol, a top-level const object))
  • content/docs/releases/v17/17-5.mdx (via ComponentPropsMap (symbol, a top-level const object))
  • content/docs/releases/v17/17-7.mdx (via ComponentPropsMap (symbol, a top-level const object), PageComponentSchema (symbol, a top-level const))

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
  • 3 changed file(s) yielded no anchor (packages/spec/src/migrations/registry.ts.template, packages/spec/src/ui/component-type-vocabulary.ts, packages/spec/vitest.repo-tests.json) — pages documenting those are invisible to this run
  • 3 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 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.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 143 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 e74ec56acc33316a21d41fdde7f6d34a44d6a792 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 06b656ad6b0aa24fe1b8b944203788b9bcb1f450 — the merge of head 603c1a10c9fac263d7f9b3a6bca3de3240d24d82 into base e74ec56acc33316a21d41fdde7f6d34a44d6a792, 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 06b656ad6b0aa24fe1b8b944203788b9bcb1f450 && git checkout 06b656ad6b0aa24fe1b8b944203788b9bcb1f450
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e74ec56acc33316a21d41fdde7f6d34a44d6a792 603c1a10c9fac263d7f9b3a6bca3de3240d24d82 && git checkout -B drift-repro e74ec56acc33316a21d41fdde7f6d34a44d6a792 && git merge --no-ff 603c1a10c9fac263d7f9b3a6bca3de3240d24d82

node scripts/docs-audit/affected-docs.mjs --json e74ec56acc33316a21d41fdde7f6d34a44d6a792

⚠️ 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 e74ec56acc33316a21d41fdde7f6d34a44d6a792 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: fc6245ba2170cbc51c9ca4cafad41a1dc0c1401c
Local-runs: none
Scope: packages/spec/src/migrations/entries/semantic/18.ui-cloud-connection-widgets-unknown-keys-refused.ts, packages/spec/src/migrations/entries/semantic/18.ui-marketplace-installed-list-retired.ts, packages/spec/src/migrations/entries/semantic/18.ui-mcp-connect-agent-unknown-keys-refused.ts, packages/spec/src/migrations/registry.ts.template, packages/spec/src/ui/component-type-vocabulary.ts, packages/spec/src/ui/component.zod.ts, packages/spec/src/ui/page.zod.ts + packages/spec/src/ui/component-marketplace-installed-list-retirement.test.ts, packages/spec/src/ui/component-type-vocabulary.test.ts, packages/spec/src/ui/component.test.ts, packages/spec/src/ui/component-record-related-list-parent-23134.test.ts, packages/spec/src/ui/page-print.test.ts (the print census), packages/spec/src/ui/app.zod.ts (ComponentNavItemSchema), packages/spec/src/migrations/types.ts, packages/spec/src/conversions/registry.ts (the element-filter-removed docblock), packages/spec/vitest.repo-tests.json, packages/lint/src/validate-component-types.ts, packages/lint/src/validate-component-types.test.ts, packages/lint/src/validate-component-props.test.ts, packages/lint/src/validate-print-page-blocks.ts, packages/cli/test/migrate-meta-engine-guidance.test.ts (the guidance census), packages/cli/test/platform-page-i18n-parity.test.ts, packages/cloud-connection/src/marketplace-ui.ts (the "Installed Apps" entry), scripts/pm/clause2-line.mjs, scripts/check-changeset-no-major.mjs, scripts/check-adr-0087-registration.mjs, scripts/check-doc-authoring.mjs (its position list), scripts/cross-package-test-inputs.mjs, scripts/build-console.sh, .github/workflows/ci.yml (Console Pin Gate, Build Core, Test Core), .github/workflows/lint.yml, .github/workflows/pr-automation.yml (Check Changeset), .claude/skills/pm-dispatch/references/lanes/spec.md and contract-review.md (the clause-② rule), the rest of the diff (.changeset/24230-marketplace-installed-list-retired.md, content/docs/references/ui/page.mdx), the precedent PR #24170 at 030a7b83e with its records 6234523454 / 6235567508 and its changeset, and the objectui sibling checkout at the pinned 5e15928b46 (InstalledListWidget.tsx, registry-inputs-spec-parity.test.ts, packages/cli/src/utils/known-schema-types.ts).

① Derived judgments

Every door marketplace:installed-list was accepted at is now a refusal, each judged right.

  • PageComponentSchema.type, the open string arm. The existing superRefine (page.zod.ts) looks the type up in RETIRED_PAGE_COMPONENT_TYPES, so the node is refused at its own path with code: 'custom', path: ['type'], params.retiredComponentType: 'marketplace:installed-list' — bare, {}-bag and keyed alike. The type was never a PageComponentType member, so there is no enum error-map door and no value to remove: the map entry is the ONLY parse door, and without it the name falls back to the open arm and parses in silence (pinned: marketplace:installed-list-v2 still parses). Right.
  • ComponentPropsMap['marketplace:installed-list']. Kept as retiredComponentProps('marketplace:installed-list'): a z.never whose error callback returns the map's own guidance, described [REMOVED] …, where the factory throws at module load if the map has no entry — one string at both doors, no drift possible. {} and the former keyed bag are each refused with one invalid_type issue at []. Keeping the row is required, and here more than for record:json: KNOWN_COMPONENT_TYPES is the enum plus the row keys plus the string-arm ledger (component-type-vocabulary.ts), RESERVED_COMPONENT_TYPE_NAMESPACES derives from the enum alone so marketplace: is unreserved, lint's props gate skips a rowless type as an unregistered custom string, and check-yaml-examples judges only rowed types — delete the row and every reader that dispatches on it demotes the retirement to a silent skip. Pinned in component-type-vocabulary.test.ts: known only through the row, out of KNOWN_COMPONENT_TYPE_CANDIDATES (KNOWN minus the retired map), hasReservedComponentNamespace false, cloud-connection:panel as the lit control. Right.
  • PageSchema at the element path. Refused at regions[0].components[1].type, one custom issue, with the same page parsing when cloud-connection:panel sits in that slot. Right.
  • The lint door. validate-component-types.ts reads the map: component-type-unknown as error at …type, message = retiredTypeHead(prescription) ("marketplace:installed-list was removed in @objectstack/spec 18 (ADR-0049)") plus the fixed relay clause, inside the 200-character one-line pin; hint = retiredTypeRemedy(prescription), which takes the prescription from its first "delete the" — the fix sentence itself, no earlier occurrence — and strips the trailing period: 194 characters with it, 193 without, under the 200 cap so no dash cut. component-props-invalid at …properties for every bag, {} included, because the row is z.never. The typo suggester drops the name without an edit. The accept row left validate-component-types.test.ts; the map-driven flags %s, the [#22161] one-line-verdict and one-line-fix cases iterate RETIRED_PAGE_COMPONENT_TYPES, so the type rule is pinned map-wide; validate-component-props.test.ts flips the keyed-bag and {} cases into one whole-bag refusal pin (COMPONENT_PROPS_INVALID, error) with the sibling's {} as the silent control. Right.
  • The prescription against the playbook's conventions. Backticked fully qualified name first; "was removed in @objectstack/spec 18 (ADR-0049)" — the type shipped in 17.3.0 and the removal ships on the 18 line, so 18 is right; a dash clause saying why (the view it drew was retired, no renderer, the console shows "Unknown component type"); the replacement named (Setup → Packages filtered to Source = marketplace); the imperative fix. The fix spelling — componentRef: 'developer:packages', params: { source: 'marketplace' } — is byte-identical to the bundle's own "Installed Apps" entry (marketplace-ui.ts) and validates against ComponentNavItemSchema (type: 'component', componentRef string, params record). No os migrate meta sentence, right because no conversion covers the surface; no tracker number, pinned by the test's ISSUE_ID regex and reached by check:doc-authoring (the map is a guidance position). Right.
  • The print row. PRINT_REFUSED_PAGE_COMPONENT_TYPES loses its row — required, not optional: page-print.test.ts reports a retired key in either print set as stale, and the map's docblock says the retired types are not repeated there. validate-print-page-blocks.ts skips retired types before any print rule reads them, so the print door's accept set does not widen end to end. Right.
  • The open arm stays open. mcp:connect-agent, custom.installed_list, object-grid and the -v2 stranger pinned parsing; the reserved-namespace set is unchanged because it is derived from the enum, which did not move. Right.
  • Nothing leaves the export surface. emptyProps mints no def, so there is no retired-defs entry to owe, no api-surface / json-schema.manifest / authorable-surface shard moves, and check:generated moved only content/docs/references/ui/page.mdx (the regenerated .describe() on two rows) — consistent with the file list. The 23134 whole-bag census gains the type (a z.never row refuses the key as invalid_type, not unrecognized_keys). Right.
  • Registration keys are spelled as the gates read them. 18.ui-marketplace-installed-list-retired.ts is named for its id and carries the SemanticMigration shape (id, surface, replacement, reason, acceptanceCriteria; no conversionIds, right because no D2); acceptanceCriteria names the os validate report at the node's own type path with params.retiredComponentType, which is what the superRefine emits. The STEP18_RATIONALE fragment sits at its sorted id between ui-form-layout-inline-grid-retired and ui-object-form-custom-fields-typed, order: 102 = the list's highest (101) plus one, as the template header and step18-rationale-merge.test.ts require. check:spec-changes, check:upgrade-guide and check:generated --reconcile-only are green in Type Check · source gates. Right.
  • No D2 conversion — right. The type never took a key, so there is nothing a walker could strip and leave a valid node behind; deleting an authored page node is the layout decision conversions/registry.ts's element-filter-removed docblock says a mechanical conversion must not make; zero authored nodes were measured in objectstack and the bundle serves no page since cloud-connection: the "Installed Apps" entry opens Setup Packages filtered to Source = marketplace (ruling B on #23892; after the objectui card lands and the pin moves) #23933. The D3 entry carries the delegation, and os migrate meta prints every MIGRATIONS_BY_MAJOR[18].semantic entry under manual changes. Right.
  • Every runtime string is tracker-free. Scanned every added line of the diff: each #NNNNN sits in a // or * comment or in the changeset's summary line (the precedent's house form); the STEP18_RATIONALE text: reads "(ADR-0049 enforce-or-remove)", the D3 entry's four strings, the amended entry's three, the mcp clause, the prescription and the .describe() carry none. The defect the precedent's first record failed on is absent here. check:doc-authoring does not reach text: or SemanticMigration fields, but the cli guidance census (migrate-meta-engine-guidance.test.ts, hosted by Test Core) prints every semantic entry's block and refuses a tracker id in any — both the new and the amended entry pass that reading on the text as written. Right.
  • The amendment of ui-cloud-connection-widgets-unknown-keys-refused is accurate against main's text: surface, replacement and acceptanceCriteria narrowed to cloud-connection:panel; reason keeps the two-instance history and gains the pointer to the retirement entry. Keeping the id is required: the cli census's REWRITTEN list holds it ("family lost …" on deletion) and shipped packages/spec/CHANGELOG.md text names it. The mcp entry's one historical clause changes no guidance. The new pin asserts the narrowed entry no longer names the retired type in surface or acceptanceCriteria. Right.
  • The tree-scoped absence walk is a complete pin. Same five roots, same authoring-shape matcher (a type key valued the name, inline code stripped), same seed spelling byte for byte as the landed component-record-json-retirement.test.ts (check:cross-package-test-inputs green in Lint · CI, release & engine gates); the exclusions are the two pins that author the node to assert its refusal, release-owned prose, the gitignored json-schema/ tree and CHANGELOG.md, each with its reason; matcher self-test and anti-vacuity floors present; registered in vitest.repo-tests.json, so it runs under Test Core's turbo run test test:repo. The three survivors outside the diff (content/docs/releases/v17/17-3.mdx, the packages/cloud-connection test doc comment, the liveness/page.json note) are prose mentions the matcher does not judge. Right.

② Semver level

  • .changeset/24230-marketplace-installed-list-retired.md: '@objectstack/spec': minor, a feat(spec)!: title, the BREAKING banner, a FROM → TO table with the one-line fix, and the adr-0087: registered ui-marketplace-installed-list-retired marker — the LEVEL matches what the diff publishes: an accept-set narrowing on a published authoring surface, no export removed, no JSON Schema unpublished, nothing widened. minor rather than major is the launch-window convention check-changeset-no-major.mjs enforces; Check Changeset (which hosts both that gate and check-adr-0087-registration.mjs) is success on the head. content/docs/releases/, .changeset/pre/ and every CHANGELOG.md are untouched. The level is right.
  • The Clause-②: line is wrong in VALUE, and split between its two carriers. The vocabulary is scripts/pm/clause2-line.mjs, the fleet's one reader: the value answers one question — 「本卡放宽接受集或扩大公开面吗」 — and the spelling yes (narrowing) means "a diff that widens one surface and narrows another"; check-changeset-no-major.mjs's header reads clause ② as "a new key on a published payload"; the spec lane's own rule (lanes/spec.md) is 「放宽接受集或扩大公开面的卡,不论多小,即条款②;收窄仍是契约面,不触条款②」. This diff adds no key and widens nothing: every door above narrows, the open arm and every other row are byte-identical (the body and the changeset both say so), and no export is added. So a yes declares a widening the diff does not contain; the truthful spelling is no (narrowing) — exactly what the record:json precedent (030a7b83e, the same shape surface for surface) shipped, and what its record 6234523454 ruled when it judged the ai:chat_window spelling: "the precedent's yes (narrowing) would have over-declared (this diff widens nothing)". The PR body's difference table grounds the yes in "the type shipped in stable 17.3.0" — but the vocabulary ties the value to the DIRECTION of the change, not to the release line a surface shipped on; stable-versus-prerelease governs the ADR-0087 disposition and the FROM → TO text, both of which are right here, and nothing about the value. Second, the two carriers disagree: the PR body reads yes and the changeset yes (narrowing). The body is the ONE carrier check-changeset-no-major.mjs reads (its reading on this PR: "direction arm: none declared"), so the gate's record of this PR declares no direction for a breaking change, while check-adr-0087-registration.mjs reads the arm from the changeset alone — which is why both are green, and why their green carries no information about the value. The precedent's record held the same spelling "at the start of a line in both the PR body and the changeset". Fix: the line Clause-②: no (narrowing) at the start of a line in the changeset (one line; the minor, the bang, the banner and the marker stay — check-adr-0087-registration reads the narrowing arm, and check-changeset-no-major keeps the level axis carried on no (narrowing)), and the same line in the PR body (the seat's write). The dev copied the claim's yes by instruction, and the triage grade carried yes (narrowing); aligning those two records is the seat's and triage's work, not the dev's — the PR and its changeset are what land, so the correction is owed there.

③ Boundary flags

  • Deviation 1, the Clause-② spelling: answered in ② — the value, not only the arm's placement, is the defect.
  • Deviation 2, the row kept rather than deleted: right and required, judged in ①; the card's "the row goes" is met as the ACCEPTING row going, with the key kept so keyof typeof ComponentPropsMap and objectui's partition key set are unchanged.
  • Deviation 3, component-record-related-list-parent-23134.test.ts edited: right — the whole-bag census is a pin of the retired set and the precedent edited it for the same reason.
  • Deviation 4, the cli SAMPLE_PAGE fixture: right. The file never parses the page (no PageSchema read), so it did not fail; it authored the retired node inside the walk's radius, and the alternative — an EXCLUDED row for a file whose job is not to author the node — is the allowlist the retirement playbook refuses. Header copy is all the parity gate reads; the body block is now a live element:divider. A test-fixture edit, nothing published.
  • Deviation 5, the OS_SKIP_DTS=1 local closure: local hygiene, and every family it tripped is hosted on the head and green: check:dts-closure by Build Core, Type Check · debt ledger and Type Check · consumer gates (all success); check:dual-build-cjs-loads by Build Core (success); check-plugin-teardown-shape.mjs --self-test by Lint · CI, release & engine gates (success); check:skill-examples, re-run green locally after a DTS build, by Type Check · consumer gates (success). All three NOT-MEASURED families covered and concluded.
  • Deviation 6, commit trailers: verified on all four branch commits — the model-free pair AGENTS.md requires; right.
  • Open question, amend or supersede the two semantic/18.* entries: A, confirmed. Both entries sit in the same major-18 step as the new one, so a 17 → 18 upgrader reads all three, and "keep the node, validate clean" beside a by-name refusal is contradictory guidance in one replay; the amended id is referenced by shipped CHANGELOG text and held by the cli census, so superseding with deletion reds the census and superseding without deletion leaves the contradiction in place. One entry per surface, id stable, is the long-term shape.
  • Out-of-scope note 1, objectui's parity entry and known-schema-types.ts: confirmed, and sharpened for the carrier. At the pin 5e15928b46, registry-inputs-spec-parity.test.ts's rot check reads isRetiredUpstream(type) straight from RETIRED_PAGE_COMPONENT_TYPES and refuses an "EMPTY SPEC SHAPE" entry for a type the spec retires ("rewrite the entry as RETIRED UPSTREAM"), so the rewrite is mechanically demanded the day objectui installs a spec carrying this retirement — that is objectui's pin-bump follow-up, as the card names it. Post-Task Checklist 4 holds on this PR: the Console Pin Gate (ci.yml, scripts/build-console.sh) builds the console at the pin and asserts the dist, its stamp and its spec injection, and runs no objectui test; the pinned non-test source reads the type only as a registration string (InstalledListWidget.tsx) with no typed read of ComponentPropsMap['marketplace:installed-list'], and the key is kept. Nothing in the full battery is threatened by this merge, and .objectui-sha is rightly unmoved.
  • Out-of-scope note 2, the liveness/page.json read-point note: historical evidence at an older objectui sha, untouched; right.
  • Hold-offs: objectui, .objectui-sha, packages/cloud-connection, content/docs/releases/ and every CHANGELOG.md are absent from the file list. Right.
  • Check-runs on fc6245ba2 at read time, 40: 31 success, 5 skipped (Console Pin Gate, the Dogfood matrix shards, Dogfood Verify CLI, Packed-tarball smoke, Temporal Conformance — full-battery lanes, not PR lanes), 4 in_progress (Test Core 2/6, 3/6, 4/6, 6/6). Of the five required contexts: Lint & Repo Gates, TypeScript Type Check, Build Core and Governed Surface Queue Guard are success; the Test Core aggregator is not yet present because four shards are running. Also green: Check Changeset, Spec property liveness, Type Check · source gates (check:spec-changes, check:upgrade-guide, check:authorable-surface, check:docs, check:generated --reconcile-only), Type Check · consumer gates (check:api-surface), Lint · CI, release & engine gates (check:cross-package-test-inputs), Lint · repo & tooling gates (check:doc-authoring), Test Core 1/6 and 5/6. No check-run judges the Clause-② VALUE against the diff's direction, so the ② finding stands whatever the four shards conclude.
  • Dev-reported local results (spec build exit 0, check:generated all 14 current, 21001 spec tests, lint 6820, cli 27/27, the 6-of-30 ablation with blob restore) are recorded as reported, not re-run here; the gate families they cover are the check-runs above.
  • Governed surfaces: none in the file list (no .claude/**, skills/**, docs/adr/**, .github/workflows/**, AGENTS.md, CLAUDE.md); Governed Surface Queue Guard success; 598 changed lines, under the 3,000-line class (Check PR Size success). The record is owed by the schema face on --paths and by the narrowing, not by a governed path. Nothing to escalate.
  • The one defect is the Clause-② line (② above): one line in the changeset and one in the PR body, with the remedy named. Everything else on this head is judged right, so the re-review of the next head is that line in both carriers, the four Test Core shards that were in_progress here, and nothing else.

Implemented-by: claude/issue-24230-marketplace-installed-list-retired
Reviewed-by: session_01TyRhWbVbbQpQJTDbW8VahJ

VERDICT: FAIL


Generated by Claude Code

…-② no (narrowing) — the diff widens nothing

Claude-Session: https://claude.ai/code/session_01SovhHbD8dAQGDyEGHRoSUx
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 603c1a10c9fac263d7f9b3a6bca3de3240d24d82
Local-runs: none
Scope: packages/spec/src/migrations/entries/semantic/18.ui-cloud-connection-widgets-unknown-keys-refused.ts, packages/spec/src/migrations/entries/semantic/18.ui-marketplace-installed-list-retired.ts, packages/spec/src/migrations/entries/semantic/18.ui-mcp-connect-agent-unknown-keys-refused.ts, packages/spec/src/migrations/registry.ts.template, packages/spec/src/ui/component-type-vocabulary.ts, packages/spec/src/ui/component.zod.ts, packages/spec/src/ui/page.zod.ts + packages/spec/src/ui/component-marketplace-installed-list-retirement.test.ts, packages/spec/src/ui/component-type-vocabulary.test.ts, packages/spec/src/ui/component.test.ts, packages/spec/src/ui/component-record-related-list-parent-23134.test.ts, packages/spec/vitest.repo-tests.json, packages/lint/src/validate-component-types.ts (retiredTypeHead / retiredTypeRemedy), packages/lint/src/validate-component-types.test.ts, packages/lint/src/validate-component-props.test.ts, packages/cli/test/migrate-meta-engine-guidance.test.ts (the guidance census, its REWRITTEN list and TRACKER_ID), packages/cli/test/platform-page-i18n-parity.test.ts, packages/cloud-connection/src/marketplace-ui.ts (the "Installed Apps" entry), scripts/pm/clause2-line.mjs, scripts/pm/record-recognisers.mjs (reviewFace, read over the whole 17-path file list), scripts/check-changeset-no-major.mjs, scripts/check-adr-0087-registration.mjs, scripts/check-doc-authoring.mjs, scripts/build-console.sh, .github/workflows/ci.yml (Test Core aggregator, Console Pin Gate), .claude/skills/pm-dispatch/references/lanes/spec.md and contract-review.md (the clause-② rules), the rest of the diff (.changeset/24230-marketplace-installed-list-retired.md, content/docs/references/ui/page.mdx), the two hand-written docs the drift advisory named (content/docs/deployment/validating-metadata.mdx, content/docs/protocol/objectui/layout-dsl.mdx), the precedent PR #24170 at 030a7b83e with its records 6234523454 / 6235567508 and its changeset, the earlier record 6245719006 on this PR at fc6245ba2, and the objectui sibling checkout at the pinned 5e15928b46 (InstalledListWidget.tsx, registry-inputs-spec-parity.test.ts, packages/cli/src/utils/known-schema-types.ts).

What moved since the earlier record. fc6245ba2 is an ancestor of 603c1a10c; the delta is one commit, one file, one line: .changeset/24230-marketplace-installed-list-retired.md line 13, Clause-②: yes (narrowing) → Clause-②: no (narrowing) (git diff fc6245ba2..603c1a10c, 1 insertion, 1 deletion). No package source, test, migration entry or generated artifact moved. The PR body was edited by the seat at 05:10:09Z: line 3 reads Clause-②: no (narrowing), the difference table's Clause-② row says the same, and the Gates section now quotes the no (narrowing) LEVEL AXIS reading. Every ① judgment in 6245719006 is therefore untouched by the move; each is carried below by naming that record, and the load-bearing ones were re-read in the cited code on this head rather than taken on trust. ② is judged afresh. The scope floor was re-derived: reviewFace over all 17 changed paths returns exactly the seven schema hits above (the schema face decides before the Clause-②: line is read, record-recognisers.mjs self-test line 1634), so the floor is the seven hits, not the whole-diff floor of the narrowing face.

① Derived judgments

Every door at which marketplace:installed-list was accepted on main (cbfa5e4335) is a refusal on this head, and nothing else moved. Each judged right; where it says "carried", 6245719006 ① holds the full reading.

  • PageComponentSchema.type, the open string arm. The existing superRefine (page.zod.ts lines 620–630 at the head) looks the type up in RETIRED_PAGE_COMPONENT_TYPES and adds code: 'custom', message: guidance, params: { retiredComponentType } at ['type']. The new map entry (lines 830–837) is the only parse door: the type was never a PageComponentType member and marketplace: is unreserved, so without the entry the name falls back to the open arm and parses in silence; the pin asserts marketplace:installed-list-v2 still parses. Re-read; right.
  • ComponentPropsMap['marketplace:installed-list'] is kept as retiredComponentProps('marketplace:installed-list'), a z.never whose error callback returns the map's own text and which throws at module load if the map lacks the entry (component.zod.ts lines 486–492): one string at both doors, no drift possible. {} and the former keyed bag are each refused with one invalid_type at []. Keeping the key is required: KNOWN_COMPONENT_TYPES derives from the row keys, lint's props gate skips a rowless type as an unregistered custom string, check-yaml-examples judges rowed types only, and the objectui parity partition keys on the map. Re-read; right (carried for the vocabulary pins).
  • PageSchema refuses at regions[0].components[1].type, one custom issue, with cloud-connection:panel in the same slot as the live control. Carried; right.
  • The lint door. validate-component-types.ts reads the map; component-type-unknown as error at …type with retiredTypeHead (the text before the first —: "marketplace:installed-list was removed in @objectstack/spec 18 (ADR-0049)") and the fixed relay clause, 155 characters; hint = retiredTypeRemedy, which takes the prescription from its first "delete the" (index 400, the fix sentence itself and the only occurrence), strips the trailing period, 193 characters, under the 200 cap so no dash cut. component-props-invalid error at …properties for every bag, {} included. The accept row left validate-component-types.test.ts and the map-driven flags %s case covers the type; validate-component-props.test.ts flips the keyed-bag and {} cases into one whole-bag refusal pin with the sibling's {} as the silent control. Measured on this head; right.
  • The prescription. Fully qualified name first, "was removed in @objectstack/spec 18 (ADR-0049)" (shipped in 17.3.0, removal on the 18 line), the why clause, the replacement (Setup → Packages filtered to Source = marketplace), the imperative fix. The fix spelling componentRef: 'developer:packages', params: { source: 'marketplace' } is byte-identical to marketplace-ui.ts lines 80–81 at the head. No os migrate meta sentence (no conversion covers it); no tracker id (regex over the whole string: none; the pin's ISSUE_ID regex holds it; check-doc-authoring reaches new Map guidance tables, and Lint · repo & tooling gates is success). Right.
  • The print row leaves PRINT_REFUSED_PAGE_COMPONENT_TYPES; required, since page-print.test.ts reports a retired key in either print set as stale and the parse refuses the type before any print rule reads it. Carried; right.
  • The open arm stays open: mcp:connect-agent, custom.installed_list, object-grid and the -v2 stranger pinned parsing; RESERVED_COMPONENT_TYPE_NAMESPACES derives from the enum, which did not move. Carried; right.
  • Nothing leaves the export surface. emptyProps builds a strictObject with no exported def (component.zod.ts lines 458–466), so no retired-defs entry is owed and no api-surface / json-schema.manifest / authorable-surface shard moves; the file list carries only content/docs/references/ui/page.mdx (the regenerated .describe() on two rows), and Type Check · source gates (check:generated --reconcile-only, check:docs, check:authorable-surface) and Type Check · consumer gates (check:api-surface) are success on this head. The whole-bag census gains the type. Right.
  • Registration keys are spelled as the gates read them. 18.ui-marketplace-installed-list-retired.ts carries the SemanticMigration shape with no conversionIds (no D2, right: the type never took a key, and deleting an authored node is the layout decision element-filter-removed's rule reserves to the author); acceptanceCriteria names the type path and params.retiredComponentType, which the superRefine emits. The STEP18_RATIONALE fragment sits at its sorted id with order: 102 — the list's maximum at the merge base is 101, and 102 appears once at the head. check:spec-changes and check:upgrade-guide ride Type Check · source gates, success. Right.
  • Every runtime string is tracker-free. The three semantic entries at the head, with // lines stripped, carry no four- or five-digit # id (the cli census's TRACKER_ID); the text: fragment reads "(ADR-0049 enforce-or-remove)". Test Core, which hosts the census, is success. Right.
  • The amendment of ui-cloud-connection-widgets-unknown-keys-refused: surface, replacement and acceptanceCriteria narrowed to cloud-connection:panel, reason keeps the two-instance history and points at the retirement entry, id kept. Keeping the id is required: migrate-meta-engine-guidance.test.ts line 301 holds it in REWRITTEN and asserts "family lost" on deletion, and shipped CHANGELOG text names it. The mcp entry's one clause changes no guidance. The new pin asserts the narrowed entry names the control and not the retired type in surface and acceptanceCriteria. Right.
  • The tree-scoped absence walk uses the same roots, matcher, seed spelling and anti-vacuity floors as the landed record:json pin; the exclusions are the two pins that author the node to assert its refusal, release-owned prose, the gitignored json-schema/ tree and CHANGELOG.md, each with a reason; registered in vitest.repo-tests.json at its sorted position. check:cross-package-test-inputs rides Lint · CI, release & engine gates, success. Right.
  • Docs the drift advisory named (validating-metadata.mdx, layout-dsl.mdx) never mention the type; nothing in them is falsified. Right.

② Semver level

  • .changeset/24230-marketplace-installed-list-retired.md: '@objectstack/spec': minor, a feat(spec)!: title, the BREAKING banner, a FROM → TO table with the one-line fix, and the marker adr-0087: registered ui-marketplace-installed-list-retired. The LEVEL matches what the diff publishes: an accept-set narrowing on a published authoring surface, no export removed, no JSON Schema unpublished, nothing widened; minor rather than major is the launch-window convention check-changeset-no-major.mjs enforces, and the precedent 030a7b83e shipped the same shape. content/docs/releases/, .changeset/pre/ and every CHANGELOG.md are untouched. Right.
  • The Clause-②: line is now right, in value and in placement, on both carriers. Changeset line 13 and PR body line 3 both read Clause-②: no (narrowing), bare, at the start of a line of their own. Against the one reader, scripts/pm/clause2-line.mjs: no (narrowing) is "NOT a widening, but breaking — the whole point of the arm", and this diff widens nothing (every door above narrows; the open arm and every other row are byte-identical; no export is added). Against both gates: check-changeset-no-major.mjs reads the PR body, and a no carrying the narrowing arm keeps the level axis standing (its lines 1808–1814); check-adr-0087-registration.mjs reads the changeset body through the same reader and raises the clause-②-narrowing signal (its lines 683–684). Check Changeset is success on this head twice, at 04:44:52Z and again at 05:11:43Z after the body edit, so the gate's record of this PR now declares the direction. This is the spelling the record:json precedent shipped at both carriers and its PASS record 6235567508 held. The remedy 6245719006 ② named is applied in full, and the two carriers agree. Right.
  • One note for the seat, not a defect on this head: lanes/spec.md line 22 holds that a narrowing declared yes is never an error, so the earlier record's "wrong in VALUE" framing was stronger than the lane rule warrants; what that record was owed under the lane rule was one spelling on both carriers and the truthful direction, and this head carries both. The verdict here stands on no (narrowing) being right, not on yes having been wrong.

③ Boundary flags

  • Report 1 (6245513040) deviation 1, the Clause-② spelling: closed on this head, ② above.
  • Deviation 2, the row kept rather than deleted: right and required, ① above; the card's "the row goes" is met as the accepting row going, with the key kept so keyof typeof ComponentPropsMap and objectui's partition key set are unchanged.
  • Deviation 3, component-record-related-list-parent-23134.test.ts edited: right, the whole-bag census is a pin of the retired set and the precedent edited it for the same reason.
  • Deviation 4, the cli SAMPLE_PAGE fixture: right. The file never parses the page, so it did not fail; it authored the node inside the walk's radius, and an EXCLUDED row for a file whose job is not to author the node is the allowlist the retirement playbook refuses. Header copy is all the parity gate reads; the body block is a live element:divider. Test fixture only, nothing published.
  • Deviation 5, the OS_SKIP_DTS=1 local closure: local hygiene; every family it tripped is hosted and success on this head: check:dts-closure and check:dual-build-cjs-loads under Build Core, check-plugin-teardown-shape.mjs --self-test under Lint · CI, release & engine gates, check:skill-examples under Type Check · consumer gates.
  • Deviation 6, commit trailers: all five branch commits over cbfa5e4335 carry Co-authored-by: Claude and Claude-Session: …session_01SovhHbD8dAQGDyEGHRoSUx, the model-free pair; right.
  • Report 2 (6245768083) deviation, the PR body's stale Gates prose: closed. The body as it stands (edited 05:10:09Z) quotes the no (narrowing) LEVEL AXIS line and no longer says "declares clause-② yes".
  • Open question, amend or supersede the two semantic/18.* entries: A, confirmed. Both sit in the same major-18 step as the new entry, so a 17 → 18 upgrader reads all three, and "keep the node, validate clean" beside a by-name refusal is contradictory guidance in one replay; the amended id is held by the cli census and named in shipped CHANGELOG text, so superseding with deletion reds the census and superseding without deletion keeps the contradiction. One entry per surface, id stable.
  • Out-of-scope note 1, objectui's parity entry and known-schema-types.ts: confirmed at the pin 5e15928b46: registry-inputs-spec-parity.test.ts line 722 defines isRetiredUpstream over RETIRED_PAGE_COMPONENT_TYPES and line 4673 refuses an "EMPTY SPEC SHAPE" entry for a type the installed spec retires, so the rewrite to RETIRED UPSTREAM is mechanically demanded the day objectui installs a spec with this retirement — objectui's pin-bump follow-up, as the card names it. Post-Task Checklist 4 holds here: at the pin the non-test source reads the type only as a registration string (InstalledListWidget.tsx line 37) and a CLI string list; there is no typed read of ComponentPropsMap['marketplace:installed-list']; the key is kept; the Console Pin Gate (ci.yml, scripts/build-console.sh) builds the console at the pin and runs no objectui test. Nothing in the full battery is threatened, and .objectui-sha is rightly unmoved.
  • Out-of-scope note 2, the liveness/page.json read-point note: historical evidence at an older objectui sha, untouched; right.
  • Hold-offs: objectui, .objectui-sha, packages/cloud-connection, content/docs/releases/ and every CHANGELOG.md are absent from the file list. Right.
  • Check-runs on 603c1a10c, read at 05:17Z: 48, all complete — 41 success, 7 skipped, 0 failed. The five required contexts are success: Lint & Repo Gates (04:48Z), TypeScript Type Check (04:57Z), Build Core (04:51Z), Governed Surface Queue Guard (04:44Z), and the Test Core aggregator (05:16:54Z, all six shards success). Also success: Check Changeset (twice), Spec property liveness, Type Check · source gates, Type Check · consumer gates, Type Check · debt ledger, Type Check · workspace, every Lint · lane, Check PR Size, Dogfood Regression Gate, the card and single-writer claim checks. The 7 skipped are full-battery or opt-in lanes on a PR run (Console Pin Gate, the Dogfood matrix shards, Dogfood Verify CLI, Packed-tarball smoke, Temporal Conformance) plus the duplicate Auto Label / Check PR Size rows. An earlier read at 05:11Z had three Test Core shards in_progress; they concluded success before this record was written.
  • Dev-reported local results (spec build exit 0, check:generated all 14 current, 21001 spec tests, lint 6820, cli 27/27, the 6-of-30 ablation with blob restore, and the round-1 re-runs of both changeset gates) are recorded as reported, not re-run here; the gate families they cover are the check-runs above.
  • Governed surfaces: none in the file list; Governed Surface Queue Guard success; 598 changed lines, under the 3,000-line class. The record is owed by the schema face on --paths and by the narrowing, not by a governed path. Nothing to escalate.
  • The PR is still draft, as a dispatched dev leaves it; readying and arming are the owning seat's acts after this record, not a finding.

Implemented-by: claude/issue-24230-marketplace-installed-list-retired
Reviewed-by: session_01TyRhWbVbbQpQJTDbW8VahJ

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · PR #24255 @ 603c1a10c9 (#24230) · domain:spec seat 1 · os-project-manager · session session_01TyRhWbVbbQpQJTDbW8VahJ · 2026-10-18T05:22Z

Reviewer of record. Every item below was checked against GitHub and the code, not against the reports (6245513040, 6245768083 on #24230).

  • Shape: draft, base main. The first line is Fixes #24230, the body's only closing keyword, then Clause-②: no (narrowing), the same spelling as the changeset's line. 17 files, +523/−75, assignee os-project-manager. Not governed: check-governed-merges.mjs --pr 24255 reads 0 of 17 paths on the register, 598 changed lines, under 3000. Mergeable, state clean.
  • What it lands:
    • marketplace:installed-list joins RETIRED_PAGE_COMPONENT_TYPES. An authored node is refused by name at PageComponentSchema.type and PageSchema (code: 'custom', params.retiredComponentType). The message is the one prescription: a component navigation item with componentRef: 'developer:packages' and params: { source: 'marketplace' }, the spelling MARKETPLACE_INSTALLED_UI_BUNDLE's "Installed Apps" entry already uses.
    • The ComponentPropsMap row stays as retiredComponentProps and refuses every bag. For a type outside the PageComponentType enum, the row is the only thing that keeps the name known, so the key is kept (pinned).
    • The print row leaves. The lint component-type-unknown and component-props-invalid pins flip to refusals.
    • D3 entry ui-marketplace-installed-list-retired, step 18, order: 102. ui-cloud-connection-widgets-unknown-keys-refused is amended in place to cloud-connection:panel; the cli census and shipped CHANGELOG text hold its id. ui-mcp-connect-agent-unknown-keys-refused gains one historical clause.
    • No export leaves: emptyProps minted no def, and check:generated moved only content/docs/references/ui/page.mdx.
    • A changeset of spec minor, BREAKING, with FROM → TO and the marker adr-0087: registered ui-marketplace-installed-list-retired.
  • Reverse proof (report): the map key renamed and the row restored to emptyProps. That reds the retirement pin (4 of 10) and the vocabulary pin (2 of 22). Both files were restored to their HEAD blobs.
  • Contract review:
    • FAIL 6245719006 on fc6245ba2, on ② only: the Clause-② value.
    • Patch round 1 changed one changeset line (6245768083), and the seat corrected the PR body.
    • PASS 6246040858 on this head (CONTRACT_REVIEW_TIER). It answers the open question A (amend in place).
  • The Clause-② record, corrected: claim 6245064045 carried Clause-②: yes, and triage 6243387750 / 6245014494 carried yes (narrowing). The truthful spelling for this diff is no (narrowing): it widens nothing and narrows one accept set. Both carriers now say so, as the record:json precedent did. As the PASS record notes, lanes/spec.md holds that declaring yes on a narrowing is never an error, so the earlier record's "wrong in value" framing overstated the defect. The PASS stands on no (narrowing) being true on both carriers.
  • Cross-lane: declared on the domain:cli seat 1 post (6245535618), for the one test fixture in packages/cli/test/platform-page-i18n-parity.test.ts. No objection was raised.
  • Gates: 48 check-runs on 603c1a10c9, all completed: 41 success, 7 skipped. All 7 skipped are on check-expected-skips.mjs's roster, matched by name. The five required contexts are success, including the Test Core aggregator with all six shards.
  • Deviations, accepted:
    • The accepting row goes and a refusing row stays (the precedent's shape).
    • The whole-bag census test was edited.
    • The cli fixture was moved out of the absence walk's radius; that file never parses the page.
    • The OS_SKIP_DTS local closure: every family it tripped is hosted and green.
    • The model-free trailer pair on every commit.
  • Follow-up, no card: objectui's registry-inputs-spec-parity.test.ts entry and its known-schema-types.ts string leave in objectui's own pin bump, as the card names. At the pin 5e15928b46, the parity test's isRetiredUpstream reads RETIRED_PAGE_COMPONENT_TYPES, so the bump is told mechanically to rewrite the entry. No typed read of the row exists there, and the key is kept, so the Console Pin Gate build is not at risk. .objectui-sha is unmoved.

The PR goes to the merge queue in this act. The cloud dev session is archived.


Generated by Claude Code

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/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spec(ui): retire marketplace:installed-list once objectui#12733 lands: no renderer draws it, yet the page vocabulary and the page lint still accept it

2 participants