Skip to content

fix(cli): retire objectui add and analyze's two flags, no-ops that exited 0; one enumeration pin over the built CLI's commands (objectui#11496) - #11499

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-11496-retire-cli-add
Oct 2, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-11496-retire-cli-add

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #11496

Clause-②: yes

What

objectui add COMPONENT was declared ("Add a new component renderer to your project") and documented with an example. Its action printed "Feature not implemented yet.", wrote nothing and exited 0. Triage ruled it retired, with no placeholder (ruling comment 5958245941, on the precedents 5955124315 and 5957399263). The ruling also asked for a family close-out over every command and flag, plus one enumeration pin over the built CLI's commands. This PR:

  • removes the add command from packages/cli/src/cli.ts and deletes packages/cli/src/commands/add.ts;
  • retires analyze --render-performance, the one further no-op the close-out found, and analyze --bundle-size with it (see Contract notes). Their option lines go from cli.ts, and the placeholder function and the option plumbing go from commands/analyze.ts;
  • drops the add section and the analyze flag table from content/docs/utilities/cli.mdx, replaces its stored command count with a pointer to objectui --help, and drops the add section from packages/cli/README.md;
  • adds the pins in packages/cli/src/__tests__/cli-bin.test.ts, all run through the built dist/cli.js;
  • adds .changeset/11496-retire-cli-add.md (@object-ui/cli minor, BREAKING banner, one FROM to TO line per retired surface, a Clause-② line).

No refusal code was needed. Measured on the BASE build before any edit: the program declares no default command, allowUnknownOption, passThroughOptions or allowExcessArguments. objectui bogus exits 1 with error: unknown command 'bogus', and objectui --bogus exits 1 with error: unknown option '--bogus'. So commander's default refusal applies once a command or option is undeclared.

Serial: PR objectui#11495 (generate --from) landed as 1fe05ff37 before the first edit here. This branch was fast-forwarded onto it, so 1fe05ff37 is the base. origin/main has not moved since.

Contract notes

  • The accept set narrows (Clause-② yes). The published objectui bin refuses three surfaces it used to accept:

    • FROM objectui add COMPONENT (exit 0, nothing written) TO a non-zero exit with error: unknown command 'add', nothing written.
    • FROM objectui analyze --render-performance (exit 0, fixed text) TO a non-zero exit with error: unknown option '--render-performance'.
    • FROM objectui analyze --bundle-size TO a non-zero exit with error: unknown option '--bundle-size'. The replacement is objectui analyze, which prints the same bundle report.

    There is no alias, no deprecation window and no silent accept.

  • Why --bundle-size goes too. It only chose between the bundle report and the render section. With the render section retired, the flag would be declared, documented and read by nothing, which is why generate --output was retired. Keeping it would leave that defect in place, so it goes. This is a judgement on top of triage's ruling; it is raised as an open question in the dev report so the contract review can overturn it.

  • Unchanged. objectui analyze with no flag prints the bundle-size report of dist/ byte for byte as before, minus the fixed render section. Its help description is untouched. No exported symbol of @object-ui/cli moves: cli.ts is the bin entry, and analyze is not in the package's exports (src/index.ts exports serve and init only).

  • validate and check are not edited. Draft PR objectui#11069 owns them. Both measured as working (table below). That PR also edits the README's validate section and the docs' validate / check sections. Those regions do not touch the ones edited here: four untouched README lines separate the nearest hunks.

Family close-out: every command and flag cli.ts declares

One run per row in a fresh temp directory, on the built CLI (exit code, files written). The rows were measured on the build of 4abc0aafa, which differs from base 1fe05ff37 only by generate --from, plus the post-fix build for the rows marked "after". The help texts are commander's. Placeholders are spelled in capitals, because GitHub strips angle-bracket shapes from a saved body.

Surface --help says cli.mdx says Built CLI, measured Class
-V, --version output the version number (not listed) prints 17.6.0, exit 0 works
-h, --help display help for command npx @object-ui/cli --help usage plus the command list, exit 0 works
serve [schema] Start a development server with your JSON/YAML schema legacy alias of dev, "same positional argument and -p/-h flags as dev (no --no-open)" empty dir: exit 1, "Schema file not found: app.json". Real project (app.json, deps installed): HTTP 200 from the dev server works
serve -p, -h Port / Host as dev bound to the given port and host works
serve --no-open Do not open browser automatically says serve has no such flag honoured: no browser attempt with it; without it, the "could not open the browser automatically" line works; the docs row is wrong (Acceptance notes)
dev [schema], -p, -h, --no-open Start development server (alias for serve) as --help empty dir: exit 1. Real project: HTTP 200, --no-open honoured works
build [schema], -o, --out-dir, --clean Build application for production as --help empty dir: exit 1. Real project: wrote out/index.html and out/assets/, exit 0; --clean removed a sentinel file works
start, -p, -h, -d, --dir Start production server as --help empty dir: exit 1, "Build directory not found". Built out/: HTTP 200 on / and on a deep route (SPA fallback) works
init [name], -t, --template Initialize a new Object UI application with sample schema as --help 13 files written, exit 0; -t form honoured; -t nope exits 1 works (-t nope leaves an empty directory, Acceptance notes)
lint, --fix Lint the generated application code Lint the generated application code with ESLint fresh dir: exit 1, "No Object UI application found". Past its precondition: ESLint finds no config, reported as "Linting found issues", exit 1 partial: cannot succeed on the app dev generates
test, -w, -c, --ui Run tests for the application Run the application's tests with Vitest fresh dir: exit 1. Past its precondition: "No test files found", reported as "Some tests failed", exit 1 partial: cannot succeed on the app dev generates
generate/g TYPE NAME Generate new resources (objects, pages, plugins) as --help page, object, resource and plugin each write their file, exit 0; an unknown type exits 1 works
doctor Diagnose and fix common issues Diagnose common environment issues (Node version, deps, config sanity) diagnoses deps, Tailwind and tsconfig; writes nothing; prints no Node line; exit 0 even with an error-level finding partial: no "fix" half, no Node check
add COMPONENT Add a new component renderer to your project Add a new component renderer scaffold to your project three lines, nothing written, exit 0. After: exit 1, error: unknown command 'add' no-op, retired here
studio Start the visual designer Launch the visual designer (@object-ui/plugin-designer) against the local project in an objectui checkout: starts apps/console's Vite dev server (MSW mode) on its fixed port, not the local project. In a simulated published install: exit 1, "Console app not found in workspace" partial
check Advisory JSON file sweep; run objectui validate for a verdict as --help empty dir: tally, exit 0; one recognised file: tally, exit 0 works (owned by objectui#11069, not edited)
validate [schema] Validate a schema file against ObjectUI specifications as --help valid app.json: exit 0; missing file: exit 1 works (owned by objectui#11069, not edited)
create TYPE NAME Create new resources Scaffold a new ObjectUI plugin via @object-ui/create-plugin create plugin my-widget: exit 1, Cannot find module on a create-plugin/dist/index.js path, in the checkout and in a simulated published install; another type exits 1 partial: never succeeds
analyze Analyze application performance Analyze the built application with dist/: totals and the ten largest files; without: a warning, then "Analysis complete", exit 0 works (exit 0 without dist/, Acceptance notes)
analyze --bundle-size Analyze bundle size Inspect bundle size the same report as analyze, alone. After: exit 1, unknown option retired here (see Contract notes)
analyze --render-performance Analyze render performance Inspect render performance fixed text, byte for byte the same in an empty directory and in a built project with dist/ (same md5); exit 0. After: exit 1, unknown option no-op, retired here
help [command] commander's built-in (not listed) works works (commander)

Pins

All of them are in cli-bin.test.ts and run through the built dist/cli.js:

  1. --help > lists exactly the declared commands, no more and no fewer. This is the enumeration pin. It parses the Commands section of the root --help and asserts that the names equal SUBCOMMANDS, in both directions and without duplicates. Its lit control: commander's own help entry is read as the last entry, which proves the parse reached the end of the section. It replaces a containment check that a retired command coming back would have passed.
  2. the retired add command is refused (objectui#11496): add Input in an empty temp directory exits non-zero, stderr names unknown command 'add', and the directory stays empty. Its control: g page Probe in the same directory then exits 0 and writes pages/probe.json.
  3. analyze refuses its retired flags (objectui#11496): each flag exits non-zero naming itself as an unknown option, and writes nothing. The control: analyze with no flag over a planted dist/ exits 0, prints the bundle report and the planted file, and prints no render section. analyze --help lists neither flag, with a lit control on its own usage line.

SUBCOMMANDS drops add, and the analyze row leaves the "exposes the documented flags" table.

Reverse verification

Predictions were written down before each run. Every leg ran on final head 5e7b89431, with the fix committed.

  • BASE leg. cli.ts, commands/analyze.ts and commands/add.ts were checked out at base 1fe05ff37, with the pins at HEAD. Each blob equalled its base blob: ab22eb7e6fa6, 7d9e7e3af440, b2fd2fcae3e9. The CLI was rebuilt: dist markers add=1, render-performance=1. Predicted 6 red. Observed Tests 6 failed | 41 passed (47): pin 1, pin 2, both flag refusals, the no-flag control (it printed the render section), and the analyze --help pin.
  • Restore 1. cli.ts and analyze.ts blobs equal HEAD (004165f17300, 63659c0b30c9), add.ts is absent, git diff HEAD is empty and git status --porcelain is empty.
  • Ablation. objectstack's scripts/ablation-replace.mjs ran in wrap mode on the committed fix, with its restore trap. It planted back into cli.ts an add command that prints one line and exits 0, plus both analyze option lines; analyze.ts stayed fixed. Anchor x1 -> x0, blob 004165f17300 -> cdd4d9455089. Source markers add=1 render-perf=1 bundle=1; the CLI was rebuilt; dist markers add=1 render-perf=1 bundle=1. Predicted 5 red, with the no-flag control staying green because analyze.ts was not mutated. Observed Tests 5 failed | 42 passed (47), on exactly those five names.
  • Restore 2. The tool restored through git checkout HEAD -- on the absolute path. Blob after = HEAD blob 004165f17300, git diff HEAD is empty and git status --porcelain is empty. CLI rebuilt; dist markers all 0; Tests 47 passed (47).
  • The same two legs ran once before, on d9294d27b, with identical counts. The only change since is reading the last --help entry by index rather than with Array.at.

Tests and gates

All of these ran on final head 5e7b89431.

  • pnpm --filter @object-ui/cli build: exit 0. dist/ carries 0 hits each of command("add"), render-performance and bundle-size.
  • pnpm --filter @object-ui/cli type-check (tsc --noEmit): exit 0. --listFiles covers cli.ts, commands/analyze.ts and cli-bin.test.ts. An earlier run caught Array.at, which is not in this package's ES2020 lib; that is fixed.
  • pnpm exec vitest run packages/cli/, plus the cross-package readers of cli.ts, cli.mdx, the generator or the CLI bin: toc-anchor-parity, nested-page-children-11223, page-node-headings-drawn-11436, body-dialect-census, filter-builder-mirror-6939, check-node-esm-load, one-authority-per-exported-name-6273, markdown-test-inputs, check-pending-changeset-literals. Result: Test Files 34 passed (34), Tests 665 passed (665).
  • The card's reproduction on the built CLI: node packages/cli/dist/cli.js add Input exits 1 with error: unknown command 'add', and the directory stays empty.
  • pnpm docs:check-links: Links are valid across 17 scan roots.
  • pnpm check:doc-fences: ✅
  • node scripts/markdown-test-inputs.mjs --audit: 115 candidate test files, all adjudicated; 82 declared entries, all present.
  • pnpm check:control-bytes: ✅ OK
  • pnpm check:new-line-citations: VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0
  • node scripts/check-changeset-presence.mjs: exit 0. check-changeset-no-major.mjs: ✅. check-changeset-overwrite.mjs: ✅
  • pnpm check:changeset-claims (report-only) names two pending changesets that mention a file this change touches. 7658-toc-code-span-anchor-parity names cli.mdx and the README for the add heading its slug fix repaired; it is a past-tense account of that fix and is still true. 7694-chart-series-chart-type-alias-refusal names cli.ts as the home of objectui validate, which is still true.
  • pnpm check:pending-changeset-literals, check:test-path-roots, check:unreferenced-sources, check:doc-types and check:doc-example-ids: exit 0.
  • ESLint, as a proved narrowing.
    • ① Population: CI lints this package through turbo run lint, which runs the package's eslint src against the root eslint.config.js (the package has no config of its own). I ran that same eslint src.
    • ② --format json counts 51 files linted, equal to the 51 tracked ts/js files under packages/cli/src. It reports 0 errors and 5 no-explicit-any warnings, all in untouched files. The three edited source files read 0/0.
    • ③ Invariance: the config enables no type-aware linting (no parserOptions or projectService) and no import plugin, and no rule under eslint-rules/ reads the filesystem. So this diff cannot move a verdict on a file it does not touch.
    • cli.mdx, the README and the changeset are outside every eslint files glob. The repo-wide pnpm lint is left to CI.
  • NOT MEASURED: check:doc-snippets and check:doc-examples. Reason: PRECONDITION NOT MET (exit 2), because their scoped 34-package build was not run. The docs edit touches no ts or json fence; it removes one bash fence and one table. check:readme-exports is NOT MEASURED for the same reason (unbuilt packages); none of its unjudged lines is in packages/cli/README.md. The full pnpm test is CI's.

Acceptance notes

Named here and not changed, per the close-out ruling (partials are named, never implemented).

  • create plugin never succeeds. The script path is resolved one directory too high from the CLI's dist/: ../../../create-plugin/dist/index.js lands on the repo root, or on a top-level node_modules/create-plugin in an install. @object-ui/create-plugin is not a dependency of @object-ui/cli either. Reported to the seat as a defect finding.
  • lint and test cannot succeed on the app dev generates. The temp app declares neither ESLint nor Vitest and carries no config and no tests. The tool's own error is relabelled ("Linting found issues", "Some tests failed"). Measured past the precondition with a hand-built .objectui-tmp, not one a real dev run produced; said so in the report. Reported as a finding.
  • studio runs the objectui console's dev server on its fixed port in a checkout, and refuses in a published install. The docs say it launches the designer against the local project. Reported as a finding.
  • doctor: its help promises "fix", and nothing is written; its docs promise a Node version check, and none is printed; it exits 0 with an error-level finding.
  • serve --no-open is declared and honoured, but the docs say serve has no such flag.
  • analyze without dist/ prints a warning and then "Analysis complete", exit 0.
  • init -t nope refuses with exit 1 but leaves the empty project directory behind.
  • dev without --no-open, where no browser opener exists, prints Vite's raw spawn xdg-open ENOENT; serve prints a readable line for the same case.
  • toc-anchor-parity.test.tsx (packages/plugin-markdown) keeps an add heading row in LIVE_SHAPES whose where names cli.mdx and the README. That attribution is now stale; the row still exercises the slugger on its literal. It is outside this card's file surface.
  • The enumeration pin reads the built CLI only, not the docs. Holding the docs' ### objectui NAME headings to the same list from cli-bin.test.ts reds markdown-test-inputs --audit unless the test gains a row in that script's ADJUDICATED ledger. That file is outside this card's file surface, so the docs half is left to the seat (one ledger row plus about ten test lines). The SUBCOMMANDS comment says the docs headings are kept in step by hand.

Implemented by the os-dev agent dispatched by the domain:ui seat 1 PM, session https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37.


Generated by Claude Code

claude added 3 commits October 2, 2026 18:26
…t exited 0; one enumeration pin over the built CLI's commands (objectui#11496)

`add` printed "Feature not implemented yet." and wrote nothing, exit 0.
The family close-out over every command and flag found one more no-op:
`analyze --render-performance` printed fixed text in any directory.
`--bundle-size` goes with it, having nothing left to choose between.
The bin refuses all three; the docs and README drop them.

Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37
Co-authored-by: Claude <noreply@anthropic.com>
…e docs from this test needs a markdown-test-inputs ledger row outside this card's file surface (objectui#11496)

Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37
Co-authored-by: Claude <noreply@anthropic.com>
…lib has no Array.at (objectui#11496)

Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests package: cli labels Oct 2, 2026
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 2 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/7658-toc-code-span-anchor-parity.md

  • names content/docs/utilities/cli.mdx → content/docs/utilities/cli.mdx — edited by this change

    Seven live headings in this repo's own docs were affected (content/docs/utilities/cli.mdx, content/docs/utilities/runner.mdx, packages/cli/README.md). Pinned against the real render pipeline rather than a second derivation of the slug rules: the new test renders each heading through MarkdownImpl and compares extractToc's id to the id attribute rehype-slug actually emitted.

  • names packages/cli/README.md → packages/cli/README.md — edited by this change

    Seven live headings in this repo's own docs were affected (content/docs/utilities/cli.mdx, content/docs/utilities/runner.mdx, packages/cli/README.md). Pinned against the real render pipeline rather than a second derivation of the slug rules: the new test renders each heading through MarkdownImpl and compares extractToc's id to the id attribute rehype-slug actually emitted.

.changeset/7694-chart-series-chart-type-alias-refusal.md

  • names packages/cli/src/cli.ts → packages/cli/src/cli.ts — edited by this change

    • Before: series: [{ name: 'revenue', chartType: 'line' }] validated green through @object-ui/types/zod (safeValidateSchema, objectui check / objectui validate, any pipeline that keeps parse()'s output) — and the key was gone from the output, so a consumer of the parse result drew that series in the chart's own family, precisely what the author was overriding. On the TypeScript face the key was merely an excess property on a fresh literal; a widened object carrying it assigned structurally. - After: the same document REFUSES at series[i].chartType (issue code invalid_type) with one message on both channels — the parse-time issue and the .describe() metadata: Unrecognized key(s) on this chart series: \chartType`. Did you mean `chartType` → `type`? …followed by the reason and the remedy. Writetype: 'bar' | 'line' | 'area'. On the TypeScript face ChartDataSeries.chartTypeis a?: nevertombstone, so both the fresh literal and the widened assignment aretsc errors. - **Both written** ({ type: 'bar', chartType: 'line' }) is refused at chartTypealone — the key is not folded ontotypeand no precedence is minted between the two spellings. - **Which documents to scan.** The narrowing does not stop atChartDataSeriesSchema; it reaches every document through the parents that embed it — ChartSchema.series (zod/data-display.zod.ts, z.array(ChartDataSeriesSchema)) and, one level further out, ReportSectionSchema.chart (zod/reports.zod.ts, ChartSchema.optional()). Authors meet it through safeValidateSchema() (zod/index.zod.ts, which parses AnyComponentSchema) and through the CLI's objectui validate command (packages/cli/src/cli.ts). In practice: every chartnode'sseries[], and every report section whose chart` carries one.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with 1fe05ff37 (merge-base with origin/main): 6 file(s) changed outside .changeset/, read against 2042 pending declaration(s) that publish a body (2671 pending in total). · run

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3551.1 KB 3574.6 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-CzJ1ahWB.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 571.20KB 136.84KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 230.46KB 63.94KB
fields (index.js) 261.51KB 66.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.36KB 11.18KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.53KB 22.84KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.20KB 38.29KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.43KB 64.53KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 233.13KB 63.89KB
plugin-kanban (index.js) 49.51KB 15.54KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.04KB 12.21KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 3.32KB 1.64KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 5e7b894313cb899540946edcb9cea832b4f27421
Local-runs: none
Rendered: 2026-10-02T19:17Z

PR objectui#11499 (card objectui#11496), judged against triage's ruling 5958245941 ("Ruling: retire", with the family close-out over every command and flag cli.ts declares), on the precedents PR objectui#11487 (record 5957439389) and PR objectui#11495 (record 5958276867). Read for this record: the card body and all four comments on it; the PR body with its close-out table, and its 7-file list; the net diff of the head against main (merge-base 1fe05ff37..head, +141 / −107 over .changeset/11496-retire-cli-add.md, content/docs/utilities/cli.mdx, packages/cli/README.md, packages/cli/src/__tests__/cli-bin.test.ts, packages/cli/src/cli.ts, packages/cli/src/commands/add.ts deleted, packages/cli/src/commands/analyze.ts; main has since moved one commit to b654d4ed5, PR objectui#11497, whose diff over packages/cli, cli.mdx and .changeset/ adds one unrelated changeset and nothing else, and the three-dot diff against current main is byte-identical to the merge-base diff); and the check-runs on the head, polled at one-minute intervals until every run had completed. Nothing was built, run or re-run locally: the head's tree is read with git show / git grep against the fetched ref, the dev's reverse-verification legs are read as reported, and the head's own check-runs are the gate verdicts. Placeholders are spelled in capitals (COMPONENT, TYPE NAME) because the body sanitizer strips angle-bracket shapes.

① Derived judgments

  1. The published bin's accept set narrows by one command — right. cli.ts at the head declares no add; the import of ./commands/add.js is gone and the file is deleted. packages/cli/src sets no allowUnknownOption, passThroughOptions, allowExcessArguments, enablePositionalOptions or exitOverride (grep at the head: none), and the CLI runs commander ^15, whose default refuses an undeclared command with error: unknown command 'add' and a non-zero exit before any action runs. So the retirement is a refusal, not a silent accept, and nothing is written. No bespoke refusal branch was needed and none was added, which is the ruling's "no placeholder kept".
  2. ...and by two options — right. analyze declares no .option( at the head; commander's default refuses --render-performance and --bundle-size as unknown options. The one measured no-op (--render-performance: fixed text, byte-identical in an empty directory and in a built project, exit 0) is retired under the ruling's close-out clause, "any other no-op found is retired in the same PR".
  3. --bundle-size goes with it — right (the dev's open question 1, option A). Before, the flag chose between the bundle report and the render section; with the render section retired it would select between nothing and be read by no code, which is exactly the shape ruling 5955124315 retired generate --output for. It is a no-op the same PR creates, so the close-out clause covers it. No producer of the spelling exists at the head (git grep for --bundle-size finds only the changeset, the pins and unrelated prose about size budgets). The seat answered A; this record concurs.
  4. Nothing stands in for any of the three — right. add.ts is deleted, not stubbed; analyze.ts loses AnalyzeOptions, analyzeRenderPerformance and the runAll selector, and analyze() now runs analyzeBundleSize() and nothing else. The no-flag report is the old report minus the render section, which is what the control pin asserts.
  5. The root --help narrows, and the enumeration pin reads both directions — right. cli.ts at the head carries 14 .command( declarations (serve dev build start init lint test generate doctor studio check validate create analyze), and SUBCOMMANDS in cli-bin.test.ts is those 14. helpCommandNames parses the Commands: section (an entry starts with exactly two spaces, a wrapped description line does not, generate|g reads as generate), the lit control reads commander's own help as the last entry, and the assertions are set equality plus no duplicates. It replaces a toContain loop that a retired command coming back would have passed. This is the ruling's "one enumeration pin over the built CLI's commands".
  6. The docs surface narrows — right where the diff reaches, and one published file beyond the diff is left stale. In cli.mdx the add section goes, the analyze flag table becomes one paragraph that matches analyze.ts at the head (total, JavaScript and CSS sizes of dist/ under the current directory, the ten largest files; objectui build does default to dist, cli.ts:80 and commands/build.ts:26), and the stored count "The CLI exposes 15 commands" becomes a pointer to objectui --help, so it cannot go stale again. The heading list at main and at the head differs only by the removed add heading. packages/cli/README.md loses its add section; its combined check / doctor / studio / analyze / create plugin heading names no flag and needs no change. But skills/objectui/guides/project-setup.md, unchanged from main, still carries in its "CLI commands" table row 174, objectui add — "Add a component renderer scaffold", and row 177, objectui analyze — "Analyze bundle size / render performance". After this diff the first prescribes a command the bin refuses and the second claims a capability the bin no longer has. The file is in the published skills catalog, outside the ruling's named surfaces and outside the claim's file surface, and neither the dev report, the PR body nor the seat's ACCEPT names it. Judged: the diff is right, and the add reader sweep was not run beyond packages/cli and content/docs; carried to ③ with its remedy. Every other objectui add hit at the head is a literal slug fixture (toc-anchor-parity.test.tsx LIVE_SHAPES, the check-doc-links test and comment) or the 7658 changeset's past-tense account, none a prescription to run the command.
  7. Where analyze reads is unchanged — right. dist/ under the current directory, the "Bundle Size Analysis" banner and paths relative to dist/ (assets/probe-bundle.js) are what the control pin asserts. The command's help description, "Analyze application performance", and its first printed line, "ObjectUI Performance Analyzer", are untouched and now read wider than the bundle report that is all it does — a wording residue of the doctor kind the PR already lists in Acceptance notes, not an accept-set change; named for the next toucher, not blocking.
  8. No programmatic export moves — right. @object-ui/cli's exports is ./dist/index.js, which re-exports serve and init only; cli.ts is the bin entry and tsup builds cli and index as separate entries. package.json is not in the diff. The "no exported symbol moves" sentence in the PR body and the changeset holds.
  9. The family close-out — right in shape and coverage. The PR body's 22 rows cover every .command( and every .option( cli.ts declares at the head, plus -V / -h and commander's help, each with the help text, the docs text and the measured built-CLI behaviour. Partials are named, not implemented; validate and check are left to draft PR objectui#11069 as the claim required; the three class (a) failures (create plugin, lint / test, studio) are carried by objectui#11500 (open, created 2026-10-02T19:04Z).
  10. The pins pin the ruling, through the built bin — right. The add refusal (exit non-zero, stderr matches unknown command 'add', the directory stays empty) carries a same-directory write control (g page Probe then exits 0 and writes exactly pages, pages/probe.json), so an empty tree cannot be a read-only directory. The analyze refusals are an it.each over both flags with the same three assertions; the control plants dist/assets/probe-bundle.js and asserts exit 0, the banner, the file and no render section; the help pin's lit control is analyze's own usage line. All spawn dist/cli.js, where the card measured the defect. readdirSync with recursive: true needs Node 20 or later; engines pins 22.11 or later. The Array.at call was replaced by an index read because the package's tsconfig lib is ES2020 (judged by Type Check, tally below). The dev's reverse verification is read, not re-run: BASE 6 failed / 41 passed on the six predicted names; the ablation planted an exit-0 add and both option lines back into the committed cli.ts and failed the predicted five (the no-flag control stays green because analyze.ts was not mutated); restored, 47 passed. The diff's own index lines (ab22eb7e6..004165f17 for cli.ts, 7d9e7e3af..63659c0b3 for analyze.ts, b2fd2fcae for the deleted add.ts) name the same blobs the dev reports. cli-bin.test.ts is a *.test.ts file, not in the dist project, so the pins are judged by the eight Test (shard N/8) runs.
  11. Serial and base — right. The merge-base 1fe05ff37 IS the landing commit of PR objectui#11495, the ruling's named serial constraint, so this diff sits on top of the --from retirement rather than beside it. main has moved one commit (PR objectui#11497), which adds .changeset/11479-producers-declared-types.md and touches nothing under packages/cli, cli.mdx or the README, so not merging main was right and the queue's rebuild carries no risk from this diff.
  12. Repository surface — right. Three commits, each with the model-free trailer pair AGENTS.md prescribes; no model identifier in the PR title, body, changeset or commits. Governed Surface Queue Guard is green: the 7 paths are not a governed surface.

② Semver level

  • .changeset/11496-retire-cli-add.md declares '@object-ui/cli': minor. The diff removes a command and two options an author can write at the command line, so in semver terms it is BREAKING; this repo's release model (objectui AGENTS.md's version-number policy: the fixed group's major follows the @objectstack major, objectui's own breaking changes ship as minor with the break spelled out, and scripts/check-changeset-no-major.mjs behind Changeset Bump Policy refuses major) makes minor right. @object-ui/cli is in the one fixed group at the head (40 members). patch would understate a narrowing; major is refused outside the once-per-objectstack-major sync. The changeset says so itself in its parenthetical, in the same form as the two precedents.
  • The body carries what a breaking changeset owes: the BREAKING banner naming the package, three FROM → TO lines each with the one-line fix (drop the add call, nothing replaces it; drop the --render-performance call, nothing replaces it; drop --bundle-size, objectui analyze prints the same report), the why, the command-line delta and Clause-②: yes. Each sentence was checked against the diff and the head: all hold. One reading note: "objectui analyze --help lists no flags" means none of the command's own — commander still prints -h, --help — and the pin asserts exactly that the two retired flags are absent.
  • Not a skip-changeset case: packages/cli/src/cli.ts is the published bin of a released package (@object-ui/cli 17.6.0), so a changeset is owed and present (Changeset Declaration green). Changeset Bump Policy, Changeset Overwrite Report, Changeset Claim Re-read and Changeset Fixed Group Check are green too.
  • The claim re-read's two pending changesets, read against the diff: 7658-toc-code-span-anchor-parity names cli.mdx and the README for the add heading its slug fix repaired; that is a past-tense account of the fix and stays true, though the heading is now gone from both files, which is why the where attribution of the add row in toc-anchor-parity.test.tsx is stale (the dev's note; the row renders its literal and reads no file; outside this surface). 7694-chart-series-chart-type-alias-refusal names cli.ts as the home of objectui validate, which still declares .command('validate') at the head. No correction owed.
  • Clause-②: line — right. PR body line 3 reads Clause-②: yes; the seat's claim 5958361376 and the changeset say the same. It is a narrowing: one command and two options the published bin accepted (and answered with no-ops) are now refused. No gate at the head reads an arm on the line, and objectui has no ADR-0087 registration gate (the two adr-0087 spellings under scripts/ are unrelated to changesets), so the bare Clause-②: yes follows the repo's own precedent, as in records 5957439389 and 5958276867.

③ Boundary flags

Dev report 5959395505: two open questions, seven deviations, eight out-of-scope findings. Each answered or escalated:

Open questions

  1. --bundle-size: retire (A) or keep (B)? A — right, as implemented, for the reasons in ①.3: a kept flag would be declared, documented and read by nothing, the exact defect ruling 5955124315 retired; it is a no-op the same PR creates, so the close-out clause covers it; the FROM → TO is one word; no producer of the spelling exists. B would re-create the family's defect on the day it was closed. The seat answered A; concurred.
  2. Should the enumeration pin also read the docs' ### objectui NAME headings (A, extending the surface by a markdown-test-inputs ledger row), or stay on the built CLI only (B)? B satisfies the ruling, which asks for "one enumeration pin over the built CLI's commands", and that pin is present and two-directional. A is not owed by this card: it needs a row in scripts/markdown-test-inputs.mjs, outside the claim's surface, and it would not have caught the one stale reader this review did find (①.6), which is in a different file. The seat answered B; concurred. If a docs-to-bin lock is wanted later, it is its own card.

Deviations

  1. pnpm install --config.engine-strict=false — brief-directed and local to the dev's container; nothing on the head depends on it. Answered.
  2. The enumeration pin on the built CLI only — open question 2. Answered.
  3. commands/analyze.ts edited rather than deleted — right: the claim's surface names "any other packages/cli/src/commands/*.ts the close-out retires", and the ruling's no-placeholder clause requires the dead function and its option plumbing to go, not to stay reachable. The file keeps the live bundle report. Lint and Type Check on the head judge the edit (tally below).
  4. The studio probe started this checkout's apps/console dev server on :5180 for its 30 s timeout — local, ended, nothing left running by the dev's own process check; reported rather than hidden. Answered.
  5. One manual npm install in the probe project because the CLI's --prefer-offline install hit a stale npm cache — local; the probe directory was removed; the CLI's own step then passed. Answered.
  6. Model-free trailer pair instead of the harness's model-named trailer — AGENTS.md's commit-message rule; not a deviation. Answered.
  7. Worktree and private refs removed after the PR opened — hygiene. Answered.

Out-of-scope findings

  • Class (a) ×3 (create plugin resolves a missing path; lint / test relabel setup errors as findings; studio needs this repo's console) — escalated by the seat as objectui#11500, verified open at review time. Right to leave them out of this diff: the ruling names partials, it does not implement them.
  • Carrier none ×5 (doctor's "fix" and Node-check promises, serve --no-open's docs row, analyze without dist/, the directory init -t nope leaves behind, dev's raw spawn xdg-open ENOENT) and the stale where attribution in toc-anchor-parity.test.tsx — in the PR's Acceptance notes, unfiled. Answered.
  • The npm-cache observation — environment-bound; answered.

Reviewer's finding, escalated to the seat (not a dev flag; found in ①.6). skills/objectui/guides/project-setup.md rows 174 (objectui add) and 177 (objectui analyze — "… / render performance") are stale at the head. Remedy: delete row 174 and reword row 177 to the bundle report. ⛔ Not by a patch round on this PR: skills/** is a governed surface in objectui (GOVERNED_SURFACES, id skills-catalog, in scripts/check-governed-queue-guard.mjs), so adding that file here would turn this 7-path landing into a governed one awaiting an authorized APPROVED review for two table rows. It is a follow-up edit on the skills catalog, owed before the next skills publish; it does not bar this landing, because where the guide used to send an agent into a silent exit 0 it now sends it into a loud unknown command 'add', and every surface the ruling names is met.

  • The dev report's "CI in_progress, not waited on" — answered by the completed set below.

Check-runs on the head

43 check-runs on 5e7b894313cb899540946edcb9cea832b4f27421, every one completed (the aggregate Test landed last, at 2026-10-02T19:10Z): 40 success · 3 skipped · 0 failure (0 cancelled, 0 timed out, 0 neutral, 0 action required). The three skipped are the push-only coverage lanes (Test (coverage), Test (coverage shard N/4)) and dependabot; none is a verdict on this diff. Green and material here: Test (shard 1/8) through Test (shard 8/8) (the lane that runs cli-bin.test.ts: the enumeration pin, the add refusal with its write control, the analyze refusals with their control and help pin), Test (the per-shard roll-up), Test (dist pins), Type Check (the narrowed analyze action and the Array.at replacement), Lint (the three edited source files), Build & E2E, Build Docs, Internal Docs Link Check, Doc Snippet Type Check and README Export Check (the two gates the dev could not measure locally), Doc Fence Language Check, Doc Component Type Check, Doc Example Id Check, Changeset Declaration, Changeset Bump Policy, Changeset Overwrite Report, Changeset Claim Re-read, Changeset Fixed Group Check, Line Citation Gate, Governed Surface Queue Guard, Skill Guide Path Check, Spec Main Shape Gate. Polled three times at one-minute spacing (read 2026-10-02T19:06Z, 2026-10-02T19:09Z and 2026-10-02T19:13Z); the third read found the set complete. These conclusions are the gate verdicts; none was re-run here.

Implemented-by: claude/issue-11496-retire-cli-add
Reviewed-by: session_01YLg8XqWGJ785fwQ5v4pH37

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 2, 2026 19:19
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 2, 2026 19:19
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit ea39141 Oct 2, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11496-retire-cli-add branch October 2, 2026 19:35
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 package: cli tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cli: objectui add COMPONENT prints "Feature not implemented yet." and exits 0 — a documented command that writes nothing reads as success to a script

2 participants