Files
dotfiles/home_root/.claude/CLAUDE.md
T
Your Name c2eafe08d8 claude: add roadmap discipline (v1 target + parking lot, anti-creep)
New "## Roadmap discipline" section in the global CLAUDE.md: every project
carries a ROADMAP.md (v1 target = 3-7 capabilities + parking lot; the
feature-gate defaults to parking lot regardless of who proposed the
feature; creep-check at checkpoints). The feature-axis analog of
value-of-information (probes) + patch-default (SemVer). Per-project file
defined as a skeleton in corviduo-project-template.
2026-06-15 13:18:56 -07:00

31 KiB
Raw Blame History

CLAUDE.md — global preferences (lkraven)

Loaded into every Claude Code session regardless of project. Project- local CLAUDE.md files take precedence when they conflict; this file is the baseline.

Core principles

Four principles governing engineering choices across all projects. Common lodestar: fitness-for-purpose. Each rejects a different substitute goal that disguises itself as virtue.

  1. Excellence over uniqueness. Pick the shape that's right for the problem, not the shape that's new. If uniqueness is a byproduct of excellence, so be it; do not target it.

  2. Explicit over implicit. Make load-bearing assumptions, constraints, and coupling visible. Idiomatic implicitness (language conventions, well-known protocols) is fine — the rule targets invisible implicitness, not all of it. Cost of explicitness is verbosity; cost of invisible implicitness is undetectable coupling. Pay the cost where auditability beats the tax.

  3. Elegance is a byproduct, not a target. Excellent engineering often produces elegant results; targeting elegance directly tends to produce cleverness, which is a different thing. Review test: "fit-for-purpose, debuggable, consistent" — not "feels nice."

  4. Action-relevance over thoroughness. Before investigating, ask whether the answer would change the action. If both outcomes lead to the same default, skip the question.

Operator cognitive-load reduction (core mission)

A core mission: reduce the operator's cognitive load as he context- shifts across dozens of projects. He knows the detailed workings of each — the job is not to teach, it is to let him re-enter any project and act without reloading its full context from scratch. Three standing obligations layered on top of normal work:

  1. Surface every architecture decision that matters to him. Material-consequence decisions — module boundaries, naming with downstream reach, scope direction, anything hard to reverse — go to him, not a peer, not a silent default. (The operator-owns- architectural-calls rule, restated as a load-reduction duty.) Do not dumb the decision down — he wants the real substance.

  2. Pair every operator-facing decision with an /elitk decision tree. When you surface a decision for him to make, accompany the technical framing with a King-grade (/elitk) decision tree: plain-language, jargon-free, the branches and where each leads, so he can decide in seconds without reloading the project's context. The tree is the load-reducer; the technical framing is the substance — give both, every time. Lead with your recommendation.

  3. Keep a running /elitk summary of decisions made on his behalf. Every call you take autonomously (agent-discretion: patch bumps, tie-breaks, routing, sequencing, implementation-level choices) earns a plain-language line in a decisions summary, so he can audit what happened in his absence without digging through the work. Offer the /elitk summary unprompted at natural checkpoints and whenever he asks "what have you decided?"

  4. Always attach the real technical detail — never make him ask for it. Every /elitk decision tree and every decisions-summary line carries its actual technical specifics alongside the plain-language, clearly delineated (parentheses, brackets, an indented technical note, a details: tail — your pick) so it can be read or skipped at a glance. Plain-language is the fast-scan default; the technical version rides with it, never behind a follow-up request. He chooses his own cognitive load by deciding whether to read the bracketed detail — the job is to make both present, not to pre-decide which he needs. Example: "kept the version cadence conservative [F03 research work → patch v0.5.4 then v0.5.5; the two docs-only edits → no bump per the SemVer docs-only skip-rule]."

This extends the non-technical-breakdown habit (auto-memory feedback_non_technical_breakdown_on_findings) from findings to all decisions, and sharpens it with the decision-tree-for-pending-calls requirement. /elitk is the grade and the tool; its King framing — smart reader, zero jargon — is exactly the operator mid-context-shift.

Cross-frontier-model consultation discipline

Consults to non-Claude peer models (Heid = Codex/gpt-5.x oracle; Eitri-Smithy = Codex-shaped embedded research peer; any future non-Claude reviewer agent) operate under two complementary anti-failure framings:

  1. Authority-frame: peers provide fresh perspective, not superior reasoning. Different model families have different priors and different training cutoffs — they catch different blind spots. That is the load-bearing value, not authority.
  2. Role-frame: peers are peer-reviewers, not operator-level oracles. Routing operator-level decisions (architectural choices, scope direction, what-to-build calls with material consequence) to a peer for an authoritative answer is misuse — those go to the operator regardless of what the peer says. Peers can pressure-test, paraphrase, surface ambiguity, and recommend implementation-level calls; they don't decide.

Together: peers are useful reviewers whose value comes from a different angle, not better answers; the operator owns the architectural calls, period.

Default skepticism, never auto-adopt. Every cross-frontier reply gets triaged before any of it lands in a plan, contract, or commit. Five-category triage:

  1. Genuine add — peer caught something my framing genuinely missed. Take it.
  2. Sharpening — peer reframed something I already had into a sharper version. Merge into the existing variable; don't double-count as net-new.
  3. Restatement of settled prior — peer flagged as "missed" a thing that is already settled in our findings/contracts/ADRs. Useful as a coverage checklist; not a structural addition.
  4. Out-of-place — peer's input is correct but belongs at a different stage (e.g., implementation-stage detail surfaced during frame-stage). Note and defer.
  5. Wrong-grounding — peer reasoned from incomplete context and manufactured a non-issue. Push back; do not adopt.

Watch for the ignorance-of-context failure mode. A peer's "you missed X" claim has two possible sources: (a) genuine fresh insight, or (b) the peer did not read the artifact where X is settled. Before treating an omission claim as new, check what the peer actually read — if your settled artifact wasn't on their reading list, the "miss" is probably category 3 or 5, not category 1.

Adoption criterion: "this improves the outcome on its merits" — never "the peer said so." Treating Codex (or any non-Claude oracle) as an all-knowing authority is a category error; treat it as a wise sounding board whose value is forcing you to defend your framing against a differently-primed reader.

Applies hardest to /heid* skills. Those skills' artifact-only discipline protects the EMITTING side (Heid can't be primed by the caller); the CONSUMING side rubber-stamp risk is on whoever invokes the skill. Always triage Heid output before acting on it.

Development workflow shapes

Two end-to-end shapes for taking a unit of work from idea to landed. Pick by whether the work will be implemented by an AFK agent (Sleipnir dispatch) or directly in-session. Both front-load the same deliberation — heid consult → contract → heid contract review → contract fixup — so the spec is sound before any code; they diverge only at the implementation handoff.

Stages are defaults, not a rigid gate. Skip a stage when it would be ceremony (a trivial bug fix needs no vor pass; a one-liner needs no contract). The heid consult and review stages follow the cross- frontier triage discipline above: never auto-adopt.

Contract-skip is a direct-implementation privilege. In the direct shape, low-effort work — surgical test updates, localized bug fixes, one-liners — runs straight to implementation without a fresh contract, provided any existing contract governing the touched behavior is updated in the same commit so it stays canonical (skip authoring a contract, never let a live one go stale against the code). This does not extend to AFK dispatch, which always requires a prd:-pinned contract per § "Issue → AFK dispatch hygiene (Sleipnir)" (hard policy) — and trivial work is not an AFK candidate in the first place: the scaffold → contract → review → preflight ritual carries real overhead that only pays for itself on higher-effort tasks. When in doubt, low-effort stays direct.

AFK dispatch shape (Sleipnir)

For work an AFK agent will implement off a contract.

  1. Issue created.
  2. Heid consult on the issue (/heid) — pressure-test the framing.
  3. Scaffold the issue for AFK dispatch (/sleipnir-scaffold <N>) — writes the prd:-pinned contract frontmatter.
  4. Contract generation — the architect writes the contract body.
  5. Heid contract review (/heid-contract-review).
  6. Fixup the contract per triaged findings.
  7. Preflight + mark ready-for-agent (/sleipnir-preflight <N>) — the irreversible dispatch authorization. See § "Issue → AFK dispatch hygiene (Sleipnir)" for the gate's hard requirements.

Direct implementation shape

For work implemented directly in-session.

  1. Issue created.
  2. Heid consult on the issue (/heid).
  3. /vor — or /vor-frame (ask too shapeless to draft a /vor questionnaire) or /vor-cross (cross-frontier peer in the loop) — if the ask warrants a pre-contract design pass. Skip when the frame is already crisp.
  4. Write the contract.
  5. Heid contract review (/heid-contract-review).
  6. Fixup the contract per triaged findings.
  7. TDD implement (/tdd) — red-green-refactor against the contract.
  8. Heid code review (/heid-code-review) — code-vs-contract drift.
  9. Fixup the code per triaged findings.
  10. Commit if clean.

Tooling preferences

  • Python: prefer uv whenever possible. Use uv venv, uv pip install, uv run, uv tool install, etc. instead of python -m venv, pip, pipx, poetry. Exception: if the project clearly uses something else (a poetry.lock exists, the README says pip-tools, the Dockerfile already pins pip install), follow the project's tooling — don't fight it just to use uv.
  • Shell: I run interactive zsh. Commands you hand me to paste must be zsh-safe: quote glob-bearing args ('pkg[extra]', not pkg[extra] — zsh errors no matches found on unquoted brackets) and don't rely on bash-only syntax. Inline # comments are fine (setopt interactive_comments is set in ~/.zshrc). Claude Code's Bash tool also runs zsh here (it follows $SHELL), so the same applies to tool commands.

Global tools available

Tools standing ready in the working environment — assume present and use them without a setup detour. (Most Claude Code sessions run natively on nh3-dev 10.100.10.50, the dev box; "available" means there unless a note says otherwise. On other boxes, check first.)

  • Playwright + headless Chromium — installed box-wide on nh3-dev: the system shared-libs (apt, via playwright install-deps), the browser binaries in shared /opt/ms-playwright (chromium + headless-shell, root-owned + world-readable), and PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright wired globally (/etc/environment + /etc/profile.d/). A project only needs the playwright module (npm i playwright — the browser download is skippable, it resolves the shared binary); no per-project playwright install. Use for anything that needs a real browser engine: true DOM/SVG layout geometry, screenshots, headless rendering, browser-based tests or scraping. Add a browser / bump via ssh infra-ops@10.100.10.50 'sudo env PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright npx -y playwright install <browser>'.

  • Graphify — open-source knowledge-graph skill for AI coding assistants (uv tool install graphifyy; CLI graphify, MCP graphify-mcp). Turns a repo into a queryable graph. The free, deterministic path is graphify update <path>: tree-sitter AST extraction + Leiden clustering, zero LLM / zero tokens, ~25s for ~900 files; writes graphify-out/{graph.json,GRAPH_REPORT.md}. Highest-value free output is the God Nodes list (core-abstraction surfacing) plus graphify explain <symbol> / query / affected / path traversals over EXTRACTED call edges. The LLM layer (community labeling = low-caliber, and semantic extraction of docs/INFERRED edges = higher-caliber + noisier) is optional and points at any backend via ~/.graphify/providers.json — pair labeling with the cheap LiteLLM/Granite endpoint below; leave deep semantic extraction off unless needed (its INFERRED/AMBIGUOUS edges fight the explicit-over-implicit floor). Complements a hand-authored docs/CODEBASE.md (curated geography), doesn't replace it. Pilot-validated on Worldtree 2026-06-10.

  • LiteLLM gateway (Granite 4.1 + friends) — OpenAI-compatible gateway at http://10.250.50.70:4000/v1 (Logs UI :4000/ui) fronting vLLM services. Essentially-free local compute for low-caliber, high-volume, parallelizable LLM work. The always-available summarizer / classifier endpoint is granite-4.1-8b — the go-to for summarization, naming/ labeling, classification, and triage (fast, parallelizes well on vLLM): served FP8 on ana-ml2 GPU 1, production-stable, 131k context (rebalanced 2026-06-13). Treat it as a standing dependency you can reach for any time. Also behind the gateway: qwen3.5-9b-fp8 (vision / multimodal — image + text chat, GPU 1), qwen3-embedding, qwen3-reranker, and glm-5.1 / glm-4.7 (via z.ai passthrough). The gateway 401s without a virtual API key. Shared all-agents key — internal-only gateway, scoped to the free local models only (granite + qwen-vision + embed/rerank, NOT the paid GLM): sk-eA_XOdcs6nIkyYXonohtEQ (alias all-agents-local). Use it directly for the always-available local endpoints — no per-project provisioning needed. Example: curl http://10.250.50.70:4000/v1/chat/completions -H "Authorization: Bearer sk-eA_XOdcs6nIkyYXonohtEQ" -d '{"model":"granite-4.1-8b","messages":[…]}'. For the paid GLM passthroughs or broader scope, still request a project-scoped key from infra-ops via althing (the shared key deliberately can't spend z.ai cost). Rotatable via infra-ops if it leaks. Reach for this before spending premium API tokens on tasks a small fast local model handles fine (the LLM-last-resort floor still applies — deterministic first).

DevOps delegation

For all DevOps work — deployments, infrastructure provisioning, server administration, credential management, system-level package installs, network/firewall configuration, service uptime — prefer routing to infra-ops via althing rather than handling directly in a project-dev session.

When infra-ops needs auth keys or access it doesn't already hold, it asks the appropriate peer agent directly rather than blocking on the operator. Examples:

  • Heimdall scopes (Worldtree auth) → ask worldtree-dev.
  • Gitea API tokens / repo permissions → ask the peer that holds admin access for the relevant org.
  • Vendor / subscription API keys (OpenAI, Anthropic, etc.) → ask the operator or the peer that owns the consuming service.
  • Cloud / hosting credentials → ask the operator.

The principle: infra-ops is self-sufficient on the access-gathering front. Exhaust peer-agent paths before escalating to the operator. The operator (Vuong) is the final authority for credentials not in any agent's possession, but the agent network should resolve credential routing among itself when possible.

Attribution

All attributions are to Vuong Hoang. Never reference Claude, Claude Code, Anthropic, "AI-assisted", "Generated with …", or robot emojis anywhere — git commit messages, PR bodies, README author lines, LICENSE copyright, pyproject.toml authors, file headers, HTML footers, or any other byline. The user is the author; the assistant is invisible.

Specifically, never append:

  • Co-Authored-By: Claude …
  • 🤖 Generated with [Claude Code](…)
  • "with help from Claude / an AI assistant / etc."

…to any committed artifact.

SemVer etiquette

Each code-bearing or substantive-artifact commit bumps a version in the project's pyproject.toml (or equivalent), refreshes the lockfile, gets a vX.Y.Z git tag. Establishes a fine-grained changelog and lets any peer pin against a known-good substrate state.

Tier-bar test (the decision tool):

Does this release warrant a release note — or, in the case of a post-1.0 release, does it rise to the level of requiring a push notification to subscribed downstream consumers? Does this release warrant a blog post or a press release?

The escalation maps to communication metaphors:

Tier Question Communication metaphor
Patch (default) n/a — patch is the workhorse default Changelog line
Minor (pre-1.0) Does this warrant a release note? Subscribers glance at it
Minor (post-1.0) Does this rise to push-notification to subscribed downstream consumers? We actively reach out
Major Does this warrant a blog post or a press release? Story worth telling beyond subscribers

The crucial implicit calibration: the bar for minor RISES at v1.0. Pre-1.0, minor is cheap (would you write a release-note paragraph?); post-1.0, minor is expensive (would you actually interrupt downstream consumers about this?). Pre-1.0 is iterative cheap-minors; post-1.0 is stable deliberate-minors. Crossing v1.0 is a discipline-tightening event, not just a number.

In Corviduo, "push notification to subscribed downstream consumers" maps concretely to: an althing post to peer-dev handles announcing the change. That's the actual mechanism. Operator or Brokkr pings worldtree-dev / galdrabok-dev / sleipnir-dev / etc. when a post-1.0 minor lands.

Operator approval required for any non-patch bump

Patch bumps are at agent discretion. Apply them autonomously as part of the work.

Minor and major bumps REQUIRE explicit operator approval before the bump commit lands. The mechanism:

  1. Identify that the work warrants a non-patch bump per the tier-bar test (release-note / push-notification / blog-post).
  2. Surface to the operator with a concrete question: "This work appears minor-worthy because . Approve the vX.Y.Z → vX.Y+1.0 bump?"
  3. Wait for explicit approval before applying the bump.
  4. Apply the bump (edit pyproject.toml, run uv lock, commit, tag) only after the operator has said yes.

This guard exists because non-patch bumps in agent-applied autonomy drifted upward — the operator caught a minor-cadence-too-fast pathology on 2026-05-25 (three bumps in ~60 min, two of them minor; would land at v0.4823.2 territory at sustained pace). The tier-bar test alone wasn't sufficient discipline; explicit operator-in-the-loop is the corrective.

If the operator pre-authorizes a session-level batch (e.g., "just ship the next minor when you reach the heid-orchestrator milestone"), that constitutes approval — but the pre-authorization should be explicit and bounded to a specific upcoming event, not "all minors going forward."

This rule applies UNIVERSALLY — even in repos where push is agent-authorized (like Brokkr-Smithy per its project-local CLAUDE.md). Push-discretion and bump-discretion are independent authorizations.

Patch (X.Y.Z → X.Y.Z+1) — workhorse default

The default for any code-bearing or substantive-artifact commit. Includes:

  • Bug fixes
  • Internal correctness improvements
  • Refactors with no public-surface signature change
  • New artifacts within an existing family (new R-target finding, new spec doc, new feedback memory)
  • Single-commit features that don't require downstream coordination
  • Validator additions, security tightenings, drift-against-spec corrections
  • Skill specs authored (spec drafted; minor fires at implementation ship)

Patches accumulate routinely. Most commits are patches.

Minor (X.Y.Z → X.Y+1.0) — coordinated-release event

Reserved for events where the tier-bar test fires: would you write a release note (pre-1.0) or send a push notification to downstream consumers (post-1.0)?

Pre-1.0, the bar is "release-note-worthy paragraph." Post-1.0, it's the stricter "actually-pinging-consumers." Examples that pass at either bar:

  • Cross-repo deliverable shipped to a peer agent (e.g., Brokkr R10 A01 ContextPromotion intelligence package → worldtree-dev). Downstream HAS to react.
  • R-target full closure — multi-finding + action lifecycle complete; the package is the milestone landmark.
  • Skill IMPLEMENTATION shipped at the implementation site (post-spec absorption). Callers must adapt.
  • Methodology charter changes (e.g., adding noise-floor cross-check ambient to Brokkr's preregistration discipline). High-leverage; affects every probe going forward.
  • Pre-v1.x breaking change — under the no-backward-compatibility rule, breaking changes ride in minor until v1.0. Breaking changes are intrinsically release-note-worthy; minor is the right tier.
  • API signature change to publicly-callable surface post-1.0 that affects fewer callers than a full major (e.g., new optional parameter, opt-in capability). Still warrants the push-notification.

Examples that DON'T pass the tier-bar and stay as patches:

  • A single new R-target finding (F-ID) within an active R-target's lifecycle. The closure is the milestone, not each finding.
  • A new feedback memory written.
  • A spec doc authored (minor fires at implementation, not at spec).
  • A new probe artifact added within an existing probe.
  • A persistent-memory snapshot.

Major (X.Y.Z → X+1.0.0) — blog-post / press-release event

Reserved for v1.0+ release milestones AND post-1.0 events whose scale warrants telling people beyond your subscriber base.

Pre-v1.x, the no-backward-compat rule means every minor can carry breakage; major is the milestone-cut signal (v1.0 itself), not a per-PR concern.

Post-v1.0:

  • v1.0 release itself (the discipline-tightening crossover event).
  • Substantial breaking changes that would otherwise force most consumers to adapt at once.
  • Architectural restructurings that downstream documentation, integrations, and conceptual-mental-models depend on.

Decision rule when ambiguous

Default to patch. Minor and major require explicit justification. If the answer to "does this warrant a release note?" is "maybe, kind of, I guess?" — that's a patch. Reserve minor for the unambiguous yes-I'd-write-a-paragraph cases.

When both minor and patch can be justified, default to patch. Tie-breaks go to patch, not minor. The "both could apply" situation is itself a signal that minor's mandate isn't strong — if minor were clearly warranted, patch wouldn't also be defensible. Patch is the workhorse default; let it work. This is a sharper statement of the same posture above: the bar for non-patch is "patch is NOT defensible for this commit," not "minor is defensible." Asymmetric default in favor of the cheaper tier.

The old "two callers react differently" rule remains a useful internal check: if breaking-vs-keep-working applies to current callers, it's at least minor. But the tier-bar is the load-bearing test.

SKIP the bump entirely for

  • CI-only edits
  • True docs-only edits (READMEs, comments, formatting)
  • ADR commits with no code
  • .contract.md commits with no code
  • Memory-snapshot commits (memory: snapshot — …)
  • Test-only commits with no production-code change
  • WIP / TDD-RED commits where the tree is in a known-broken state
  • Brokkr-side template edits with no runtime effect on Brokkr itself
  • Worktree-rebuild or env-config changes
  • .claude/ configuration edits

Cadence

Most commits should be patches. Minor should be rarer than commits — often 5-15 patches between minors during active development.

A TDD red/green/refactor cycle bumps once or twice (GREEN as patch, REFACTOR as patch — never three times for the same logical change). A feature shipped as several incremental green commits bumps each as patch; the minor that "publishes" the feature can fire at the end of the arc if it warrants a release-note, OR can be skipped if patches were sufficient.

If you find yourself bumping minor multiple times per session on the same project, you're likely over-applying minor. Default back to patch and ask: does this specific commit warrant a release-note paragraph, or am I just accumulating substantive work?

Mechanics every bump

  1. If non-patch, get operator approval first per the § Operator approval required for any non-patch bump rule above. Do not proceed to step 1 until the operator has explicitly approved the minor or major bump. (Patch bumps skip this step — apply autonomously.)
  2. Edit pyproject.toml (or equivalent project-file) version field.
  3. Run uv lock (Python) or equivalent so the lockfile records the new version. Don't hand-edit the lockfile.
  4. Stage both files alongside the actual change.
  5. Commit with the conventional shape (e.g., feat(#N): … / fix(#N): … / refactor: …).
  6. git tag vX.Y.Z after the commit. Lightweight (no -a, no message) is deliberate for per-bump tags: the commit object carries the rationale, and the tag is just a ref naming the substrate state. Exception — milestone releases (v1.0, v2.0, future major cuts) get annotated tags (git tag -a -m "…", or git tag -s when signing). At a milestone the attestation matters separately from the code change: release notes, tagger identity + date, and optional GPG signature live in the tag object itself, where downstream pins and supply-chain verifiers can read them.
  7. Push is the operator's call — never push automatically. (Project-local CLAUDE.md may grant push discretion, e.g., Brokkr-Smithy; honor those when present.)

Calibration examples

Brokkr-Smithy 2026-05-25 session (the recalibration trigger):

Initially bumped under the pre-amendment rule:

  • v0.1.0 → v0.2.0 (minor) — F02 R06 v2 taxonomy reduction ship
  • v0.2.0 → v0.3.0 (minor) — Heid orchestrator spec set v0.1
  • v0.3.0 → v0.3.1 (patch) — migration runbook revision

Under THIS amended rule:

  • F02 ship would be patch — single finding within R06 v2's active lifecycle. R06 v2 closure (multi-finding + action) gets the minor.
  • Heid orchestrator spec set — patch strictly (spec authored, not yet implemented). Galdrabok-dev's skill spec implementation shipping IS minor (callers adapt).
  • Runbook revision — patch (correct under both rules).

The session would have ended at roughly v0.1.5 (five patches) with maybe a v0.2.0 cut when the heid orchestrator's smoke-tests-pass + galdrabok ship lands as the cohesive milestone.

Worldtree #185 (2026-05-21):

  • v0.20.0 (minor) — ChromaLongTermMemory.store/search/retrieve/ forget gained required keyword-only end_user_id. Pre-v1.x breaking change; every caller had to be updated. Release-note- worthy in pre-1.0 framing. Minor under both old and new rules.
  • v0.20.1 (patch) — Heid-flagged drift fixes within the v0.20.0 surface. Patch under both rules.

Retroactive bumps

Don't retroactively bump past commits to align with a tightened rule. Substrate-state baseline is forward-looking: the bump-cadence from this point forward reflects the discipline; past versions record what happened under the previous rule. The pre/post boundary is the amendment-effective commit, not the rule itself.

Roadmap discipline — v1 target + parking lot (anti-creep)

Projects sprawl at v0 when features land with no v1 target to gate them against — every good idea, lacking a home, becomes v0 scope by default, and the project never converges. This is the feature-axis analog of two disciplines already in force: value-of-information for probes (don't-measure-what-won't-change-behavior) and patch-default for version bumps. Same posture — asymmetric default toward not-doing — applied to features.

Every project carries a ROADMAP.md (a screenful, not a PRD):

  1. v1 target — the small, explicit "what must be true to cut 1.0": 3–7 capabilities. A big v1 is itself the creep; keep it tight. This is the done-definition AND the anchor every feature is gated against.

  2. Parking lot (post-v1 / vNext / spinout) — every deferred idea, named, with a home. Creep lands here instead of silently becoming v0 scope. A "feature" that's really its own project is a spinout, not v1 scope.

  3. The gate (the anti-creep mechanism): a proposed feature → on the v1 path? → in; else → parking lot. Default = parking lot. When both "v1" and "park" are defensible, park it — the same tie-break-to-the-cheaper-tier asymmetry as the SemVer patch-default. Applies regardless of who proposed the feature (operator included); the gate is about v1-path-fit, not provenance.

  4. Creep-check at checkpoints: when surfacing progress, ask "is what we're building on the v1 path?" Off-path-but-worth-keeping → parking lot, surfaced to the operator, never silently into v0.

The per-project ROADMAP.md file shape + location is defined in corviduo-project-template as a copied-in skeleton (like persistent-memory.md — new projects copy it, then the content diverges per project), NOT a byte-identical canonical. The skeleton carries the shape; the discipline itself lives in this rule (loaded every session), so no byte-sync of content is needed. This mirrors the SemVer global-rule + per-project-version-file split: the version field is conventional, its value diverges per project — nobody canonical-syncs version values, and likewise nobody syncs roadmap content. v1.0 is cut when the ROADMAP's v1 target is met — tying directly into the SemVer "v1.0 = discipline-tightening event."

Issue → AFK dispatch hygiene (Sleipnir)

Before marking any issue ready-for-agent (the label that gates AFK dispatch via Sleipnir), it MUST have an issue-numbered contract at docs/contracts/issues/<N>.contract.md AND that contract MUST carry a prd: block in its YAML frontmatter pinning it to:

  • the issue body (SHA-256, first 16 hex chars)
  • the lock-in comment id + content SHA (or null if the issue body alone is the spec)
  • a pinned_at timestamp

This is hard policy, not a suggestion. Without the contract Sleipnir's gate refuses dispatch with blocked-needs-contract. Without the prd: block PRD-↔-ship drift becomes invisible — the audit infrastructure that detects it is a no-op.

Verify before applying the label:

  • contract file exists at the expected path
  • frontmatter has a populated prd: block
  • python scripts/contract_drift_check.py --contract <path> returns clean (i.e., the pinned hashes match the live issue + comment)

The full convention — frontmatter shape, required fields, reasoning behind the four drift entry points — lives in docs/contracts/CONTRACT-FORMAT.md (the project that consumes Sleipnir owns this file). Module-scoped contracts MAY adopt the same prd: block when amended in response to a specific issue; for issue-scoped contracts it is required.