PipeWhy Query Contract C7 version 1.0
October 30, 2026 | PW-11.01-.04 | Consumes C1/C5/C6 and L1 1.0
Specification for the next implementation; not a claim of released query commands.
Mandatory engineering gate Q1 v1.0 applies to every implementation/verification task.

PW-11.01 Snapshot, artifact and path selectors
Snapshot selection uses an explicit canonical 32-lowercase-hex C5 snapshot ID.
No implicit latest, wall-clock ordering, path-as-ID or source-version-as-time alias
is introduced. A coordinator may list candidates, but must pin the selected ID
before a query/cursor is constructed. Namespace and captured scope qualify artifact
IDs; equal numeric IDs in unrelated namespaces do not identify one artifact.

ArtifactCatalog binds one SnapshotMetadata, explicit discovery_complete boolean,
C1 artifact columns and its captured UTF-8 name dictionary. C5 names alone do not
infer semantic array roles; a producer/coordinator supplies these validated inputs.
Artifact IDs are unique non-sentinel uint64, names resolve in the captured dictionary,
and containment is acyclic. An explicitly scoped inventory may retain parent IDs
outside it; those references limit full-path resolution, rather than becoming roots.
Borrowed artifact aliases remain stable for the catalog's lifetime. Captured name
storage is validated and retained; no current source is consulted for a missing name.

A typed ArtifactSelector selects exactly one of artifact_id, name, path. Numeric
names remain text and are never parsed as IDs. Names and path components use exact
captured Unicode identity, without stripping, case folding or logical-profile
normalization. Empty captured labels remain valid exact names. A path is a nonempty
immutable tuple of string name components (including empty captured labels), root
first. A slash in a component is literal; this is not an OS/filesystem path.
CLI string escaping/notation is defined separately in PW-12. An omitted selector
means all represented rows in a query family; it is not a malformed empty selector.

Unqualified names may match multiple artifacts. Full paths consider every matching
root/branch through the final component, so an ambiguous prefix may later become
unique. No first-row/lowest-ID tie breaker chooses an artifact. Results distinguish
FOUND, NOT_FOUND_WITHIN_SCOPE, AMBIGUOUS and UNAVAILABLE. Only FOUND contains one
selected artifact ID. Invalid selector types/IDs/path shapes raise explicit errors.
Ambiguous/unavailable selection cannot silently become a successful query. A captured
stable ID can resolve uniquely despite other discovery gaps. Name/path uniqueness
requires complete discovery in this initial catalog protocol: one represented match
with incomplete discovery remains UNAVAILABLE; two known matches are AMBIGUOUS.

Resolution keeps a bounded immutable sorted candidate-ID prefix (default 32, explicit
positive uint64 max_candidates) and the count of all represented matches. This prefix is diagnostic,
not a chosen result or a claim of complete output. An absent ID/name in incomplete
discovery is UNAVAILABLE, not proof of absence. Full-path selection with missing
ancestry is UNAVAILABLE unless the captured evidence suffices to establish all
matches. NOT_FOUND_WITHIN_SCOPE makes no claim outside the namespace/scope snapshot.

PW-11.02 Typed result families and ownership
Query results are typed by family: SNAPSHOT, DIFF, LINEAGE, INCIDENT, IMPACT, INTEGRITY.
Every page binds query schema version, family, immutable source identities/revisions,
canonical selection/filter/resolution/order, availability/reason and original
coverage/evidence context. Main table columns are flat integer arrays; selected text
lives in UTF-8 payload/offset/length dictionaries. Outputs own immutable selected
arrays and retain source/control owners while consumers use referenced evidence.
Renderers receive this page, not a source adapter or permission to rescan a dataset.

SNAPSHOT: selected captured C1 artifact rows plus SnapshotMetadata, explicit discovery
coverage and requested/retained resolution. Label expansion is confined to selected
rows. Dataset summaries cannot manufacture record/value detail. No inferred semantic
roles for arbitrary C5 arrays are accepted.

DIFF: selected C6 comparison rows, both full contexts, requested resolution and all
original status/reason/flags/observation links. Parent/child-derived changes remain
distinct from direct value changes. Selection/pagination cannot revise C6 certainty.

LINEAGE: selected explicit C1 edge rows and bounded related node IDs, with graph
namespace/declaration/scope/coverage/failures/evidence references. Direction is explicit
forward or reverse; nonnegative depth is minimum-hop distance from pinned starts.
Depth zero selects starts and no edges. Positive depth admits encountered edges
from vertices nearer than the bound, retaining both endpoints, cycles and parallel
edges without duplication. Edge pages sort by stable edge ID; related nodes are
unique sorted endpoints plus selected starts, bounded by twice the edge-page size
plus the start count. Containment is never inserted into lineage. Traversal is a
query operation; a DOT renderer does not discover omitted branches itself.

INCIDENT: selected registry episode rows retain registry identity, explicit policy,
full grouping/observation/timing keys, qualification flags and occurrence counts.
Original divergence/check/observation metadata is carried when supplied and bound.
A saved registry alone is AVAILABLE for grouping state but cannot reconstruct why
evidence: analysis availability then explicitly says REFERENCE_EVIDENCE_NOT_SUPPLIED.
Never represent missing explanation inputs as verified provenance or a clean graph.

IMPACT: selected L1 impact rows retain original graph/divergence context, start IDs,
relation selection and separate POTENTIAL / OBSERVED_DOWNSTREAM_CHANGE flags. Counts
refer to unique matched artifacts, with observed availability separate when no
divergence was supplied. No page turns all reachable nodes into observed corruption.

INTEGRITY: typed aggregate metrics retain selection scope, full matching denominators
and source contexts. C6 status counts include SAME/CHANGED/ADDED/REMOVED/UNKNOWN/
INCOMPARABLE independently and sum to represented matched rows. Content comparability
is a separate denominator: direct SAME/NONE and CHANGED/VALUE_CHANGED rows at observed
non-container levels. Presence/parent moves, derived container changes, unknown and
incompatible rows are not counted as tested content. Registry episode count and sum
of distinct observation occurrences are separate units, never subtracted from an
artifact denominator or described as proven physical corruption events. Cross-registry
IDs qualify by registry identity. Aggregates reconcile with full filtered inputs,
not just the displayed page; page-local counts are explicitly labeled when requested.

Concrete Python family objects/column inventories are published with implementation
and exporter acceptance. There is no guessed generic result that drops source-specific
evidence. L1/C6 required context remains part of each consuming family boundary.

PW-11.03 Bounds, deterministic ordering and cursor validity
All query pages have an explicit positive row limit, default 1000 and maximum 100000
for this initial resource-policy version. Invalid/zero/bool/over-limit bounds fail;
they are not silently clamped. Internal source/index scans may validate/count matching
rows, but output arrays and label expansion remain bounded by the requested page.
The renderer never materializes a whole source merely to print its first page.

Each family declares a total order with unique stable tie-breakers. Artifact snapshot,
diff and impact rows use artifact ID; edge rows use edge ID; registry episodes use
registry-qualified incident ID; fixed integrity metrics use published metric order.
Physical input positions and display labels do not establish cursor order. Returned
rows preserve their original evidence indexes/references beside presentation order.

Page metadata distinguishes total matching count, returned count, truncation and
next cursor. An available empty selection returns zero with no continuation. A final
page has no next cursor; a nonfinal page sets truncated and supplies a continuation.
UNAVAILABLE is distinct from an available zero-row page, even when both have no rows.

Cursor format query-cursor-v1 is opaque URL-safe base64 of canonical UTF-8 JSON,
binding query/result schema versions, a full SHA-256 query identity and a canonical
uint64 decimal-string continuation position. The identity binds exact source snapshot/
registry/context identities, full immutable result/catalog column and label content
digest, selector/filter/resolution, stable ordering and row limit. Digest framing
includes names, dtype, lengths and raw canonical bytes, so ambiguous concatenation
does not alias distinct tables. Validate UTF-8/JSON, exact fields/version/encoding,
identity, position range and source revision before returning another page.

Changing snapshots, catalog content, registry state, filters, ordering, resolution
or page limit invalidates the old cursor. Malformed/stale cursors fail explicitly;
there is no restart-at-zero fallback. Reopening exactly the same immutable input
may reuse its descriptor-bound cursor. These tokens bind read pagination; they are
not authentication, authorization or a secret-bearing remote API capability. No
cryptographic authenticity claim is attached to an unkeyed content identity.

PW-11.04 Coverage, evidence and historical unavailability
Preserve discovery completeness independently from data read/retention coverage and
graph inventory completeness. A complete selected row may coexist with unrelated
capture failures; a small page cannot upgrade the full scope's uncertainty. Keep
full-scope coverage, selection match accounting and pagination truncation distinct.

Retained record/value requests require actual compatible retained inputs at that
resolution. Missing historical payload/ancestry/control evidence returns UNAVAILABLE
with an explicit reason and requested-versus-retained metadata. It never falls back
to a current adapter read or reconstructs fine values from an aggregate fingerprint.
Unknown provenance, operation timing, unsupported rules and incompatible policies
retain their L1/C6 labels and selected metadata. Queries may filter labels explicitly,
but report the filter and cannot claim excluded unknowns were tested or repaired.

Exporter boundary receives only selected family arrays/text and bounded related
evidence, plus all required metadata/control references. JSON uint64 values are exact
decimal strings. Names are presentation; source/observation/registry identities remain
stable. An explanation limited by missing references says so. Further rendering,
CSV/DOT escaping, CLI exit policy and installed command acceptance belong to PW-12.

Implemented selector boundary (PW-11.05)
pipewhy.query exports ArtifactCatalog, frozen ArtifactSelector, Selection,
SelectionStatus and SelectionReason. ArtifactCatalog(metadata, columns, labels,
discovery_complete=...) consumes the explicit C1 table/name triple above. It borrows
read-only artifact columns under stable aliases and owns a validated copied name
dictionary. metadata/discovery_complete/columns/sorted_ids/name_arrays are read-only
properties; resolve_name selects a captured dictionary entry. kind_id stays opaque.

catalog.resolve(selector, max_candidates=32) returns Selection(metadata,
discovery_complete, selector, status, reason, artifact_id, candidate_count,
candidate_ids). Candidate IDs are owned immutable sorted uint64 storage. artifact_id
is NULL_ID unless status=FOUND. candidate_count counts represented matches before
diagnostic-prefix truncation; incomplete discovery can conceal additional matches,
which remains explicit in status and discovery_complete. SelectionStatus strings
are FOUND, NOT_FOUND_WITHIN_SCOPE, AMBIGUOUS, UNAVAILABLE. SelectionReason strings
are MATCH, NO_MATCH, NOT_UNIQUE, DISCOVERY_INCOMPLETE, PATH_ANCESTRY_UNAVAILABLE.

Path resolution uses flat branch masks through every exact component and terminates
without recursion on deep captured containment. Catalog/C1/C6 share one validated
parent-index cycle walk while preserving each boundary's original parent-reference
rules and diagnostic text. C1 tables still reject dangling parents; scoped C6 and
catalog views may preserve external parents. Integration verifies complete and
scoped C4 discoveries saved/reopened through C5 at two capture batch sizes.
Snapshot/diff/lineage/incident/report pagination APIs remain subsequent PW-11 tasks.

Implemented snapshot inventory pages (PW-11.06; PW-11.12 foundation)
snapshot_query(catalog, selector=None, limit=1000, cursor=None,
max_label_bytes=1048576) returns SnapshotPage. It pages the captured artifact
inventory, not normalized record/value payloads. Full SnapshotMetadata exposes
capture scope, retention resolution/counts/failures and fingerprint policy, while
discovery_complete remains independent. No requested finer-payload capability is
implied by this inventory API. Fine historical availability is subsequent work.

SnapshotPage fields are metadata, discovery_complete, selection, availability,
reason, columns, names, total_count, start, limit, max_label_bytes, next_cursor,
query_id. Properties
schema_version=1.0, family=snapshot, returned_count and truncated are explicit.
availability reuses C6 Availability.AVAILABLE/UNAVAILABLE. Snapshot reasons are NONE,
NO_MATCH, AMBIGUOUS_SELECTION, SELECTION_UNAVAILABLE or LABEL_BUDGET_EXCEEDED.
Ambiguous/unavailable selection yields no result rows or continuation, with the
bounded Selection diagnostics retained. Complete absence yields AVAILABLE/NO_MATCH.
An unfiltered partial inventory remains AVAILABLE for represented rows with its
false discovery completeness and original capture failures preserved.

Columns preserve C1 artifact_id/parent_id/name_id as uint64 and opaque kind_id as
uint8, sorted by stable artifact ID. name_id remains the original captured ID.
SelectedNames contains immutable name_ids:uint64, payload:uint8, offsets:uint64,
lengths:uint64, sorted by original unique name ID; resolve(name_id) returns only
a selected captured string. Renderers receive this bounded selected dictionary,
not the full catalog. Empty labels remain empty. Repeated names consume UTF-8 byte
budget once per unique captured name ID. Label byte lengths are checked before
expansion; exceeding the positive explicit budget yields UNAVAILABLE with no
partial/truncated name invention, no result rows and no cursor. Total matching count
and query/source metadata remain available. Changing the budget changes the cursor
binding. Source catalog validation/indexing may process full captured inputs; output
rows/text are bounded separately and no unmeasured memory/latency claim is made.

ArtifactCatalog.identity caches a full SHA-256 over canonical complete metadata,
explicit discovery flag and sorted column/name dictionary framing. Each frame has
an eight-byte little-endian byte length followed by bytes; column frames include
name, logical dtype and contiguous canonical integer bytes. The domain prefix is
pipewhy.query.source.v1 followed by NUL. Descriptor JSON uses C5's existing canonical
encoder. Query identity separately binds schema/family/view, exact selector, order,
row limit and label budget with domain pipewhy.query.v1 followed by NUL. Catalog
artifact aliases must remain stable throughout this cached identity's lifetime.

Cursor payload fields are exactly version=query-cursor-v1, query_id and decimal
position, encoded as unpadded URL-safe base64 of C5-canonical UTF-8 JSON. Schema
version is bound through query_id. Tokens are bounded to 1024 characters; malformed
encoding/UTF-8/JSON, extra fields, noncanonical base64/JSON/position, wrong version,
stale context and positions outside a continuation are rejected. A continuation
position is strictly between zero and total_count. Query digest framing has an
independent literal vector in unit tests. C4 discovery/C5 reopen integration resumes
a real snapshot page on an identically reopened catalog at two capture batch sizes.
Other result-family paging remains pending before PW-11.12 can be closed.

Implemented diff pages (PW-11.07; PW-11.12 foundation)
diff_query(result, selector=None, catalog=None, limit=1000, cursor=None,
max_label_bytes=1048576) pages trusted C6 ComparisonResult producer output. It copies
selected original C6 columns/reasons/flags/observation references without changing
comparison or scope certainty. Full before/after ComparisonContexts, original overall
scope_status/scope_reason and result resolution remain independent from query
availability and row selection. scope_row_count is the original represented count;
total_count is matching represented rows, or null when selection cannot be resolved.
A one-row SAME view cannot turn a changed/uncertain scope into a clean result.

DiffPage fields: before, after, scope_status, scope_reason, resolution, selector,
selection_diagnostics, names_source, names_discovery_complete, availability, reason,
columns, artifact_name_ids, names, name_availability, missing_name_count,
scope_row_count, total_count, start, limit, max_label_bytes, next_cursor, query_id.
Properties schema_version=1.0, family=diff, returned_count and truncated are explicit.
QueryReason adds LABEL_CATALOG_UNAVAILABLE and CONTEXT_INCOMPARABLE for this family.
An incompatible comparison remains inspectable with its exact C6 scope reason,
including when it has no aligned rows; it is never reinterpreted as a clean diff.

Stable ID selectors address comparison rows directly, including REMOVED artifacts
that are absent from an after-snapshot name inventory. Names/paths require an explicit
catalog anchored to a pinned before or after snapshot. No automatic cross-version
name search guesses which name was intended. Binding verifies snapshot ID, namespace,
source version, scope, full fingerprint context and sufficient retained resolution.
Capture/discovery qualifiers from the comparison and name catalog remain independent
and preserved. A missing label catalog prevents name/path selection, with null match
count and no rows/cursor. Ambiguous or incomplete name selection similarly remains
unavailable with its bounded Selection diagnostics.

Absent ID selection needs complete discovery and a sufficient represented projection
to establish NO_MATCH. A known catalog artifact outside a conservative C6 node view,
or an absent ID with incomplete discovery/coarser projection, remains UNAVAILABLE.
The function never supplies missing historical rows from live reads or an aggregate.
Known comparison rows remain available even when their names are unavailable.

artifact_name_ids is an immutable uint64 vector aligned with returned C6 rows;
entries reference original captured IDs in the bounded SelectedNames dictionary.
NULL_ID marks unavailable names. name_availability and missing_name_count describe
returned-row naming, separately from data-query availability. names_source and
names_discovery_complete identify the exact optional captured catalog. Removed rows
can therefore retain their C6 REMOVED fact with an unavailable after-version name,
or obtain a captured name through an explicitly supplied before catalog. No label
or missing label changes a data status. The same selected-name/UTF-8-byte budget
implementation serves snapshot and diff pages; exceeding it returns no partial
data/text page and preserves original contexts/counts with an explicit reason.

Diff cursor identity binds both contexts, scope verdict, result resolution, exact
C6 columns and optional catalog identity, then selector/order/row/label budgets.
Result column hashing scans the captured immutable source buffers per query call;
it does not create a Python object per source row or promise unmeasured latency.
Cross-family, changed-content/context/selection/catalog and changed-bound cursors
are rejected. Reference and native C4/C5 integration saves C1 names and C6 states
together, reopens both, and verifies bounded raw statuses/uncertainty at each page.
Lineage and incident projections are described in the following sections.

Implemented lineage pages (PW-11.08; PW-11.12 foundation)
lineage_query(index, selector, direction=forward, depth=1,
relations=(COPY,TRANSFORM,DERIVED), catalog=None, evidence=(), limit=1000,
cursor=None, max_label_bytes=1048576) selects explicit graph edges. The selector
is a typed ArtifactSelector. depth is a nonnegative uint64; None explicitly requests
all captured reachable depths. A shared frontier traversal with reachability/impact
computes minimum-hop layers, terminates on cycles, preserves parallel/self edges
and marks encountered original edge rows. It never traverses containment or infers
timing/equality edges. LineageIndex.edge_order is immutable original row positions
sorted by stable edge ID, reused for deterministic edge pagination.

LineagePage fields: graph, selector, selection_diagnostics, selected_artifact_id,
direction, depth, relations, availability, reason, columns, node_ids, node_name_ids,
names, names_source, names_discovery_complete, name_availability, missing_name_count,
evidence, missing_evidence_ids, evidence_availability, scope_node_count,
total_node_count, total_count, start, limit, max_label_bytes, next_cursor, query_id.
Properties schema_version=1.0, family=lineage, returned_count and truncated apply.
Original C1 edge columns retain their dtypes and reference IDs. scope_node_count
is captured inventory size; total_node_count is unique captured reachable nodes
including the start; total_count is matched captured edges. Unresolved selection
uses null matching counts. Known isolated/depth-zero starts have one selected root
node and zero edges, distinct from an unavailable unknown graph start.

node_ids are sorted unique returned-edge endpoints plus the selected start, at most
2*limit+1; node_name_ids references original captured dictionary IDs or NULL_ID.
These are page-related nodes, not the entire reachable set. The last edge page can
still omit earlier edges: start and total_count must accompany next_cursor/truncated.
A page cannot certify completeness of a displayed path or uncaptured graph scope.
Names follow the same selected-name byte budget and missing-name qualifications
as diff pages. Name/path root selection requires an explicit captured catalog;
unknown/ambiguous/incomplete roots do not become successful empty graphs. Complete
name absence is scoped to the chosen catalog. Namespace/scope and an explicit
graph snapshot binding must match the catalog. Declaration version and endpoint
data source version are distinct; the query does not equate those version strings.

Optional evidence is an immutable tuple of selected captured Evidence DTOs. Input
IDs must be unique in graph reference context, and a known evidence source version
must match declaration version. Tuple delivery order is canonicalized by evidence
ID. Only payloads referenced by returned edges are included in the page; absent
payload IDs remain in immutable missing_evidence_ids. evidence_availability reports
payload availability for returned references, not completeness/verification of the
whole graph or an operation. Empty edge pages require no payloads. Supplied UNKNOWN
or incomplete provenance remains visible even when its payload is available. All
Evidence kind/producer/version/diagnostic/time/clock qualifiers remain unchanged.
Complete DECLARED evidence describes intent; it does not prove copying occurred.

Cursor identity binds exact graph context/inventory/edge content, optional catalog,
canonical supplied evidence and selection/direction/depth/relations/row/label budgets.
Missing names/evidence do not erase known edges; original inventory coverage/failures
remain explicit. The reference allocator does input traversal/hashing in the query,
not the renderer. Tests include a literal branch/cycle truth set, 24 independent
minimum-distance graph oracles, a 1501-node chain, legacy reach/impact oracles,
bounded related-node counts, selected evidence gaps/order and stored C4/C5 consumers.
Incident family paging is described next.

Implemented incident registry pages (PW-11.09 component; PW-11.12 foundation)
incident_query(registry, selector=None, view=episodes, limit=1000, cursor=None,
event_limit=1000, max_key_bytes=1048576) pages immutable registry state. IncidentFilter
combines registry-local incident ID, exact namespace, scope and artifact ID filters.
Scope needs its namespace; artifact ID needs both. No bare artifact ID is treated
as globally unique. Absent IDs yield scoped empty results in this registry only.

IncidentPage preserves registry_id, policy, selector, view, scope episode/observation
counts, matching count, position/limits, query identity and continuation. Episode
columns retain registry-local incident IDs and exact L1 summaries, including unknown
anchors, mergeability and distinct observation counts. Related events are a bounded
prefix with original observation indices, references, flags, total and explicit
events_truncated. The observations view independently pages every matching event,
including references beyond that prefix, with its incident and group key IDs.
Repeated registration does not create another stored observation or change cursors.

SelectedNames keys retain original registry dictionary IDs and complete canonical
group/observation/timing strings. The shared byte-budget projection preflights UTF-8
lengths and returns an explicit KEY_BUDGET_EXCEEDED unavailable page rather than
partial identities. Arrays and strings are owned immutable selections. The query
hashes the full exported registry plus filters/view/order/bounds; reopened identical
state resumes, while changed state or bounds reject old cursors. This reference
implementation scans/copies registry inputs in the query, never in a renderer;
no measured large-registry latency or allocation guarantee is claimed.

Grouping state includes durable divergence references, not original C6/L1 explanation
payloads. analysis_availability is UNAVAILABLE with REFERENCE_EVIDENCE_NOT_SUPPLIED
for this component. It does not reconstruct missing snapshots, treat stored flags
as verified causes or fetch current data. Selected captured analysis projection
extends this registry-only component as described below.

Selected captured incident analysis (PW-11.09; PW-11.12)
incident_query additionally accepts sources=(), an immutable tuple of producer
IncidentObservations, and support_limit=1000 (1..100000). It validates the policy
and regenerates canonical references from each supplied ranking. Duplicate full
observation identities reject ambiguous explanation inputs. A registry event binds
the exact observation AND timing key; conflicting timing raises rather than revising
the registered fact. Source dictionary positions and numeric IDs are not matched
across independently allocated dictionaries. Source tuple order does not affect
query identity; content, checks/evidence, ranking and support limit do.

IncidentPage.analysis is IncidentAnalysisSelection(availability, reason, items,
missing_observation_indices, support_count, support_total_count), with a
supports_truncated property. Page analysis_availability/analysis_reason delegate
to it. Missing payloads remain explicit original observation indices while available
matched analyses remain inspectable. Grouping availability is independent. An empty
selected set is available when explicit analysis inputs are supplied; no inputs
still declare REFERENCE_EVIDENCE_NOT_SUPPLIED. Key-budget failure exposes no analysis.

Each IncidentAnalysis contains observation_index, full graph/before/after contexts,
scope status/reason/resolution, owned one-row candidate/comparison/timing columns,
resolved clock_domain or null, original ranking_status and full-scope candidate/
earliest counts. It carries bounded supports and corresponding original EdgeCheck
DTOs, support_total_count and supports_truncated. Checks retain qualified and raw
statuses, endpoint observations, provenance qualifiers and transform references;
they do not reconstruct retained transform payloads or certify a physical cause.
Support links use original candidate/check indices and endpoint roles, sorted by
edge ID then role. One support_limit applies across all returned analyses; omitted
supports keep exact totals and an explicit truncation flag. Ranking counts never
require exporting the entire earliest set. Related event limits still apply; the
independent observations view reaches omitted events without expanding every episode.

The renderer receives no original IncidentObservations, ranking or divergence owner.
Large-input acceptance uses 1501 candidates with three episode rows, two related
events and two one-row analysis selections. Shared cursor/row/text bounds now serve
snapshot, diff, lineage and incident families; final cross-family verification and
exporter schema publication remain PW-11.14/.16/.17.

Implemented impact pages (PW-11.10)
impact_query(result, catalog=None, limit=1000, cursor=None, max_label_bytes=1048576,
start_limit=1000) consumes trusted L1 ImpactResult, already selected by explicit
start IDs, relations and include_starts. It does not infer roots from a failed check.
ImpactPage keeps original graph, optional before/after contexts, scope status/reason/
resolution, relation filter and include_starts. Main columns are exact L1 artifact_id,
comparison_index, status, reason and flags, ordered by unique artifact ID. Cycles,
parallel paths and repeated roots cannot duplicate result counts.

scope_potential_count, scope_observed_changed_count and scope_without_observation_count
refer to the full selected L1 result, independently of page size. observed_availability
is AVAILABLE only when a divergence input was supplied; it reports input presence,
not complete testing or verified corruption. UNKNOWN/INCOMPARABLE rows remain visible.
POTENTIAL reachability and OBSERVED_DOWNSTREAM_CHANGE labels are never conflated.
The result does not retain the original unbounded divergence/comparison objects.

start_ids is an owned sorted prefix of at most start_limit (1..100000), with full
scope_start_count and starts_truncated. This explicitly bounds metadata for queries
with many starting artifacts, without implying that omitted starts were not traversed.
A 1501-root test selects two output rows and only three root references. An available
empty potential set is scoped to those starts/relations, not a clean-source finding.

Optional selected names use the same byte budget, original dictionary IDs, missing
name count and separate name availability as diff pages. Shared catalog helpers now
serve comparison/graph binding and diff/impact name projection. Catalog namespace,
scope and explicit graph snapshot binding must match; with observations, it also
binds an explicit comparison endpoint and its version/fingerprint/retention context.
Graph declaration version is not equated with captured data version. Budget failure
returns no partial impact rows/names, preserving full counts/context. Cursor binds
the graph, exact impact columns and full roots, contexts, relation/roots policy,
catalog and row/text/root-prefix limits. No live-source lookup or causal claim occurs.

Implemented integrity totals (PW-11.11; reconciliation PW-11.15)
integrity_query(comparison, registry=None, impact_result=None, limit=1000,
cursor=None, start_limit=1000) counts the full supplied C6 scope. Metric pagination
never changes the population being counted. IntegrityPage preserves full before/
after contexts, scope status/reason, resolution and comparison_scope_row_count.
Optional registry identity/policy and full registry episode/observation counts remain
separate metadata. Optional impact graph/relations/include_starts and a bounded
owned start-ID prefix retain full root count and impact_starts_truncated.

IntegrityMetric IDs 0..14, in published order:
SAME, CHANGED, ADDED, REMOVED, UNKNOWN, INCOMPARABLE, CONTENT_COMPARABLE, CONTENT_SAME,
CONTENT_CHANGED, CONTENT_UNTESTED, INCIDENT_EPISODES, INCIDENT_OBSERVATIONS,
POTENTIAL_IMPACT, OBSERVED_IMPACT, IMPACT_WITHOUT_OBSERVATION.
Selected metric_names and metric_units (artifact/episode/observation) align with
flat columns metric_id:uint8, value:uint64, denominator:uint64, available:uint8
(0 unavailable/1 available), reason:uint8. MetricReason codes: NONE=0,
SOURCE_NOT_SUPPLIED=1, OBSERVATIONS_NOT_SUPPLIED=2. An unavailable zero is not a
known empty population. NULL_ID denominator means not applicable; zero means an
actually empty denominator, never permission to report a successful percentage.

The first six status counts sum to represented comparison rows and use that row
count as denominator. CONTENT_COMPARABLE counts non-container SAME/NONE and
CHANGED/VALUE_CHANGED rows. CONTENT_SAME/CONTENT_CHANGED use only that comparable
count as denominator. CONTENT_UNTESTED equals represented minus comparable rows;
it and CONTENT_COMPARABLE use represented rows as denominator. Parent moves,
presence changes, derived container changes, unknowns and incompatibility do not
become tested content. Different resolutions remain explicit; dataset counts do
not claim individually tested records/values or physical corruption events.

Registry metrics count distinct stored observations with the exact comparison
snapshot pair, namespace/scope, fingerprint policies and represented artifact ID,
plus the distinct episodes touched by those matches. A registry can include other
captures/policies/namespaces; their entries remain in registry_scope_* metadata
but not those selected metrics. An episode spanning other snapshot pairs contributes
only matching observations here. Exact repeated reporting does not increment counts.
Incident denominators are not artifact counts; their denominator is not applicable.

Impact graph namespace/scope and explicit snapshot must bind the comparison. When
observations are supplied, the impact divergence must bind the exact C6 comparison
content/context/resolution. This prevents combining independently changed analyses.
Unique potential, observed and missing-row counts stay independent metrics with
not-applicable denominators. Graph-only potential is available while OBSERVED_IMPACT
is unavailable with OBSERVATIONS_NOT_SUPPLIED. Missing optional sources keep explicit
unavailable metrics, rather than collapsing into a green report or failing known C6
counts. No supplied unbounded result/registry/ranking is retained in the output.

Cursor identity binds exact C6 facts/context, full optional registry state and impact
columns/roots/graph/policy, plus metric order and row/root-prefix bounds. Tests use
literal counts for all six statuses, parent/container exclusions, zero and incompatible
populations, mixed namespace/policy/snapshot registries, repeats after reopening and
independently known native C4/C5 fixture totals across complete/mutated/missing reads.

Historical resolution availability (PW-11.13)
diff_query accepts resolution=None (the materialized result resolution) or an
explicit dataset/record/value request. DiffPage.requested_resolution keeps that
request separate from resolution (the actual C6 materialization) and each endpoint's
retained context resolution. A request finer than either retained endpoint returns
UNAVAILABLE/DETAIL_NOT_RETAINED, no rows/names/cursor and unknown matching total
(null, not zero). Original scope verdict, coarse source row count, capture failures,
metadata and selection diagnostics remain visible. This also catches a C6 fine
comparison that already reports RESOLUTION_UNAVAILABLE with zero rows: those rows
cannot be interpreted as a successful empty history.

When both captures retain the requested detail but the supplied C6 result is
coarser, availability is UNAVAILABLE/COMPARISON_DETAIL_NOT_SUPPLIED. The query does
not claim data was lost; a coordinator can supply a separately materialized captured
C6 result. Coarser-than-materialized requests reject explicitly and must be produced
through the existing C6 compare resolution interface. Invalid resolution names/types
reject; explicit and implicit equal resolutions share cursor identity. Changed
requests invalidate cursors. The query accepts only captured result/catalog inputs;
it cannot consult an adapter, reconstruct fine values from fingerprints or replace
historical data with current data. Snapshot inventory queries remain explicitly
inventory-only; missing captured labels/ancestry and missing incident explanation
inputs use their own qualified availability rather than fabricated detail.

C7 exporter handoff and verification (PW-11.14/.16/.17)
The public query schema is QUERY_SCHEMA_VERSION=1.0. Portable baseline
tests/fixtures/query_schema_v1.json freezes all six page shapes, related selection/
analysis/text DTO fields, exact reason/metric/selection codes, scalar properties,
flat table dtypes, cursor version and required uncertainty/identity qualifications.
C5/C6/L1 context contracts remain authoritative for referenced metadata. Result
properties supplement listed NamedTuple fields. Dict keys/tuple delivery order are
not output row ordering contracts; published stable ID orders are authoritative.

tests/fixtures/query_consumer_v1.json is an independently specified selected-output
truth transcript. tests/unit/test_query_schema.py constructs validated captured
observations/comparisons/checks, reopens a repeated registry and hands its consumer
ONLY six bounded pages.
The consumer resolves only selected text, preserves exact uint64 decimal strings,
unknown timing, declared intent, partial graph failures, bounded support checks,
potential-versus-observed impact and full-denominator metric metadata. It receives
no adapter, inventory, C6 source arrays, graph index, ranking or registry to rescan.
This is a consumer acceptance fixture, not the PW-12 JSON serializer implementation.
IDs above JSON floating-point precision retain their exact decimal representation.

PW-11.14 verification covers all 30 unequal source/target pairs across the six query
families: a cursor from any other family rejects without restart. Each family resumes
its own bound source. Existing selector/page suites cover malformed/noncanonical/
padded/overlong cursor tokens; changed source/context/content/order/filter/limit/
text/key/evidence/root/support bounds; duplicate names; incomplete discovery;
missing ancestry; exact numeric/slash/empty names and independent catalog reopening.
Selections never guess a first ambiguous row or silently substitute live labels.

PW-11.16 verification checks owned immutable contiguous uint8/uint64 family tables,
selected dictionaries and incident observation/event variants against the portable
schema. Empty/unknown matching totals, page and evidence-prefix truncation, exact
UTF-8 budgets and failures outside selected rows remain qualified independently.
The 1501-node lineage, 1501-candidate incident and 1501-root impact cases establish
bounded returned arrays/control prefixes, without claiming constant query-side
allocation or measured native instruction coverage. Separate native/reference C4/C5
consumers verify persisted identities, missing reads, original statuses and requested
historical detail availability. Capture failures remain in metadata even when a
selected row is SAME. A renderer must show omitted/unknown scope rather than infer
that an available page is complete or that an absent continuation proves full scope.

Initial exporter capabilities are selected-family text/JSON, tabular CSV with its
metadata policy and explicit-edge DOT. Format grammar/escaping, CLI configuration,
exit codes and stdout/stderr separation remain PW-12 implementation. Adapters and
entire captures belong to coordination/query producers, not serializers. Changes to
published fields/codes/semantics require explicit schema/version compatibility review
and a corresponding portable/reference-consumer update.
