Repository navigation
tooling(ui-wiring): inert workspace, turbo and CI wiring for the ui/ tree (objectstack#25697 PR A) - #25710
Conversation
…tree (objectstack#25697) pnpm-workspace.yaml gains ui, ui/packages/*, ui/apps/* and ui/examples/*. They match no directory until objectui is imported under ui/, so `pnpm install --frozen-lockfile` and `pnpm install --lockfile-only` leave pnpm-lock.yaml byte-identical and `pnpm -r ls --depth -1` is unchanged. objectui declares no onlyBuiltDependencies, so the union is this list. turbo.json gains the four task names objectui's packages use and the root lacks: type-check, lint, test:dist, test:watch, with objectui's inputs, outputs, dependsOn and cache settings. Its repo-root inputs are re-rooted under $TURBO_ROOT$/ui/. Two dependsOn edges are not carried: //#lint:root and //#type-check:e2e bind objectui's ROOT manifest, which is the `ui` member here, and a package-named dependsOn on a package that does not exist yet makes turbo refuse the whole run. The ui CI jobs run those two programs as their own steps instead. Its globalDependencies (pin plumbing) are not ported. `turbo run build --dry=json` lists the same 84 tasks with the same 84 hashes before and after. Two gates read "turbo.json describes something absent" as a defect, which is right except for a tree that is about to arrive: - check-turbo-task-graph: type-check, lint and test:dist are held by no member until the import. GENERIC_TASKS_AWAITING_UI_IMPORT holds them only while ui/package.json is absent; the hold is void once it exists, and a held key turbo.json does not declare is itself a finding. - check-cross-package-test-inputs: `ui` is a top-level segment git does not track yet. TOP_LEVEL_DIRECTORIES_AWAITING_IMPORT excuses it only while untracked; once tracked it owes a recognised or pending entry. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RSDL3SFtJaKzcymvCD8RsU
… (objectstack#25697) ci.yml's filter job gains three outputs: `ui` (ui/** and the root files the ui jobs build from), `ui_consumers` (the seven packages objectui installs from this tree: spec, client, core, formula, lint, sdui-parser, types) and `ui_tree` (ui/package.json exists, from an unconditional step). Four jobs, ported from objectui's ci.yml and lint.yml: - Type Check UI: objectui's coverage guard, its check:* source gates and root tsc programs, then `turbo run type-check` over the ui packages, affected-only on pull_request / merge_group. Runs on `ui` OR `ui_consumers`, so a spec change compiles the Console in its own PR. - Test UI (n/16): objectui's vitest root, sharded by its own LPT sequencer. N stays 16: by package the 1.3 max/mean bound admits at most 4 legs (app-shell is 104.2 of 325.7 summed minutes); by file the bound never binds and 16 legs carry 20.4 summed minutes each. - Lint UI: objectui's lint job, with //#lint:root as its own step. - Build & E2E UI: the Console build and Playwright chromium, on `ui` OR `ui_consumers`. Every job's `if:` is `!cancelled() && ui_tree != 'false' && <paths>`, so with ui/ absent each one is skipped on every event, never failed and never started. None is a required context or an aggregator member. The .objectstack-pin plumbing is replaced by a turbo build of the seven @objectstack packages; objectui root scripts run with working-directory: ui, turbo runs from the root with directory filters. check-expected-skips declares the four names as by-design skips. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RSDL3SFtJaKzcymvCD8RsU
…o not misread them (objectstack#25697) This repo's workflow gates key `scripts/<x>` and `pnpm <alias>` against the repository root and do not read `working-directory`. Under `working-directory: ui`, objectui's `node scripts/check-entry-guard.mjs` was credited to objectstack's file of the same name, and `scripts/check-lint-coverage.mjs`, which only objectui has, read as a missing script (check-self-test-wired --self-test went red on it). Every objectui command in the ui jobs is now `pnpm --dir ui run <its alias>` or `pnpm --dir ui exec ...`. Test UI drops objectui's per-file timings reporter and its upload: both feed the dataset refresh workflow, which is in the governance-workflow audit, and the sequencer reads the committed dataset meanwhile. check-llms-txt opens every manifest under the workspace globs, so the ui roots are declared as `ui/**/package.json` beside the others. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RSDL3SFtJaKzcymvCD8RsU
…s (objectstack#25697) Three gates hold a hand-written copy of pnpm-workspace.yaml's `packages:` block and red when the live file names a root they do not declare. Each now declares the ui roots, which match nothing until the import: - check-published-files: ROOT_DIR_WATCH_HINTS gains ui/*, ui/packages/*, ui/apps/*, ui/examples/* (ui/* stands for the bare `ui` member, spelled with a separator as the declaration requires). - check-test-source-alias: WORKSPACE_PARENT_GLOBS gains the three `/*` roots; the bare `ui` member is declared as WORKSPACE_BARE_MEMBER_MANIFESTS (`ui/package.json`), walked as the one package at that directory and reconciled against the live file like the globs. - check-undeclared-dep-imports: its parser refused any entry that is not `<dir>/*`, so the bare `ui` entry made the sweep fatal. A bare `<dir>` is now the one package at that directory, absent contributes nothing; two new refusal-battery cases drive both directions, and `ui/**` joins ROOT_DIR_WATCH_HINTS. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RSDL3SFtJaKzcymvCD8RsU
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
…roots (objectstack#25697) PR A's first CI run turned two gates red that the derived gate list for its paths did not name, both because pnpm-workspace.yaml now declares four globs that match nothing until the import: - check-dispatcher-error-vocabulary refuses any workspace glob that expands to no member (#16649), in production and in its self-test. WORKSPACE_GLOBS_AWAITING_IMPORT excuses the four ui globs ONLY while ui/package.json is absent (awaitingImportGlobs); the self-test holds the map against the live workspace, pins the exact key set, and drives both marker states on a scratch root so the excuse voids itself at the import. The excuse is opt-in at the call site, never a default. - check-duration-unit-keys (packages/spec) mirrors the workspace roots as ROOT_DIR_WATCH_HINTS literals and holds them against the live file in both directions; the four ui roots are declared as `ui/src/**`, `ui/packages/*/src/**`, `ui/apps/*/src/**`, `ui/examples/*/src/**`. Both gates and their self-tests exit 0 on the PR merge commit; every gate the dispatch derivation names for these two files exits 0. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RSDL3SFtJaKzcymvCD8RsU
|
CI on
Neither gate is in the The approval already on record is unaffected by the push (unpinned since 2026-09-04); auto-merge stays armed. Changed lines are now 1,019 (+1,019 / −33 → 1,052 total), still under the human-merge line. |
…e Pin Gate, prerelease-pin-watch (#25827) Part of #25697 (item 6, PR B). PR A (#25710) carried items 1 to 5 and is merged; the card stays open for the epic PM, who hands this PR to the cutover. Blocked-by: #25752 (cutover PR first) Part of objectstack#25677 Clause-②: no Metadata-protocol: none ## What this retires Once `ui/` lives in this repository, the gates that proved the objectui pin from the outside have nothing left to prove. This PR deletes them: - `.github/workflows/spec-shape-gate.yml` (**Spec Shape Gate**), with `scripts/ci/spec-shape-gate.mjs` and `scripts/ci/spec-shape-retirements.json`. - The `console-pin` job (**Console Pin Gate**) in `ci.yml`, and the `console` list and output of its `filter` job. - `.github/workflows/prerelease-pin-watch.yml` (**Stable release watch**). - The `Spec Shape Gate` row of `RELEASE_GATE_WORKFLOWS` in `scripts/ci/scheduled-full-run.mjs`. The release gate now reads `CI` and `Lint & Type Check`. `release.yml` and `cut-rc.yml` have no read of their own (measured); both reach the roster only through `scheduled-full-run.mjs --release-gate`. What replaces them is already on `main` from PR A: `Type Check UI` and `Build & E2E UI` compile and build the Console from `ui/` in the PR that changes one of the seven packages objectui installs (`ui_consumers` filter). The console scripts (`build-console.sh`, `check-console-sha.mjs`, `check-console-injection.mjs`, `console-spec-probes.mjs`, `assert-console-spec-injection.mjs`) stay, as the order says. 4a #25745 deletes them with the pin. ## Hit-class table Census: `git grep -n -E 'spec-shape-gate|Spec Shape Gate|spec-shape-retirements|prerelease-pin-watch|Console Pin Gate|console-pin'` at the base `52f3f518e1` gives 169 hits in 33 files. Also posted on the card: #25697 (comment) | Class | Files (hits) | Treatment | |---|---|---| | The retired gates themselves | `spec-shape-gate.yml` (15), `scripts/ci/spec-shape-gate.mjs` (21), `scripts/ci/spec-shape-retirements.json` (1), `prerelease-pin-watch.yml` (6) | deleted | | `ci.yml` job and filter | `ci.yml` (7) | `console-pin` job, `console` filter list and output deleted; the comments that pointed at them re-worded | | Release-gate roster | `scripts/ci/scheduled-full-run.mjs` (19) | roster row dropped; the self-tests that encoded a three-row roster are rewritten to the two-row roster with the same assertion shape (none deleted or skipped); two dated diagnosis fixtures kept verbatim | | Gates that encode the deleted job or script | `check-ci-filter-parity.mjs` (5), `check-expected-skips.mjs` (5), `dispatch-gates.self-test.mjs` (20), `dispatch-gates.mjs` (7) | filter-parity `console` subject retired with its battery (floor 10 to 9); the `Console Pin Gate` expected-skip row removed and its recorded runs re-spelled to the live roster; the live-tree job-filter cases re-pointed at `Build Core`; synthetic specimens kept; tense fixes | | Orphan the deletion forces | `scripts/check-prerelease-pin-watch.mjs` (15), `package.json` (2) | deleted, with the `check:spec-shape-gate` and `check:prerelease-pins` aliases (deviation 1) | | Instruction prose naming a deleted gate as live | `AGENTS.md` (2), `docs/releases-maintenance.md` (2) | prose fixes, listed below | | Comments naming a retired gate as live | `cut-rc.yml:358`, `docs-deploy.yml`, `lint.yml` (2), `release-coverage-patrol.yml`, `release.yml:1510`, `check-release-section-coverage.mjs` (2), `check-self-test-workflow-commands.mjs`, `check-vendor-version-stamps.mjs` (2), `check-required-contexts.mjs` | past tense, or a one-paragraph addendum to the existing tombstone | | Left for 4a #25745, which deletes or rewrites them | `release.yml:1874` and `:1917`, `cut-rc.yml:383`, `packages/console/README.md:54`, `check-console-injection.mjs` (6) | untouched here, so the two PRs do not conflict on them | | Dated history and fixtures | `docs/audits/*` (5), `scripts/docs-audit/README.md`, `scripts/fixtures/merge-queue-triage/*.json` (2), the `fleet-write/validate.mjs` fixture, `packages/spec/liveness/dashboard.json:146`, `pnpm-workspace.yaml:184`, the #9533 tombstone in `check-required-contexts.mjs` | kept as written | ## Tier H prose touched - `AGENTS.md` line 533: drops `Console Pin Gate` from the list of full-battery jobs. - `AGENTS.md` lines 1103 to 1104: the sibling-removal rule named the full battery's `Console Pin Gate` as what reds a breaking removal on `main`. It now names `Type Check UI`, which compiles the Console under `ui/` in the PR that makes the removal. Line count unchanged (1117, the ratchet ceiling). - `docs/releases-maintenance.md`: the "What still checks the pin" paragraph is now "What used to check the pin", and the release-gate roster reads `CI`, `Lint & Type Check`. No ADR is touched. ## Required contexts that vanish **None.** Read at the time of this PR: the `main` ruleset requires `TypeScript Type Check`, `Test Core`, `Build Core`, `Lint & Repo Gates`, `Governed Surface Queue Guard`, and classic branch protection requires `TypeScript Type Check`, `Build Core`, `Test Core`, `Dogfood Regression Gate`. Neither `Spec Shape Gate` nor `Console Pin Gate` is in either list, so the sitting needs no ruleset change for this PR. `node scripts/check-required-contexts.mjs --verify-required-set` exits 0: the registry and the live set agree in both directions. ## Landing with 4a #25745 This PR and 4a are two halves of one change and land as a batch, 4a first: - **On `main` alone this PR is red in one place.** The order keeps `check-console-injection.mjs` and `console-spec-probes.mjs` until 4a and deletes `Console Pin Gate`, their only PR-time runner. Two live-tree cases of the dispatch-gates fast tier then red: the silent load-break pair `check:console-injection` from `console-spec-probes.mjs`, and the `pull_request`-only narrowing of the scheduled-only zero. That step belongs to `Lint & Repo Gates`. With 4a merged first, the same tier passes 1917 of 1917 (verification record below). Neither case was weakened. - **Two files overlap.** `package.json` (both PRs delete the `check:prerelease-pins` alias) and one comment in `scripts/pm/dispatch-gates.self-test.mjs` near line 1006. Take the `main` side (4a) in both; checked on the local merge below. ## Deviations from the order 1. `scripts/check-prerelease-pin-watch.mjs` and its `check:prerelease-pins` alias are deleted here as well. Once the workflow is gone the script has no CI caller and `check-self-test-wired` reds the orphan. 4a deletes the same file, so the two deletions agree. 2. `prerelease-pin-watch.yml` does not watch the objectui pin. It watched better-auth prerelease overrides in `pnpm-workspace.yaml`, and its watch list was already empty. It is deleted as ordered. 3. Beyond the order's file list, these gates had to follow the deletion so they stay true: `check-ci-filter-parity.mjs`, `check-expected-skips.mjs`, `dispatch-gates.self-test.mjs`. Each keeps its assertion shape; nothing is skipped or loosened. ## Verification record Head `1776dbd798a4ebde5abc974e5b8d01c6db3fd3ef`, base `52f3f518e1`. - **Derived gate sweep** (`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`): 86 derived, 82 run. 81 exit 0. `pnpm check:pm-dispatch-gates` exits 1 (the two cases above, 2 of 1917). 4 exit 3, prerequisite not met, because they need every workspace dist built: `check:dts-closure`, `check:dual-build-cjs-loads`, `check:lean-entry-closure`, `check:sourcemap-no-sources-content`. `Build Core` runs them on this PR. `dispatch-gates.mjs --ran`: 86 accounted, 0 unrun. - **Named by the order:** `node scripts/ci/scheduled-full-run.mjs --self-test` 0, `pnpm check:shard-attestation` 0, `pnpm --filter @objectstack/spec check:liveness` 0, `check-required-contexts.mjs --verify-required-set` 0. - **Merged tree** (`main` `abebc4e14d` + 4a `4ac569dc00` + this PR, local, conflicts resolved to the `main` side): `pnpm check:pm-dispatch-gates` exit 0 (fast tier 1917 of 1917). The same 86-command sweep on the merged tree: 80 exit 0, 6 exit 3 (prerequisite not met: the throwaway worktree has no package dists or package-level installs, so `check:doc-formula-expressions` and `check:type-check-debt` join the four above; both exit 0 on this branch), no finding. ```text exit command (this branch, head 1776dbd) 0 node scripts/check-aggregator-roster.mjs 0 node scripts/check-aggregator-roster.mjs --self-test 0 node scripts/check-ci-filter-parity.mjs 0 node scripts/check-ci-filter-parity.mjs --self-test 0 node scripts/check-closing-keyword-parity.mjs 0 node scripts/check-closing-keyword-parity.mjs --self-test 0 node scripts/check-comment-mask-corpus.mjs 0 node scripts/check-declaration-mirrors.mjs 0 node scripts/check-declaration-mirrors.mjs --self-test 0 node scripts/check-dts-emitted.mjs --self-test 0 node scripts/check-merged-branch-reaper-outcome.mjs 0 node scripts/check-merged-branch-reaper-outcome.mjs --self-test 0 node scripts/check-position-name-fold-loaders.mjs 0 node scripts/check-position-name-fold-loaders.mjs --self-test 0 node scripts/check-release-section-coverage.mjs 0 node scripts/check-release-section-coverage.mjs --self-test 0 node scripts/check-release-section-coverage.mjs --strict 0 node scripts/check-scripts-symbol-anchors.mjs 0 node scripts/check-scripts-symbol-anchors.mjs --self-test 0 node scripts/check-self-test-wired.mjs 0 node scripts/check-self-test-wired.mjs --self-test 0 node scripts/check-self-test-workflow-commands.mjs 0 node scripts/check-self-test-workflow-commands.mjs --self-test 0 node scripts/check-step-collectors.mjs 0 node scripts/check-step-collectors.mjs --self-test 0 node scripts/check-whole-set-label-write.mjs 0 node scripts/check-whole-set-label-write.mjs --self-test 0 node scripts/ci/assert-turbo-remote-cache.mjs --self-test 0 node scripts/ci/prune-turbo-cache.mjs --self-test 0 node scripts/ci/scheduled-full-run.mjs --self-test 0 node scripts/docs-audit/check-drift-comment.mjs 0 node scripts/pm/bare-root-worklist.mjs --self-test 0 node scripts/pm/ci-failure.mjs --self-test 0 node scripts/release-dist-tags.mjs --self-test 0 node scripts/release-verify-npm.mjs --self-test 0 node scripts/render-release-coverage-anchor.mjs --self-test 0 pnpm --filter @objectstack/lint run check:doc-formula-expressions 0 pnpm check:agent-test-spelling 0 pnpm check:bash32-floor 0 pnpm check:cli-command-ids 0 pnpm check:cross-package-test-inputs 0 pnpm check:declared-population-live 0 pnpm check:doc-authoring 0 pnpm check:docs-audit-scope 0 pnpm check:driver-memory-census 0 pnpm check:entry-guard 0 pnpm check:gitlink-declared 0 pnpm check:manifest-repository-directory 0 pnpm check:merge-driver 0 pnpm check:node-version 0 pnpm check:nul-bytes 0 pnpm check:parse-guard 0 pnpm check:pm-close-cards 0 pnpm check:pm-expected-skips 0 pnpm check:pm-fleet-write-dispatch 0 pnpm check:pm-fleet-write-execute 0 pnpm check:pm-fleet-write-validate 0 pnpm check:pm-governed-merges 0 pnpm check:pm-governed-prose 0 pnpm check:pm-issue-transfer 0 pnpm check:pm-post-stamped 0 pnpm check:pm-record-recognisers 0 pnpm check:pm-skill-id-lint 0 pnpm check:pm-skill-ratchet 0 pnpm check:pnpm-acquisition 0 pnpm check:pnpm-filter-targets 0 pnpm check:pnpm-flag-spellings 0 pnpm check:ratchet-remedy-authority 0 pnpm check:refd-timer-probe 0 pnpm check:required-contexts 0 pnpm check:select-gate-families 0 pnpm check:shard-attestation 0 pnpm check:stall-guard-budget 0 pnpm check:stall-guard-headroom 0 pnpm check:turbo-task-graph 0 pnpm check:type-check-coverage 0 pnpm check:type-check-debt 0 pnpm check:vendor-version-stamps 0 pnpm check:watch-hint-literal 0 pnpm check:workflow-status-functions 0 pnpm check:workflow-step-name-quoting 1 pnpm check:pm-dispatch-gates 3 pnpm check:dts-closure 3 pnpm check:dual-build-cjs-loads 3 pnpm check:lean-entry-closure 3 pnpm check:sourcemap-no-sources-content ``` ## 维护者速读(草稿) **改了什么**:删掉三个只为「跨仓库钉版本」存在的门禁:Spec Shape Gate(每小时拉 objectui main 编译一遍)、Console Pin Gate(按 `.objectui-sha` 克隆 objectui 构建控制台)、prerelease-pin-watch(盯 better-auth 预发布版本,清单早已为空)。发布前的全量电池名单从三个工作流减为 `CI` 与 `Lint & Type Check`。AGENTS.md 两处、发布维护文档一处把它们改为过去时。 **为什么改**:objectui 合入 `ui/` 之后,控制台在同一个 PR 里由 `Type Check UI`、`Build & E2E UI` 编译构建,规格一改就当场验证,不再需要隔一小时去克隆另一个仓库。留着旧门禁只会对着已不存在的钉版本报错。 **风险与代价(含回滚)**:不影响必需检查(这三个都不在必需集合里)。必须在 4a #25745 之后合入:单独合入时 `Lint & Repo Gates` 会因控制台脚本失去 PR 期运行者而红两条,4a 删除这些脚本后即消失。回滚就是还原此 PR,三个工作流与脚本原样恢复。 **席位意见**: **你要做的**:切换当天在 4a 之后合入本 PR(Tier H,需你批准)。规则集无需改动。 --- _Generated by [Claude Code](https://claude.ai/code/session_01H835wAyqCCeF7jiYq7XSxi)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Part of #25697 (PR A of two; PR B, which retires the two-repo pin gates, is drafted later and merges in the cutover window). Part of #25677.
What
The objectstack side of importing objectui under
ui/, landed inert: untilui/package.jsonexists, nothing in this PR changes what pnpm installs, what turbo builds, or what CI runs.Workspace.
pnpm-workspace.yamladdsui,ui/packages/*,ui/apps/*,ui/examples/*. objectui declares noonlyBuiltDependencies, so the union with ours is our list unchanged. objectui's overrides and its@radix-ui/react-focus-scopepatch arrive with the import, not here.Root turbo.
turbo.jsonaddstype-check,lint,test:dist,test:watchwith objectui's inputs, outputs, dependsOn and cache settings. Its repo-root inputs are re-rooted under$TURBO_ROOT$/ui/. Two things are not carried over://#lint:rootand//#type-check:e2edependsOn edges. Turbo refuses a whole run over a package-named dependsOn whose package does not exist yet, so those two programs are steps in the ui jobs instead.globalDependencies(pin plumbing).CI jobs in
ci.yml, ported from objectui'sci.ymlandlint.yml:Type Check UITest UI (n/16)Lint UIBuild & E2E UIThe
filterjob gains three outputs:ui(ui/**plus the root files the jobs build from),ui_consumers(the seven packages objectui installs: spec, client, core, formula, lint, sdui-parser, types) andui_tree(whetherui/package.jsonexists, set by a step with noif:). Every job'sif:follows THE FILTER CONTRACT:!cancelled() && needs.filter.outputs.ui_tree != 'false' && PATH_OUTPUTS != 'false'. Withui/absent, every job is skipped on every event. None of them is a required context or an aggregator member.A spec change compiles the Console.
Type Check UIandBuild & E2E UIalso run onui_consumers. On pull_request and merge_group, Type Check UI uses turbo--filter=...[base], so a spec change selects every ui package that depends on spec.Roster audit of objectui's 28 workflows: see the table below.
Gates that had to learn about a tree that has not arrived yet
Several repo gates treat "config describes something absent" as a defect. That reading is correct except for a tree that is about to be imported. Each gate below now declares the ui roots, and each hold is narrow:
check-turbo-task-graph: the generic keystype-check,lintandtest:disthave no holder until the import.GENERIC_TASKS_AWAITING_UI_IMPORTholds them only whileui/package.jsonis absent. A held key that turbo.json does not declare is itself a finding. 7 new self-test cases.check-cross-package-test-inputs:uiis a$TURBO_ROOT$segment that git does not track yet.TOP_LEVEL_DIRECTORIES_AWAITING_IMPORTexcuses it only while it is untracked. Once tracked, it owes a recognised or pending entry.check-published-files,check-test-source-alias,check-undeclared-dep-imports,check-llms-txt: each holds a hand copy of the workspace globs, and each now declares the four ui roots.check-undeclared-dep-importsalso learned the bareDIRworkspace entry; before, it made the whole sweep fatal. 2 new cases.check-expected-skips: the four* UInames are declared as by-design skips.Why objectui commands are spelled
pnpm --dir ui run ALIASThis repo's workflow gates (
check-self-test-wired, the dispatch-gates derivation and others) keyscripts/NAMEandpnpm ALIASagainst this repo's root, and none of them readsworking-directory. Underworking-directory: ui, objectui'sscripts/check-entry-guard.mjswas credited to objectstack's file of the same name.scripts/check-lint-coverage.mjs, which only objectui has, read as a missing script.Test UI shard count
N = 16, chosen the way
scripts/partition-test-shards.mjschooses Test Core's N: max/mean ≤ 1.3, from ui/scripts/test-shard-timings.json (4979 files, 325.7 summed minutes).@object-ui/app-shellalone is 104.2 minutes, so the bound admits at most 4 legs.The suite must run with cwd =
ui/, because the dataset keys are relative to the vitest root.Verification (local, on
issue-25697at 597471c)pnpm install --frozen-lockfile --prefer-offline && git diff --exit-code pnpm-lock.yaml--lockfile-only)pnpm -r ls --depth -1with the base workspace file vs the new oneturbo run build --dry=json, before vs afterpackages/spec/scripts/check-llms-txt.tsis an input of@objectstack/spec#build.turbo run type-check / lint / test:dist / test:watch --dry=jsonui/is absent.actionlint 1.7.7 -shellcheck= .github/workflows/ci.yml(shellcheck not installed)node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, run in full, pluspnpm check:pm-dispatch-gates--ranreconciliation: 118 derived, 118 run, 0 NOT-MEASURED, 0 UNRUN (all with recorded exit codes).pnpm check:type-check-debt(underscripts/pm/os-verify-lock.sh)eslint --no-inline-configon the 7 changed scriptsThrowaway import (local, never pushed, deleted afterwards). Built from this branch plus the #25678 spike's adapted
ui/tree, overrides and patch, then a lockfile recompute. Results:pnpm install: 48 s.pnpm -r ls --depth -1lists 45@object-ui/*packages plusobject-ui-monorepo.turbo run type-check --filter='./ui/packages/types' --dry=jsonresolves@objectstack/spec#build → @object-ui/types#type-check.@objectstack/*type-check and not theuiroot (which would recurse).packages/spec/srcselects 44 ui packages under the affected filter.pnpm --dir ui run type-check:coverage,lint:coverage,check:phantom-depsandcheck:entry-guard --self-testall exit 0.Not verified here, owed by the CI runs on #25697 (a
DO NOT MERGEbranch = this head + the subtree import):ui/present;Type Check UIred on aui/file;check-required-contexts --verify-required-set), which cannot run from a dev seat. The new names are not inREQUIRED_CONTEXTS.Acceptance notes: what the import commit will turn red (measured on the throwaway tree)
None of these is reachable while
ui/is absent. Each needs a decision in the cutover PR (sub-issue 5) or in sub-issue 2:check-turbo-task-graphandcheck-workspace-manifest-cyclesself-tests: theirDECLARED_WATCH_HINTSdo not coverui/**/package.json. They cannot declare it today, because both also red on a pattern that covers zero manifests.check-published-filesself-test:EXPORTS_CENSUS_FLOOR(50) must rise. The live publishable count goes 73 → 112.check-undeclared-dep-imports: 9 findings.@object-ui/consoleimports@objectstack/specand@objectstack/clientbut declares them only as devDependencies.check-type-check-coverage: it cannot parseui/tsconfig.json, which is JSONC.check-cross-package-test-inputsself-test: the trackedui/segment must be recognised or pending, as designed.pnpm build(turbo run build) would includeobject-ui-monorepo#build, which is itselfturbo run build, and the rootpnpm lint(eslint .) would sweepui/.Roster audit (item 5)
ci.yml: Type Check · Test (shard n/16) · Build & E2Eci.yml: Test (dist pins) · coverage lane · Build Docsci.yml: Test (aggregate)ci.yml: Changeset Fixed Group Checklint.ymllive-e2e,lockfile-dedupe,lockfile-integrity,node-esm-load-gate,performance-budget,published-dist-gate,shadcn-checkspec-range-floorsworkspace:^makes the floor the workspace version)governed-surface-guard,half-state-patrol,hook-selftests,labeler,required-check-set-patrolboard-snapshot,changelog,changeset-guard,changeset-presence,changeset-release,check-links,cross-repo-issue-closer,dependabot-auto-merge,docs-deploy,line-citation-gate,merge-queue-head-patrol,repo-gates,test-shard-timings-refreshThe full table, one line per workflow with notes, goes on #25697 as a comment (the seat posts it).
维护者速读
改了什么 —— objectstack 这一侧为导入 objectui(
ui/子目录)预先铺线,全部惰性:在ui/package.json出现之前,pnpm 装什么、turbo 建什么、CI 跑什么,一个字节都不变。具体是 workspace 四条ui通配、根 turbo 四个任务名(type-check/lint/test:dist/test:watch)、ci.yml四个新 job(Type Check UI / Test UI 16 片 / Lint UI / Build & E2E UI,都挂在"ui/树存在"这一个开关上,不存在就 skipped,且都不是必查项),以及 7 个仓内门禁学会这四个还不存在的根目录。附 objectui 28 个 workflow 的去向表。为什么改 —— 让后面那个 2.59 M 行的导入提交只做一件事:
git subtree add。接线先行、并且先在今天的树上过一轮 CI,导入那天就不用边导入边改 CI。spec 一改就编译 Console(Type Check UI 对ui_consumers也触发)是把"objectui 被 spec 改坏"从发版后发现提前到 PR 上发现。风险与代价(含回滚) —— 对现有流水线零影响的证据:锁文件逐字节不变(
--frozen-lockfile过)、turbo run build --dry=json前后同为 84 个任务、121 条派生门禁全部 exit 0、actionlint 过。代价是ci.yml多了 624 行当前全部 skipped 的 job;导入后每个碰ui/的 PR 多跑 16 个测试 runner(与 objectui 今天一样)。回滚 = revert 一个 squash 提交,无发布、无数据副作用。未在本地量到的只有导入后 Type Check UI / Build & E2E UI 的冷热分钟数,靠下一步的 DO NOT MERGE 验证分支量。席位意见 —— 建议批准。这是子单 3 的 PR A;PR B(退役两仓 pin 门禁)单独起草、只在切换窗口合。
你要做的(一个动作) —— 在本 PR 上留一条 APPROVED review;之后由派发席翻 ready、挂 auto-merge 走合并队列。
Landing
Tier H:
.github/workflows/**. Draft until an APPROVED review fromGOVERNED_APPROVERSis on record; then the dispatch seat lands it through the merge queue (maintainer ruling C). No seat flips it ready before that.No changeset: the diff touches workflows, root config,
scripts/**andpackages/spec/scripts/**(not in spec'sfiles[]), so nothing published changes.Changed lines: 964 (931 additions, 33 deletions), under the human-merge threshold.
Clause-②: no
Metadata-protocol: none
🤖 Generated with Claude Code
https://claude.ai/code/session_01RSDL3SFtJaKzcymvCD8RsU