Skip to content
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased] — PROVING GROUND

### Added

- **`coverage` view** — Code-to-spec gap analysis: identifies `crate:`/`module:`/`pkg:` nodes lacking `implements` edges to `spec:`/`adr:` targets. Returns `meta.linked`, `meta.unlinked`, and `meta.coveragePct`
- **Echo ecosystem seed fixture** — `test/fixtures/echo-seed.yaml` with 55 nodes and 70 edges for integration testing (5 milestones, 5 specs, 5 ADRs, 5 docs, 15 crates, 11 tasks, 9 issues)
- **PROVING GROUND integration tests** — `test/proving-ground.test.js` validates 5 real project management questions against the Echo seed with deterministic ground truth
- **Dogfood session transcript** — `docs/dogfood-session.md` documents CLI walkthrough of all 5 questions with answers and timing

### Changed

- **Test count** — 162 tests across 9 files (was 143 across 8)

## [2.0.0-alpha.1] - 2026-02-11

### Added
Expand Down
147 changes: 147 additions & 0 deletions docs/dogfood-session.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# PROVING GROUND — Dogfood Session Transcript

> **Date**: 2026-02-11
> **Seed**: `test/fixtures/echo-seed.yaml` — Echo ecosystem (55 nodes, 70 edges)
> **Runtime**: Node.js 20, vitest 3.2.4

## Setup

```bash
$ git mind init
Initialized empty git-mind graph

$ git mind import test/fixtures/echo-seed.yaml
Imported 55 nodes, 70 edges (144ms)
```

---

## Q1: What blocks milestone M2?

**View**: `milestone`

```bash
$ git mind view milestone --json | jq '.meta.milestoneStats["milestone:M2"]'
{
"total": 2,
"done": 0,
"pct": 0,
"blockers": ["issue:E-003", "issue:E-004"]
}
```

**Answer**: Two issues block M2 — `issue:E-003` (REST schema breaks on nested objects) blocks `task:E-007`, and `issue:E-004` (validation rejects valid payloads) blocks `task:E-008`. Both M2 tasks are incomplete (0%).

**Timing**: <1ms

---

## Q2: Which ADRs lack implementation?

**View**: `traceability`

```bash
$ git mind view traceability --json | jq '.meta.gaps | map(select(startswith("adr:")))'
[
"adr:003-encryption-at-rest",
"adr:004-rest-vs-grpc"
]
```

**Answer**: 2 of 5 ADRs have no `implements` edge pointing at them. ADR-003 (encryption at rest for PII) and ADR-004 (REST over gRPC) are decisions with no code backing. The other 3 ADRs are covered: `echo-core` implements ADR-001, `echo-db` implements ADR-002, `echo-api` implements ADR-005.

**Timing**: <1ms

---

## Q3: Which crates are unlinked to specs?

**View**: `coverage` (new in PROVING GROUND)

```bash
$ git mind view coverage --json | jq '.meta'
{
"linked": [
"crate:echo-core",
"crate:echo-api",
"crate:echo-db",
"crate:echo-auth",
"crate:echo-queue",
"crate:echo-web"
],
"unlinked": [
"crate:echo-crypto",
"crate:echo-cli",
"crate:echo-config",
"crate:echo-log",
"crate:echo-test-utils",
"crate:echo-bench",
"crate:echo-migrate",
"crate:echo-plugin",
"crate:echo-sdk"
],
"coveragePct": 40
}
```

**Answer**: 9 of 15 crates have no `implements` edge to any spec or ADR. Coverage is 40%. The unlinked crates are utility/tooling crates (crypto, cli, config, log, test-utils, bench, migrate, plugin, sdk) — they may not need formal specs, but the gap is now visible.

**Timing**: <1ms

---

## Q4: What should a new engineer read first?

**View**: `onboarding`

```bash
$ git mind view onboarding --json | jq '.meta.readingOrder | map(select(startswith("doc:")))'
[
"doc:getting-started",
"doc:architecture-overview",
"doc:api-reference",
"doc:contributing",
"doc:deployment-guide"
]
```

**Answer**: Start with `doc:getting-started` (the root — no dependencies). Then `doc:architecture-overview` (depends on getting-started). After that, `doc:api-reference` and `doc:contributing` (both depend on architecture-overview). Finally `doc:deployment-guide` (depends on getting-started, so it could be read earlier, but topological sort with alphabetical tie-breaking places it last).

**Timing**: <1ms

---

## Q5: What's low-confidence?

**View**: `suggestions` + `computeStatus()`

```bash
$ git mind view suggestions --json | jq '.edges[] | {from, to, label, confidence: .props.confidence}'
{ "from": "issue:E-016", "to": "issue:E-017", "label": "relates-to", "confidence": 0.2 }
{ "from": "issue:E-018", "to": "crate:echo-crypto", "label": "relates-to", "confidence": 0.3 }
{ "from": "issue:E-019", "to": "spec:003-web-sockets", "label": "relates-to", "confidence": 0.4 }
{ "from": "issue:E-020", "to": "doc:contributing", "label": "relates-to", "confidence": 0.3 }

$ git mind status --json | jq '.health.lowConfidence'
4
```

**Answer**: 4 edges have confidence below 0.5 (the low-confidence threshold). All are `relates-to` edges — likely AI-suggested links that haven't been reviewed. Confidence values range from 0.2 to 0.4.

**Timing**: <1ms

---

## Summary

| # | Question | View | Answer | Time |
|---|----------|------|--------|------|
| 1 | What blocks M2? | `milestone` | `issue:E-003`, `issue:E-004` | <1ms |
| 2 | ADRs lacking impl? | `traceability` | `adr:003-encryption-at-rest`, `adr:004-rest-vs-grpc` | <1ms |
| 3 | Unlinked crates? | `coverage` | 9 of 15 (40% coverage) | <1ms |
| 4 | Read first? | `onboarding` | `doc:getting-started` → `doc:architecture-overview` | <1ms |
| 5 | Low-confidence? | `suggestions` | 4 edges (0.2–0.4) | <1ms |

**Total query time**: ~1ms for all 5 questions against a 55-node, 70-edge graph.

All 5 questions answered correctly from the graph alone — no manual inspection, no external tools, just views.
45 changes: 45 additions & 0 deletions src/views.js
Original file line number Diff line number Diff line change
Expand Up @@ -401,5 +401,50 @@ defineView('onboarding', (nodes, edges) => {
};
});

defineView('coverage', (nodes, edges) => {
// Code-to-spec gap analysis: which code nodes lack implements edges to specs?
const codePrefixes = new Set(['crate', 'module', 'pkg']);
const specPrefixes = new Set(['spec', 'adr']);

const codeNodes = nodes.filter(n => {
const p = extractPrefix(n);
return p && codePrefixes.has(p);
});
const specNodes = new Set(
nodes.filter(n => {
const p = extractPrefix(n);
return p && specPrefixes.has(p);
})
);

// Code nodes that have at least one implements edge to a spec/adr
const linkedSet = new Set(
edges
.filter(e => e.label === 'implements' && specNodes.has(e.to))
.map(e => e.from)
);

const linked = codeNodes.filter(n => linkedSet.has(n));
const unlinked = codeNodes.filter(n => !linkedSet.has(n));

// Self-contained subgraph: edges where both endpoints are in the result
const resultNodes = new Set([...codeNodes, ...specNodes]);
const resultEdges = edges.filter(
e => e.label === 'implements' && resultNodes.has(e.from) && resultNodes.has(e.to)
);

return {
nodes: [...resultNodes],
edges: resultEdges,
meta: {
linked,
unlinked,
coveragePct: codeNodes.length > 0
? Math.round((linked.length / codeNodes.length) * 100)
: 100,
},
};
});

// Capture built-in names after all registrations
builtInNames = new Set(registry.keys());
Loading