Phase NXP — NEXT provenance + board identity activation
Status: Thinking freeze — awaiting review. NXP-a is spec-only; no code lands in this
phase. NXP-b (Auto) may not start until this document carries a pass review stamp.
phase: NXP
outputs:
- id: nxp-next-provenance
path: docs/archive/phases/PHASE-NXP-NEXT-PROVENANCE.md
frozen: true
frozen_inputs:
- id: ons-operator-next-surfacing
path: docs/archive/phases/PHASE-ONS-OPERATOR-NEXT-SURFACING.md
- id: k13-multi-repo-workspace-lanes
path: docs/archive/phases/MULTI-REPO-WORKSPACE-LANES-FREEZE.md
- id: kh1-relay-standard
path: docs/archive/phases/PHASE-KH1-HANDOVER-RELAY-STANDARD.md
- id: print-next-extract
path: tools/print_next/extract.py
- id: next-command
path: cli/commands/next.py
- id: workspace-board-names
path: tools/workspace/board_names.py
- id: workspace-check-next
path: tools/workspace/check_next.py
- id: status-command
path: cli/commands/status.py
- id: session-start-hook
path: cursor/hooks/session-start-next.sh
- id: test-tiers
path: policy/test-tiers.yaml
- id: model-labels
path: policy/model-labels.yaml
review_stamp:
reviewed_at: '2026-09-05T00:10:47Z'
verdict: pass
reviewer_mode: agent
reviewer_model: thinking-high
reviewer_provider: local
kit_version: 0.1.0
artifact_digest: sha256:2a1e297bfb81246fd29268a3399da23dfbcf20d6941ca85afcf99afe918ec46d
Downstream edge: NXP-b treats this document as ground truth without re-deriving it (SPEC §6 mandatory reviewed freeze).
Review record (§6.2): every freeze-review finding MUST cite file+line per SPEC §6;
uncited findings are invalid and are discarded. Fixes during the loop are Tier 1 (feature
branch); merge to main is Tier 3 and is never part of this loop.
| Round | Reviewer | Verdict | Resolution |
|---|---|---|---|
| NXP-r1 | ok review --freeze (checklist, local) |
findings | F1 MINOR C8 — citation-readiness discipline not evidenced (docs/archive/phases/PHASE-NXP-NEXT-PROVENANCE.md:1). Fixed by adding this §6.2 review record. |
| NXP-r2 | Semantic re-read (thinking, authoring session — not independent) | findings | S1 layout supersede left existing ONS §ONS.5.4 assertions undefined, invitable as "regression" (PHASE-NXP-NEXT-PROVENANCE.md:117) → new §NXP.3.3. S2 read_at made full-stdout golden tests impossible; no clock seam frozen (PHASE-NXP-NEXT-PROVENANCE.md:138) → new §NXP.3.4. S3 N4 advisory undefined under docs.lanes (which lane? how many lines?) (PHASE-NXP-NEXT-PROVENANCE.md:216) → lane rule added to §NXP.6. |
| NXP-r3 | ok review --freeze (checklist, local) |
pass | Checklist clean (0 findings) after S1–S3 fixes; stamp rewritten. |
§NXP.0 — Simple summary
A ok next block cannot be traced back to the repo it came from. The heading
## CURRENT NEXT — paste this is byte-identical for every repo on the machine. When two or
more repos inject blocks into one chat, the operator and the agent must guess which authority
each block carries. This phase makes the printed block say where it came from, and turns on
the board-name identity the kit already built but never activated.
This phase does not disable session hooks. Hooks are the mechanism that keeps stale instructions out of a session; the repo that caused the live incident is the one with no hook. This phase sequences provenance before wider hook enablement.
§NXP.1 — Verified problem (do not redesign)
Each claim below was confirmed live on this repo in the authoring session. NXP-b must not re-litigate them.
| # | Verified fact | Evidence |
|---|---|---|
| V1 | Human stdout carries no repo identity. format_current_next emits heading + blank + fenced body only. |
tools/print_next/extract.py:129 (format_current_next), contract at docs/archive/phases/PHASE-ONS-OPERATOR-NEXT-SURFACING.md §ONS.5.4 steps 1–9 |
| V2 | The identity data already exists in memory at print time and is simply not emitted. | tools/print_next/extract.py:35-41 — CurrentNextResult holds path and lane |
| V3 | --json is already self-identifying; only the human surface is anonymous. |
docs/archive/phases/PHASE-ONS-OPERATOR-NEXT-SURFACING.md §ONS.5.5 — path, lane keys |
| V4 | The frozen heading is byte-identical across all repos, so two adjacent blocks are indistinguishable at the heading level. | §ONS.5.3 CURRENT_NEXT_HEADING; asserted byte-for-byte by tests |
| V5 | Repo-prefixed board names are already specified and already built — not a new idea. | docs/archive/phases/MULTI-REPO-WORKSPACE-LANES-FREEZE.md §MR.6.5 ({n}-OVERSEER-HANDOVER.md, e.g. SCOOLING-OVERSEER-HANDOVER.md); H17 predicate implemented at tools/workspace/board_names.py:94 (board_name_violation) |
| V6 | That identity check is silently inert: with no workspace: configured it prints a notice and exits 0. |
Live run: ok workspace check-next → workspace not configured (check-next requires workspace:), exit 0; gate at tools/workspace/check_next.py:117 |
| V7 | Nothing nags an unconfigured repo toward board identity, so V5's shipped feature stays off indefinitely. | V6 exit 0 + ok status reporting workspace_relay: not_configured as informational only |
Root cause statement (frozen): the kit built board identity (V5) but gated it entirely behind an opt-in manifest whose absence is a silent success (V6, V7), while the one surface an operator actually reads in chat omits identity it already holds (V1, V2).
§NXP.2 — Scope
In scope (NXP-b):
- A visible provenance line on
ok nexthuman stdout (N1). - Additive
--jsonidentity keys (N2). ok workspace check-nextstops being a silent success when unconfigured (N3).- A non-blocking bare-board-name advisory in
ok statusoutside workspace mode (N4). - Hook-enablement sequencing statement (N5).
Out of scope — explicitly not this phase:
- Renaming any consumer repo's handover files. That is operator work, per-repo, Tier 2/3.
- Authoring
.overseer/workspace.yamlfor any consumer constellation. - Auto-enabling hooks anywhere (deferred to a separate phase; see N5).
- Any change to fence body bytes.
extract_paste_fence_bodyand the GS-PASTE regen contract are not reopened. - Any change to
CURRENT_NEXT_HEADINGitself (§ONS.5.3 stays byte-exact). - Per-branch handover filenames — remains forbidden by §ONS.3 A1.2.
§NXP.3 — N1. Provenance line on human stdout
§NXP.3.1 — Narrow supersede of §ONS.5.4
This is a named, narrow supersede of ONS §ONS.5.4's byte layout. Everything else in ONS
stands. The heading remains line 1 so existing startswith / grep assertions and the operator's
visual anchor are preserved.
Frozen byte layout (UTF-8, trailing newline on last line):
CURRENT_NEXT_HEADING— unchanged, still line 1- newline
- newline (blank line)
- provenance line (§NXP.3.2) — new
- newline
- newline (blank line)
- opening fence line
```text - newline
- fence body from
extract_paste_fence_body— unchanged bytes - if body does not end with newline, append one newline
- closing fence line
``` - newline
§NXP.3.2 — Provenance line format (frozen)
Exactly one line, rendered visibly (not an HTML comment — it must survive markdown rendering in a chat surface):
**Source:** `<repo_name>` · `<repo_root_abs>` · `<doc_rel>` · lane `<lane>` · read `<read_at>`
| Field | Value | Fallback |
|---|---|---|
repo_name |
config.repo.name |
literal unknown when absent |
repo_root_abs |
absolute POSIX path of the resolved repo root (folder containing .overseer/) |
never empty; resolution failure is a §NXP.3.4 refusal |
doc_rel |
repo-relative POSIX handover path — the existing CurrentNextResult.path |
required |
lane |
resolved lane name; literal - when docs.lanes unset |
- |
read_at |
UTC ISO-8601 YYYY-MM-DDTHH:MM:SSZ, second precision, at read time |
required |
Separator is · (space, U+00B7, space). Constant name in code: PROVENANCE_LINE_TEMPLATE.
Tests assert the exact template and the exact separator.
read_at MUST be the time the bytes were read from disk, not a cached or doc-embedded stamp.
It is the operator's staleness signal: a block pasted from an old chat carries an old read_at.
§NXP.3.3 — Existing ONS layout tests are updated, not regressions
ONS-b's tests assert the §ONS.5.4 nine-step layout. Because §NXP.3.1 narrowly supersedes that
layout, those assertions will fail until updated. NXP-b MUST update them to the twelve-step
layout and MUST NOT interpret their failure as a regression to be worked around by suppressing
the provenance line. CURRENT_NEXT_HEADING assertions (§ONS.5.3) and fence-body assertions must
continue to pass unchanged — if either of those breaks, that is a real regression.
§NXP.3.4 — Injectable clock (test determinism)
read_at changes on every invocation, so full-stdout golden comparisons are otherwise
impossible. The clock MUST be injectable (parameter or module-level seam) so tests can pin
read_at to a fixed instant. Production callers use the real UTC clock. NXP-b MUST NOT make the
timestamp omittable in production to satisfy tests — the seam is injection, not omission.
§NXP.3.5 — Constraints inherited (unchanged)
ok nextstill MUST NOT callmuseorgit(§ONS.5.1). Provenance is config load + filesystem resolution + clock only.--quietstill prints the whole block including provenance.--print-nextsynonym prints identically.- Diagnostics stay on stderr; the block stays on stdout.
§NXP.3.6 — Fail-closed
If repo root cannot be resolved to an absolute path, ok next MUST refuse rather than print an
anonymous block: exit 2, reason token repo_root_unresolved, message containing
cannot resolve repo root for provenance. Printing a block without provenance is not an
acceptable degrade path — that is the exact defect this phase closes.
§NXP.4 — N2. --json identity keys (additive)
Add three keys. All existing keys and their types are unchanged; consumers keying on ok,
path, lane, heading, fence, error are unaffected.
| Key | Type | Value |
|---|---|---|
repo_name |
string | null | config.repo.name, else null |
repo_root |
string | absolute POSIX repo root |
read_at |
string | same UTC ISO-8601 value rendered in §NXP.3.2 |
On the failure shape (ok: false), repo_name and repo_root are emitted when resolvable and
null otherwise; read_at is always emitted.
§NXP.5 — N3. check-next stops being a silent success
ok workspace check-next with no workspace: configured currently prints a notice and exits
0 (V6). Frozen behavior:
| Condition | stdout/stderr | Exit |
|---|---|---|
workspace: configured |
unchanged (K13 §MR behavior, exit 35 on violation) |
unchanged |
workspace: absent, board names already prefixed per §MR.6.5 |
advisory: workspace not configured; board names already compliant | 0 |
workspace: absent, board names bare/legacy |
advisory naming the bare basename and the compliant {n}- target |
0 |
Exit code stays 0 in both unconfigured cases. Raising it to a failure would break every
existing consumer that never opted in, which §NXP.7 forbids. The fix is visibility, not a
new gate. The advisory MUST name the actual basename found and the exact compliant target so
the operator can act without reading the spec.
Reuse board_name_violation (tools/workspace/board_names.py:94) with strict=True for this
advisory. Do not fork the predicate.
§NXP.6 — N4. Bare-board-name advisory in ok status
When workspace: is absent and the resolved handover or roadmap basename is bare/legacy per
board_name_violation, ok status emits one advisory line naming the compliant target.
When docs.lanes is configured, evaluate every lane's handover and roadmap basenames and
emit at most one advisory line, naming the count of non-compliant lanes and the first
offending basename. Rationale: one line keeps ok status readable; the operator gets the exact
first target and can re-run per lane. When docs.lanes is unset, evaluate the single configured
pair.
This is a warn, never a gate. It MUST NOT contribute to --exit-code, MUST NOT change the
frozen exit precedence (2 > 6 > 35 > 3 > 0), and MUST NOT block DONE. Rationale: board naming
is an operator hygiene preference; the kit's hard gates are reserved for correctness failures
(substrate, muse-sync, footprint integrity). Turning a naming preference into a gate would
false-close working consumer repos.
§NXP.7 — N5. Hook sequencing (frozen decision)
Session hooks are not disabled, discouraged, or removed by this phase.
Frozen ordering: the exploration-backlog idea "Auto-enable session hooks on ok sync" MUST
NOT be promoted to a build phase until N1 has a pass build verification. Enabling hooks more
widely while blocks remain anonymous multiplies the exact ambiguity this phase closes — more
repos pasting more identical headings into one chat.
Once N1 ships, wider hook enablement becomes strictly beneficial and may be freshly frozen on its own merits.
§NXP.8 — Seven-tier test matrix (NXP-b)
| Tier | Coverage |
|---|---|
| unit | PROVENANCE_LINE_TEMPLATE exact string + · separator; each field's fallback (unknown name, - lane); read_at format YYYY-MM-DDTHH:MM:SSZ (second precision, Z suffix); byte layout §NXP.3.1 steps 1–12 including both blank lines; heading still line 1; board_name_violation reuse (no forked predicate) |
| integration | ok next on single-lane fixture; --lane on two-lane fixture emits that lane; --print-next synonym identical bytes; --quiet still includes provenance; --json carries repo_name/repo_root/read_at with all pre-existing keys unchanged; check-next advisory in both unconfigured branches; ok status advisory present when bare, absent when prefixed |
| e2e | Two distinct fixture repos printed into one captured stream — assert each block is attributable to its own root; ok status --exit-code unchanged by the N4 advisory (bare-name fixture still exits on its pre-existing conditions only) |
| stress | Deep nested repo root; long repo names; unicode + spaces in path; very long fence body; repo root at filesystem root; docs.lanes with many lanes |
| data-integrity | Fence body bytes are byte-identical before/after this change (golden comparison against pre-NXP output); CURRENT_NEXT_HEADING unchanged; JSON pre-existing keys unchanged in name, order-independence, and type |
| performance | ok next performs no muse/git subprocess (assert via subprocess spy); added cost is config + path resolve + one clock read |
| security | Provenance leaks no secrets: emits repo name, absolute path, lane, timestamp only — never config values, env, tokens, or remote URLs. Absolute local path disclosure is accepted and documented (§NXP.9) |
§NXP.9 — Security / privacy
The provenance line discloses an absolute local filesystem path. This is intended — it is
the disambiguator — and is consistent with existing kit output (ok status already prints repo
root context). It is local-operator-facing output. NXP-b MUST NOT add remote URLs, branch names,
tokens, or any config value beyond repo.name to this line.
§NXP.10 — Definition of Done (NXP-b)
- N1–N4 implemented exactly as frozen; N5 recorded in
docs/ROADMAP.mdbacklog row. - Seven-tier matrix §NXP.8 green; full existing suite green with no regression.
- Fence body and
CURRENT_NEXT_HEADINGbyte-identical to pre-NXP (data-integrity tier). - No new hard gate;
--exit-codeprecedence unchanged. - Build verification
passbefore ROADMAP → DONE. - Both governance docs updated together in the closing feature-branch commit (SD-17).
§NXP.11 — Hard stops
- Do not disable, remove, or discourage session hooks.
- Do not rename consumer repo handovers or author consumer
workspace.yamlin NXP-b. - Do not change fence body bytes or the frozen heading.
- Do not introduce per-branch handover filenames (§ONS.3 A1.2).
- Do not make board naming a blocking gate.
- Do not print a NEXT block without provenance as a degrade path (§NXP.3.4).
- No merge to
mainwithout Tier 3.
§NXP.12 — Cross-references
| Doc | Relationship |
|---|---|
docs/archive/phases/PHASE-ONS-OPERATOR-NEXT-SURFACING.md |
§ONS.5.4 byte layout narrowly superseded by §NXP.3.1; all else stands |
docs/archive/phases/MULTI-REPO-WORKSPACE-LANES-FREEZE.md |
§MR.6.5 board identity activated as advisory outside workspace mode (N3, N4) |
docs/archive/phases/PHASE-KH1-HANDOVER-RELAY-STANDARD.md |
Relay shape unchanged |