Goal
Invert surfaces.py + envelope.py from “bundle precomputed surfaces, emit row counts” into “select computed analytics and assemble the full tier catalogue” (R1, R4). Deliver the full 15-tier catalogue — 14 analytic selectors, each a selector over an EXISTING intel-query surface returning rows + a dark flag, plus 1 coverage-gaps meta-tier realized from those dark flags.
Implementation Sketch
The catalogue is 15 tiers: 14 analytic selectors over live intel-query surfaces plus 1 coverage-gaps meta-tier. This 15-tier total is what sc-0002 (All 15 tiers emit {rows, dark}) gates against — the count below is the deliverable side of that acceptance gate.
- New
scripts/intel_package_runtime/tiers.pyholds a single tier registry. Each registry entry is one tier keyed by tier name, carrying four fields:source_query(the exactintel-query.shsubcommand orcypherquery the selector runs),row_schema(the shape of one emitted row),dark_condition(the concrete predicate that flipsdark: true), andowning_target_kinds(which target kinds include the tier — the vocabularytarget-kind-tierss-aa802633tier_selection.pyconsumes). This registry is the SSOT for tier names;genre-inversion-tiersandtarget-kind-tiersshare it so neither re-declares a tier vocabulary. - The 14 analytic selectors (one registry entry each): terrain (
file-symbols), dependency-graph (cypherintra-set CALLS), semantic neighbors (similar), hidden cross-module callers (cypher), surprises (cyphersurprise_score+ call-resolution-artifact flag), co-change (Commit TOUCHEDcypher), community span (IN_COMMUNITYcypher), test-posture (tests::callercypher), per-symbol churn (hotspot_scorecypher), bug cluster (title+subsystem +blocks), missing-abstraction (MISSING_ABSTRACTIONcypher), plan ownership (symbol-plans), prior-art (cross-reposimilarSOURCE +fixed/search/compare), sentiment (pain_pctile+FailureModecypher). - Tier 15 — Declared coverage gaps (meta-tier): not an independent surface selector. It is the union of every analytic tier whose
darkflag istrue, rendered as one honesty block naming which tiers returned no live rows and why (R8). It is realized entirely by the per-selectordarkflag — no new query — and rounds the catalogue to 15. - Each analytic selector returns
{rows, dark}. Thedark_conditionpredicate is per tier class:- graph-backed tiers (
cypher,file-symbols,callers/callees):dark: truewhenintel-query.sh statusreports the graphstale: true, or the query returns zero rows. - query tiers (
symbol-plans,blocks,fixed/search/compare):dark: trueon a zero-result return. similar(embedding-backed) tiers:dark: truewhen embeddings are stale perintel-query.sh status, or on a zero-neighbor return.- This predicate is consistent with query-selfheal (s-fa1f33bc) serve-stale-and-flag: a refresh-failure degraded read still serves rows AND sets
dark: truerather than dropping the tier. The shared_is_dark(surface_name, rows, graph_status) -> boolutility is owned HERE intiers.py— it realizes each registry entry’sdark_condition, so it lands with the batch-A registry work item (w-08b753bd). Thecypher-reachable graph properties (hotspot_score,IN_COMMUNITY,MISSING_ABSTRACTION,pain_pctile,FailureMode) are graph node/property names reached via thecyphersurface, not dedicatedintel-query.shsubcommands; a property absent from the live graph schema simply returns zero rows for its selector, flipping that tierdark: truevia_is_dark(R8 honesty) — no separate existence-verification deliverable is needed.
- graph-backed tiers (
- Retire the
envelope.pycounts-manifest emission (the### surface - N rowsshape).
Dependencies and Test Gates
- Predecessor: walking-skeleton (s-9948c200) wires ONE tier end-to-end and lands the minimal
surfaces.pyadjacency-row builder; this section fans that one wired tier out to the full 15-tier catalogue and owns the_is_darkpredicate + the tier registry. Successor: the tests section (s-15e599fa) gates the per-tier rows/dark fixtures (a missing graph property surfaces as a dark tier through_is_dark, so it needs no dedicated existence gate). The plan is an INV-19 strict-linear-DAG: the lexorank chain already places walking-skeleton before this section and this section before the tests section, so those contracts are encoded by linear order — no explicitdepends_onedge is added (a diamonddepends_onwould violate INV-19). - Test gates are owned by the tests section (s-15e599fa); this section does not duplicate the matrix. s-15e599fa delivers, per the tier registry: one non-dark rows fixture and one dark-condition fixture per tier class, a counts-manifest-absent negative (asserting no
### surface - N rowsline is emitted, so sc-0002 cannot pass with always-empty selectors), the per-target-kind tier-subset matrix (sc-0005), andtier_selectionactive_tiersverification. Tier 15 coverage-gaps is gated by a fixture forcing >=1 tier dark and asserting the honesty block names it.
Spec References
scripts/intel_package_runtime/surfaces.py(184 lines),envelope.py(369 lines)scripts/intel-query.sh(read-surface inventory)intel-package-rebuild-notes.mdR1, R4;intel-package-example.md§3-§8
Work Items
- Tier registry + analytic selectors batch A (9 of 14): terrain, dependency-graph, semantic neighbors, hidden callers, surprises (+artifact flag), co-change, community span, test-posture, churn. Establishes the registry entry shape (source_query, row_schema, dark_condition, owning_target_kinds).
- Analytic selectors batch B (5 of 14): bug cluster, missing-abstraction, plan ownership, prior-art (cross-lang SOURCE + issues), sentiment. Plus tier 15 — the coverage-gaps meta-tier rendered from the union of dark-flagged analytic tiers (no new surface query). Batch A + batch B + coverage-gaps = 15 tiers, satisfying sc-0002.
- Retire the
envelope.pycounts-manifest; the 15-tier set replaces it as the package body model.