roadmap

package
v0.8.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 24, 2026 License: AGPL-3.0, AGPL-3.0-or-later Imports: 17 Imported by: 0

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

View Source
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).

View Source
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

func CurrentTreeDigest(ctx context.Context, root string, timeout time.Duration) (string, error)

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

func WorktreeDirty(ctx context.Context, root string, timeout time.Duration) (bool, error)

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

func LoadDocState(path, localID string) DocState

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 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

type Requirement struct {
	ID    string
	File  string
	Line  string
	Title string
}

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

func Compile(ctx context.Context, options Options) (*Snapshot, []byte, error)

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL