Documentation
¶
Overview ¶
Package roadmap joins the human-owned roadmap ticket store (`atm`) to current source evidence (docs/specs/REQUIREMENTS.tsv), current test receipts (a configured testvalidity.Projection receipts directory), and generated-doc state (a configured docs-state file) for the local dashboard snapshot (IPR-10, docs/plans/integrated-product-roadmap-2026-09-12.md).
This join never mutates the planning store: it runs only `atm roadmap` and `atm ticket show`, both listed read verbs (AGENTS.md invariant 4). Every missing or refused input is an explicit NOT_OBSERVED with a reason; nothing here invents a passing receipt, a resolved requirement, or a ready doc (AGENTS.md invariant 2). Ticket completion still requires the owning accepted criteria/gate workflow — this package only reports what it observed.
Index ¶
- Constants
- func CurrentTreeDigest(ctx context.Context, root string, timeout time.Duration) (string, error)
- func LoadRequirements(path string) (map[string]Requirement, error)
- func WorktreeDirty(ctx context.Context, root string, timeout time.Duration) (bool, error)
- type Blocker
- type DocState
- type EvidenceLink
- type MilestoneGroup
- type Options
- type Requirement
- type Snapshot
- type TestReceipt
- type Ticket
Constants ¶
const ErrorProfile = "corvint-dashboard-roadmap-error/0"
ErrorProfile is this join's error envelope profile, in the same style as corvint-dashboard-error/0 (cmd/corvint-dashboard-snapshot/main.go).
const Schema = "corvint-dashboard-roadmap/0"
Schema is this join's own wire profile. It is deliberately separate from corvint-dashboard-snapshot/0 (internal/dashboard/model): the roadmap join composes a different, less strictly typed input (a planning-store CLI) than the snapshot's git-repository/adapter pipeline, and folding it into that hashed, invariant-checked schema would require touching the snapshot compiler and its acceptance tests, which sit outside IPR-10's owned files.
Variables ¶
This section is empty.
Functions ¶
func CurrentTreeDigest ¶
CurrentTreeDigest reports the current HEAD tree object id for root via `git rev-parse HEAD^{tree}`, used to classify receipts as CURRENT or STALE. It reports the last committed tree, not uncommitted worktree edits — a receipt measured against a dirty tree is out of this join's scope and is a documented gap (see the IPR-10 dashboard evidence note).
func LoadRequirements ¶
func LoadRequirements(path string) (map[string]Requirement, error)
LoadRequirements parses docs/specs/REQUIREMENTS.tsv (an "id\tfile\tline\t title" header followed by one requirement per row) into an id-keyed lookup. It is strictly read-only: this package never writes to that file. The table is opened without blocking and read only as a regular file of at most maxInputFileBytes; a FIFO, device, or oversize table is an error. A row with fewer than four tab-separated fields is skipped rather than causing the whole load to fail, since a malformed row must not turn every requirement reference on the roadmap into a load error.
func WorktreeDirty ¶
WorktreeDirty reports whether root's worktree has any change not reflected in the tree CurrentTreeDigest measured, via `git status --porcelain=v1 --untracked-files=all --ignored=no` (no filters, no hooks). Non-empty output means dirty. A boundary failure is itself missing evidence (AGENTS.md invariant 2): it is reported dirty=true alongside the error so a caller that only checks the bool still refuses to render an unverifiable tree as clean.
Types ¶
type Blocker ¶
type Blocker struct {
Code string `json:"code"`
Detail string `json:"detail"`
TicketID *string `json:"ticketId,omitempty"`
}
Blocker mirrors one `atm ticket show` blocker entry verbatim.
type DocState ¶
type DocState struct {
Path string `json:"path,omitempty"`
SHA256 string `json:"sha256,omitempty"`
State string `json:"state"`
Reason string `json:"reason,omitempty"`
}
DocState is one ticket's generated-doc state, read from the configured docs-state file (internal/mcp/docsbridge's READY / SOURCE_REDERIVED consume states plus the page's content hash). State is NOT_OBSERVED (with Reason set) when no docs-state file is configured or no entry exists.
func LoadDocState ¶
LoadDocState reads localID's entry out of the configured docs-state JSON file (a map keyed by ticket local id, e.g. "IPR-10"). No repository convention for this file exists yet; it is a proposed minimal contract (see the IPR-10 dashboard evidence note). An absent path, unreadable, non-regular or oversize file, malformed JSON, or missing entry reports NOT_OBSERVED with a reason rather than an invented ready state.
type EvidenceLink ¶
type EvidenceLink struct {
RequirementID string `json:"requirementId"`
File string `json:"file,omitempty"`
Line string `json:"line,omitempty"`
Title string `json:"title,omitempty"`
Resolved bool `json:"resolved"`
Reason string `json:"reason,omitempty"`
}
EvidenceLink is one requirementRefs entry resolved against docs/specs/REQUIREMENTS.tsv. Resolved is false, and File/Line/Title stay empty, when the id has no row in that snapshot of the file — "unresolved" is reported explicitly rather than silently dropped. Reason is set when the table itself could not be read, so an unobserved table never reads as an ID the table lacks.
func ResolveRequirement ¶
func ResolveRequirement(requirements map[string]Requirement, id string) EvidenceLink
ResolveRequirement looks up id in requirements, reporting an EvidenceLink that states "unresolved" (Resolved: false, no file/line/title) rather than inventing a location when the id has no row in this snapshot of the file.
type MilestoneGroup ¶
type MilestoneGroup struct {
Milestone string `json:"milestone"`
Tickets []Ticket `json:"tickets"`
}
MilestoneGroup is every ticket sharing one milestone, in first-observed order from `atm roadmap`.
type Options ¶
type Options struct {
AtmBinary string
StoreRoot string
// RepoRoot is the repository whose tree TreeDigest names; the dirty
// check runs there, never in the planning store.
RepoRoot string
RequirementsTSV string
ReceiptsDir string
DocsStatePath string
TreeDigest string
GeneratedAt string
Timeout time.Duration
}
Options configures one Compile call.
type Requirement ¶
Requirement is one docs/specs/REQUIREMENTS.tsv row.
type Snapshot ¶
type Snapshot struct {
Schema string `json:"schema"`
GeneratedAt string `json:"generatedAt"`
Outcome string `json:"outcome"`
Reason string `json:"reason,omitempty"`
WorktreeDirty bool `json:"worktreeDirty"`
Milestones []MilestoneGroup `json:"milestones"`
}
Snapshot is the roadmap join's whole rendered result. Outcome is "OK" or NOT_OBSERVED (with Reason set) for the whole join — for example, `atm` refused or could not be run at all. A partial per-ticket failure does not abort the join; it shows up as that ticket's own NOT_OBSERVED blocker.
func Compile ¶
Compile joins `atm roadmap`, `atm ticket show` per ticket, docs/specs/REQUIREMENTS.tsv, the configured test-receipts directory, and the configured docs-state file into one roadmap Snapshot, grouped by milestone in `atm roadmap`'s own order. It only ever runs the `roadmap` and `ticket show` read verbs; it never mutates the planning store.
A refused or unreachable `atm roadmap` call produces a whole-snapshot NOT_OBSERVED outcome with a reason — never an empty ticket list reported as success. A per-ticket `ticket show` failure does not abort the join; that ticket instead carries a synthetic NOT_OBSERVED blocker explaining what could not be observed, so one bad ticket cannot hide every other ticket's real evidence.
type TestReceipt ¶
type TestReceipt struct {
RequirementID string `json:"requirementId"`
State string `json:"state"`
Reason string `json:"reason,omitempty"`
InputIdentity string `json:"inputIdentity,omitempty"`
Projection *testvalidity.Projection `json:"projection,omitempty"`
}
TestReceipt is one requirement's current test-validity projection, read from the configured receipts directory. State is CURRENT when the receipt's inputIdentity matches the caller-supplied current tree digest, STALE when it does not, and NOT_OBSERVED (with Reason set) when no receipt could be read at all.
func LoadReceipt ¶
func LoadReceipt(dir, requirementID, currentTreeDigest string, worktreeDirty bool) TestReceipt
LoadReceipt reads "<dir>/<requirementID>.json" and classifies it against currentTreeDigest. A missing directory, missing file, unreadable/ malformed file, or absent current-tree digest is NOT_OBSERVED with a reason, as is a name that escapes dir, a non-regular file, or one past maxInputFileBytes — this never reports a receipt as current when it cannot verify that. worktreeDirty is whatever WorktreeDirty last observed for the same root currentTreeDigest was measured against: a dirty worktree means currentTreeDigest no longer reflects everything on disk, so CURRENT/STALE would be an invented certainty (AGENTS.md invariant 2) — the classification renders NOT_OBSERVED with reason "worktree-dirty" instead, on both a would-be match and a would-be mismatch.
type Ticket ¶
type Ticket struct {
TicketID string `json:"ticketId"`
LocalID string `json:"localId"`
Title string `json:"title"`
Milestone string `json:"milestone"`
Status string `json:"status"`
Eligibility string `json:"eligibility"`
Owner string `json:"owner"`
Priority string `json:"priority"`
Blockers []Blocker `json:"blockers"`
Evidence []EvidenceLink `json:"evidence"`
TestReceipts []TestReceipt `json:"testReceipts"`
DocState DocState `json:"docState"`
}
Ticket is one roadmap ticket joined to its evidence, receipts and doc state.