# Packaging Audit — `src/` runtime coverage & sensitive content

**Slug:** `audit-packaging-src-coverage`
**Plan:** f071a28e-82dc-4a68-b945-d0f2c235af82 (fix-npm-packaging-events-missing)
**Task:** defdc33d-7566-453d-948f-83d23ef614e9 (orderIndex 0, agent=ranger)
**Mode:** sensory-analyst (cartography + audit)
**Scope:** module:src/** + package.json
**Date:** 2026-06-28

---

## TL;DR

Current `files` whitelist in `package.json` includes only 5 of 9 `src/` subdirectories and omits all root-level `.ts` files. As a result, the published v0.2.6 tarball is **missing 15 runtime files** (including both main entry points `src/index.ts` and `src/plugin.ts`) and ships **30 test files** (357 KB) that have no runtime caller. Recommended fix: replace the granular whitelist with blanket `"src"` and add a `.npmignore` (or `!`-exclude patterns) dropping `**/__tests__/**` and `**/*.test.ts`.

---

## 1. File inventory (src/)

| Dir / root | Runtime .ts | Test .ts | Other | Total bytes |
|---|---|---|---|---|
| `src/` (root) | 3 | 1 | 0 | 153,645 |
| `src/cli/` | 7 | 5 | 0 | 113,141 |
| `src/config/` | 1 | 2 | 0 | 16,375 |
| `src/db/` | 17 | 13 | 0 | 305,938 |
| `src/events/` | 1 | 1 | 0 | 19,101 |
| `src/http/` | 10 | 4 | 15 (web assets) | 188,256 |
| `src/mem/` | 1 | 0 | 0 | 1,756 |
| `src/orchestrator/` | 4 | 2 | 0 | 45,822 |
| `src/sdk/` | 1 | 0 | 0 | 2,410 |
| `src/worktrees/` | 2 | 0 | 0 | 10,261 |
| **Total** | **47** | **28** | **15** | **~857 KB** |

Note: counts above match `find src -type f -name "*.ts"`. Root files: `index.ts` (698B), `lib.ts` (1.3KB), `plugin.ts` (65KB), `plugin.test.ts` (86KB).

---

## 2. Diff: repo (78 tracked) vs tarball v0.2.6 (80 entries)

Verified with `npm pack --dry-run` and `git ls-files src/`.

### 2.1 In repo, NOT in v0.2.6 tarball (BROKEN — runtime required)

| Path | Runtime caller(s) |
|---|---|
| `src/index.ts` | self (package.json `main` + `exports["."]`) |
| `src/lib.ts` | `src/index.ts:21,36` |
| `src/plugin.ts` | `src/index.ts:37` + self (export `./plugin`) |
| `src/events/bus.ts` | `src/db/{plans,sessions,tasks,plan-create,plan-update-status}.ts` + `src/http/routes/events.ts` |
| `src/mem/scoped.ts` | `src/lib.ts:19` |
| `src/orchestrator/background.ts` | `src/lib.ts:26` + `src/plugin.ts:83` |
| `src/orchestrator/scheduler.ts` | `src/lib.ts:46` + `src/plugin.ts:83` |
| `src/orchestrator/memory-hook.ts` | `src/lib.ts:33` |
| `src/orchestrator/reconciler.ts` | `src/lib.ts:39` |
| `src/worktrees/manager.ts` | `src/lib.ts:59` + `src/plugin.ts:83` |
| `src/worktrees/state.ts` | `src/lib.ts:65` |
| `src/plugin.test.ts` | (test — but currently NOT shipped either) |
| `src/events/__tests__/bus.test.ts` | (test — but currently NOT shipped either) |
| `src/orchestrator/background.test.ts` | (test — but currently NOT shipped either) |
| `src/orchestrator/scheduler.test.ts` | (test — but currently NOT shipped either) |

**11 runtime files missing** (incl. 2 main entrypoints + 1 critical shared dep `events/bus.ts`). **4 test files also missing** because they're under un-whitelisted dirs.

### 2.2 In v0.2.6 tarball, NOT in repo (gitignored but bundled)

17 files under `src/http/web/`:
- `index.html` (397 B)
- 16 hashed assets in `src/http/web/assets/` (7 JS + 9 CSS, ~125 KB total)

These are listed in `.gitignore` (`src/http/web/` line). npm bundles them anyway because the `files` whitelist includes the parent dir `src/http/`.

### 2.3 In both (test files currently shipped — bloat)

30 test files totaling **365,614 bytes (~357 KB)**:
- 4 `__tests__/` directories: `cli`, `config`, `events`, `http`
- 22 sibling `*.test.ts` files across `cli/`, `config/`, `db/`, `orchestrator/`
- 4 sibling test files under `db/` with non-`.test.` suffix pattern (`plan-files.test.ts`, etc.)
- `src/plugin.test.ts` (root, currently NOT shipped because dir not whitelisted)

None have runtime callers: `rg "from ['\"]\\.{1,2}/[^'\"]+\\.test\\.ts" src/` returns no matches.

---

## 3. Runtime import graph (cross-directory only)

Total cross-dir edges: 28. Full table below.

### Entry point reachability matrix

| Path | CLI (`bin`) | `index.ts` | `plugin.ts` | `db/index.ts` |
|---|---|---|---|---|
| `src/cli/*` | yes | — | — | — |
| `src/index.ts` | — | self | — | — |
| `src/lib.ts` | — | yes | yes | — |
| `src/plugin.ts` | — | yes | self | — |
| `src/config/schema.ts` | yes (serve/install) | yes (plugin) | yes | — |
| `src/db/*` | partial (serve/vacuum/smoke/analyses) | yes (plugin) | yes | yes (named) |
| `src/events/bus.ts` | yes (serve→routes/events) | yes (db/*) | yes (db/*) | — |
| `src/http/*` | yes (serve) | yes (plugin→server) | yes | — |
| `src/mem/scoped.ts` | — | yes (lib) | yes (lib) | — |
| `src/orchestrator/*` | — | yes (lib + plugin) | yes | — |
| `src/sdk/client.ts` | — | yes (plugin) | yes | — |
| `src/worktrees/*` | — | yes (lib + plugin) | yes | — |

**Closure from `src/index.ts` reaches everything runtime except `src/cli/*`.** The CLI bin entry point reaches config/db/http/events but NOT mem/orchestrator/worktrees/sdk. The two top-level entrypoints (`src/index.ts`, `src/plugin.ts`) are both **completely missing from the tarball** — the published package literally cannot be imported as a plugin.

### Top import hot-spots

- `src/db/plans.ts` imports `src/events/bus.ts` (line 14) — every DB mutation event-broadcast breaks without it
- `src/lib.ts` re-exports 11 modules from mem/orchestrator/worktrees (lines 19, 26, 33, 39, 46, 59, 65)
- `src/plugin.ts` imports 16 src/db files + 4 cross-cutting modules (lines 19-71)

---

## 4. Sensitive content scan

Searched src/ for: `.env`, secrets, fixtures, snapshots, mocks, datasets >50KB, credentials.

**Findings:**
- **No `.env`, secrets, fixtures, snapshots, mocks, or credentials under `src/`.**
- 1 non-TS/JS file >50KB: `src/http/web/assets/index-CwcPoPk5.js` (106,894 B) — vite-built SPA bundle, gitignored.
- Root `.env` (30 B) exists but is gitignored — blanket `src` won't include it.

**Test files (357 KB)** are not "sensitive" per se but are dead weight at runtime. Recommended exclude.

---

## 5. Other top-level dirs in current `files`

| Dir | Tracked | Sensitive? | Comment |
|---|---|---|---|
| `agents/` | 23 .md files | N | System prompts — required |
| `config/` | 2 JSON files | N | ndomo.config.json + ndomo.schema.json — required |
| `docs/` | 18 .md files | N | Reference docs — large but useful |
| `skills/` | 50+ .md files | N | Skill definitions — required |
| `tools/` | (verify) | (audit) | (verify) |
| `.env.example` | 1 file | N | Template only |
| `bun.lock` | 1 file | N | Reproducible installs |

Spot-checked `skills/` for `password|secret|api_key|token`: 10 hits, all are documentation references (SKILL.md text mentioning these concepts), no actual credentials. Safe to publish.

`.env` exists at root (30 B) — **gitignored**, won't ship.

---

## 6. Recommendation for new `files` field

### Option A — minimal fix (recommended)

```json
"files": [
  ".env.example",
  "agents",
  "bun.lock",
  "config",
  "docs",
  "README.md",
  "scripts/install.sh",
  "scripts/smoke-http.sh",
  "scripts/smoke-install.sh",
  "scripts/smoke-web.sh",
  "scripts/smoke.sh",
  "skills",
  "src",
  "tools"
]
```

Plus new `.npmignore`:
```gitignore
**/__tests__/**
**/*.test.ts
```

### Justification

- Blanket `"src"` includes everything tracked under src/ (78 files).
- `.npmignore` excludes 30 test files (357 KB) — no runtime caller.
- Web assets (`src/http/web/**`) are gitignored — npm won't pick them up.
- All other top-level entries unchanged.

### Effect on tarball size

| Category | v0.2.6 | proposed | delta |
|---|---|---|---|
| src/ runtime files | 47 | 47 | 0 |
| src/ test files | 28 (357 KB) | 0 | -357 KB |
| src/http/web/ | 17 (125 KB) | 0 | -125 KB |
| Other dirs | unchanged | unchanged | 0 |
| **src/ total** | ~700 KB | ~375 KB | **-482 KB (-69%)** |

### Option B — keep web assets shipped (alternative)

If shipping pre-built web assets is desired (because `web:build` is NOT auto-run by install):

```json
"files": [
  ...same as above,
  "src",
  "!src/**/*.test.ts",
  "!src/**/__tests__/**",
  ...
]
```

But this would re-introduce stale-hash risk if vite rebuilds with different hashes post-install. Also requires removing the `src/http/web/` line from `.gitignore` so npm packs them.

### Risk observations (not recommendations)

- `src/cli/install.ts` (43 KB) installs agents/skills/config but does **not** run `web:build`. After Option A, fresh users running `bunx ndomo@X.Y.Z serve` will get the HTTP server up but the SPA at `/` will 404 on assets until they manually run `bun run web:build`. This is an **install-flow gap**, independent of the `files` field. Flagged for warden to address in release notes or install.ts.
- Tests currently shipped. Removing them (Option A) is a behavior change vs v0.2.6, but tests have no runtime impact — strictly beneficial.
- `bun.lock` is included — ensures reproducible installs. Acceptable trade-off (105 KB).
- `docs/` is included — ~250 KB but useful for self-contained installs. Could be excluded if size matters.

---

## 7. Validation steps for craftsman

After applying Option A:

1. `npm pack --dry-run` — verify exactly 47 runtime src/ files + top-level dirs, no tests, no web assets.
2. `bun run typecheck` — must still pass (no source changes, only packaging metadata).
3. Extract tarball into `/tmp/opencode/ndomo-test/` and verify:
   - `node src/cli/index.ts help` errors gracefully (TS needs bun, expected)
   - `bunx --bun /tmp/opencode/ndomo-test/package/src/cli/index.ts help` works
4. Confirm `src/index.ts`, `src/plugin.ts`, `src/events/bus.ts`, `src/lib.ts`, `src/mem/scoped.ts`, `src/orchestrator/*`, `src/worktrees/*` are all present.

## 8. Validation steps for warden (post-publish smoke)

1. `bunx ndomo@0.2.7 help` — confirm bin resolves.
2. `bunx ndomo@0.2.7 serve --help` — confirm `events/bus.ts` no longer errors.
3. `bunx ndomo@0.2.7 status --plans` — confirm DB layer initializes (uses events internally).
4. Optionally check tarball on npm registry: `npm view ndomo@0.2.7 dist.tarball | xargs curl -sL | tar -tzf - | rg "src/" | wc -l` should be ~47.