PipeWhy Array Contract C1 version 0.1 PW-02.01-.04: initial CPU schema decisions, October 30, 2026 Current CUDA addendum: PW-10's CV1.1 implementation and real Windows GPU qualification are specified in CUDA_CONTRACT.txt and CUDA_ACCEPTANCE.txt. The historical CPU sections below do not themselves claim CUDA behavior. CV1 provides qualified integer borrowing/producer synchronization; fingerprint APIs explicitly transfer host C2 batches and retain owners through completion/cleanup. Borrowing a device view is not a claim of device C2 fingerprint execution. Persistent artifact identity and scan-local row indexes are distinct namespaces. Persistent identities are assigned in the source namespace and retained in a dictionary; dense local indexes accelerate computation but must not be compared across scans. A hash is never sufficient by itself to collapse two source identities. Source identity allocation and string interning implementation remain later work. ID/reference/offset columns use uint64. UINT64_MAX is the absent-reference sentinel; valid IDs and local indexes are 0 through UINT64_MAX-1. Counts/offset arithmetic must use checked bounds before allocation or conversion; no silent wrap. Payload values can use signed/unsigned 8,16,32,64-bit integers according to type semantics. Payload uint64 max is a valid value: reference sentinel rules apply to reference columns only. Timestamp, decimal and float equivalence remain normalization policy. Serialized integer storage is little-endian. CPU views currently accept native integer buffers on qualified little-endian hosts; non-native formats require an explicit normalization copy and are rejected by this borrowing interface. CUDA residency and synchronization require a separate qualified implementation. Validity uses flat uint64 words, least-significant bit first. Logical row n uses word n//64, bit n%64; 1 means present and 0 means null. The final word's unused high bits must be zero. Empty input uses zero bitmap words. Missing versus null is separate status/type evidence, not an overloaded ID value. Bitmap validation is still to be implemented with the table schema. IntegerView borrows a one-dimensional, C-contiguous integer buffer and retains its owner through Python's memoryview. It exposes logical length, dtype, read-only flag and the view itself; it does not serialize addresses or transfer memory. Mutable inputs may still change through another alias; snapshot coordination must enforce stable source ownership while kernels read. Read-only is a buffer capability, not a promise that all external aliases are immutable. Callers must not release a view while another consumer uses it. No arbitrary raw pointer constructor is provided. PW-02.05: Specify artifact columns Artifact table (schema 1.0) Row columns: artifact_id:uint64, parent_id:uint64, kind_id:uint8, name_id:uint64. artifact_id is unique and cannot equal UINT64_MAX. parent_id is either an existing artifact_id or UINT64_MAX for a root. Self-parenting and containment cycles are invalid. name_id resolves in the name dictionary; kind_id is an opaque adapter-defined code whose dictionary/version is supplied by the scan context. All four columns have exactly the same length, including zero. No physical row ordering carries identity. Names do not have to be globally unique. PW-02.06: Specify value and payload columns Value table (schema 1.0) Row columns: value_id:uint64, artifact_id:uint64, field_id:uint64, type_id:uint8, payload_offset:uint64, payload_length:uint64. Auxiliary arrays: payload_words:uint64, validity_bitmap:uint64. value_id is unique/non-sentinel; artifact_id resolves in the artifact table; field_id and type_id resolve under the normalization schema. Offset and length are measured in uint64 words, not bytes; offset <= word count and length <= word count-offset. Empty payloads may start at the end. Overlapping slices are permitted for deduplication. A null row must have zero payload length; its offset must still be within bounds. Bitmap length is ceil(row_count/64), with zero tail padding. Empty and null are distinguished through validity, not payload length. PW-02.07: Specify observation columns Observation table (schema 1.0) Row columns: observation_id:uint64, artifact_id:uint64, snapshot_id:uint64, observed_at_ns:uint64, status_id:uint8, policy_id:uint64, algorithm_id:uint64, fingerprint_offset:uint64, fingerprint_length:uint64. Auxiliary array: fingerprint_words:uint64. IDs are unique/non-sentinel only in the observation_id column; all references resolve in their named context. observed_at_ns is nonnegative Unix UTC nanoseconds for observation time, not source-event time. Status codes: 0 UNKNOWN, 1 CAPTURED, 2 ERROR. CAPTURED requires at least one fingerprint word; UNKNOWN/ERROR require zero words. Slice bounds are checked as for values. Fingerprint width is algorithm-version metadata, not a hardcoded two-lane security claim. Offsets retain flat variable-length states until PW-04 specifies an algorithm's exact lane count and combine rules. PW-02.08: Specify lineage edge columns Lineage edge table (schema 1.0) Row columns: edge_id:uint64, source_id:uint64, target_id:uint64, relation_id:uint8, evidence_id:uint64, transform_id:uint64. edge_id is unique/non-sentinel. Both endpoints resolve in the artifact table. Relation codes: 0 COPY, 1 TRANSFORM, 2 DERIVED. Evidence resolves in the evidence context. COPY requires transform_id=UINT64_MAX; TRANSFORM requires a valid transform reference; DERIVED may carry either a declared transform or sentinel. Lineage may contain cycles and self-edges; it is distinct from the acyclic artifact containment hierarchy. Edge semantics do not prove equality/causation. PW-02.09: Specify incident columns Incident table (schema 1.0) Row columns: incident_id:uint64, artifact_id:uint64, observation_id:uint64, reason_id:uint8, evidence_id:uint64, grouping_policy_id:uint64. incident_id is unique/non-sentinel. artifact_id and observation_id resolve in the respective tables, and the observation must refer to that same artifact. Evidence and grouping policy references resolve in supplied contexts. reason_id is a versioned analysis-policy code, not a global corruption assertion. All row columns have equal length. Counts and recurring grouping remain PW-09 behavior. PW-02.10: Define schema compatibility Schema versions and compatibility C1 schema 1.0 names/dtypes/units above are authoritative for initial tables. Readers require an exact version match until an explicit migration exists. Adding/removing/renaming columns, changing widths/sentinels/units or enum meaning is incompatible; do not silently reinterpret. Additive descriptive metadata can be compatible only when it cannot change logical interpretation. Schema version, normalization policy version and fingerprint algorithm version are independent. Unknown columns are rejected at this boundary rather than accidentally ignored. Version checks precede buffer inspection. Evidence/policy/snapshot/transform/name references require supplied valid-ID contexts, never guessed from integer ranges. PW-02.11: Specify logical and physical buffer descriptors Buffer descriptor (C7, CPU implementation and CUDA boundary) A descriptor has an optional logical_id (uint64 excluding UINT64_MAX), dtype, logical length, device kind, device ID when meaningful, read-only capability, access/alignment contract, and an owner-retaining buffer handle. Anonymous input views have logical_id=None; identity is never derived from a pointer. CPU views have device='cpu', device_id=None. The current CPU implementation exposes a memoryview handle and byte-safe scalar access; it does not publish an unverified raw address or imply an aligned SIMD load. Shape is strictly one-dimensional. CUDA descriptors must retain the exporting allocation, device ID and stream/event ownership. CUDA views cannot be passed to the CPU borrowing constructor; an explicit adapter/backend qualification is required in PW-10. PW-02.12: Define borrowing, ownership and invalidation Buffer ownership and lifetime IntegerView borrows storage without copying and retains an independent memoryview export, keeping the original owner alive. Releasing a caller's original memoryview does not release this export. The caller must keep aliases stable while a scan reads and must not release the exposed IntegerView.buffer during consumer use. The view descriptor is read-only; underlying writable payloads remain writable. Explicit release invalidates buffer operations with an error; it never returns empty data as a substitute. Owned normalized/transfer buffers use the same owner retention rule but their allocation/copy is explicit in the normalization/backend operation. Snapshot publication may not persist a transient pointer as identity. PW-02.13: Define synchronization and CPU alignment rules Synchronization and alignment CPU scalar views read through Python's byte-safe memoryview interface. Unaligned native integer buffers are therefore permitted for this interface, without any claim of SIMD/CUDA alignment. A backend needing stronger alignment must explicitly validate its own handle or normalize to an owned aligned allocation; it cannot assume alignment from dtype alone. Noncontiguous/multidimensional/foreign-endian or noninteger inputs require explicit normalization and are rejected here. The caller must finish writes and prevent concurrent mutation before a CPU scan. A future CUDA adapter must record producer stream/event and device identity, wait for producer completion before reads, keep allocation live until consumer completion, and synchronize explicitly before CPU observation or ownership release. Cross-device transfers must be explicit. No stream ownership or asynchronous GPU completion is inferred from the existence of a pointer. PW-10 verifies this on real supported hardware; no CUDA runtime behavior is claimed by this specification.