North-star orientation — landed evidence

One cumulative record, updated as each node of the plan lands. Anchors below are stable; the plan's evergreen sections link to them as they collapse.

Declared measures and what each has produced

MeasureEvidenceVerdict
Count disciplineSix entries write and read while the audit returns one advisory warning — § project statepass
Optional everywhereA project omitting the collection composes without gaining the key — § project statepass
Dangling reference caughtAn undeclared id returns a non-fatal diagnostic naming it, and the write still succeeds — § plan labelpass
Suite greenFull suite 1,731 passed / 0 failed at the integrated commit — § plan labelpass
Declared and renderedCockpit band renders each declaration in order with statement and live count; screenshot figure still outstanding — § prominencepartial
Plans point at themBadge and single-select facet proven; labelling reckon's own plans is the remaining node — § prominencepartial
Orientation rollupPer-direction plans, completion and remaining effort, with unoriented at info and undeclared at error — § orientation rolluppass

A north-star collection in project state

Commit cb230a2reckon/_schema.py, reckon/project_state.py, tests/test_project_state.py; 147 insertions across 3 files. Gate passed.

Each entry requires a non-empty id, name and statement of what winning looks like, and permits an optional href for a direction that needs argument rather than a sentence. Duplicate and unsafe ids are refused; entries round-trip losslessly beside sprints and milestones, reusing the rollup machinery those two already have rather than introducing a typed resource root.

The count cap is advisory by construction, which is the property worth recording: at six entries against a cap of five the write succeeds and audit_project_state returns one warning coded north-star-advisory-cap-exceeded. A project drifting past a handful of directions is reported, never blocked. A distributed project resource that omits north_stars entirely reads and composes without the key appearing, so no project is required to migrate.

MeasureResult
Scoped suitetests/test_project_state.py tests/test_schema.py — 1,121 passed, 0 failed, 20.3 s
New cases6 parameter-expanded: round-trip, each required field, advisory warning without rejection, absence preserved
Worker time324 s measured from the run's own event stream

A plan declares which direction it serves

Commit d7dfd50reckon/_plan_html.py, reckon/_store.py, reckon/_schema.py, docs/_shared/plan.schema.json, tests/test_mcp_store.py; 173 insertions across 5 files. Gate passed: 1,094 passed, 0 failed, 91.1 s, 4 new tests. This run's scope was widened mid-flight and it is therefore excluded from calibration.

plan-north-star parses from semantic HTML into typed plan state, persists through write and read, and appears in the regenerated public schema. The behaviour that matters is what happens to a label the owning project has not declared: the read returns a non-fatal diagnostic naming the unknown id, the write succeeds, and the label stays stored. Orientation is a prompt to think about direction, so a dangling reference is surfaced without becoming a barrier to writing — which is the locked unoriented-severity choice applied to the label as well as to its absence.

MeasureResult
Declared label round-tripsRead, write and meta round-trip preserve the label
Undeclared label diagnosedNon-fatal undeclared-north-star warning names the id; write succeeds; label retained
Unlabelled plans untouchedNo north_star and no validation_diagnostics keys appear, and a no-op write leaves bytes and version unchanged
Public schema regenerateddocs/_shared/plan.schema.json regenerated from the model, restoring committed-schema parity
Integrated suiteuv run pytest -q at the integrated commit — 1,731 passed, 0 failed, exit 0, 276 s

The derived-artifact dependency is worth recording because it is not visible from the plan: any change to the typed plan model invalidates the committed docs/_shared/plan.schema.json, so a node touching the model must own the generated file too or it cannot reach a green combined lane.

Directions reach the client, and the surfaces that show them

Commit 9ded8c0docs/ui/shell.jsx, docs/ui/state-loader.js, reckon/serve.py, tests/test_build.py, tests/test_crew_routes.py; 174 insertions, 3 deletions across 5 files. Gate passed: 14 passed, 0 failed, 4.3 s, 16 new assertions; reckon build exit 0; ruff clean. Scope was widened mid-flight, so this run is excluded from calibration.

The node's first act was to refuse to write. Given the cockpit, home and plan components, it audited instead and reported that the deliverable was unreachable from them: the served state carried no declarations and inventory rows carried no label, so no component could render either. It cited shell.jsx:1042 rendering CockpitBody rather than the assigned Cockpit, shell.jsx:134-256 and :950-977 owning the plan-list facets and filtering, serve.py:529-584 and :598-607 omitting the fields, and state-loader.js assembling window.STATE without them — then left the worktree clean at its base commit. That audit was worth more than a partial implementation would have been.

SurfaceResult
Served stateDiscovery and state routes both returned the declaration and the inventory alignment
Cockpit bandRenders every declaration in declaration order with its statement and its live-work count
Live count basisCounted over pending, active, in-progress and blocked plans — work in flight, not work finished
Plan badgeTitle and plan-list rows name the resolved direction
FilterOne facet selects exactly one id
Optional everywhereZero declarations omit the band and the facet; zero labels omit both badges
No entry-point drift11 checked-in = 11 served = 11 built JSX scripts

Two measures stay partial rather than passing. The declared-and-rendered gate asks for a banked screenshot, which needs the restarted server. The plans-point-at-them gate asks for all seven S7–S9 plans to carry a resolving label, which is the adoption node's work, not this one's.

The dependency scan reports how much work points at each direction

Commit d4d1502reckon/roadmap.py, tests/test_roadmap.py; 185 insertions, 1 deletion across 2 files. Gate passed: 25 passed, 0 failed, 1.0 s, 4 new tests, ruff clean.

roadmap gains a north_stars rollup — one declaration-ordered row per direction carrying plans, completed, lifecycle completion percentage and remaining effort. Declaration order rather than a computed ranking, so the reading matches how the project stated its own priorities.

CaseResult
Rollup figuresThree declared directions produced 2 plans / 1 complete / 50.0% / 3.0 remaining, 1 / 0 / 0.0% / 1.0, and 0 / 0 / 0.0% / 0
A direction nothing points atStill reported, with zeroes — an unclaimed direction is visible rather than absent
Unoriented live planExactly one unoriented-plan finding at info severity
Draft and completed plansProduce no orientation finding — only authorised, non-terminal work is asked to point somewhere
Undeclared idundeclared-north-star at error severity, naming both the slug and the id
Unmigrated projectEmpty rollup and neither finding, even with labelled and unlabelled plans in inventory

The two severities are deliberately different and both follow the locked decision. A plan that points nowhere is a prompt to think, so it is information. A plan that points at something that does not exist is a dangling reference, which is the same fault class as a dangling dependency slug and carries the same error severity — so it is repaired before execution rather than accumulating.

Reporting a zero-work direction matters more than it looks: a direction with no plans pointing at it is exactly the case the project most needs to see, and a rollup that only listed directions with work would silently hide it.