AGENTS.md@dash · git:20261031.4f642d0 · 2026-10-31 · sha256 f44d2f9c67ad2b14
AGENTS.md@dash git:20261031.4f642d0A
Immutable. This exact content never changes and is served at /api/v1/blob/f44d2f9c67ad2b14.
# Working under `dash/` KyberDash is first-party code ([ADR 0020](../../docs/adr/0020-kyberdash-one-time-fork.md)). Judge every edit here on its merits, under the repository's own gates. Do not merge from CodeBurn or any other upstream; the only trace of it left is `dash/LICENSE` and `dash/THIRD_PARTY_NOTICES.md`. ## THE RULE > **THE TRAY AND THE WEB DASHBOARD ARE DISPLAY LAYERS. NEITHER CONTAINS ISOLATED FEATURE > LOGIC, SCHEDULERS OR JOBS. ALL LOGIC AND JOBS (REFRESH SCHEDULING, CLEAN, IMPORT, PAUSE) > LIVE IN THE SHARED KYBERDASH APPLICATION (THE CLI ENGINE AND THE `kyberdash web` SERVER > BUILT FROM IT) THAT BOTH SURFACES SHARE. BOTH SURFACES USE ONE DATASTORE (canon.db, > resolved by dash/src/canon/paths.ts resolveCanonDbPath) AND ONE API LAYER > (/api/kyber/*). NO AGENT OR DESIGN MAY VIOLATE THIS.** Full text, with the boundary cases and the agent checklist: [`docs/rules/kyberdash-display-layer.md`](../../docs/rules/kyberdash-display-layer.md). Decided by [ADR 0033](../../docs/adr/0033-kyberdash-surfaces-are-display-layers.md). Architecture: [`docs/dash/architecture.md`](../../docs/dash/architecture.md). ## What lives where | Directory | Role | |---|---| | `dash/src/**` | The engine: parsers, the canonical store and projection, analyses, refresh and import, clean, the jobs hosts, the OTLP receiver, the server, the CLI commands | | `dash/web/**` | A display layer. Renders and requests over `/api/kyber/*`; holds no logic | | `dash/tray/**` | A display layer. A Tauri 2 Rust shell plus a React popover; owns pixels and lifecycle, not behaviour | Feature behaviour belongs in `dash/src`, reached over the API. A surface may render, invoke actions through `/api/kyber/*`, open links, and keep display preferences. It must never schedule, run a job, spawn a CLI child for one, host the receiver, take a non-allowlisted value import from `dash/src`, or compute a domain result (cost, coverage, ranking) in the browser. `dash/src/architecture/display-layer.test.ts` scans for exactly those and fails with the offending file, line and construct. ## Gates None of the .NET gates in the root `AGENTS.md` reach this tree. From the repository root, run each through the process watchdog: ```bash scripts/proc-guard.sh run -- npm --prefix dash run typecheck scripts/proc-guard.sh run -- npm --prefix dash run lint scripts/proc-guard.sh run -- npm --prefix dash run test scripts/proc-guard.sh run -- npm --prefix dash run check:reachable ``` Editing `dash/tray/**` also means the tray's own gates — see [`dash/tray/AGENTS.md`](tray/AGENTS.md) for the Rust and popover-UI commands. Run those through `scripts/proc-guard.sh run --` too. ## Tests that start processes A dashboard test that starts a dashboard can start another, and that is how a run fork-bombed `node` in 2026-10. These rules hold for every test under `dash/` ([ADR 0047](../docs/adr/0047-kyberdash-self-spawns-through-one-guarded-chokepoint.md), [test standard](../docs/standards/test/README.md#tests-that-start-processes)): - **Playwright runs only with the isolated config**, from the repository root: `scripts/proc-guard.sh run --timeout 600 -- npx --prefix dash playwright test --config dash/playwright.isolated.config.ts <spec>`. Never run `dash/playwright.config.ts` by hand, and never omit `--config`. - **Never start the dashboard to run a test** (`kyberdash web`, `npm run dev -- web`). The e2e boots use `dash/e2e/boot-dashboard.ts`, which injects inert spawners. - **Spawns are fake by default.** Inject a recording `spawnFn` into `createNodeSpawner`, `DetachedLauncher` or the other self-spawn seams. Under test `KYBERDASH_SPAWN_GUARD=deny` refuses any spawn that gets through, and the test that caused it fails. - **A test that needs a real child** calls `allowRealSpawns(reason)` from `dash/tests/setup/spawn-guard.ts`, with a reason that states the bound. - **Every self-spawn goes through `guardedSpawn`** in `dash/src/process/spawn-guard.ts`. Do not import `child_process` spawn for a self-spawn anywhere else; `dash/tests/spawn-sites.test.ts` fails the build if you do. **Adding a spawn site.** A new `child_process` spawn, exec or fork call, a `new Worker`, or a Playwright `webServer` under `dash/` fails `dash/tests/spawn-sites.test.ts` until it has an entry in `dash/tests/spawn-sites.allowlist.ts` with `file`, `pattern`, `bound` and `note`. The `bound` must say how the site is limited: a timeout, a tree kill, a child closed on exit, an `afterEach` kill, an injected fake, or a bounded external tool. A site with no limit is written "NO TIMEOUT" and listed as a follow-up; that is a residual, not a bound. Add the entry in the same change as the site. An entry covers one file and one API name, so a second site of that kind in the same file still needs its own bound stated in review.