Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD across contents and paths, upstream package/repo coordinates -> @golem15/msd-core and golem15com/msd-core. Deep links into upstream history, sibling upstream packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is. Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line, package/plugin identity, regenerated lockfile, install-tree fixtures, derived registries and benchmark baseline; migration checksum baseline re-locked (MSD keeps its own install state, so no install had applied the old sums); sort-order and regex-escaped expectations in tests adjusted.
199 lines
7.9 KiB
Markdown
199 lines
7.9 KiB
Markdown
# Consume the planning snapshot
|
|
|
|
You are building something that needs to know where a MSD project stands —
|
|
a dashboard, a status page, a harness UI, a bot that comments on a pull request.
|
|
`planning inspect` gives you that as one JSON document, so you never have to
|
|
parse `ROADMAP.md`, `REQUIREMENTS.md`, `*-PLAN.md`, or `*-SUMMARY.md` yourself.
|
|
|
|
This guide covers the whole path from *off* to *reading a value you can trust*,
|
|
including the part most integrations get wrong: telling **"nothing to report"**
|
|
apart from **"could not look."**
|
|
|
|
## Before you start
|
|
|
|
You need `msd-tools` on the machine, and a project directory containing
|
|
`.planning/`. Nothing has to be enabled or configured — the command is read-only
|
|
and always available.
|
|
|
|
## 1. Get a snapshot
|
|
|
|
```bash
|
|
msd-tools query planning inspect
|
|
```
|
|
|
|
The dotted form is identical, if that reads better in your code:
|
|
|
|
```bash
|
|
msd-tools query planning.inspect
|
|
```
|
|
|
|
The command takes no arguments. If you pass one, it fails loudly rather than
|
|
ignoring it — see [Troubleshooting](#troubleshooting).
|
|
|
|
To inspect a project other than your current directory, use the global `--cwd`
|
|
flag, which every `msd-tools` command accepts:
|
|
|
|
```bash
|
|
msd-tools query planning inspect --cwd /path/to/project
|
|
```
|
|
|
|
## 2. Check the schema version first
|
|
|
|
```json
|
|
{ "schema_version": 1 }
|
|
```
|
|
|
|
**Reject any version you were not written against.** Do this before you touch
|
|
any other field:
|
|
|
|
```javascript
|
|
const snapshot = JSON.parse(stdout);
|
|
if (snapshot.schema_version !== 1) {
|
|
throw new Error(`Unsupported planning snapshot schema: ${snapshot.schema_version}`);
|
|
}
|
|
```
|
|
|
|
Best-effort-parsing an unknown shape is how an integration starts silently
|
|
reporting wrong numbers after an upgrade. A hard failure is the kinder outcome.
|
|
|
|
## 3. Read a value — and check its scope
|
|
|
|
Most answers arrive alongside a `scope`. It tells you whether the value is a
|
|
real answer or a placeholder for one that could not be produced:
|
|
|
|
| `scope` | Meaning | What to render |
|
|
|---|---|---|
|
|
| `complete` | The read succeeded. The value is real — **including when it is `0` or `[]`** | The value |
|
|
| `truncated` | Part of the source could not be read | The value, marked partial |
|
|
| `unscoped` | The source exists but nothing could be located in it | "Unknown" |
|
|
| `unreadable` | The source could not be read at all | "Unknown" |
|
|
|
|
The distinction that matters: **`complete` with an empty value is a real answer.**
|
|
A milestone with zero phases genuinely has zero phases. `unreadable` with an
|
|
empty value means nobody looked. Rendering both as "0 phases" is the bug this
|
|
field exists to prevent.
|
|
|
|
```javascript
|
|
const phases = snapshot.progress.accepted_phases;
|
|
if (phases.scope !== 'complete') {
|
|
render('Progress unavailable'); // could not look
|
|
} else {
|
|
render(`${phases.completed} / ${phases.total}`); // real, even if 0 / 0
|
|
}
|
|
```
|
|
|
|
## 4. Handle a withheld percentage
|
|
|
|
`progress.accepted_phases` and `progress.completed_plans` each carry
|
|
`{completed, total, percent, scope}`. **`percent` is `null` whenever `scope` is
|
|
not `complete`.**
|
|
|
|
That is deliberate. A percentage computed from a partial phase set is a
|
|
confidently wrong number, and a consumer cannot tell it apart from a real one.
|
|
Do not substitute `0`, and do not compute your own from `completed / total` —
|
|
those counts are partial too.
|
|
|
|
```javascript
|
|
const { percent } = snapshot.progress.completed_plans;
|
|
render(percent === null ? '—' : `${percent}%`);
|
|
```
|
|
|
|
`percent: 0` under a `complete` scope is a real 0 and should be rendered.
|
|
|
|
## 5. Read the three kinds of phase evidence separately
|
|
|
|
Each entry in `phases[]` reports three independent signals. **They are not
|
|
combined into one verdict, and you should not combine them either** — they
|
|
answer different questions and can legitimately disagree.
|
|
|
|
| Field | Question it answers |
|
|
|---|---|
|
|
| `verification` | Did the verifier pass this phase? This is what `complete` is derived from |
|
|
| `roadmap_acceptance` | Is the ROADMAP checkbox ticked? |
|
|
| `uat` | Are there unresolved user-acceptance items? |
|
|
|
|
`roadmap_acceptance` carries `authoritative: false`, and it means it. A ticked
|
|
checkbox is a human annotation with no machine authority — completion comes from
|
|
disk state. If you show the checkbox, label it as an annotation, not as status.
|
|
|
|
A phase can be `complete: true` with open UAT items. That is a real state, not a
|
|
contradiction.
|
|
|
|
## 6. Handle `unknown` rather than guessing
|
|
|
|
Where evidence is absent or two sources disagree, the value is `null` or
|
|
`"unknown"` and `diagnostics[]` says why. Nothing is inferred.
|
|
|
|
The case you will hit most often is task-scoped file provenance:
|
|
|
|
| `provenance` | What it means | What to show |
|
|
|---|---|---|
|
|
| `task_scoped` | The summary attributed files to this exact task | The file list |
|
|
| `plan_scoped` | A summary exists, but only lists files for the whole plan | "Not attributed" — **not** the plan's list |
|
|
| `absent` | No summary yet | "Not started" |
|
|
|
|
`plan_scoped` is the common case and is not an error. Attributing a plan's file
|
|
list to one of its tasks would be a guess, so the snapshot declines to make it.
|
|
The plan-level list is still available at `plans[].changed_files`, where it is
|
|
accurate.
|
|
|
|
When a task's planned and changed files both exist and disagree, `agreement` is
|
|
`"conflicting"` and both lists are present, unreconciled. Show both; do not pick.
|
|
|
|
## 7. Read the diagnostics
|
|
|
|
Every non-answer above has a matching entry in `diagnostics[]`:
|
|
|
|
```json
|
|
{ "code": "requirement_unmapped", "subject": "AUTH-03", "detail": "..." }
|
|
```
|
|
|
|
`code` is a stable identifier from a frozen vocabulary — match on it, never on
|
|
`detail`, whose wording may change. Common codes:
|
|
|
|
| Code | Meaning |
|
|
|---|---|
|
|
| `planning_root_absent` | No `.planning/` directory — every section below is a non-answer |
|
|
| `roadmap_unscoped` | No milestone version could be resolved; none was invented |
|
|
| `requirements_absent` | No `REQUIREMENTS.md` |
|
|
| `requirement_unmapped` | A requirement no Traceability row maps to a phase |
|
|
| `requirement_phase_unknown` | A requirement mapped to a phase that is not on disk |
|
|
| `orphan_phase_dir` | A phase directory the current milestone does not declare |
|
|
| `task_changed_files_plan_scoped` | Task-level file attribution unavailable (see step 6) |
|
|
| `task_changed_files_conflicting` | Planned and changed files disagree |
|
|
| `percent_withheld` | A percentage was suppressed because its scope was not `complete` |
|
|
|
|
An empty `diagnostics[]` means every value in the snapshot is a real answer.
|
|
|
|
## 8. Handle a large payload
|
|
|
|
On a big project the JSON can exceed the ~50 KB console limit. `msd-tools`
|
|
handles this for you: it writes to a temp file and resolves the reference before
|
|
writing to stdout, so you always receive JSON. If you are invoking `msd-tools`
|
|
through a shell wrapper that captures stdout directly, no special handling is
|
|
needed.
|
|
|
|
## Troubleshooting
|
|
|
|
**`Unknown planning subcommand. Available: inspect`**
|
|
You typed a subcommand that does not exist. `inspect` is the only one.
|
|
|
|
**`planning inspect takes no arguments; got flag: --phase`**
|
|
v1 always returns the whole project. It refuses scoping arguments rather than
|
|
ignoring them — silently returning an unscoped snapshot to a caller who asked
|
|
for a scoped one would be worse. Filter the `phases[]` array on your side.
|
|
|
|
**Everything is `unknown` and `diagnostics[0].code` is `planning_root_absent`**
|
|
You are not in a MSD project directory. Use `--cwd`, or `cd` first.
|
|
|
|
**A phase you expect is missing from `phases[]`**
|
|
Check `orphan_phase_dirs[]`. `phases[]` is scoped to the phases the current
|
|
milestone's ROADMAP window declares; a directory on disk that the roadmap never
|
|
mentions is reported there instead, so that a genuinely orphaned directory
|
|
cannot masquerade as a planned phase.
|
|
|
|
## Related
|
|
|
|
- [`planning inspect` reference](../CLI-TOOLS.md#planning-inspect) — every field, with exact semantics
|
|
- [Resolve unreachable-guard findings](resolve-unreachable-guard-findings.md) — the same "nothing to report vs. could not look" distinction, one layer down
|