Racing handle.finished against a self-managed setTimeout deadline is flaky
under CI event-loop starvation: when the worker thread resumes, the job's
promotion timer and the deadline expire in the same libuv batch and the
deadline's synchronous resolve('timeout') beats the job's multi-hop async
completion chain, so the race settles 'timeout' even though the job finished
moments later. Await handle.finished directly and assert the terminal
snapshot status; vitest's per-test timeout bounds a genuine hang with a
clearer error. Applied to all five occurrences that shared the pattern.
`htmlPath: ''` already makes WindowManager skip content loading so a domain
service can load the window itself, but the behavior was implicit — undocumented
at the type level and untested as a contract.
- types.ts: document that `htmlPath: ''` is a consumer-loaded window and how the
consumer loads content afterward (getWindow(id) -> webContents.loadURL/loadFile,
plus show/close ownership); fix the preload cross-reference that wrongly claimed
htmlPath is three-state.
- WindowManager.test.ts: lock the contract — empty htmlPath skips loadFile/loadURL,
non-empty htmlPath loads on create.
- usage guide: add a "Consumer-loaded windows" section (recipe + getWindow caveat).
The barrel/module-boundary rules (naming-conventions.md §6.4) were warn-only
while the codebase was being brought into compliance. The full tree is now
barrel-clean (lint reports 0 barrel findings), so promote all seven rules —
no-export-star, index-no-impl, no-index-tsx, named-only, closed, no-nesting,
no-bucket-root — from warn to error to lock the boundary against regressions.
Close the last 14 barrel/closed (§6.4) violations in the knowledge feature: both
v1→v2 migrators deep-imported knowledge internals to rebuild a base's index.sqlite.
Extract the shared open sequence into createKnowledgeIndexStoreAtPath (also adopted
by KnowledgeVectorStoreService, deduping the runtime) and the snapshot assembly into
build{Url,Note}SnapshotFile (adopted by capture*SnapshotFile); add index-count reads
to KnowledgeIndexStore; re-export a curated rebuild surface from the knowledge barrel.
The migrators now import only @main/features/knowledge — the engine internals
(driver/schema/meta/vector index) stay private behind the factory.
Every §6.4 `barrel/closed` warning on these six main barrels came from
external code deep-importing internals. Route each consumer through the
barrel, widening a door only with symbols that keep it one cohesive unit,
and trim dead re-exports.
- filesystem: export resolveFilesystemBaseDir
- observability: export the 3 lifecycle services (ClaudeCode/Node/TraceStorage)
- fileProcessing: export the job-result contract (artifact helpers + payload type)
- webSearch: export isPermanentWebSearchConfigError
- knowledge: export KnowledgeVectorStoreService; drop internal-only Lock/Workflow re-exports
- migration/v2: export isSchemaOutOfSyncError; drop dead BaseMigrator/reader re-exports;
fold the gate's redundant versionPolicy deep-imports back through the barrel
Relocate two misplaced concerns the deep imports surfaced:
- isAbortError (generic) -> @main/utils/error, out of webSearch
- legacyTypes (v1 @deprecated) -> data/migration/, out of the v2 barrel; delete dead MistralClientManager
Update v2MigrationGate's barrel mock to match the consolidated import, and
fix a stale migrator-registration path in the migration README.
The remaining knowledge migrator coupling (KnowledgeVectorMigrator /
KnowledgeMigrator) is deferred to a fix-upstream follow-up.
Clear all 8 `closed` deep-import warnings on five directories, applying the
topic-subdir-vs-type-bucket distinction (naming §6.4 / renderer §5):
- hooks/translate, hooks/command, components/ActionTools — cohesive topic
subdirs / component framework: keep the curated door, route the stray deep
imports through it.
- pages/knowledge/hooks — a page-internal type bucket (named `hooks`, not a
topic): drop the barrel per rule 3/§4.8; four consumers deep-import the leaf
hooks (matching the no-door home/notes/paintings siblings).
- components/composer/tokenView — heavy component + light vocab aggregator:
keep the component door, move the token vocabulary out
(tokenView.ts -> composer/chatTokenView.ts) so light consumers no longer
pull the ComposerToken graph through the door.
Retarget the knowledge tests' barrel mocks to the leaf modules.
Fix two barrel/closed violations where Shell and ResourceList deep-imported
CommandId from shared/utils/command/definitions instead of the barrel. The
command/ barrel is a cohesive subsystem (command/keybinding/menu/context-
expression); it stays as-is — only the two stray deep-import paths are corrected.