Repository navigation
fix(pm): derive the always-runs tail dispatch-gates could never name - #13501
Merged
os-project-manager merged 2 commits intoAug 30, 2026
Merged
Conversation
…13333) Report the unconditional CI steps the family derivation names NOTHING for, instead of widening a matcher for the one gate that reddened. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
…spatch-gates-always-runs-tail
os-project-manager
marked this pull request as ready for review
August 30, 2026 15:17
os-project-manager
enabled auto-merge
August 30, 2026 15:17
os-project-manager
deleted the
claude/issue-13333-dispatch-gates-always-runs-tail
branch
August 30, 2026 15:41
This was referenced Aug 30, 2026
os-tesla
pushed a commit
that referenced
this pull request
Oct 25, 2026
…escription to the viewer's language (objectui#13488) (#13501) <!-- claude-projects-attribution: {"github_login":"os-elon-musk"} --> _Requested by **Elon** · [project thread](https://claude.ai/code/project/chan_01WedDzV26nniwxv7jC88B9D?thread=cmsg_01WedDzV26nniwxv7jC88B9DRqbNi4iARYYtqZmwLSPhaR)_ - [x] Adds no product-specific widget, dialog, hook or string (see AGENTS.md › Product-neutral renderer) Fixes #13488 Clause-②: no Metadata-protocol: none ## What changed `PageSchema` in `@objectstack/spec` types a page's `label` and `description` as `I18nLabel`, so an inline locale map such as `{ 'zh-CN', en }` is valid metadata, and the `/meta` read serves it unchanged. Two packages drew it raw on a page route, and React refused the object as a child (error #31), so the route was blank for every viewer: - **`@object-ui/app-shell`, `AppHeader`'s page branch.** It handed the served label to `pageLabel` as its fallback, and `pageLabel` returns an unmatched fallback untouched, so the map became the phone bar's title. It now resolves through `metadataText` in the viewer's language (`useObjectTranslation().language`), the call the report branch has used since objectui#13470, and still passes through the `pages.NAME.label` bundle lookup. The humanized slug stays the fallback when no label resolves. - **`@object-ui/components`, `PageRenderer`.** The page's own implicit heading (`schema.title ?? schema.label`), the line under it (`schema.description`), and the description it hands a titled `page:header` through `PageDescriptionContext` were all drawn raw. Each now resolves through `pickLocalized` in the viewer's language, the resolver `page:header` already uses for its own title in the same package. With only the app bar fixed, an `app`, `home` or `utility` page with a map label stayed blank through this heading (measured, below), so the claim was widened to this file (claim amendment on #13488). - **Swept, same file, same call:** `AppHeader`'s dashboard branch drew a served dashboard label straight into the phone bar's title. `DashboardSchema.label` is `I18nLabel` too, so it is now `metadataText(…) ?? dashboardLabel(…)`. A plain-string label or description draws exactly as before: `metadataText` and `pickLocalized` both pass a string through, and an empty one still falls to the slug or hides the description. Studio's page previews (`SourcePageEditor`, `PagePreview`) render through the same `PageRenderer`, so they get the fix too. One changeset: `@object-ui/app-shell` and `@object-ui/components` patch. ## Tests New pins, each mounting the real component under a real `I18nProvider`, each leg in `en` and `zh-CN` reading different strings out of one map, with plain strings as the control: - `packages/app-shell/src/layout/__tests__/AppHeader.pageDashboardTitleInlineLocale-13488.test.tsx`: the `AppHeader.reportCrumbInlineLocale-13470` harness with `useObjectLabel` real. Legs `PAGE_LABEL_MAP_RESOLVES`, `DASHBOARD_LABEL_MAP_RESOLVES`, two `PLAIN_STRING_CONTROL`s. - `packages/components/src/__tests__/page-inline-locale-label-13488.test.tsx`: an `app` page through the real `SchemaRenderer` and `PageRenderer`. Legs `HEADING_MAP_RESOLVES`, `DESCRIPTION_MAP_RESOLVES`, `HEADER_DESCRIPTION_MAP_RESOLVES` (titled `page:header`), `PLAIN_STRING_CONTROL`. Readings, final head `2c82e03` unless stated: - The two new files: Test Files 2 passed (2), Tests 16 passed (16). - Every test file that names `AppHeader`, `PageView`, `PageRenderer`, `SourcePageEditor`, `PagePreview` or `pageKindNode`, plus every `packages/components` test that names `PageRenderer`, `page:header`, `pageType`, the page renderer module or an `app`/`home`/`utility` page node (212 files, found by `git grep -lE` over test files), with `pnpm exec vitest run --maxWorkers=2`: Test Files 212 passed (212), Tests 2161 passed (2161). Run at `bf37518`; the only later commit, `2c82e03`, changes the type annotation of one new test's fixture, and both new files were re-run at `2c82e03` above. - `turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/components --concurrency=2 --continue`: 31 successful, 31 total. Both packages' `type-check` chain `tsconfig.test.json`, so the new test files are type-checked. - eslint on the five touched files: 0 errors. Every warning is on a line this PR does not add; the one on a changed line in `page.tsx` is the `(schema as any).label` read the old line already had. - `node scripts/check-changeset-presence.mjs`: pass (4 source files of 2 released packages, 1 changeset). `node scripts/check-changeset-no-major.mjs`: pass. `pnpm check:new-line-citations`: 0 new citations. Narrowed, declared: the whole `packages/app-shell/` and `packages/components/` suites were not run locally; CI's sharded `pnpm test` runs them. The narrowed set's blind spot is a test that mounts these components through another import path without naming them. Probe before the fix, on main `85b6a48`, through the real `SchemaRenderer` and `PageRenderer` (a throwaway file, not committed): an `app` page with a map `label`, one with a map `description`, and one with a titled `page:header` and a map `description` all failed on `Objects are not valid as a React child (found: object with keys {zh-CN, en})`. Ablation, one site at a time on the committed fix, through `scripts/ablation-replace.mjs` (anchor must hit once, blob must change, restore proven by blob equal to `HEAD` and an empty `git diff HEAD`), running the two new files each time: - page branch reverted (`pageDef?.label || humanizeSlug(pageName)`): 2 failed, 14 passed. Only `PAGE_LABEL_MAP_RESOLVES` fails, in both languages, on React error #31. - dashboard branch reverted (`dashboardDef?.label || dashboardLabel(…)`): 2 failed, 14 passed. Only `DASHBOARD_LABEL_MAP_RESOLVES` fails, on the same error. - `PageRenderer` heading reverted (`schema.title ?? schema.label` raw): 2 failed, 14 passed. Only `HEADING_MAP_RESOLVES` fails, on the same error. - `PageRenderer` description reverted (raw `schema.description`): 4 failed, 12 passed. `DESCRIPTION_MAP_RESOLVES` and `HEADER_DESCRIPTION_MAP_RESOLVES` fail, on the same error. ## Acceptance notes - `InterfaceListPage` (an interface page's list surface) reads `typeof page.label === 'string' ? page.label : page.name` for its heading and its record drawer's title, and draws `page.description` only when it is a string. A page with a map label does not blank there, but it shows the page's machine name instead of its label, and a map description is not shown. Read from the code on `85b6a48`, not measured; outside this claim's file surface. Handed to the seat. - `AppHeader`'s view branch hands `viewDef?.label || viewDef?.title` to `viewTabLabel`, and a list view's `label` is `I18nLabel` in the spec as well. The object page's tab bar (`ObjectView`) hands the same label to the same function, so whether a map view label blanks a view route is a question about `ObjectView`, not this header alone. Read from the code, not measured; not changed here. - The page's phone-bar title still passes the resolved label through the `pages.NAME.label` bundle lookup, while the page's own heading draws the served label. That split predates this PR and is unchanged, as on the report route. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_012oUFcAgU5BgTKe6fa7RxD8 --------- Co-authored-by: Claude <noreply@anthropic.com>
os-tesla
pushed a commit
that referenced
this pull request
Oct 25, 2026
…ke test-only reset helpers off the barrels (objectui#13453, part 1) (#13506) <!-- claude-projects-attribution: {"github_login":"os-elon-musk"} --> _Requested by **Elon** · [project thread](https://claude.ai/code/project/chan_01WedDzV26nniwxv7jC88B9D?thread=cmsg_01WedDzV26nniwxv7jC88B9D4nNtkcxk6i4sCKHsvYsQgG)_ Part of #13453 Clause-②: no (nothing added a consumer or author can target) Metadata-protocol: none First of the two PRs the claim amendment (comment 6393918010) cuts on the governed line. This one is Tier S: no file under `.claude/**`, `skills/**`, `AGENTS.md` or `docs/adr/**`. #13453 remains open for PR 2 (the providers trio, the contributor-guide sentence and the two `skills/objectui/guides` files, Tier H) and for the 122 dead i18n keys. ## What this removes **1. Nine whole modules with no reader** (2,211 lines plus their own tests): - `@object-ui/core`: `builder/schema-builder.ts` (`form`/`button`/`input`/`card`/`grid`/`flex` and the six `*Builder` classes) and the whole `protocols/` directory (`DndProtocol`, `KeyboardProtocol`, `SharingProtocol`, and its now-empty `index.ts`). The barrel lines become short removal notes, the same disposition `NotificationProtocol` and `ResponsiveProtocol` got. - `@object-ui/react`: `useFocusTrap`, `useFocusManagement` (`useFocusReturn`, `useRovingFocus`), `usePageTransition`, `useSchemaPersistence` (+ `createLocalStorageAdapter`), with the two `useSchemaPersistence.*.test.tsx` files. The stale `check-doc-example-types.mjs` row for the deleted hook goes too. - `@object-ui/collaboration`: `LiveCursors` (+ `LiveCursorsProps`); the package README drops its section. `usePresence` still reports cursors. - Comments that named the deleted files (`types/src/index.ts`, `crud-retirement-5373.test.ts`, `useAnimation.ts`, `useETagCache.ts` and its test) now say "since-retired". **2. `@object-ui/runner` is private and out of the release group.** `private: true`; it leaves the `fixed` group for `ignore`, because `check-changeset-fixed.mjs` wants every workspace package classified. Two consequences handled here: - Two pending changesets, `13464-declare-side-effects.md` and `25685-one-react-line.md`, each listed `"@object-ui/runner": patch`. With runner ignored, changesets refuses them as mixed ("Found mixed changeset 13464-declare-side-effects … Mixed changesets that contain both ignored and not ignored packages are not allowed", read from `pnpm exec changeset status` on this tree before the edit). The runner line is deleted from both; nothing else in them changes. `check-changeset-overwrite` reports the modification (report-only); after it, `pnpm exec changeset status --since=origin/main` exits 0. - `check-published-tsconfig-tooling-exclude.mjs` reported `FAIL [stale-carve-out] @object-ui/runner`, so its runner carve-out entry is deleted and the shipped-list pin in its test shrinks to four. `check-changeset-presence.test.ts` pinned `packages/runner/index.html` as a guarded file; an unreleased package's entry is not guarded, so the pin moves it to the not-guarded list. - Docs: `content/docs/utilities/runner.mdx` and `packages/runner/README.md` no longer say it is on npm; the root README table marks it private. **3. Test-only reset helpers off the public barrels:** `resetColumnIdentityWarnings`, `resetRetiredSortSpellingReports`, `resetDashboardFilterWarnings`, `resetReferenceKeyWarnings` (core), `resetRuntimeConfigForTesting` (app-shell), `resetInflightGetsForTesting` (types), `__clearRecordEditableCache` (plugin-detail). The module keeps the export and the barrel stops re-exporting it; the 15 test files outside the owning package that imported one from a package root now import the module's `src` path relatively, the pattern `__resetVisibilityPredicateWarnings` and `useRecordEditable` already follow. Core's four `export *` lines for those modules become named lists, with a one-line note on each. ⛔ Not here, per the claim: `resetActionKeyWarnings` (its barrel path is `core/src/actions/index.ts`) and `clearSharedDiscoveryCache` (`data-objectstack`) wait for #13442, which holds those files. ## Census before deleting (lit controls) | Repository | Read at | Searched | Hits | Control | |---|---|---|---|---| | objectui | `76c560e` (branch base) | `git grep -w` for every exported name of the nine modules and the seven helpers; generic builder names (`form`, `card`, …) searched as named imports from `@object-ui/core` | only the module, its own tests, its barrel line and comments | `SchemaRenderer` lit | | objectstack | `d1e329e` | same name list | one prose mention of `LiveCursors` in `docs/qa/platform-checklist/FOLLOW-UPS.md`; no import | `@object-ui/` lit in 150 files, `SchemaRenderer` in 38 | | hotcrm | `700b567` | same name list | none | `@object-ui/` lit in 5 files, `SchemaRenderer` in 3 | | cloud, npm dependents | n/a | **NOT MEASURED**: not reachable from this session | n/a | n/a | ## Changesets One per package, all `minor` with the removal named (`13453-core-retire-dead-modules.md`, `13453-react-retire-dead-hooks.md`, `13453-collaboration-retire-live-cursors.md`, `13453-test-helpers-off-barrels.md`). Runner gets none: it is ignored now, and naming it would be a mixed changeset. ## Verification (local) The type-check and vitest readings below were taken on the branch while it still carried PR 2's providers commits too, so the tree they read is this PR plus the providers retirement. The gates line was re-run on this PR's own head. - **type-check** (`turbo run type-check --continue`, under the verify lock): core, react, collaboration, providers, types, app-shell, plugin-detail, plugin-grid, plugin-view, plugin-calendar, console, runner and the byo example. First run caught `http-inflight.test.ts` importing the helper from `../index.js`; fixed in `44c01fe`, after which `packages/types` type-check exits 0. - **vitest, whole packages** core, types, providers, collaboration, plugin-detail, react: Test Files 1028 passed, 1 skipped; Tests 19019 passed. - **vitest, files** (every touched test file outside those packages, plus the script tests that read runner or the release config): 21 files / 432 tests, one red, `check-changeset-presence.test.ts` (the runner pin above), fixed in `45580a0` and re-run green (53/53). Console project, the three touched files: 28/28. A wider sweep of 95 `scripts/__tests__` files that mention runner, providers or the release config: green apart from `check-doc-links.test.ts` and `check-skills-paths.test.ts`, which read paths PR 2 deletes; both scripts exit 0 on this PR's head. - **gates**, at `a5dc7bb`: `check-changeset-presence`, `check-changeset-no-major`, `check-changeset-fixed`, `check-changeset-claims`, `check-pending-changeset-literals`, `check-published-tsconfig-tooling-exclude`, `check-new-cross-file-line-citations`, `check-control-bytes`, `check-skills-paths`, `check-doc-links` all exit 0; earlier on this branch also `check:phantom-deps`, `check:unused-deps`, `check:lockfile-integrity`, `check:lockfile-dedupe`, `check:test-path-roots`, `check:unreferenced-sources`, `check:side-effects-array`, `check:sdui-registration-pins`, `check:self-import`, `check:vi-mock-specifiers`, `check:lint-rule-coverage`, `check:node-esm-load`. - **eslint** on the touched files with the repo config: 0 errors. With `--no-inline-config` there are 2 errors, both on untouched lines and both present at the base (`useETagCache.ts` preserve-caught-error, `types/src/index.ts` restricted `FormField` import). - **NOT MEASURED locally:** the whole `app-shell` package suite (its touched files ran), `check:readme-exports` and `check:doc-snippets` (need every package's `dist`); CI runs them. ## Follow-ups - **Stale published guides until PR 2 lands:** `skills/objectui/guides/project-setup.md` and `skills/objectui/guides/architecture.md` still describe `@object-ui/runner` as a standalone runtime; PR 2 fixes them (Tier H). - **Release-lane hazard to watch:** any open PR whose new changeset lists `"@object-ui/runner"` alongside other packages becomes a mixed changeset once this merges, and nothing on a PR runs `changeset status`. None of the pending changesets on `main` at `5399bbc` names it. - `origin/main` moved two commits (#13501, #13503) after the branch base; neither touches a file in this diff. --- _Generated by [Claude Code](https://claude.ai/code/session_011yfYeuX2ptMSCcYZiq61tS)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #13333
Triage adjudicated option (b) on this card — have
dispatch-gatesenumerate theunconditional
Lint & Repo Gatessteps as an "always runs" tail — and explicitlyrefused option (a), adding
check-reference-carrier-shapeto the derivation. Thisimplements (b), derived rather than hand-listed.
What was measured first
Reproduced on current
origin/main, with positive controls, because the card's ownfigures had drifted:
reference-carrierindispatch-gates.mjswhere-matcher, same filecheck-reference-carrier-shapeinlint.yml:3281-3284:3338-3339--residueuniverse of 187 familiesturbo-task-graph1,where-matcher2So the gate is not in the
silentbucket and not inundetermined— it is in nobucket at all, the one output shape this file's contract forbids.
H1 as stated is FALSIFIED, and the falsification changes the fix
The sharpened mechanism on the card is "every package-local script invoked by path
inside a multi-line
run: |block". Measured over all 26 workflows:run: |half is already handled —runCommandTextshas read block-scalarbodies since [finding] dispatch-gates.mjs does not derive pr-automation.yml's Check Changeset for
.changeset/paths — a breaking changeset shipped locally-green and went red only in CI #8410, and 3 of the 5 invisible gates are plain one-linerun:steps.It is not a reason today at all.
(
packages/cli/bin/run.jsis the other package-localnodeinvocation and is a CLIsmoke run, not a gate.)
A fix built on that mechanism would therefore have been option (a) with extra steps.
The population that is real is the one triage named — unconditional steps — and
it is invisible for at least three unrelated reasons: a package-local path, an
interpreter that is not
node, and a root script not namedcheck:*. That is why nofourth widening of the three matchers was going to be the last one.
The coverage measurement triage asked for
Derived live, on the merge commit of this branch:
with no
paths:filter, in jobs and steps with noif:(11 conditional jobs and 12conditional steps excluded, and both counts printed rather than dropped);
Proof that it reaches the CLASS, not the instance
The tail names the card's gate and members invisible for different reasons:
pnpm lintand the twobash … --self-teststeps are real verification that nowidening of the
node scripts/…matchers would ever have reached.That claim is a self-test case, derived live, not a sentence here: the tail must contain
a member whose interpreter is not
nodeand that member must not be the card's owngate. Reverse verification (ablation, run against the committed implementation, the
mutation confirmed on disk by object hash
8e8d9489->ac39a3dfbefore any reading,restored and re-proved byte-identical to the
HEADblob afterwards):The instance case (
a package-local gate invoked by path IS in the tail) stayed greenthrough that ablation — which is exactly the discriminator between (a) and (b).
Why this is not "22 leads is the same as none"
The header's refusal stands: 166 of 189 discovered families sit outside both path
declarations CI obeys, and naming them per card would say nothing. This tail is the
complement of that set, not a slice of it — a step leaves the list the moment the
derivation names any family for it, so it is bounded by the derivation's own blind spot
and shrinks as discovery improves. It carries no per-card claim and says so.
What it deliberately does NOT do
check-reference-carrier-shape, or extend discovery to reach it.pnpm installandpnpm lintareboth in the tail; every rule separating them is a guess about a step's intent.
about derivation on a stale tree ([finding]
dispatch-gates.mjsEXITS 0 on a STALE TREE — a green-looking answer that silently omits newly-landed gate families; cost one CI cycle today, and was caught by luck on a second PR the same hour #13392), fabricated leads ([finding]dispatch-gates --residueprints THREE fabricated leads for check:query-options-erasure — literals naming files that have never existed, unannotated because one live sibling keeps the family reachable #13312, [finding]check:doc-anchorsdeclares a fabricated watch hintscripts/scripts/check-doc-anchors.mjs— a remedy string meant to run from the repo root is resolved module-relative, doubling the prefix #13449) ordownstream truncation (A
pnpm check:harvest ofdispatch-gates.mjsoutput silently drops a third of the gate list #13462), and a gate unreachable for the [finding] dispatch-gates never names a family for an edit to a first-party module its gate script IMPORTS — 228 (family, module) pairs unreached, measured #13126 reason isdiscovered, so the tail does not name it either. The header states this so a green tail
is not read as the class being closed. [finding] an
.objectui-shadiff derives NO pin-critical gate — the gates a pin bump most needs are the ones structurally excluded from path derivation, and one of them shipped a red on PR #12955 #12956 is not folded in and is not touched.Verification
All on
263b4923, exit codes captured before any pipe.check:pm-dispatch-gates— EXIT=0,✓ dispatch-gates self-test: 976 cases pass.(944 -> 976, +32 cases: the walk's fixtures, the renderer's refusals, and the live
class pins.)
bare-root-worklist.mjs --self-test— EXIT=0,OK self-test: 51 live row(s), 43 unreachable as spelled, 43 recorded verdict(s) — none stale, none missing, none contradicted.dispatch-gatesderives for this diff — all EXIT=0, includingcheck:watch-hint-literal,check:entry-guard,check:parse-guard,check:self-test-wired(✓ every one of the 152 script(s) CI runs that ship a --self-test has that self-test run by CI)and
check:nul-bytes.check-test-completeness.mjs— EXIT=3 = NOT MEASURED, neither red nor green, perits own printed refusal.
eslint scripts/pm/dispatch-gates.mjs --no-inline-config --format json-> EXIT=0, 1 file, 0 errors, 0 warnings, 0 suppressed. The narrowing issound because (i) the linted population and the rules are read from ESLint's own
--print-configfor this path, not guessed — 2 rules apply,comment-swallow/no-code-inside-block-commentandno-restricted-imports; (ii) the filecount is ESLint's own
--format jsonoutput; (iii)eslint.config.mjsstates, with arecorded positive-control measurement, that this repo never enables type-aware linting
for any file (
no parserOptions.project, no typed @typescript-eslint rules), confirmedlive here (
parserOptions.project present: false), so a one-file diff cannot move anyuntouched file's verdict. The repo-wide
eslint .is CI's run.scripts/pm/**only and publishes from no package, soskip-changesetis applied on this PR.Generated by Claude Code
Generated by Claude Code