<!-- ✂ docujoint template sample — replace with your own content, then delete this comment. -->

# {{NAME}}

A software-system knowledge base governed by a declarative format
(`format.yaml`) and checked by docujoint. Scaffolded {{DATE}} from the
`programming` template.

```sh
dj lint --all --vault vault --format format.yaml          # enforce the format
dj index --vault vault --format format.yaml --write       # maintain the catalogue
dj report --vault vault --format format.yaml \
  --dashboard dashboard.yaml                                  # evaluate indicators
dj dashboard --vault vault --format format.yaml \
  --dashboard dashboard.yaml --out dashboard.html             # interactive app
```

## How this vault segments the system

| directory | types | the idea |
|---|---|---|
| `Apps/<App>/` | app, page, module | one doc per app; its pages and app-local modules beneath it |
| `Shared/` | module | cross-app reusable pieces — placement documents ownership |
| `Services/` | service, integration | internal services and third-party providers, with typed `## Endpoints` |
| `Events/` | event | one doc per topic/queue: message contract + producers/consumers |
| `Data/<db>/` | database, table, enum | per-database docs; tables with typed `## Columns`, canonical values as parsed `## Values` |
| `Flows/<Flow>/` | flow | trunk doc (shared steps + `## Scenarios` + `## Features`) with branch docs beside it — steps are content, never files |
| `Actors/` | actor | who acts — so "everything the buyer touches" is a query |
| `Engineering/` | engineering-note, decision | practices and ADRs (with a parsed status) |
| `Conventions/` | convention | glossary and writing rules |
| `Team/` | person | who is on the team — what an `Owner` cell links to |

## The load-bearing ideas

- **State is derived, never stored.** Features derive built/partial/missing/
  drift from Implemented + Gap + evidence; scenarios derive covered/untested
  from test evidence. Status columns are forbidden by the format.
- **Tests are evidence, not documents** — `test://` URIs on the exact row they
  prove; the dashboard computes "untested unhappy paths" as a number.
- **Open questions are the doubt channel** — every type carries them, and
  `About` ties a question to the exact feature it blocks. Ship each question
  with proposed `Options` (one `(Recommended)`) so answering is picking a
  verdict, not composing prose.
- **Answered is not done.** An answer is knowledge that arrived; the work is
  folding it into the prose or a feature's Gap. Only then does the row move to
  `archived` — so the question list is a worklist, never a graveyard.
- **Flows carry both surfaces.** `## Scenarios` enumerate the paths with test
  coverage; `## Features` carry the traceability of what each step must do,
  with evidence (`step` is their usual kind). Anomalies point at scenarios;
  open questions point at features.
- **Evidence schemes** (`repo:// route:// api:// db:// event:// test://`) keep
  claims checkable; connect a scanner via `--inventory` to detect drift.
- **Ownership is per FEATURE, not per document** — the `Owner` cell holds a
  LINK into `Team/`, so "what is Robin on?" is a query over the graph. When one
  document's rows point at different people the format says so
  (`features-owner-split`): nobody holds the whole path.
- **Anomalies are open questions aimed at a scenario** whose documented outcome
  reads like a defect. They assert nothing the scenario does not already say,
  and always offer "this is intended" — the judgement belongs to the reader.

## The interactive surfaces

`dj dashboard` (or `dj dashboard`, which writes back) renders more than a
report — the format declares what is editable and the host decides where those
writes go:

- **Inline controls.** `Status` and `Owner` cells are dropdowns: a single-field
  edit form (`forms.set-status`, `forms.assign`) attached to its own column.
  The assign picker's choices are the documents in `Team/` (`from_concepts`),
  and a status picker reads the column's declared `enum` (`from_enum`) — no
  option list is ever hand-written.
- **Answer forms.** A question or anomaly row answers in place, choosing from
  the row's OWN proposed `Options` (`;`-separated, one marked `(Recommended)`).
- **Capture.** The same questions become ledger entries (`feedback.jsonl`)
  where the host cannot write documents — that is what `when: read-only` says.
- **Power search.** The Work page composes filters as tokens of
  *property · operator · value*: assigned to X, of this kind, still lacking
  evidence. Properties are declared columns plus `state` / `document` / `type`;
  vocabularies come from the format and the vault.
- **A composed view.** `views:` in dashboard.yaml is an ordered list of widgets
  (`dj catalog` lists every name) — the Triage page is a note, a stat row
  and two row tables, arranged by the definition rather than by a template.
- **A board per person.** `for_each: { type: person }` instantiates ONE view
  definition once per document of that type, substituting `{title}`, `{path}`
  and any frontmatter field. Each board carries five numbers of its own
  (pending features · open questions · open anomalies · pending gaps ·
  untested) and the three tables behind them as **tabs**, each tab showing its
  own count. Add a person to `Team/` and their board appears — no dashboard
  edit. `navigation:` points at the whole set with `views: person-board`.
- **Long lists fold.** Every rows view groups by the document that owns the
  rows, and each group collapses — with one control to fold or unfold all of
  them. State is per view, so the tabs on a board fold independently.
