Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

ci: reconcile cross-workspace test consumers with selected proof inventories

Closed
#2,404 4 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@schlessera is already working on this.

Since Oct 20, 2026.

  • #2454 by @schlessera — merged

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
bun, typescript
Domain
ci-cd, testing

Research direction

Start with scripts/ci-plan.ts:99-112 and scripts/ci-proof.ts:33-43, then reproduce the reported production planChecks, workspaces, and unitFiles inventory for packages/ui-server/src/brain/application.ts. Audit whether selected categories execute packages/ui-react/tests/share-draft-runtime.test.ts and retain the exact receipts. Done means a measured correction preserves discovery, shard coverage, worker metadata, refusal guards, and passes the specified consumer scenarios.

Written by the indexing model from the issue text.

Description

area: ci needs: decision priority: p1 type: test

Context

Hosted ready-candidate unit proof can omit real cross-workspace test consumers.

  • affectedWorkspaces (scripts/ci-plan.ts:99-113) computes the reverse closure from manifest edges only (workspaces, scripts/ci-plan.ts:86-96: dependencies, devDependencies, peerDependencies, optionalDependencies).
  • For a package-code change without an explicit inventory, unitFiles (scripts/ci-proof.ts:36-48) discovers root tests/ plus the test roots of the affected packages.
  • So a test in workspace X that imports workspace Y (by package name or by a relative ../../<y>/tests/helpers/... path), where X's manifest does not declare Y, is not selected when only Y changes.

Local check:pr also runs bun run test --changed=<merge-base> as import-graph feedback (localChecks, scripts/check-pr.ts:16-19). That step is documented as feedback only; complete hosted discovery is the required proof (docs/process/testing.md, "Required proof for a PR"). Local feedback can therefore run a consumer that hosted proof leaves out. That is how this gap was found (#2401, #1665).

Policy context:

  • docs/decisions/ci-utility.md ("Local feedback and authoritative proof") promises "affected workspaces and every reverse dependant, plus root tooling tests". It does not say whether "dependant" means manifest edges or import edges.
  • The browser, layout, endurance and captures categories already select from static-import discovery plus validated declarations (#2125 ruling, 2026-10-16, ci-utility "Browser proof input ownership"; selectBrowserClosures, scripts/ci-plan.ts:296). That ruling's rule is "Do not silently omit an input because it is absent from the import graph."
  • Root tests/**, scripts/**, experiments/** and website/** changes use a conservative reverse reference closure (rootConsumers, scripts/ci-plan.ts:135).
  • No ruling covers unit consumers of package changes.
Evidence (main e16b8407f, 2026-10-19)
  • Production planChecks([packages/ui-server/src/brain/application.ts], workspaces(root), root) then unitFiles gives affected: ["ui-server"] and 404 files. packages/ui-react/tests/share-draft-runtime.test.ts is absent. It imports @schlessera/brain-ui-server and two ../../ui-server/tests/helpers/* fixtures (lines 7-9), and packages/ui-react/package.json declares neither.

  • A scan of packages/*/tests/** finds 20 undeclared cross-workspace test edges:

    Edge Files
    ui-react → ui-server 25
    ui-kit → ui-react 10
    ui-react → module-diagrams 9
    ui-sdk → ui-server 5
    ui-backend-claude → ui-server 3
    ui-react → core 3
    ui-react → geo 3
    ui-sdk → ui-backend-claude 3

    The other 12 edges have one file each, including ui-server → module-jobs, ui-server → ui-react, ui-backend-pi → ui-backend-claude and module-travel → module-speaking.

  • For 10 sampled edges (changing packages/<target>/src/index.ts), the planner missed 9. Only geo → ui-react/tests/track-uploads.test.ts was covered, and only transitively. Table: comment.

  • In-memory comparison, declaring all 20 edges in the workspace snapshot (no manifest edits):

    Changed workspace Unit files now With the 20 edges declared
    ui-server 404 1082
    core 680 1082
    module-jobs 171 1082
    ui-backend-claude 483 1082

    For module-jobs, browser proof also switches from unselected to selected. A common change already selects 1068 files today.

Open decision (needs: decision)

Which mechanism makes complete affected unit proof include cross-workspace test consumers?

  • A. Declare the edges as devDependencies, plus a lint that every cross-workspace import under packages/*/tests/** is declared.
    • Uses the existing planner unchanged and is simple to audit.
    • Measured above, it pushes almost every package change to about 1082 files and widens browser selection and forward builds (selectBuildPackages, scripts/publishable-packages.ts:95-117). That works against #1849/#1326.
    • It adds dev cycles (ui-react ↔ ui-server, ui-kit ↔ ui-react). Publish order ignores devDeps, so the cycles are harmless there.
    • One global bun.lock PR.
  • B. Have the planner add reverse test-import consumers to the unit inventory.
    • For package changes, add every test file anywhere under packages/*/tests or tests/ whose static import closure (package specifiers and relative paths, through shared helpers) reaches a changed file. Add these files on top of manifest-closure discovery, never instead of it.
    • Reuse the static-import resolution behind #2125 (scripts/browser-input-closure.ts) or the rootConsumers reference scan.
    • Unresolvable or unsupported edges fall back to the existing broad or global selection.
    • Selects only the actual consumers (for example, about 25 ui-react files for a ui-server change instead of all 580 in the workspace).
    • Unit-category analogue of #2125 option D.
  • C. Reuse bun test --changed in hosted CI.
    • Contradicts its documented feedback-only status. It misses spawned and file-read inputs.
    • Not verified to produce a listable inventory that unitFiles can check against discovery and shard.

Recommendation: B. Optionally add A's lint as a report-only check, without requiring manifest declarations. B keeps the existing closure as the floor and adds exact consumers. It follows the import-discovery rule the maintainer already chose for browser categories, and it avoids A's measured near-global widening. Recommendation only; not approved.

Scope (after the ruling)

  • Implement the chosen mechanism in scripts/ci-plan.ts / scripts/ci-proof.ts (or the manifests plus lint, if A).
  • Update docs/decisions/ci-utility.md ("Local feedback and authoritative proof", plus "Independent Bun test-only changes" if affected) in the same PR. Keep any file:line citations into moved lines correct.
  • Cover both package-specifier and relative cross-workspace test imports, including imports through shared test helpers.

Out of scope

  • Removing local import-graph feedback.
  • Narrowing existing manifest-closure discovery, shard coverage or category selection.
  • Relaxing guards.
  • Adding a global-everything fallback without measured relevance.
  • Treating a manual isolated pass as a selection fix.
  • Changing #1665's activation scope or claiming a product regression.
  • The stopped #2284 investigation.
  • Cross-category equivalence for browser-category specs: #2125 already owns those closures.

Acceptance criteria

  • Failing first. A unit test in tests/ci-plan.test.ts (or an equivalent production-planner test) asserts that unitFiles(planChecks([<ws>/src change], workspaces(root), root), root) contains a cross-workspace consumer. It covers at least ui-server → packages/ui-react/tests/share-draft-runtime.test.ts (package and relative import) and module-jobs → packages/ui-server/tests/jobs-board-selection-http.test.ts. It fails on current main for the missing file and passes after the fix.
  • Mutation receipt. Disabling the new consumer edge (or removing the declaration, if A) turns that test red on the named assertion. Restoring it turns it green.
  • Whole class covered. A repository-level check lists every cross-workspace import under packages/*/tests/** and fails if the planner would not select the importer for a change to the imported workspace. The 20 edges above all pass.
  • No loss of existing proof. For every sampled change, existing selections are a subset of the new ones. Global and unknown inputs still expand to complete discovery. Duplicate, missing or empty inventories still refuse (unitFiles). Shard balancing and test-worker metadata are unchanged.
  • Unresolvable edges fail open. An unresolvable or dynamic cross-workspace import falls back to the broad selection rather than being dropped (controlled test).
  • Measured widening. The PR records unit-file counts before and after for ui-server, core, module-jobs and ui-backend-claude changes.
  • Policy updated. docs/decisions/ci-utility.md states the chosen rule.

Verification

  • bun run test tests/ci-plan.test.ts (plus any new test file).
  • Production planner diagnostic: planChecks(changedFiles(...), workspaces(root), root) and unitFiles for the sampled edges, before and after.
  • bun run check:pr --base origin/main.
  • Explicit ready-candidate CI with the complete selected inventory and actual head/base/checkout in the aggregate.

Contract impact

None. Repository CI tooling only (scripts/ci-plan.ts header: "Product CLI/MCP contracts are unaffected"). Option A would edit package manifests' devDependencies only, which do not ship to consumers.

History

  • 2026-10-18 (filing): the #1665 candidate 13601e76668b5801b4cc0aa5259a2df5a50ae42b on base 775eb17aab740fa759c2182f306c38fc17acbcbe gave affected: [ui-server], global: false and 404 hosted unit files, without share-draft-runtime.test.ts and with claude-cancellation.test.ts. Local import-graph feedback selected it and produced the three initial-confirmation failures recorded in #2401. Later scoped runs pass but do not diagnose the original combined failure.
  • 2026-10-18, second pass: production planChecks, workspaces, unitFiles and categoryCommands at 775eb17a gave 403 files without the share consumer. The diagnostic exits 1 on the missing-consumer assertion.
  • 2026-10-18, third pass: adding only an in-memory ui-react → ui-server edge selects the consumer (403 → 580 files; affected module-diagrams, ui-react, ui-server). This confirms that manifest closure is the cause.
  • 2026-10-19, class reproduction at 09eb1f78e: about 20 undeclared edges; the planner missed 9 of 10 sampled. needs: repro removed.
  • #2413 records the ui-server → module-jobs instance. #2399 notes that its own SDK change widened the normal closure and did not modify selection.

Triage 2026-10-19: re-verified at e16b8407f (404 files, 20 edges). Corrected citations (affectedWorkspaces 99-113, unitFiles 36-48, share-draft imports 7-9). Recorded that no ruling covers unit-consumer selection and that local --changed is deliberately feedback-only. Measured option A in memory. Added the decision question with options and a recommendation (B). Labels: needs: decision, priority: p1. Attached to #1849.

Dominant language
TypeScript
Stars
1
Forks
0
Avg merge
4h 41m
Merged PRs (30d)
954

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from schlessera/brain-kit

All issues in schlessera/brain-kit

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.