Model
All nouns live in the files matched by [prodc].needs. Any file may carry needs:, goals:, releases:, roles:, principles:, decisions:. Cross-references are string ids, checked at load.
Nouns
| Noun |
One line |
Key |
| Need |
what a named person wants; a flow is a need with children |
needs: |
| Source |
where it came from; primary/secondary/assumption — no primary/secondary = opinion |
sources: on a need |
| Proof |
<adapter>:<payload> resolved against the repo |
proofs: on a need |
| Goal |
measurable objective needs trace up to; id, text, metric |
goals: |
| Release |
ship slice; list order = ship order; id, text |
releases: |
| Role |
a named function in the product's world; who+client is an instance of it (John@Sincerely is the owner); id, text |
roles: |
| Principle |
the product vision, held as given (not validated); an out_of_scope withdrawal cites it, and revising it re-opens decisions taken under it |
principles: |
| Decision |
the solution chosen for a need over the alternatives rejected (OST), resting on which principles; needs required |
decisions: |
| Attestation |
a review that the proofs establish the need; verdict pass/concerns/fail (only pass clears it) |
attestation: on a need |
File-level who, client default every need in that file.
Need fields
| Field |
Means |
id |
unique across all files |
text |
the need; EARS shape (When …, who can …) is checked softly |
description |
optional free-form markdown detail (edge cases, rationale, a worked scenario); not EARS-checked — keeps the one-line text scannable (#73) |
who |
the person (free text — John, Jacob) |
role |
Role id — the role who plays; checked against declared roles: |
must |
must-have; a must with no proof tops the board |
contradicts |
need ids this one opposes (symmetric); lint flags a pair left both-live |
sources |
evidence list (see ladder) |
proofs |
locators (leaf needs only; a flow uses seam) |
children |
sub-need ids; makes this a flow that rolls them up |
seam |
end-to-end locators for a flow's between-steps behaviour; flow is DELIVERED only when every child and the seam are green |
client |
this instance is for one client; absent = shared baseline |
variant_of |
baseline id this specialises; variants cannot chain |
not_variant_of |
ids confirmed not a shared baseline; silences recurrence --suggest / lint for that pair |
not_duplicate_of |
ids confirmed not a duplicate; silences dupes / lint for that pair |
importance |
positive int, refines plan ranking only; must be on the [importance] rubric when one is declared |
importance_set_at |
ISO date importance was last set; set importance= stamps it, lint flags it missing or older than [lint].importance_revisit_days |
draft |
true = staged: loads, but hidden and uncounted until promoted (set <id> draft=false); --include-drafts shows it |
claim |
what delivering this would establish |
attestation |
who, date, kind human/ai, verdict, comment |
goal |
Goal id; absent = flagged ungoaled |
release |
Release id |
product |
false = infra/NFR, listed but not counted |
withdrawn |
reason, date — a decision against the need (won't-do): always off the active board and out of coverage, with the record as its trace; set with withdraw, cleared with reinstate (#74) |
answer |
yes/no/inconclusive — which way a settled need resolved. DELIVERED = settled; answer is the direction. A settled-NO (a disproven hypothesis, a failed A/B test, a refuted conjecture) is DELIVERED and still counts — a result, not a gap, and not withdrawn. Universal: a product bet and a research question use it the same way. Authored, never computed; unset = open-ended. Flagged if set while not DELIVERED |
States
| State |
Means |
Fails? |
| DELIVERED |
every proof passes (* = declared by tag/existence, no results) |
no |
| PENDING |
proof found, not green |
no |
| HOLE |
no proof — an honest gap |
never |
| BROKEN |
a locator resolves to nothing |
yes |
| UNRESOLVED |
a source could not be read (sibling absent) |
no, excluded from coverage |
Source fields
| Field |
Means |
kind |
see ladder below |
who |
the person (a primary source needs one) |
date |
when it was said/written; missing = warned |
quote |
verbatim (a primary source wants a quote or a locator) |
locator |
ticket/doc ref (a secondary source needs one); [sources.*] adapters check it resolves |
observed_at |
ISO date the evidence was recorded; capture stamps it. Newest across sources = the need's evidence age (status --stale, [lint].stale_after_days) |
Ladders
Strongest first — the academic primary/secondary split, plus the floor.
Source kind |
Is |
primary |
straight from the user: an interview, their own email / message / ticket |
secondary |
existing/mediated material about them: a report, a third-party or internal doc |
assumption |
our own stated guess — no external evidence yet (the floor every need has at least) |
A need with no primary or secondary source — only an assumption, or nothing — is an
opinion (nothing from the user or the world yet). Old kind names still load, mapped on:
interview→primary, artifact→secondary, proxy/internal→assumption.
Attestation kind |
Is |
human |
a person reviewed the proof link |
ai |
a model reviewed it (who = model id) |
| (none) |
DELIVERED but unreviewed — warned |