Quickstart — Doctrine Delivery Reachability

Mission: doctrine-delivery-reachability-01KYMXD6 | Date: 2026-07-28

How to reproduce the defects, run the right gates, and avoid the traps that cost the discovery pass several wrong numbers.


Reproduce the defects before changing anything

Per C-006 every requirement lands red-first. These are the reproductions.

The steady-state zero

# The first load is rich; every load after is empty.
rm -f .kittify/charter/context-state.json          # simulate a fresh project
spec-kitty charter context --action implement --mission-type software-dev --json \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['mode'], d['first_load'], len(d['text']))"
# expect: bootstrap True ~31000

spec-kitty charter context --action implement --mission-type software-dev --json \
  | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['mode'], d['first_load'], len(d['text']))"
# expect: compact False ~6000

There is no --depth flag. Depth is inferred from first-load state. This is why the original assessment measured zero and concluded activation was inert — it was reading the compact rail.

Styleguides and toolguides resolved, then dropped

PYTHONPATH=src python3 - <<'PY'
# the bundle resolves them; the render emits none of them
PY

Compare styleguide_ids / toolguide_ids on the resolved bundle against literal id occurrences in the rendered text. Expect non-empty resolution and zero occurrences.

The unguarded writer

# Break project_drg._serialize_graph (drop a field), then:
PWHEADLESS=1 pytest tests/charter/synthesizer/test_project_drg.py -q
# expect: 23 passed — identical to baseline. Nothing pins it.

The reference cap

# Change BOTH [:10] sites in src/charter/context.py to [:1], then:
PWHEADLESS=1 pytest tests/charter/test_context.py tests/charter/test_compact.py -q
# expect: unchanged counts. No test pins the cap.

Measure reachability correctly

Call resolve_context. Do not reimplement the walk. Four independent lenses produced four different unreachability numbers (91 / 88 / 78 / 59) precisely because each wrote its own BFS.

resolve_context walks scope at depth 1, then requires transitively from directly-scoped artefacts only, then suggests capped at depth. It never follows instantiates. Any hand-rolled {scope, requires, suggests, instantiates} traversal will disagree with it.

Two named sets, both required:

setdepthwhy
compactd=1the steady state — what every agent gets after first load, and the stricter measure
bootstrapd=2what the action-doctrine bundle calls

Seeds are action nodes and activated agent profiles (D2).


Run the right tests

# Parallel, per CLAUDE.md
PWHEADLESS=1 pytest tests/ -n auto --dist loadfile -p no:cacheprovider

# Named gate files for this mission — NOT the full architectural suite
PWHEADLESS=1 pytest \
  tests/doctrine/drg/migration/test_extractor_projection.py \
  tests/doctrine/drg/test_model_strictness_roundtrip.py \
  tests/doctrine/drg/test_kind_mapping_totality.py \
  tests/architectural/test_layer_rules.py \
  tests/architectural/test_runtime_charter_doctrine_boundary.py -q

# Before pushing anything under src/doctrine/ or user-facing prose (~0.1s, CI-only gate otherwise)
pytest tests/architectural/test_no_legacy_terminology.py

Baseline-red discipline. A broad run shows red that is not yours. Classify before fixing: known-P0 reds on main, CI-environment failures (auth, sync toggles), and stale-install false reds (pip install -e . after touching anything that shells out to spec-kitty). Confirm against the merge-base before folding a failure into your work.

Baseline for this mission (all green at ed470756e): test_extractor_projection.py + test_runtime_charter_doctrine_boundary.py → 10 passed; test_template_asset_e2e.py + test_extractor_asset.py + test_artifact_kinds.py → 50 passed; test_docs_structural_lint.py → 29 passed; test_layer_rules.py → 17 passed.


Verify the asset path the way SC-003 requires

In-repo verification cannot failresolve_doctrine_root() falls back to the dev layout. The criterion needs a built wheel in a clean environment with the repository root absent from resolution inputs:

uv build --wheel
python3 -m venv /tmp/sc003 && /tmp/sc003/bin/pip install dist/spec_kitty_cli-*.whl
cd /tmp && /tmp/sc003/bin/spec-kitty doctrine asset path common-docs-structural-lint

Traps that already cost time

TrapWhat happens
charter_file:Does not exist. The pointer is charter: and already ships. Introducing the other name mints a competing pointer — the defect FR-017 removes
Deleting the mirror first_charter_activated_urns reads config.yaml's activated_*. Delete it before repointing and the gate's floor assertion fails while its stray guard goes vacuously true
Fixing resolver.py aloneChanges nothing observable. _render_text never reads those four fields; the drop is in _render_bootstrap_text
Trusting rewrite_opposed_by is unguardedIt is guarded (test_model_strictness_roundtrip.py:520/557) and goes red when B1 lands. project_drg is the unguarded one
Adding asset to some kind mapsTwo of the four _PROJECT_KIND_DIRS copies are exempted from the totality guard, so a partial fix goes green and the scaffold writes where the resolver never reads
Non-recursive overlay globBaseDoctrineRepository._project_scan uses glob, not rglob. Org-pack assets at the ADR-mandated nested path are never discovered
Anchor asymmetryBuilt-in blob paths anchor at the parent of assets/built-in; org/project anchor at the dir. One shared rule yields .../built-in/built-in/...
Counting id normalization as progressNormalizing the directive id form swings the unreachable count ~20 with zero reachability change. C-009 excludes it from SC-005
Line numbers from the discovery docsFour anchors in the fix-sizing table drifted. Function names are correct — grep by symbol

Landing order

IC-01 first and alone. It is the B1 unblock and must carry no inbound dependency (C-005). Land it even if everything else takes review rounds.

Then: IC-02 and IC-04 (independent) → IC-03 (needs IC-02) and IC-05 (needs IC-04) → IC-06 (needs IC-04, IC-05) → IC-07 and IC-08 (need IC-06) → IC-09 (needs IC-03, IC-05).

C-005's limit: the independence is a build-order claim only. Once IC-06 lands, the project-tier graph is merged into the graph every agent's context traverses, so IC-01's tests must cover the merged-graph read path, not only the write path.