AGENTS.md@packages/blackhole-plugin/src/client · git:20260907.33d6653 · 2026-09-07 · sha256 93f668ccb794d348

AGENTS.md@packages/blackhole-plugin/src/client git:20260907.33d6653A

Immutable. This exact content is served forever at /api/v1/blob/93f668ccb794d348.

# DOX — packages/blackhole-plugin/src/client

Files in this directory. One row per source file. See change: add-blackhole-plugin.

| File | Purpose |
|------|---------|
| `BlackholeSettings.tsx` | `settings-section` component (general tab). Three self-produced states: not-installed (registry says `pi-blackhole` missing), parse-error (NO form, explicit DISABLED save control, recovery actions), form (scalar accordions + chain editors). Saves through the host Save Bar via `useSettingsDraftSource({ id: "plugin:blackhole" })`. Exports `buildPayload(draft)` — scalars + chains split back to `<worker>Model`/`<worker>FallbackModels`, `null` unsets, `NaN`/`undefined` says nothing. Copy never demands a restart; apply is attributed to the extension. |
| `ChainEditor.tsx` | One worker's ordered chain. Ranked list, expandable per-model fields (`provider`, `id`, `thinking`, `cooldownHours`, `contextWindow`). Move-up/down/remove are real `<button>`s with accessible names naming the model; boundary controls DISABLED not absent; no remove on a single-entry chain. Renders the shared `base model → session model` tail as non-entry text, marked `data-excluded` when `sessionFallback` is off. |
| `blackhole-api.ts` | REST client. `getConfig` (a 409 parse-error is a RESULT, not a throw), `putConfig`, and `isExtensionInstalled` — REPOINTED at the plugin's own `GET /api/plugins/blackhole/status` (design D1; was `GET /api/plugins` `missingRequirements`). Fail-open on unknown: network error, non-200 (incl. the 503 of a scan failure), malformed body → `true` — an unknown answer must not fabricate a not-installed state. The boot gate fails CLOSED on the same uncertainty — opposite stakes, deliberate. See change: add-blackhole-plugin, add-blackhole-session-pipeline. |
| `detail-navigation.ts` | Module-scoped navigation state for the `content-view` drill-in (F8). `openPipelineDetail(id)`/`closePipelineDetail()` flip `activeForSessionId` + `bumpSlotClaimsVersion()`; `isPipelineDetailActive(session)` — the manifest predicate string — returns false until explicit navigation and only for THAT session. See change: add-blackhole-session-pipeline. |
| `installed-gate.ts` | Client boot gate (design D4). `shouldRenderMemorySubcard()` — synchronous, fails closed until resolve (F1); manifest `shouldRender` name. `resolveInstalled({fetchImpl,backoffMs,slowIntervalMs})` — fetches `/status`; network error/non-200/malformed body are transient: capped backoff ×3 then ~60s fixed interval UNTIL first success, never gives up (X1/X2); success finalizes page-lifetime value, `bumpSlotClaimsVersion()` once, no re-poll. `isTestEnvironment()` — `import.meta.vitest` / typeof-guarded `process.env.VITEST` (NOT `MODE`); `typeof process` guard is load-bearing for the browser bundle. See change: add-blackhole-session-pipeline. |
| `MemorySubcard.tsx` | `session-card-memory` claim component. Mount-time fetch of ONE `/session/:id` response (idle sessions are snapshots — accepted trade-off); derives states via `pipeline-state.ts`: healthy row / no-activity-yet / workers-off (no meter) / cooldown advisory (model + remaining min) / pending-batch advisory (count + /blackhole flush). Worker indicators: textual id + state-describing `aria-label`, never colour-alone (F7). Exact lag alongside approximate proximity; detail affordance in EVERY state (F10). See change: add-blackhole-session-pipeline. |
| `PipelineDetailView.tsx` | `content-view` claim component (one-active). Provenance labels: cursors → `<id>-pending.json`, resolved model + reason → `pi-blackhole-cooldown.json`, proximity → dashboard accounting with non-convertibility caveat. NO in-memory-only values (`consolidationInFlight`, counts, last errors); transcript pointer present. `onClose` + `closePipelineDetail()` = the return path. Session-scoped — the settings page renders none of this. See change: add-blackhole-session-pipeline. |
| `pipeline-api.ts` | Typed client for `/session/:id` (`getSessionPipeline`) + the `SessionPipelineResponse` shape mirrored from the server reader; `WORKER_IDS`. See change: add-blackhole-session-pipeline. |
| `pipeline-state.ts` | Pure derivation of the subcard view model (no DOM): `deriveSubcardState`, `deriveLag` (E11 — tip − cursor exact; cursor==tip → 0; cursor AHEAD → `{kind:"stale"}`, no numeric), `deriveProximity` (F5/F6 — fraction for an UNSCALED fill; null when `contextTokens` or `compactAfterTokens` missing; never a number/percentage/threshold/alert in render). See change: add-blackhole-session-pipeline. |
| `routes.ts` | Shared client route paths: `STATUS_ROUTE`, `SESSION_ROUTE_BASE`, `sessionRoute(id)`. See change: add-blackhole-session-pipeline. |
| `field-groups.ts` | Display copy + grouping only (control kind derives from `FIELD_DESCRIPTORS`). `FIELD_GROUPS` = compaction behaviour, observational memory, trigger thresholds, token budgets, runtime & diagnostics. `WORKER_META` = observer/reflector/dropper name, role, and config key pair. |
| `index.tsx` | Client entry barrel. Exports the components the manifest claims reference (`BlackholeSettings`, `MemorySubcard`, `PipelineDetailView`), the gate (`shouldRenderMemorySubcard`), the predicate (`isPipelineDetailActive`), and the i18n `catalog`. Module-scope boot check: `if (!isTestEnvironment()) resolveInstalled()` — GUARDED (F4): importing under vitest issues no network request; `resolveInstalled` stays explicitly invokable. See change: add-blackhole-plugin, add-blackhole-session-pipeline. |
| `__tests__/BlackholeSettings.test.tsx` | L1. The three states at component level: not-installed from the status route (E23, F6) and that it is SELF-produced; installed-but-never-run rendering defaults not the missing state (E22), incl. an unreported probe never fabricating not-installed; parse-error rendering no form + a disabled save control (X1, X3); no-restart / attributed-apply copy (F7); chain render order (E18). Plus the payload rule: `buildPayload(toDraft(...))` emits ONLY file-set or user-edited keys, never materialising untouched defaults, and validates against the server validator. Status-route mock answers `{installed}`; one test asserts the repointed source (`/status` called, `/api/plugins` never). See change: add-blackhole-plugin, add-blackhole-session-pipeline. |
| `__tests__/ChainEditor.test.tsx` | L1. Ordering + promotion (E19), boundary controls disabled-not-absent (F2), no remove on a single-entry chain (E21), accessible names naming the model on every control (F1, F3), real focusable `<button>`s, the implicit tail shown as a non-entry and `data-excluded` per `sessionFallback` (F4, F5), and per-model field typing — numeric edits emit NUMBERS and `(inherit)` omits `thinking`, round-tripped through the real server validator. |
| `__tests__/client-entry.test.ts` | L1 (F4). Imports the ENTRY barrel with `fetch` spied: spy uncalled (guarded kick); `resolveInstalled` still invokable with an injected fetch. See change: add-blackhole-session-pipeline. |
| `__tests__/installed-gate.test.ts` | L1 (F1, X1, X2). Sync fail-closed before resolve; fails ×4 then succeeds → 3 backoff retries + slow-interval attempt, gate flips, exactly ONE `bumpSlotClaimsVersion`, no further polling; 404/500/garbage-body each transient, value never finalized, eventual success still lands; definitive `false` is authoritative + final. `isTestEnvironment` override/probe checks. See change: add-blackhole-session-pipeline. |
| `__tests__/MemorySubcard.test.tsx` | L1 (E10, E11, F5, F6, F7, F10). State fixtures: healthy row / no-activity / workers-off (+compaction-still-runs, no meter) / cooldown advisory naming model + minutes / pending-batch advisory. Lag: 38 exact not approximate, 0 caught up, stale-cursor indicator with no numeric. Proximity: ≈ label, reachable explanation, no token counts/percent/scale, no alert; omitted when `contextTokens` or `compactAfterTokens` missing while workers+lag persist. Detail affordance in EVERY state. See change: add-blackhole-session-pipeline. |
| `__tests__/PipelineDetailView.test.tsx` | L1 (F8, F11; 6.3). Predicate false by default, explicit navigation activates THAT session, back affordance resets + fires `onClose`. Provenance: pending-file / cooldown-file / dashboard-accounting attributions; no `consolidationInFlight`/counts/last-error; transcript pointer. Settings surface renders no per-session pipeline state. See change: add-blackhole-session-pipeline. |