PipeWhy Lineage/Incident Contract L1 version 1.0 October 30, 2026 | PW-09.01-.07 | Refines C1, C6 and C7 Scope and D6 implementation choice The initial enforceable transform is C4's declared cents_to_dollars_v1: stable row keys/count unchanged and target_amount * 100 == source_amount. This is a bounded fixture-supported implementation choice under continued-development authorization, not a claim that arbitrary enterprise transformations or causal tracing are solved. Only explicit declared/observed edges are accepted; equal fingerprints create no edges. Unknown provenance, timing, unsupported rules and missing detail stay visible. The implementation remains for accidental drift detection under C3 limitations. PW-09.01 Relation semantics and flat representation Containment is the acyclic parent forest from C1/C6. It is excluded from lineage traversal. C1 edge relation codes remain COPY=0, TRANSFORM=1, DERIVED=2; no codes are reassigned. COPY requires a sentinel transform ID. TRANSFORM requires a declared transform ID. DERIVED is a declared dependence, optionally naming a transform; it supports reachability, with no generic equality/transform inference rule. Lineage cycles, self-edges and parallel edges are valid. Dangling endpoints, duplicate edge IDs, unsupported relation codes and broken evidence/transform references fail. Namespace/scope accompany stable artifact IDs. Names and physical row indexes never establish cross-snapshot identity. Graph inputs borrow stable C1 integer buffers. Build forward/reverse CSR indexes: a sorted stable artifact ID vector; uint64 offsets of length vertex_count+1; uint64 original edge-row indexes of length edge_count. An edge row is a position, not its edge_id. Retain original edges and evidence links. No retained nested adjacency lists or per-node Python graph replaces flat storage. Traversal terminates on cycles and emits each selected stable ID at most once, in sorted ID order. Default reachability excludes the selected start even if a cycle reaches it again; an explicit include_self option includes it. An unknown start ID is an error, not an alleged known empty graph. Relation filters are explicit and never introduce containment. Scope coverage accompanies otherwise valid results. PW-09.02 Evidence and completeness Each edge references a non-sentinel evidence ID. Evidence records carry provenance kind (DECLARED=0, OBSERVED=1, UNKNOWN=2), producer/version identity, source version, capture time/window and clock domain when known, completeness and diagnostic detail. Text lives in immutable UTF-8/offset/length dictionaries or compact control metadata; bulk computational/reference fields remain flat integer arrays with stable IDs. The implementation publishes exact evidence columns before accepting a consumer. Unknown metadata uses explicit validity/sentinel fields rather than guessed values. Timing-known windows require start<=finish and an identified clock domain. A timestamp of zero is a possible epoch value when timing is valid; it is not a universal null. Evidence describes what was supplied, with independent confidence/completeness: DECLARED records intended dependence; OBSERVED records a producer-reported operation or observation; UNKNOWN lacks usable provenance. A complete declaration is still a declaration. Producer source versions identify the evidence capture; endpoint data versions and snapshot/observation references identify the values being checked. Never equate a declaration-document version with both endpoint data versions. Operational claims additionally need explicit endpoint version/observation links. Retain complete/partial/unavailable evidence coverage and failure diagnostics. C4 lineage is declared fixture intent, captured without operation execution times or endpoint version bindings. Preserve this limitation even though its induced scope graph is COMPLETE_WITHIN_SCOPE. A snapshot's read window does not invent the execution time of a copy. Missing evidence does not remove an observed edge or make it verified. Incomplete graph scope limits impact claims beyond the captured edges. PW-09.03 Allowed transformation and exact verification Rule name cents_to_dollars_v1, integer factor 100, key_field_id=0, amount_field_id=1, source unit cents, target unit dollars. Other rules are explicitly unsupported. Source keys/amounts are C2 integers; target keys are C2 integers and amounts finite C2 Decimals. Row keys are unique, matched by identity independently of physical ordering, and expected/returned counts must be complete on both sides. Extra, missing or duplicate keys cannot be silently ignored. Required fields, profile IDs, scope/source identity and retained record/value evidence must be validated. The invariant compares exact signed integer cents with the finite decimal's coefficient times 10^(exponent+2). It uses bounded integer arithmetic, not float conversion or ambient Decimal precision. Reject malformed C2 payloads. Unsupported valid types/policies/rules return INCOMPARABLE with a reason. Null/missing/nonfinite amounts or unavailable required historical detail prevent a proven invariant and return UNKNOWN with their reason. Source/target count/key differences in complete captures yield FAIL. Resource limits are explicit; huge exponents never allocate an unbounded power of ten. Zero, sign, coefficient and exponent boundaries are tested. Checks return PASS=0, FAIL=1, UNKNOWN=2, INCOMPARABLE=3, plus reason/evidence and input snapshot/version/observation references. PASS means this declared invariant holds for captured rows; FAIL means observed values violate it. Neither diagnoses physical corruption or an execution origin. TRANSFORM fingerprint differences alone are expected, so they are not a generic FAIL. Copy checks can compare fully captured eligible C3 states; equality is probabilistic under C3, not proof of a copy operation. Strict representation remains the default for hashing/comparison. This explicitly named business invariant may relate integer cents to Decimal dollars without changing either snapshot/profile, converting raw C6 comparison results or enabling logical normalization globally. C4 baseline C is a valid transform of B; the mutated B amount 251 versus retained C amount 2.50 fails the numeric invariant under this fixture rule. PW-09.04 Divergence eligibility and certainty Use C6 compatible captured observations and direct content-change evidence. Structural parent moves, added/removed presence and child-derived parent changes retain their own meanings; they do not automatically become direct content divergence candidates. Missing/incomplete reads, incompatible contexts or missing retained rows remain UNKNOWN/INCOMPARABLE, not silent negative results. Known eligible facts may coexist with unknown evidence elsewhere; preserve scope uncertainty independently. A direct changed node and an incoming declared COPY/TRANSFORM check failure support an observed divergence candidate with edge/check/observation evidence. They do not prove that the edge executed, that the target caused the difference or that this was the first physical corruption point. Source changes can make unchanged targets differ from a newer source; retain which endpoint actually changed. An upstream changed node with absent/ineligible incoming evidence remains a candidate with explicit insufficient provenance, rather than being dropped or declared a verified root cause. Multiple possible upstream causes, cycles and missing branches remain ambiguity. PW-09.05 Earliest observed ranking and temporal ambiguity Rank first observation of supported divergence, not unobserved execution/corruption time. Input times must have declared validity and the same explicit clock domain. Do not infer a common clock from integer units or use source-version strings as a timestamp order. Keep capture interval [start,finish] when available; point observations are equal-endpoint intervals. Before-snapshot observations remain separately linked. Candidate A is definitely earlier than B only when A.finish < B.start in a comparable clock domain. Equal times, touching/overlapping intervals and unknown/incompatible clocks preserve ties/uncertainty. The earliest set contains candidates with no other candidate definitely before them; unknown-time candidates remain unresolved alongside known-time earliest candidates. No ID/label/traversal order breaks a temporal tie. Zero candidates is distinct from insufficient evidence. Ranking never produces a single certain origin merely because deterministic sorting has a first row. PW-09.06 Potential impact and observed downstream changes Potential impact is the unique forward lineage-reachable set from the selected candidate(s), excluding starts by default. Cycles/shared descendants are deduplicated. COPY, TRANSFORM and DERIVED indicate declared dependence, so this is potential exposure within captured scope. A reachable node with no observation is still a potentially affected node; it is not an observed changed node. Separate flat labels record POTENTIAL and OBSERVED_DOWNSTREAM_CHANGE. The latter requires eligible C6 direct content-change evidence at a reachable node, with its own observation links. Reachability plus change is evidence consistent with propagation; it does not prove transmission/causation or replace missing operation/version/time provenance. Unchanged or unknown downstream nodes keep their respective evidence. Report potential unique count separately from observed changed unique count; never sum branch paths or label every reachable target as corrupted. Scope incompleteness and uncertainty flags remain explicit even when some impact facts are known. PW-09.07 Incident identity, recurrence and repeat-scan deduplication Policy anchored-window-v1 requires an explicit positive recurrence_window_ns and clock-domain configuration. No undocumented default business/SLA window is inferred. Group compatibility includes source namespace/scope, stable artifact ID, reason category, full algorithm/profile/schema/mode identities and grouping-policy/config identity. Different incompatible contexts remain separate incidents. Known-time episodes anchor on first observed supported divergence. Observations in [anchor,anchor+window) can recur in that episode; exactly at the end starts a new episode. Use exact nonoverflowing integer comparisons. Late/out-of-order inputs must not retroactively rewrite existing stable episode identities; report or handle them under a documented deterministic policy rather than silently shifting anchors. Unknown/incomparable times permit exact observation deduplication but no guessed temporal merge. A new distinct unknown-time observation stays a separate uncertain episode unless explicit stronger provenance identifies it as the same observation. An exact observation identity includes before/after snapshot IDs, stable artifact ID, reason/category and supporting observation/evidence references. Rerunning the same comparison/evidence contributes once. Recurrence counts count distinct observations, not repeated executions of a scan/report. Reachable impact counts are independently deduplicated and are not incident recurrence counts. Allocate stable unique uint64 incident IDs within a versioned registry; preserve full canonical grouping/observation identities and registry identity beside them. Do not truncate a cryptographic digest into an alleged collision-free uint64 ID. Registry state can be exported as flat arrays/dictionaries and persisted with C5; repeated calls reuse identities. Query/CLI consumers preserve registry/policy identity, time ambiguity and supporting evidence. Final exact result columns/codes are published with the implementation and reference consumer acceptance in PW-09.23. Qualification required by later PW-09 subtasks An independent set/graph oracle verifies branches, cycles, disconnected nodes, forward/reverse relation filtering and deduplication. Authored truth fixtures verify copy, valid cents/dollars transforms, mutation, missing reads/detail, ambiguous times, multiple candidates and duplicate observations. C4/C5/C6 integration must retain provenance limitations. Formatting, typing, unit-only coverage, package integrity and verified CI delivery follow Q1. This specification itself implements no graph, invariant checker or incident registry and claims no Python coverage pass. Implemented graph boundary (PW-09.08) pipewhy.lineage exposes LineageContext, LineageGraph and Relation. The context binds source namespace, declaration source version, scope, inventory coverage/failures and an optional C5 snapshot ID. COMPLETE_WITHIN_SCOPE requires no inventory failures; PARTIAL/UNKNOWN require explicit failure diagnostics. This is edge-inventory coverage, not operation verification or evidence-payload completeness. LineageGraph accepts context, artifact_ids and the exact C1 edge columns, plus explicit evidence_ids and transform_ids reference buffers. It reuses C1 relationships and persistent-ID validation. It preserves original artifact/edge order, exposes a separate owned immutable sorted ID vector, and borrows read-only exports of inputs. All source aliases must remain stable for the graph's lifetime. Reference IDs alone do not supply or verify provenance/time payloads. Evidence checking/traversal are separate later operations; constructing a graph claims no verified propagation. Implemented adjacency boundary (PW-09.09) LineageIndex(graph) builds forward/reverse Adjacency values. offsets and edge_indices are owned immutable contiguous uint64 views; graph.sorted_ids defines vertex positions. Forward buckets use source_id; reverse buckets use target_id. Edges within a bucket retain original input row order, including parallel edges. Empty edge inventories preserve isolated vertices; a zero-vertex graph has offsets=[0]. The index retains its graph owner and requires the graph's borrowed source aliases to stay stable. Implemented reachability boundary (PW-09.10/.11) reachable(index, artifact_id, direction="forward", relations=(0,1,2), include_self=False) returns Reachability(context, start_id, direction, relations, include_self, artifact_ids). Direction is FORWARD="forward" or REVERSE="reverse". Relation filters are canonicalized/deduplicated; an empty filter visits no edges. The source is excluded by default even on cycles, or included as an explicit zero-hop result when include_self=True. An unseen source raises KeyError; malformed IDs, directions, filters and flags raise explicit errors. No source is read to fill gaps. The traversal uses a flat visited bitmap/vertex stack and the selected CSR, avoiding recursion and duplicate IDs. Output IDs are sorted, owned immutable uint64 storage. The original inventory coverage/failures and declaration context are preserved; reachability alone is not a content/operation check or a propagation verdict. Implemented selected copy/evidence boundary (PW-09.12) Evidence is immutable metadata for one selected evidence ID, not a replacement for the bulk flat graph. Fields: evidence_id, kind (DECLARED=0, OBSERVED=1, UNKNOWN=2), producer/source_version (text or explicit None), complete boolean, diagnostic tuple, optional started_at_ns/finished_at_ns and optional clock_domain. Both window endpoints are supplied together or neither. uint64 zero/max are valid timestamps. A window without a clock is retained but timing_known=False; a clock without a window is invalid. Complete evidence requires known producer/version/kind and no diagnostics; incomplete evidence requires diagnostics. OBSERVED remains a producer-reported classification, not an independently proven operation. This selected metadata contains no asserted endpoint execution/version bindings and creates no causal claim. check_copy(graph, observations, edge_id, evidence=...) returns EdgeCheck with both graph and data contexts, stable edge/endpoints/evidence/transform IDs, both observed IDs/timestamps, overall CheckStatus/CheckReason, separate content_status/content_reason and the selected Evidence or None. Data contexts are C6 ArtifactObservations; the shared C6 captured-content comparator preserves read/error/partial/ordered-offset semantics. Namespace/scope mismatches do not claim matching observation IDs. Different endpoint levels use C6 LEVEL_CHANGED to mean incompatible endpoint level semantics in this edge check. Containment parent IDs do not determine copy content equality. Overall CheckStatus remains PASS=0, FAIL=1, UNKNOWN=2, INCOMPARABLE=3. CheckReason is a control-metadata string enum: MATCH, DIFFERENT, DATA_UNKNOWN, DATA_INCOMPARABLE, EVIDENCE_UNAVAILABLE, EVIDENCE_INCOMPLETE, EVIDENCE_MISMATCH, EVIDENCE_VERSION_MISMATCH, SNAPSHOT_MISMATCH, RELATION_UNSUPPORTED. Mismatched evidence ID/declaration version, an explicit wrong graph snapshot binding or a non-COPY relation is INCOMPARABLE. Incomparable captured data remains so even when provenance is absent. Absent/incomplete evidence is UNKNOWN, preserving any independently observed content difference. Missing/partial reads remain UNKNOWN. Only complete matching selected evidence plus comparable captured content yields PASS for SAME or FAIL for CHANGED. The producer/declaration version is compared to the graph context; it is not incorrectly required to equal the endpoint data version. Unknown edge selections/invalid API inputs raise explicit errors. PASS/FAIL refer to this local captured copy condition under C3, not proof of edge execution, source authenticity or physical corruption. Timing/clock uncertainty, graph inventory failures and unrelated capture failures stay in the returned metadata even when a fully captured local condition is PASS. No scope-wide completeness is inferred. Bulk incident/query results will use flat arrays/dictionaries under PW-09.23. This API selects both endpoints from one C6 context; heterogeneous per-endpoint policy contexts cannot be coerced into that view to force eligibility. Producer timing in Evidence does not establish the clock domain of separate data observation timestamps. C4 integration content-addresses captured declaration payloads because that provider has no server-issued declaration version or execution clock; it does not invent them. Retained-record binding component (PW-09.13 in progress) RetainedRecords(metadata, artifact_id, observation_id, records) pairs actual C5 SnapshotMetadata with a C2 RecordBatch. It is a selected payload interface, not an automatic source reader. The batch profile must match its snapshot. Buffers remain borrowed/stable during validation and subsequent use; LocalSnapshotStore.open should validate persisted bytes before this interface is used. check_retained_records(details, observations, artifact_id, record_limit=65536, word_limit=1048576) checks exact snapshot/namespace/source-version/scope/fingerprint context and artifact/observation links. Unsupported policies stay INCOMPARABLE. Absent/uncaptured/error/partial observations cannot prove a complete retained input. C5 value-level retention is required; newly supplied rows cannot turn a dataset/record capture into retained value evidence. Dataset-only C6 node views may remain conservative while a separately supplied C5 value payload is validated for a specialized rule; this does not create finer generic drill-down nodes. All frames and limits are checked, record count is compared before hashing, and the supplied rows' C3 state must match the actual captured state, including original ordered positions. No full-source object materialization occurs; reference hashing uses one bounded temporary record frame at a time. This correspondence has C3's probabilistic limitations and is not adversarial authentication. Wrong metadata/state is INCOMPARABLE; missing retention/read evidence is UNKNOWN. Malformed wire/limits are explicit errors. PASS yields borrowed read-only pool/offset/length views; other results have records=None. RetainedCheck keeps both metadata/context, observation links and a RetainedReason: MATCH, UNAVAILABLE, CONTEXT_MISMATCH, UNSUPPORTED_POLICY, OBSERVATION_UNAVAILABLE, READ_ERROR, PARTIAL_READ or FINGERPRINT_MISMATCH. No live read or normalization/profile conversion is attempted. The dataset evaluator below consumes this retained evidence. Selected numeric invariant component (PW-09.13) check_cents_to_dollars(source, target, word_limit=256) accepts current C2 EncodedValue amounts. It compares signed int64/nonnegative uint64 cents against finite Decimal dollars using exact coefficient/exponent integer arithmetic. It performs no float conversion or Decimal arithmetic/context rounding. The default bound is 256 uint64 payload words per amount; malformed supported numeric payloads or exceeded/invalid limits raise explicit errors. Digit/exponent bounds prevent unbounded powers of ten, including the full uint64 exponent range. Finite signed zero compares numerically. NumericCheck returns CheckStatus with NumericReason MATCH, DIFFERENT, AMOUNT_UNAVAILABLE, NONFINITE or UNSUPPORTED_TYPE. Null/missing amounts are UNKNOWN; nonfinite Decimal targets are UNKNOWN; other valid types, including float/bool cents, are INCOMPARABLE. Supported numeric shapes/flags/coefficient widths are validated; this is not a generic decoder for unsupported scalar types. This selected-value API makes no snapshot, key-alignment, completeness or provenance assertion. The retained dataset/edge evaluator below binds those contexts separately. Keyed retained transform evaluation (PW-09.13 / PW-09.20) check_transform(graph, observations, edge_id, rule=..., source=..., target=..., evidence=...) checks only explicit TRANSFORM edges. TransformRule binds the edge's transform ID and declaration source version. The supported definition is exactly cents_to_dollars_v1, key field 0, amount field 1, factor 100, cents to dollars. Other valid definitions are INCOMPARABLE; malformed declarations raise errors. Missing rules are UNKNOWN. RetainedRecords on both endpoints must pass the C5/C3 binding checks above before any row condition is accepted. No live reads occur. Keys are exact typed signed-int64/nonnegative-uint64 C2 values. Record order is irrelevant to the rule, including when each endpoint uses its own valid ordered fingerprint offset. Keys sort through flat index vectors; physical row positions are preserved. Every member of a duplicate key group fails without arbitrary pairing. Missing/null keys are UNKNOWN; other key types are INCOMPARABLE. A one-sided known key fails only when the opposite side has no unusable keys that could conceal its counterpart. Extra fields outside the declared two-field rule are INCOMPARABLE. Amounts use the bounded exact numeric condition above. Complete empty inputs pass the declared empty identity. A known failing row dominates other uncertain rows, which remain present in the row evidence. No generic transformation language exists. TransformCheck retains the rule, both RetainedCheck results, a qualified EdgeCheck and immutable row columns: source_index Q, target_index Q, status B, reason B. Indices address logical offset-vector positions; absent sides use NULL_ID. Status uses CheckStatus (PASS 0, FAIL 1, UNKNOWN 2, INCOMPARABLE 3), not C6 Status codes. RowReason codes are MATCH 0, DIFFERENT 1, KEY_UNAVAILABLE 2, KEY_UNSUPPORTED 3, DUPLICATE_KEY 4, MISSING_SOURCE 5, MISSING_TARGET 6, COUNTERPART_KEY_UNAVAILABLE 7, AMOUNT_UNAVAILABLE 8, NONFINITE 9, AMOUNT_UNSUPPORTED 10, EXTRA_FIELDS 11. EdgeCheck.content_status/content_reason preserve the original raw fingerprint comparison, which may differ even for a valid transform. Qualified status checks the rule, retained evidence, snapshot/declaration bindings and provenance. Missing or incomplete provenance cannot become PASS/FAIL merely from matching row values. Declared lineage describes intent; this result proves neither execution timing, physical cause nor adversarial integrity. Accidental drift/corruption detection inherits the experimental C3 fingerprint limitations. Direct divergence candidates (PW-09.14) divergence_candidates(index, before, after, checks=()) retains a direct C6 classify result, without hierarchy propagation, and selects only CHANGED rows with VALUE_CHANGED reasons. Presence/containment/level changes, derived container changes, read failures and incompatible policies are retained in comparison but not promoted to direct content candidates. Zero candidates is not a claim of complete equality; consumers must inspect the comparison's status, contexts, flags and diagnostics. The graph namespace/scope and optional snapshot binding must match the after view; invalid API bindings raise errors. Before/after comparison incompatibility remains a normal C6 result. Selected EdgeCheck results must bind this graph, the after data context, actual edge references and endpoint observation IDs/timestamps. Duplicate checks for an edge are rejected rather than double counted. Check results are trusted selected API outputs, not authenticated externally supplied certificates. DivergenceResult contains graph context, full direct comparison, the selected check tuple, candidate columns and support columns. All result arrays are owned immutable uint64 views. Candidate columns: artifact_id, comparison_index, incoming_edge_count, incoming_check_count, incoming_failed_count, outgoing_failed_count, flags. Candidate IDs follow stable ascending comparison ID order. Missing graph inventory does not erase a directly observed candidate. Support columns candidate_index, check_index, endpoint link selected check positions and candidate rows. Endpoint SOURCE=0 and TARGET=1 distinguish which endpoint actually changed; a self-edge may link both. Parallel edges remain distinct evidence without duplicating candidate rows. CandidateFlags bits: INCOMING_FAILED=1, INCOMING_PASSED=2, INCOMING_UNKNOWN=4, INCOMING_INCOMPARABLE=8, OUTGOING_FAILED=16, NO_INCOMING_CHECK=32, OUTSIDE_GRAPH=64, GRAPH_INCOMPLETE=128, UNCHECKED_INCOMING=256. A passed copy or transform condition cannot erase a supported historical change. Unknown/unsupported checks preserve their own status and raw content evidence; unchecked incoming edges remain visible. Inventory coverage and unrelated read failures stay independent. These are observed divergence candidates, with no inferred execution order, proven physical origin or causal attribution. Earliest ranking is a separate explicit-time operation; evidence capture windows do not supply data observation timing. Observed-time ranking (PW-09.15) ObservationWindows(snapshot_id, columns, clock_domains=()) validates flat uint64 observation_id, started_at_ns, finished_at_ns, clock_id and time_valid columns. Observation IDs are unique non-sentinel IDs. The snapshot binds the after data; clock_domains is an immutable tuple of unique nonempty clock identity strings. clock_id indexes that dictionary, or NULL_ID for an unidentified clock. time_valid is 0/1. Unknown windows require zero endpoints and NULL_ID clock; known windows require start<=finish and may still have an unknown clock. Zero and uint64 maximum are valid known endpoints. Views borrow stable source aliases like C1/C6. rank_earliest(divergence, windows=None) selects timing by the candidate's after observation ID and verifies its captured observed_at_ns falls within the supplied data-observation window. Inconsistent snapshot/time bindings raise explicit errors. Missing timing and known windows with no clock stay unresolved. No timing is inferred from edge Evidence, integer units, snapshot IDs or source-version strings. Other supplied observation windows do not participate in candidate ranking. Within each identified clock, a candidate is excluded from the earliest set only if another candidate's finish is strictly less than its start. Equal, overlapping or touching windows remain tied. Unknown time/clock candidates remain in the set alongside every clock's earliest candidates. The implementation computes per-clock minimum finishes in linear time after ID lookup; it does not compare every pair. No order is inferred across different clock identities. This ranks selected observed changes in this comparison; it is not a global history search or corruption time. EarliestResult retains divergence and windows, immutable columns and an immutable uint64 earliest_candidate_indices vector. Columns: candidate_index, window_index, started_at_ns, finished_at_ns, clock_id, time_valid, earliest (uint64); reason (uint8). Missing window indexes use NULL_ID. TimingReason codes UNKNOWN_TIME=0, UNKNOWN_CLOCK=1, EARLIEST_WITHIN_CLOCK=2, DEFINITELY_LATER=3. RankingStatus is EMPTY=0, UNIQUE_EARLIEST=1, AMBIGUOUS=2, UNKNOWN=3. EMPTY describes no candidates, with original comparison uncertainty still retained. UNKNOWN denotes absent timing, unidentified clocks or multiple clock domains. UNIQUE_EARLIEST requires one earliest candidate and complete timing in one clock; it asserts no physical/causal origin. Underlying graph and data coverage limitations remain in the retained divergence. Potential exposure and observed downstream content (PW-09.16 / PW-09.17) impact(index, start_ids, divergence=None, relations=(COPY,TRANSFORM,DERIVED), include_starts=False) performs one shared multi-source forward CSR traversal. Repeated starts, cycles, parallel paths and shared descendants contribute each artifact once. Every selected start is excluded by default, even if another start or a cycle reaches it. include_starts=True includes the zero-hop selection. Unknown/out-of-inventory starts raise errors; they are not silently dropped. Empty starts and known disconnected vertices have known empty reachable sets. Relation filters use the same canonical semantics as reachable; no containment edges or inferred equal-content edges participate. Work is linear in visited graph structure apart from existing sorted-ID lookups, rather than repeated per-root walks. ImpactResult retains graph context, immutable sorted unique start_ids, relation selection, include_starts, optional DivergenceResult and immutable output columns. Columns artifact_id, comparison_index and flags are uint64; status and reason are the original C6 uint8 codes. Missing comparison rows use NULL_ID and UNKNOWN / SELECTION_UNAVAILABLE, unless comparison policies are themselves incompatible. Incompatible policy/scope remains INCOMPARABLE even without alignable rows. Divergence must carry the same lineage context, including declaration version, scope, coverage/failures and optional snapshot binding. Original comparison contexts, observations, read failures and uncertainty remain available through it. ImpactFlags are POTENTIAL=1, OBSERVED_DOWNSTREAM_CHANGE=2, WITHOUT_OBSERVATION_ROW=4, GRAPH_INCOMPLETE=8. Every output node is potentially exposed within captured declared lineage. The observed label additionally requires a direct C6 CHANGED / VALUE_CHANGED fact at that reachable node. Added/removed presence, parent moves, unknown reads and unsupported policies do not satisfy it. Without supplied divergence, observed evidence is unavailable, not a complete negative finding. potential_count and observed_changed_count count unique artifacts independently, never branch paths, repeat scans or incident occurrences. A known local change can coexist with unrelated read failures or incomplete graph scope. Reachability plus change is consistent with propagation but does not establish transmission, execution timing, physical corruption or cause. Incident identity component (PW-09.18) IncidentPolicy(recurrence_window_ns, clock_domain) requires an explicit positive uint64 window and nonempty clock identity; it has no default business window. incident_observations(ranking, policy) creates canonical full keys and flat columns for every direct candidate, including candidates outside the earliest set. This key preparation API does not allocate incident IDs or merge recurrence. Full keys use compact UTF-8 JSON with non-ASCII text preserved and uint64 references represented as decimal strings. Keys are interned through the existing exact-byte LabelDictionary, never truncated to a purportedly collision-free numeric digest. Key IDs are local dictionary indexes, not durable incident IDs. Results preserve the ranking and policy. Grouping key is the JSON array [anchored-window-v1, window_ns, configured_clock, namespace, scope, artifact_id, DIRECT_CONTENT_CHANGE, algorithm_id, profile_id, schema_id, mode]. All identities are full values. Observation key is [observed-divergence-v1, full_group_key, before_snapshot_id, after_snapshot_id, before_observation_id, after_observation_id, declaration_source_version, references]. References contain edge_id/source_id/target_id/evidence_id/transform_id as decimal strings and endpoint code as an integer, sorted by stable edge ID then endpoint. Reordering selected checks does not change identity. Different supporting reference sets remain distinct evidence observations; repeating the same set does not invent a new observation identity. Referenced payload authenticity is not established here. Timing has a separate key [observation-window-v1, time_valid, actual_clock_or_null, start_ns, finish_ns]. Clock dictionary row order is not identity. Timing refinement does not rewrite the exact data/evidence observation key; the registry must handle conflicting timing explicitly. Missing data timing does not prevent repeat detection. Columns candidate_index, group_key_id, observation_key_id, timing_key_id, started_at_ns, finished_at_ns, time_valid, clock_compatible, mergeable are immutable uint64 views. Keys are immutable UTF-8 payload/uint64 offset/length buffers; IncidentObservations.resolve_key selects full key text. No source reads occur. clock_compatible requires known timing in the explicitly configured clock. mergeable also requires finish-start < recurrence_window_ns: a wide or boundary-spanning interval cannot be reduced to a guessed point for temporal recurrence. Its complete timing key is retained. Anchored episode membership requires the whole interval inside the episode's half-open window, as implemented by the registry below. Incident registry allocation (PW-09.18) IncidentRegistry(registry_id, policy) requires a canonical 32-character lowercase hex registry identity and an explicit IncidentPolicy. register(IncidentObservations) returns IncidentUpdate with a new registry, the original input and immutable uint64 assignment columns candidate_index, incident_id, observation_index, flags. Previous registry instances remain unchanged, including on validation/timing conflicts. IDs are append positions scoped by registry_id; never compare them across registries. Flat episode and distinct observation tables retain full key IDs, anchors and counts. resolve_key retrieves original full identities. This reference allocator scans flat episode rows and makes no unmeasured performance claim. Exact observation keys are checked before timing/lateness grouping. An exact repeat reuses both incident and observation positions without incrementing occurrence_count. Changed timing for the same exact observation is an explicit error; this operation does not silently refine metadata or move an existing assignment. Different compatible observations can recur only if their entire known interval is inside the episode's [anchor,anchor+window) boundary. Difference arithmetic avoids uint64 wraparound. Wide/unknown/incompatible-clock intervals remain separate episodes. A new episode anchors at the first interval's start in the configured clock, when compatible. Late policy separate-late-v1: a distinct observation whose known start is below the group's latest accepted known start gets a separate nonmergeable episode. It cannot reanchor previous episodes, and subsequent late observations remain separate. Exact repeats of earlier evidence still reuse their original assignment. Stable streaming assignments therefore depend on documented arrival order; they do not claim to reconstruct unobserved event order. occurrence_count counts distinct captured data/evidence identities, not proven corruption events or repeated report execution. IncidentFlags NEW_EPISODE=1, RECURRENCE=2, REPEATED=4, TIME_UNKNOWN=8, LATE=16, WINDOW_AMBIGUOUS=32 distinguish outcomes. Repeat outputs preserve timing/late/wide qualifiers but replace NEW_EPISODE/RECURRENCE with REPEATED. Registry episodes expose uint64 group_key_id, anchor_at_ns, anchor_valid, last_started_at_ns, mergeable, occurrence_count. Observation rows expose observation_key_id, timing_key_id, incident_id, flags. All public tables are owned immutable snapshots. Episode/count capacity is bounded by the checked distinct observation count. Durable registry state and replay validation (PW-09.18 / .21 / .22) export_arrays() produces owned immutable metadata/key bytes and uint64 tables. metadata is canonical compact UTF-8 JSON with schema_version 1.0, registry_id, policy anchored-window-v1, decimal-string recurrence_window_ns, clock_domain and late_policy separate-late-v1. The remaining inventory is keys_payload (uint8), keys_offsets / keys_lengths (uint64), all episode columns prefixed episodes_, and all observation columns prefixed events_. Episode row positions are the registry's stable incident IDs. This exact versioned inventory rejects unknown fields/versions. IncidentRegistry.from_arrays validates types/alignment, canonical JSON identities, full supported fingerprint context, snapshot/observation and endpoint references, clock/window validity and sorted unique support links. It replays every distinct observation in original arrival order. Replayed assignments, qualification flags, episode anchors/latest starts/counts, dictionary packing/IDs and metadata must all match the saved arrays exactly. Duplicate receipts, unused keys, inconsistent summaries and unsupported policy/version state fail explicitly. Loaded registries own their state; subsequent caller buffer changes cannot alter them. Appends and exact repeats after reload retain existing registry-scoped IDs. These arrays can be stored in C5 without another serialization/dependency stack. The reference C4/native/C5 integration saves and reopens a derived registry, then repeats the same evidence while preserving a count of one. Unknown declaration timing remains TIME_UNKNOWN across this round trip. Replay establishes internal registry consistency; it does not authenticate referenced data/evidence or recreate complete C6 analyses from identity keys. Original snapshot/control evidence and uncertainty must be retained for a later why/impact explanation. C5 checksums and C3 probabilistic/accidental-drift limitations remain separate guarantees. Analysis schema handoff (PW-09.23) pipewhy.lineage.ANALYSIS_SCHEMA_VERSION is 1.0. The portable contract manifest is tests/fixtures/lineage_schema_v1.json, with exact enum values, result control fields, column dtypes and required evidence/limitations. It references the existing C6 comparison_schema_v1.json instead of assigning competing C6 status/reason codes. tests/fixtures/lineage_consumer_v1.json supplies an independent selected-result truth case. The reference consumer in tests/unit/test_lineage_schema.py joins actual comparison/check/candidate/timing/impact/registry results and retains uncertainty, endpoint roles, original metadata links and independently counted outcomes. Results use one explicitly selected L1 schema version. Consumers must retain the version and full context identities; unsupported versions require explicit rejection rather than best-effort status reinterpretation. Q means uint64 and B means uint8 on the supported little-endian C1 host protocol. Portable JSON renders uint64 values (including indexes, counts, flags and null sentinels) as exact decimal strings. Evidence/control booleans remain booleans. Do not interpret CheckStatus's UNKNOWN=2 as C6 Status's ADDED=2, or CheckStatus's PASS=0 as provenance verification. Required output context includes graph namespace/declaration version/scope/coverage, failure diagnostics and optional snapshot binding; both data contexts with complete algorithm/profile/schema/mode and capture failures; original comparison/observation links; qualified checks separate from raw content; selected evidence kind, producer, version, completeness, diagnostics and time/clock; selected transform and retained input outcomes; support endpoint roles; data timing validity/clocks/intervals and the unresolved earliest set; unique potential/observed counts with C6 reasons; and registry identity, full canonical keys, policy/config and recurrence qualifications when used. Input/result borrowing and owned immutable table rules above continue to apply. The reference projection is an acceptance consumer, not a released CLI/export API. PW-11 and PW-12 implement selected, bounded public views/exports on this boundary. Metadata and limitations must survive those selections; trimming rows cannot turn partial scope, unknown provenance or absent timing into a complete/causal answer. PW-09 implements observed candidate/impact/recurrence analysis under experimental C3 limits. It does not identify a proven physical corruption point or authenticate data.