100%

Goal

Target-kind-aware tier selection (R3): the active_tiers set per target kind — bug, plan-section, symbol-set, diff, subsystem. A tier renders only when its key is in the kind’s active set, and only active-tier selectors execute their graph queries.

Implementation Sketch

  • scripts/intel_package_runtime/tier_selection.py: derives the active tier set per target kind by INVERTING the tier registry’s owning_target_kinds field (the tiers.py registry is the SSOT per genre-inversion-tiers s-1fe9a664 — active_tiers(kind) = [t for t in REGISTRY if kind in t["owning_target_kinds"]]). It carries NO hard-coded kind->tier-list vocabulary; the tier vocabulary lives in exactly one place (the registry’s 15 entries). Because the derivation is a pure inversion of owning_target_kinds, the body names NO tier key outside the registry SSOT — the authoritative per-kind mapping is asserted by the active_tiers verification test (tests section s-15e599fa), not duplicated as source data here.
  • The TARGET_KINDS reconcile is ALREADY DONE in code (work item w-bca82065 reconcile sub-unit below). The single SSOT is scripts/intel_package_runtime/target_kinds.py (the closed frozenset {plan-section, bug, diff, symbol-set, subsystem}, lifted to its own module to break the envelope -> tiers import cycle). envelope.py:24 re-exports it (from .target_kinds import TARGET_KINDS; the envelope.py:26 name is now a re-export, NOT a divergent declaration) and tiers.py:25 imports it the same way (from .target_kinds import TARGET_KINDS). No divergent re-declaration remains in tiers.py. subsystem is already present in the SSOT. Remaining w-bca82065 work is the per-kind active-tier THREADING, not the taxonomy reconcile.
  • The subsystem target kind is ALREADY present across every SSOT sync point (target_kinds.py, envelope.py SURFACE_MATRIX + build_surfaces, target_resolve.py is_resolvable, generate.py dynamic taxonomy) — verify-only at implementation (work item w-bca82065 sub-unit below).
  • Thread the per-kind active-tier set through envelope.py:build_dossier -> tiers.py:assemble_tiers (work item w-bca82065 sub-unit below) so inactive-tier selectors are skipped before query execution.
  • The per-kind narrowing happens at the CALL SITE render.py:164 (active = active_tiers_from(tiers.keys())): change its argument from the FULL tiers.keys() set to the per-kind active_tiers(kind) list so only active-tier guards render true. The active_tiers_from FUNCTION (render.py:66) is reused unchanged — it maps names through guard_key and drops the meta-tier.

Per-kind active-tier matrix (derived, not authored)

The matrix below is the OUTPUT of active_tiers(kind) = [t for t in REGISTRY if kind in t["owning_target_kinds"]] over the reconciled TARGET_KINDS.

  • Reproduced here as a derivation check ONLY — the tiers.py:REGISTRY owning_target_kinds fields remain the SSOT and the s-15e599fa test is the authoritative assertion.

  • Counts include the always-present coverage-gaps meta-tier (_ALL_KINDS).

  • bug — every tier whose owning_target_kinds contains bug: terrain, dependency-graph, semantic-neighbors, hidden-callers, surprises, co-change, community-span, test-posture, churn, bug-cluster, plan-ownership, prior-art, sentiment, coverage-gaps (14 of 15 registry tiers; missing-abstraction is the only excluded registry tier), PLUS the bug-only defect VIRTUAL tier (15 guard keys total for bug). defect is NOT a tiers.py:REGISTRY entry and is NOT emitted by the registry inversion or render.py:_REGISTRY_TO_GUARD (line 36-54, which carries no defect key); the template guard {% if 'defect' in active_tiers %} (package.md.j2:41) gates the bug-only ## 1. The defect section (intel-package-example.md:31) on defect membership. The active-tier selector therefore INJECTS defect into the bug active set as a virtual (non-registry) guard key AFTER the registry inversion — see the virtual-tier injection in w-605bd83b. defect lights ONLY for bug; no other kind receives it. The s-15e599fa per-kind test asserts 'defect' in active_tiers(bug) AND 'defect' not in active_tiers(kind) for every non-bug kind.

  • plan-sectionterrain, dependency-graph, test-posture, plan-ownership, coverage-gaps (5).

  • symbol-setterrain, dependency-graph, semantic-neighbors, hidden-callers, missing-abstraction, prior-art, coverage-gaps (7).

  • subsystem — all 15 tiers (subsystem is in every owning_target_kinds entry, the broad-context kind).

  • diffdiff is already a member of tiers.py:350 _ALL_KINDS (the tuple is ("bug", "plan-section", "symbol-set", "subsystem", "diff"), carrying the comment “per target-kind-tiers s-aa802633”). Every tier whose owning_target_kinds is _ALL_KINDS therefore already lights for a diff target: terrain (tiers.py:360), dependency-graph (tiers.py:368), and the always-present coverage-gaps meta-tier (tiers.py:472) — a non-empty diff active set today. The s-15e599fa test test_active_tiers_diff_set_is_the_definitive_five asserts this exact 5-tier diff active set. The DEFINITIVE remaining diff-extension set (add diff to each tier’s owning_target_kinds tuple, in this order) is exactly two analytic tiers: semantic-neighbors (tiers.py:376, today ("bug", "symbol-set", "subsystem")) and hidden-callers (tiers.py:384, today ("bug", "symbol-set", "subsystem")). Both are symbol-graph-adjacency tiers that operate on the diff’s resolved changed-file symbol set (per the diff:<ref> resolver) and therefore carry real signal for a code-change target. No other analytic tier is extended for diff: surprises/co-change/community-span/churn/sentiment/bug-cluster are bug/subsystem-scoped diagnostics, test-posture/plan-ownership are plan/bug-scoped, missing-abstraction is symbol-set/subsystem-scoped — none is meaningful for a raw diff target. The resulting diff active set is therefore terrain, dependency-graph, semantic-neighbors, hidden-callers, coverage-gaps (5). The s-15e599fa per-kind test covers diff alongside the other four reconciled kinds and asserts this exact 5-tier set so no kind in the SSOT lacks a per-kind tier set + assertion.

Spec References

  • scripts/intel_package_runtime/target_kinds.pyTARGET_KINDS frozenset (the closed taxonomy SSOT; all five kinds incl. subsystem).
  • scripts/intel_package_runtime/tiers.pyREGISTRY (lines 355-476) owning_target_kinds per entry; TARGET_KINDS re-import (line 25, from .target_kinds import TARGET_KINDS); _ALL_KINDS (line 350); ANALYTIC_TIERS (line 480); assemble_tiers (line 484); semantic-neighbors entry (line 376) + hidden-callers entry (line 384) — the two diff-extension targets.
  • scripts/intel_package_runtime/envelope.pyTARGET_KINDS re-export (line 24, from .target_kinds import TARGET_KINDS); SURFACE_MATRIX (line 44, subsystem entry present); build_surfaces (line 115, subsystem branch at line 151); build_dossier.
  • scripts/intel_package_runtime/target_resolve.pyis_valid_kind (line 30); is_resolvable (line 32, subsystem branch at line 45); imports TARGET_KINDS from envelope (line 13).
  • scripts/intel_package_runtime/generate.py — invalid-kind error message (line 143, derives taxonomy from sorted(TARGET_KINDS) dynamically).
  • scripts/intel_package_runtime/render.pyactive_tiers_from FUNCTION (line 66, unchanged); its CALL SITE (line 164, active = active_tiers_from(tiers.keys())) is the per-kind narrowing point; defect None-bind block (lines 387-394, the defect-population target).
  • scripts/plan_corpus/schemas.py:1845 BUG_SUBSYSTEM_TO_CRATES — the canonical subsystem-name vocabulary the subsystem ref grammar draws from.
  • intel-package-template.md.j2 (the {% if 'tier' in active_tiers %} guards); intel-package-rebuild-notes.md R3.

Work Items

  • tier_selection.py — derive active_tiers(kind) purely by inverting tiers.py:REGISTRY owning_target_kinds; carry no hard-coded kind->tier vocabulary. AFTER the registry inversion, inject the bug-only defect VIRTUAL guard key: active_tiers(kind) appends "defect" to the result iff kind == "bug". defect is the ONLY virtual (non-registry) guard key; it is named once in tier_selection.py as the bug-only injection constant (not a tiers.py:REGISTRY entry, never round-tripped through render.py:_REGISTRY_TO_GUARD). This is what makes {% if 'defect' in active_tiers %} (package.md.j2:41) fire for bug targets and stay false for every other kind. envelope.py:build_dossier consumes the per-kind set. The implementer changes the CALLER at render.py:164 — today active = active_tiers_from(tiers.keys()) (the full registry-tier set) — to feed the per-kind active_tiers(kind) list instead: active = active_tiers_from(active_tiers(kind)) (or equivalent: pass the narrowed name list into the existing active_tiers_from). The active_tiers_from FUNCTION at render.py:66 is NOT modified — it already drops the coverage-gaps meta-tier and identity-maps non-_REGISTRY_TO_GUARD keys, so the injected defect passes through unchanged; only its CALL SITE (line 164) changes which name set it receives. Implementation notes for the call-site change: render.py today imports neither tier_selection nor active_tiers (verified — render.py imports only re, Path, Any, jinja2, and verdicts), so the implementer adds from .tier_selection import active_tiers to render.py; kind is already bound at render.py:154 (kind = _str(target.get("kind"))), so the per-kind call active_tiers(kind) at render.py:164 has its kind argument in scope without further plumbing.
  • Add the subsystem target kind AND reconcile the taxonomy SSOT AND thread the per-kind active-tier set — three sub-units of one cohesive taxonomy-extension deliverable:
    • Reconcile TARGET_KINDS to ONE SSOT — ALREADY DONE. The SSOT is scripts/intel_package_runtime/target_kinds.py (the closed frozenset, lifted to its own module to break the envelope -> tiers import cycle). envelope.py:24 re-exports it; tiers.py:25 imports it; no divergent re-declaration remains. subsystem is in the SSOT. diff STAYS a kind — it has a SURFACE_MATRIX entry (envelope.py:44) + a build_surfaces branch + an is_resolvable branch (target_resolve.py). No remaining reconcile work; the s-15e599fa per-kind tests cover all five kinds.
    • Thread the per-kind active-tier set from envelope.py:build_dossier into tiers.py:assemble_tiers (line 484) so assemble_tiers walks only the active-tier subset of ANALYTIC_TIERS (line 480) and skips every inactive-tier selector BEFORE running its query — no wasted graph calls. This threading is the genuine REMAINING w-bca82065 work. For the diff active set, extend exactly two analytic tiers’ owning_target_kinds to include diff: semantic-neighbors (tiers.py:376) and hidden-callers (tiers.py:384) — the definitive diff-extension set per the matrix diff row above (terrain/dependency-graph/coverage-gaps already carry diff via _ALL_KINDS at tiers.py:350). The s-15e599fa tests own a NEGATIVE assertion proving an inactive-tier selector is never invoked for a given kind.
    • subsystem kind across EVERY SSOT sync point — ALREADY DONE (verify-only at implementation; do NOT re-add):
    • target_kinds.py TARGET_KINDSsubsystem present in the frozenset.
    • envelope.py SURFACE_MATRIX (line 44) — subsystem entry present (("bugs-for", "insights-hotspots-view")).
    • envelope.py build_surfaces (line 151) — subsystem branch present.
    • target_resolve.py is_resolvable (line 45) — subsystem branch present implementing the subsystem ref grammar (below).
    • generate.py invalid-kind error message (line 143) — derives the taxonomy string from sorted(TARGET_KINDS) dynamically (no hardcoded string to update; subsystem flows in automatically).
    • Subsystem ref grammar (state explicitly): a subsystem:<name> ref resolves iff <name> is a key in scripts/plan_corpus/schemas.py:1845 BUG_SUBSYSTEM_TO_CRATES (typeck, codegen, parse, eval, arc, canon, runtime, diagnostic, fmt, registry, plus the exempt-tooling keys harness, tooling, scripts, docs, skills). is_resolvable("subsystem", name) already returns name in BUG_SUBSYSTEM_TO_CRATES (target_resolve.py:45, present). The resolved objective symbol set for a subsystem target is the union of symbols owned by that subsystem’s crates (resolved via per-crate file-symbols per the subsystem:<name> resolver in w-18edfbb5). The existing select_bug_cluster already consumes the subsystem string against b.subsystem='{sub}' at tiers.py:254, so the cluster kwarg is wired; the remaining work is the w-18edfbb5 resolver_fn objective-set entry, not the is_resolvable branch.

Items

  • Production per-kind objective-symbol resolver: implement real resolution of bug:/plan-section:/diff:/subsystem: target refs to objective symbol sets, naming the intel-graph edge per kind (no hand-wave; the resolver is executable-as-written):
    • bug:<id> -> symbols via the MENTIONS_CODE edge on the plan/bug DAG (:PlanBugNode -[:MENTIONS_CODE]-> symbol, per CLAUDE.md §Intelligence Graph). The objective set is the union of symbols the bug node mentions; query through scripts/intel-query.sh (the canonical graph wrapper) so the resolver degrades gracefully when the graph is down.
    • plan-section:<id> -> symbols via the same MENTIONS_CODE edge from the section node (HAS_SECTION/HAS_SUBSECTION locates the node; MENTIONS_CODE yields its symbols). Objective set = union of symbols the section mentions.
    • diff:<ref> -> symbols via changed-file -> owning-symbol resolution in a SINGLE batch query (no per-file shell-out loop): (1) enumerate the diff’s changed-file set in ONE call — scripts/intel-query.sh diff-context [--since <ref>|--staged] (intel-query.sh:122) returns the changed-file set graph-side, falling back to git diff --name-only <ref> for a SHA/range when diff-context is unavailable; (2) resolve the WHOLE changed-file set’s owning symbols in ONE batch graph read — a single scripts/intel-query.sh cypher "<query>" (read-only MATCH/RETURN; surfaces.py run_cypher rejects any write token) returning the declarations for the entire changed-file set, NOT file-symbols invoked per file in a loop (the per-file loop is the WASTE:performance shape this avoids); (3) the batch result IS the objective set. The dependency-graph tier then expands by CALLS adjacency at tier-assembly time — the resolver’s job ends at the changed-file -> owning-symbol union. Route every query through scripts/intel-query.sh so the resolver degrades gracefully when the graph is down.
    • subsystem:<name> -> symbols via crate-membership + a SINGLE batch file-symbols query (no per-crate shell-out loop): (1) look up the subsystem’s crate list — BUG_SUBSYSTEM_TO_CRATES[<name>] from scripts/plan_corpus/schemas.py:1845 (the canonical subsystem->crates map; <name> validated by target_resolve.is_resolvable("subsystem", name) which is already wired); (2) resolve the union of all those crates’ symbols in ONE batch graph read — a single scripts/intel-query.sh cypher "<query>" returning declarations for the whole crate-path set (a read-only MATCH/RETURN over the crate source roots), NOT file-symbols invoked per crate in a loop; (3) the batch result IS the objective set. Route every query through scripts/intel-query.sh for graceful degradation.
    • Make the production resolver the DEFAULT, not an injected seam. The production ResolverFn lives in a new module-level function surfaces.production_resolver(kind, ref) -> list[str] (alongside surfaces.resolve_objective_symbols at surfaces.py:154-172; it routes the four per-kind arms above through scripts/intel-query.sh per the ResolverFn type at surfaces.py:151). generate() (generate.py:113) and build_package() (generate.py:45) DEFAULT resolver_fn to surfaces.production_resolver when the caller passes None — so the real CLI path (_cmd_generate, scripts/intel_package_runtime/__main__.py:35) AND heal._regenerate_and_persist (heal.py:124, which threads only {out_dir, query_fn, status_fn} and never a resolver_fn) auto-resolve targets WITHOUT an injected seam. The injected resolver_fn parameter STAYS as a test-only override seam; the default wiring is the incident fix that stops surfaces.resolve_objective_symbols’s injected-only path from being the sole wired path. With the default in place, build_package always reaches the dossier branch (generate.py:74) for a resolvable target, never the legacy counts-manifest branch.
    • Populate the defect render block from the bug source, two-armed by plan-dir presence. render.py:387-394 currently binds defect with repro=None, divergence_rows=[], approach=None, table_headers=[] for ALL targets — a None-guarded EMPTY block. The transport: a defect-population step in envelope.build_dossier (envelope.py:221) reads the bug source and writes the parsed fields onto dossier["defect"] alongside (NOT inside) the MENTIONS_CODE symbol resolution; render.build_pkg_context (render.py:136) then reads dossier["defect"] into the render-context defect dict at render.py:387-394 instead of binding the None/[] defaults. A defect-population step in build_dossier is the cleaner site than a resolve_defect() arm of the symbol resolver — symbol resolution yields the objective set, defect population yields prose+table, two distinct outputs. The bug source has TWO arms (verified: the canonical example bug BUG-05-010 has NO plan dir on disk):
      • WHEN the bug’s plan dir at bug-tracker/plans/BUG-XX-NNN/content/ is PRESENT (rich source): repro <- the reproduction/symptom prose in content/overview/mission.md; divergence_rows + table_headers <- the divergence table in content/root-cause-analysis--s-*.md; approach <- the consensus fix prose in content/fix-consensus--s-*.md.
      • ELSE (aggregate-only bug like BUG-05-010, no plan dir): fall back to the bug’s BugTrackerEntry in bug-tracker/open-bugs.json / closed-bugs.json (the aggregate entry, keys id, subsystem, severity, title, status, plan_dir, found_date, resolved_date, repro): repro <- the entry’s repro field (or title when repro is null); approach <- left None (no consensus exists pre-fix); divergence_rows <- [] with table_headers [] (the divergence table is RCA-only). This arm STILL produces a populated ## 1. The defect section — repro + the subsystem/severity/status header all render from the aggregate entry.
      • divergence_rows shape MUST match package.md.j2:45-49: a LIST of row-LISTS, each inner list aligned positionally to table_headers (rendered {{ row | join(' | ') }}), NOT a two-key {expected, actual} dict — table_headers carries the RCA table’s actual column labels (e.g. the four-column Surface | File | Reports alignment as | Direction shape in intel-package-example.md:37-41), and each divergence_rows entry is one full table row of cell strings in column order. The defect-population step threads these onto dossier["defect"] so ## 1. The defect (intel-package-example.md:31-49) renders with real content. Non-bug targets keep the None-guarded empty block (the guard key is absent for them, so the section is suppressed regardless). This populated defect block is what closes sc-0012’s approved-example conformance — the guard-key injection in w-605bd83b makes the section RENDER; this population makes it render with CONTENT.
    • Completed-by tests s-15e599fa.

sc-0012 verification note

sc-0012 (owned by this section) drives the REAL production entry point per layer-coverage.md §1 L12 — NOT a seam-injected resolver_fn. The completion phase MUST verify ALL of the following against the real path:

  • CLI no-injection probe (primary). python -m scripts.intel_package_runtime generate --target bug:BUG-05-010 with NO injected resolver_fn. Assert: non-empty dossier-genre package.md; zero counts-manifest substrings (the dossier branch, not the legacy build_surfaces branch); adjacency rows present; DIG DEEPER block present; exactly one pinned VERDICT line.
  • Approved-example conformance — explicit defect assertion. Assert the bug: dossier renders the bug-only ## 1. The defect section (intel-package-example.md:31) WITH POPULATED content — repro text, divergence rows, and approach all non-empty (per the w-18edfbb5 defect-block population). A dossier that omits the defect section, or renders it empty (the pre-fix render.py:387-394 None-bind shape), FAILS this assertion. This is the load-bearing approved-example-conformance check; an assertion that passes on a defect-less dossier is insufficient.
  • Heal-path probe. heal._regenerate_and_persist invoked with NO injected resolver_fn (kwargs limited to {out_dir, query_fn, status_fn} as the production caller threads them). Assert the heal-regenerated package matches the dossier-genre shape — proving the resolver_fn is wired at the heal entry point, not only at the CLI entry point.
  • Per-kind CLI probes. Run generate --target <ref> for each kept kind with no injected resolver_fn, using these CONCRETE verified-resolvable refs (one per kind):
    • bug:BUG-05-010 — the canonical example bug (subject of intel-package-example.md; aggregate-only, no plan dir — exercises the cure-1 fallback arm).
    • plan-section:intel-package-dossier-rebuild/tests--s-15e599fa — a real section of this plan (sibling content file tests--s-15e599fa.md exists on disk).
    • diff:HEAD~5..HEAD — a real git range ref (resolves via the diff-context/git diff changed-file path of the cure-4 resolver).
    • subsystem:typeck — a real key in BUG_SUBSYSTEM_TO_CRATES (scripts/plan_corpus/schemas.py:1845, maps to ori_types, ori_ir).
    • symbol-set:optimize_result_repr,build_result_variants — the example objective symbols (ori_repr::layout::niche::optimize_result_repr + build_result_variants, named in intel-package-example.md:58-59; symbol-set ref carries them verbatim comma-separated). Assert each produces a dossier-genre package.md whose active-tier blocks match active_tiers(kind) from w-605bd83b (defect present ONLY for bug:BUG-05-010; the diff active set non-empty per the matrix row).