diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67e910b..cf73bdc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,7 +61,7 @@ jobs: run: python -m pytest -q tests/test_integrity.py ucns-integration: - name: Actual UCNS adapter / pinned public surface + name: Actual UCNS bridge and certification evidence runs-on: ubuntu-latest steps: @@ -79,30 +79,42 @@ jobs: python -m pip install --upgrade pip python -m pip install -e ".[dev,ucns]" - - name: Run UCNS adapter contracts + - name: Run UCNS adapter and evidence contracts run: | python -m pytest -q \ tests/test_ucns_adapter.py \ tests/test_ucns_dependency.py \ + tests/test_ucns_evidence_consumer.py \ tests/test_measurement.py \ tests/test_shared_stack_contract.py - - name: Prove actual object identity survives the EDCM path + - name: Prove canonical certified evidence survives the EDCM path run: | python - <<'PY' - from fractions import Fraction - import edcm import ucns - obj = ucns.UCNSObject(1, 1, [(Fraction(0), None)], [0]) - result = edcm.build_default_layers().run({"ucns_object": obj}) - assert result["ucns_geometry"]["stable_hash"] == ucns.stable_hash(obj) - assert result["ucns_integration"]["ucns_object_attached"] is True - assert result["ucns_integration"]["ucns_theorem_status_attached"] is False + bridge = ucns.bridge_record(ucns.S2) + factorization = ucns.factorization_evidence(ucns.S2) + result = edcm.build_default_layers().run({ + "transcript": "A: Preserve authoritative UCNS evidence.", + "ucns_bridge_record_json": bridge.to_json(), + "ucns_factorization_evidence_json": factorization.to_json(), + }) + contract = result["edcm_result"] + assert result["ucns_geometry"]["stable_hash"] == ucns.stable_hash(ucns.S2) + assert result["ucns_geometry"]["bridge_evidence_digest"] == bridge.evidence_digest + assert result["ucns_integration"]["ucns_object_attached"] is False + assert result["ucns_integration"]["ucns_bridge_record_attached"] is True + assert result["ucns_integration"]["ucns_factorization_evidence_attached"] is True + assert result["ucns_integration"]["ucns_negative_certification_attached"] is True + assert result["ucns_integration"]["ucns_theorem_status_attached"] is True assert result["metapat_integration"]["metapat_package_available"] is False - assert result["edcm_result"]["ucns_geometry_identity"]["stable_hash"] == ucns.stable_hash(obj) - assert result["edcm_result"]["status_evidence"]["proof_status_transfers_to_measurement_validity"] is False + assert contract["schema_version"] == "1.1.0" + assert contract["ucns_geometry_identity"]["stable_hash"] == bridge.object_hash + assert contract["ucns_factorization_evidence"]["evidence_digest"] == factorization.evidence_digest + assert contract["ucns_factorization_evidence"]["negative_result_certified"] is True + assert contract["status_evidence"]["proof_status_transfers_to_measurement_validity"] is False PY metapat-integration: @@ -148,6 +160,7 @@ jobs: assert result["ucns_integration"]["ucns_package_available"] is False assert result["edcm_result"]["metapat_semantic_constraints"]["source_statements"] == envelope.source_statements assert result["edcm_result"]["ucns_geometry_identity"]["state"] == "NA" + assert result["edcm_result"]["ucns_factorization_evidence"]["state"] == "NA" assert result["edcm_result"]["status_evidence"]["semantic_labels_are_measurement_values"] is False PY @@ -176,10 +189,11 @@ jobs: tests/test_metapat_adapter.py \ tests/test_ucns_adapter.py \ tests/test_ucns_dependency.py \ + tests/test_ucns_evidence_consumer.py \ tests/test_measurement.py \ tests/test_shared_stack_contract.py - - name: Prove all identities remain separate + - name: Prove all identities and evidence states remain separate run: | python - <<'PY' import edcm @@ -199,8 +213,14 @@ jobs: assert contract["metapat_semantic_constraints"]["canon_digest"] == envelope.canon_digest assert contract["metapat_semantic_constraints"]["provenance_digest"] == envelope.provenance_digest assert contract["ucns_geometry_identity"]["stable_hash"] == ucns.stable_hash(adaptation.ucns_object) + assert contract["ucns_geometry_identity"]["bridge_evidence_digest"] + assert contract["ucns_factorization_evidence"]["state"] == "NA" assert contract["edcm_policy_manifest"]["manifest_hash"] == PolicyManifest().manifest_hash() assert contract["readouts"]["state"] == "measured" + assert contract["status_evidence"]["ucns_bridge_record_attached"] is True + assert contract["status_evidence"]["ucns_factorization_evidence_attached"] is False + assert contract["status_evidence"]["ucns_negative_certification_attached"] is False + assert contract["status_evidence"]["ucns_theorem_status_attached"] is True assert contract["status_evidence"]["proof_status_transfers_to_measurement_validity"] is False assert contract["status_evidence"]["semantic_labels_are_measurement_values"] is False PY @@ -254,6 +274,7 @@ jobs: assert callable(edcm.select_metapat_adapter) assert callable(edcm.build_result_contract) assert callable(edcm.run_integrity_gate) + assert hasattr(edcm, "UCNSFactorizationEvidenceRecord") assert edcm.run_integrity_gate().passed is True assert files("edcm.measurement.canon").joinpath("data", "markers_v1.json").is_file() result = edcm.build_default_layers().run({"input": "wheel smoke"}) @@ -261,5 +282,6 @@ jobs: assert result["metapat_integration"]["metapat_package_available"] is False assert result["layer_provenance"]["measurement"]["canonical"] is True assert result["edcm_result"]["readouts"]["state"] == "NA" + assert result["edcm_result"]["ucns_factorization_evidence"]["state"] == "NA" print(f"edcm {edcm.__version__} wheel smoke passed") PY diff --git a/CLAUDE.md b/CLAUDE.md index 5f0362b..5648a4c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,7 +39,7 @@ python -m build python -m twine check dist/* ``` -CI separately verifies base, integrity, UCNS-only, METAPAT-only, full shared-stack, and clean-wheel modes. The integrity gate must also pass from the installed wheel. +CI separately verifies base, integrity, UCNS evidence, METAPAT-only, full shared-stack, and clean-wheel modes. The integrity gate must also pass from the installed wheel. ## Integrity and source of truth @@ -82,27 +82,67 @@ Preserve exact source statements, references, constraints, permitted interpretat Direct absence of `metapat` is typed unavailability. Transitive import errors, missing producer surfaces, unsupported schemas, invalid provenance, unknown fields, and wrong envelope types remain visible failures. -## UCNS geometry +## Canonical UCNS geometry and status evidence -Do not look for or recreate `ucns.SemanticsLayer`. Consume actual: +EDCM owns the consumer adapter. UCNS owns the algebra, bridge-record schema, factorization policy, and certification evidence. + +Consume only the actual producer surfaces: ```text ucns.UCNSObject -ucns.object_record -ucns.stable_hash -ucns.CANONICAL_SERIALIZATION_VERSION -typed domain prerequisite metadata +ucns.UCNSBridgeRecord +ucns.UCNSFactorizationEvidence +ucns.bridge_record +ucns.BRIDGE_RECORD_SCHEMA_ID / VERSION +ucns.FACTORIZATION_EVIDENCE_SCHEMA_ID / VERSION +producer from_json / from_dict constructors +``` + +Accepted geometry keys are mutually exclusive: + +```text +ucns_object +ucns_bridge_record +ucns_bridge_record_json +ucns_bridge_record_dict +``` + +A live object must be converted through `ucns.bridge_record()` so live and serialized geometry use one canonical identity path. + +After geometry, accepted factorization-evidence keys are mutually exclusive: + +```text +ucns_factorization_evidence +ucns_factorization_evidence_json +ucns_factorization_evidence_dict +``` + +The factorization record must bind to the same stable object hash as the geometry bridge record. A mismatch fails closed. + +Independent status fields are: + +```text +ucns_package_available +ucns_adapter_active +ucns_object_attached +ucns_bridge_record_attached +ucns_scope_metadata_attached +ucns_factorization_evidence_attached +ucns_negative_certification_attached +ucns_theorem_status_attached ``` -Direct absence of `ucns` is typed geometry absence. Transitive import errors, missing public surfaces, unsupported schemas, malformed geometry, and non-`UCNSObject` values remain visible failures. +Package availability alone attaches nothing. A validated bridge record attaches typed UCNS domain/theorem-status evidence. Negative certification attaches only when a matching authoritative factorization record passes the UCNS producer policy and states `negative_result_certified = true`. -Package availability alone never implies object, scope, negative-certification, or theorem evidence attachment. +An attached uncertified result remains evidence while the negative-certification flag stays false. Unit-domain evidence never becomes a primality certification. + +Direct absence of `ucns` is typed geometry absence. Transitive import failures, missing producer surfaces, unsupported schemas, malformed or coerced records, wrong object types, unknown fields, invalid digests, and geometry/evidence hash mismatch remain visible failures. ## Layer and result behavior `build_default_layers(policy_manifest=None)` assembles: -1. composite semantics: independent METAPAT authority and UCNS geometry sublayers; +1. composite semantics: independent METAPAT authority and UCNS geometry/status-evidence sublayers; 2. canonical `edcm.measurement`; 3. canonical shared-stack composition; 4. canonical final result-contract delivery. @@ -118,12 +158,13 @@ composition delivery ``` -Every supported pipeline result includes `edcm_result` with: +Every supported pipeline result includes `edcm_result` schema `edcm.shared-stack-result/1.1.0` with: ```text source_evidence metapat_semantic_constraints ucns_geometry_identity +ucns_factorization_evidence edcm_policy_manifest implementation_provenance readouts @@ -131,23 +172,34 @@ status_evidence unresolved_constraints ``` -`epoch_identity` binds METAPAT canon/provenance, UCNS geometry, EDCM manifest, and implementation selection. `result_identity` additionally binds source evidence and readouts. Canon or manifest rotation must change epoch identity rather than mutating historical identity. +`epoch_identity` binds METAPAT canon/provenance, UCNS bridge geometry, EDCM manifest, and implementation selection. `result_identity` additionally binds source evidence, readouts, UCNS factorization evidence, and attachment states. + +Factorization evidence changes result identity, not measurement epoch identity, because it is attached status evidence rather than readout-governing geometry or policy. Canon or manifest rotation must change epoch identity rather than mutating historical identity. ## Object and proof boundaries `ConstraintField`, `FieldMotion`, metric axes, readouts, windows, and operator turns are EDCM objects constructed using UCNS geometry. They are not substitutes for `ucns.UCNSObject`. -Keep source evidence, METAPAT semantic authority, UCNS geometry identity, EDCM policy identity, and EDCM readouts separate. +Keep source evidence, METAPAT semantic authority, UCNS geometry identity, UCNS status/certification evidence, EDCM policy identity, and EDCM readouts separate. + +UCNS equality does not imply EDCM measurement equivalence. UCNS or METAPAT theorem/domain/certification status is attached evidence only and never promotes EDCM empirical validity. -UCNS equality does not imply EDCM measurement equivalence. UCNS or METAPAT theorem/domain status is attached evidence only and never promotes EDCM empirical validity. +Every UCNS evidence view preserves: + +```text +theorem_status_transfer = false +measurement_validity_claim = false +proof_status_transfers_to_measurement_validity = false +``` ## Non-negotiable guardrails - `NA != 0`. -- No-bone, empty-field, absent-adapter, and missing-context cases remain typed absence or `NA`. +- No-bone, empty-field, absent-adapter, missing-context, and absent-evidence cases remain typed absence or `NA`. - Ordered windows compose with `SeqAppend`; never average testimony-bearing order. - METAPAT semantic labels never become measured values merely by being named. - Deterministic transcript metrics do not establish diagnosis, intent, consciousness, external truth, or root ontology. +- UCNS evidence digests establish content identity, not signed producer authentication. These frontier gates remain non-operational until their named falsifiers and tests exist: @@ -160,7 +212,19 @@ Do not replace `NotImplementedError` with constants, heuristics, language-model ## Testing expectations -Base tests pass without UCNS or METAPAT installed. Integration tests use actual pinned sibling packages. The full-stack fixture proves identity separation, deterministic measurement, `NA != 0`, fail-closed producer validation, canon/manifest epoch rotation, and no proof-status transfer. +Base tests pass without UCNS or METAPAT installed. Integration tests use actual pinned sibling packages. + +The UCNS evidence suite must prove: + +- live and serialized bridge records resolve the same stable identity; +- canonical producer constructors reject tampered, unknown, missing, coerced, or unsupported records; +- certified `S2` preserves exact search, catalogue coverage, pruning, scope, and evidence digest; +- incomplete-catalogue and unit-domain results remain uncertified; +- factorization evidence cannot attach without matching geometry; +- package availability alone attaches no evidence; +- certification never transfers to EDCM measurement validity. + +The full-stack fixture proves identity separation, deterministic measurement, `NA != 0`, fail-closed producer validation, canon/manifest epoch rotation, and no proof-status transfer. The integrity suite must include adversarial byte mutation, added/missing canon files, authority reversal, and no-fork identity checks. @@ -179,9 +243,8 @@ Optional skips are explicit. Fake sibling implementations may test adversarial c Still unresolved: -- official serialized UCNS bridge-record ingestion beyond live `UCNSObject` / `object_record`; -- validated negative-certification and theorem-status evidence envelopes; +- cryptographically signed UCNS producer or transport authentication; - repo-local skill-lib installation and drift/msdmd CI gates; - remaining historical L0/L1/L2/L3 split, P assignment, matrix wiring, bidirectional alerts, and Bridge-home decisions. -These unresolveds do not reopen measurement authority, semantic-authority ownership, integrity guarantees, or the proof-transfer firewall. +These unresolveds do not reopen measurement authority, semantic-authority ownership, canonical evidence schemas, certification policy, integrity guarantees, or the proof-transfer firewall. diff --git a/README.md b/README.md index 74d480e..efe9d08 100644 --- a/README.md +++ b/README.md @@ -37,15 +37,12 @@ Base installation does not imply that UCNS or METAPAT ran. Frozen measurement ca - the machine-readable measurement source-of-truth and compatibility policy; - the no-fork identity between `edcm.measurement.metrics` and canonical EDCM orthogonality classes. -The gate runs from both the editable source install and a clean installed wheel. Adversarial tests mutate bytes, add or remove canon files, reverse measurement authority, and verify the gate fails closed. See [`docs/integrity-gates.md`](docs/integrity-gates.md). - -Programmatic use: +The gate runs from both the editable source install and a clean installed wheel. See [`docs/integrity-gates.md`](docs/integrity-gates.md). ```python import edcm -report = edcm.run_integrity_gate() -assert report.passed +assert edcm.run_integrity_gate().passed ``` A legitimate canon change requires a new versioned file and migration record. Do not update pinned identities merely to silence CI. @@ -54,7 +51,7 @@ A legitimate canon change requires a new versioned file and migration record. Do `build_default_layers()` assembles: -1. **Semantics:** independent METAPAT semantic-authority and UCNS geometry sublayers; +1. **Semantics:** independent METAPAT semantic-authority and UCNS geometry/status-evidence sublayers; 2. **Measurement:** canonical `edcm.measurement`; 3. **Composition:** canonical shared-stack composition; 4. **Delivery:** deterministic `edcm.shared-stack-result` contract. @@ -80,7 +77,7 @@ print(result["edcm_result"]["result_identity"]) ### Base transcript mode -Without optional siblings, measurement still runs while semantic authority and geometry remain typed absence: +Without optional siblings, measurement still runs while semantic authority, geometry, and factorization evidence remain typed absence: ```python result = build_default_layers().run({"transcript": "A: We must decide."}) @@ -89,6 +86,7 @@ assert result["metapat_integration"]["metapat_package_available"] is False assert result["ucns_integration"]["ucns_package_available"] is False assert result["edcm_result"]["metapat_semantic_constraints"]["state"] == "NA" assert result["edcm_result"]["ucns_geometry_identity"]["state"] == "NA" +assert result["edcm_result"]["ucns_factorization_evidence"]["state"] == "NA" ``` `NA != 0`: absence is never reported as an enabled neutral measurement. @@ -128,31 +126,73 @@ assert result["metapat_integration"]["metapat_theorem_status_attached"] is False The consumer preserves schema identity, module identity, canon identity, exact source references and statements, constraints, permitted interpretations, unresolved `hmmm`, and provenance digest. Semantic labels are authority constraints and provenance—not calculated EDCM values. -## Actual UCNS geometry +## Canonical UCNS geometry and status evidence -EDCM does not expect UCNS to expose an EDCM-specific `SemanticsLayer`. The adapter consumes actual UCNS public surfaces: +EDCM consumes the actual public producer surfaces from `The-Interdependency/ucns`: -- `ucns.UCNSObject`; -- `ucns.object_record`; -- `ucns.stable_hash`; -- `ucns.CANONICAL_SERIALIZATION_VERSION`; -- typed domain prerequisite metadata. +```text +ucns.UCNSObject +ucns.UCNSBridgeRecord +ucns.UCNSFactorizationEvidence +ucns.bridge_record +canonical producer from_json / from_dict constructors +``` -```python -from fractions import Fraction +Supply exactly one geometry form: + +```text +ucns_object +ucns_bridge_record +ucns_bridge_record_json +ucns_bridge_record_dict +``` + +A live object is converted through `ucns.bridge_record()` so live and serialized paths share one canonical identity record. +```python import edcm import ucns -obj = ucns.UCNSObject(1, 1, [(Fraction(0), None)], [0]) +obj = ucns.S2 result = edcm.build_default_layers().run({"ucns_object": obj}) assert result["ucns_geometry"]["stable_hash"] == ucns.stable_hash(obj) assert result["ucns_integration"]["ucns_object_attached"] is True -assert result["ucns_integration"]["ucns_theorem_status_attached"] is False +assert result["ucns_integration"]["ucns_bridge_record_attached"] is True +assert result["ucns_integration"]["ucns_theorem_status_attached"] is True +assert result["ucns_integration"]["ucns_negative_certification_attached"] is False +``` + +Package import alone does not imply object, bridge, scope, factorization, negative-certification, or theorem evidence attachment. + +### Authoritative factorization evidence + +After geometry, optionally supply exactly one: + +```text +ucns_factorization_evidence +ucns_factorization_evidence_json +ucns_factorization_evidence_dict ``` -Package import alone does not imply object, scope, negative-certification, or theorem evidence attachment. +```python +bridge = ucns.bridge_record(ucns.S2) +evidence = ucns.factorization_evidence(ucns.S2) + +result = edcm.build_default_layers().run({ + "transcript": "A: Preserve authoritative evidence.", + "ucns_bridge_record_json": bridge.to_json(), + "ucns_factorization_evidence_json": evidence.to_json(), +}) + +assert result["ucns_factorization_evidence"]["evidence_digest"] == evidence.evidence_digest +assert result["ucns_integration"]["ucns_factorization_evidence_attached"] is True +assert result["ucns_integration"]["ucns_negative_certification_attached"] is True +``` + +The factorization record must bind to the same stable object hash as the geometry. An attached but uncertified record remains evidence while the certification flag stays false. + +See [`docs/ucns-adapter.md`](docs/ucns-adapter.md). ## Full UCNS / METAPAT / EDCM path @@ -176,24 +216,24 @@ result = edcm.build_default_layers().run({ contract = result["edcm_result"] assert contract["metapat_semantic_constraints"]["canon_digest"] == envelope.canon_digest assert contract["ucns_geometry_identity"]["stable_hash"] == ucns.stable_hash(adaptation.ucns_object) +assert contract["ucns_factorization_evidence"]["state"] == "NA" assert contract["status_evidence"]["proof_status_transfers_to_measurement_validity"] is False ``` ## Final result contract -`edcm_result` separates seven reviewable compartments: +Result schema `edcm.shared-stack-result/1.1.0` separates eight reviewable compartments: 1. `source_evidence` — source reference, content digest, and size; 2. `metapat_semantic_constraints` — canon identity, exact statements, constraints, and unresolved fields; -3. `ucns_geometry_identity` — stable hash, schema, structural facts, and attached domain prerequisite evidence; -4. `edcm_policy_manifest` — manifest fields and hash; -5. `implementation_provenance` — selected semantic, geometry, measurement, composition, and delivery implementations; -6. `readouts` — measured values or typed `NA`; -7. `status_evidence` — independent theorem/negative-certification attachment flags and proof-transfer firewall. - -`epoch_identity` binds METAPAT canon/provenance, UCNS geometry, EDCM manifest, and implementation selection. `result_identity` additionally binds source evidence and readouts. Canon or manifest rotation creates a new epoch rather than silently rewriting historical identity. +3. `ucns_geometry_identity` — canonical bridge identity, stable hash, schema, structural facts, and typed status evidence; +4. `ucns_factorization_evidence` — authoritative search, coverage, pruning, factor, scope, certification, and uncertified-reason evidence or typed `NA`; +5. `edcm_policy_manifest` — manifest fields and hash; +6. `implementation_provenance` — selected semantic, geometry, measurement, composition, and delivery implementations; +7. `readouts` — measured values or typed `NA`; +8. `status_evidence` — independent attachment flags and proof-transfer firewall. -A non-default policy manifest is supplied when constructing the pipeline: +`epoch_identity` binds METAPAT canon/provenance, UCNS bridge geometry, EDCM manifest, and implementation selection. `result_identity` additionally binds source evidence, readouts, UCNS factorization evidence, and attachment states. Factorization evidence changes result identity, not measurement epoch identity. ```python from edcm import build_default_layers @@ -203,6 +243,20 @@ manifest = PolicyManifest(polarity_dictionary_version="v032") result = build_default_layers(manifest).run({"transcript": "A: example"}) ``` +See [`docs/shared-stack-result.md`](docs/shared-stack-result.md). + +## Proof and measurement firewall + +UCNS geometry and factorization evidence preserve: + +```text +theorem_status_transfer = false +measurement_validity_claim = false +proof_status_transfers_to_measurement_validity = false +``` + +UCNS status evidence does not validate EDCM readouts, METAPAT ontology, external truth, diagnosis, intent, or consciousness. + ## Canonical measurement package `edcm.measurement` contains frozen canon data, transcript parsing, deterministic metric computation, projection surfaces, closed-token encoding, and the lossless structural-density codec. @@ -226,4 +280,4 @@ The ordered repair contract lives in `codex-handoff/2026-07-12-stack-repair/`. C ## hmmm -Official serialized UCNS bridge-record ingestion, validated negative-certification and theorem-status evidence envelopes, and repo-local skill-lib drift/msdmd gates remain unfinished. EDCM currently has no `.agents/skills/` installation, so no local skill drift result is claimed. +Version 1 UCNS evidence digests establish canonical content identity, not cryptographic producer signatures. Signed producer or transport authentication and repo-local skill-lib drift/msdmd gates remain unfinished. EDCM currently has no `.agents/skills/` installation, so no local skill drift result is claimed. diff --git a/codex-handoff/2026-07-12-stack-repair/IMPLEMENTATION_STATUS.md b/codex-handoff/2026-07-12-stack-repair/IMPLEMENTATION_STATUS.md index 781e8d4..5830c43 100644 --- a/codex-handoff/2026-07-12-stack-repair/IMPLEMENTATION_STATUS.md +++ b/codex-handoff/2026-07-12-stack-repair/IMPLEMENTATION_STATUS.md @@ -9,20 +9,24 @@ This ledger tracks evidence against `REQUIRED_CHANGES.md` and `COMPLETED_LOOKS_L - [x] Authoritative package metadata, version, build system, typed marker, frozen canon package data, and development dependencies — merged in PR #15. - [x] Python 3.11–3.13 base tests, source/wheel build, `twine check`, clean-wheel install, and installed public-API smoke gate — merged in PR #15. - [x] EDCM-owned UCNS adapter over actual public surfaces, typed absence, fail-closed schema/object handling, and stable-hash preservation — merged in PR #17. -- [x] UCNS package availability, adapter activation, object attachment, scope metadata, negative certification, and theorem status reported independently — merged in PR #17. - [x] Installed `edcmbone` cannot override canonical `edcm.measurement`; authority and consolidation provenance are machine-readable — merged in PR #17. - [x] Canonical METAPAT producer schema and actual-UCNS adapter established in `The-Interdependency/metapat` — merged in METAPAT PR #3. - [x] EDCM-owned METAPAT consumer validates actual envelope objects, canonical JSON, and canonical mappings through producer constructors — merged in PR #18. - [x] METAPAT canon identity, exact source statements/references, constraints, permitted interpretations, unresolved `hmmm`, and provenance digest survive the EDCM path — merged in PR #18. -- [x] Final `edcm.shared-stack-result` separates source evidence, METAPAT constraints, UCNS geometry, EDCM policy identity, implementation provenance, readouts/`NA`, status evidence, and unresolved constraints — merged in PR #18. +- [x] Final result contract separates source evidence, METAPAT constraints, UCNS geometry, EDCM policy identity, implementation provenance, readouts/`NA`, status evidence, and unresolved constraints — merged in PR #18 and extended in active PR #20. - [x] Canon or EDCM manifest rotation produces a new epoch identity; transcript measurement remains deterministic — merged in PR #18. - [x] Base, UCNS-only, METAPAT-only, full UCNS/METAPAT/EDCM, build, metadata, and clean-wheel CI gates pass — merged in PR #18. -- [x] Exact frozen-canon byte manifest, complete file-set gate, measurement-authority policy check, and orthogonality no-fork check run from source and installed wheel — active integrity branch. +- [x] Exact frozen-canon byte manifest, complete file-set gate, measurement-authority policy check, and orthogonality no-fork check run from source and installed wheel — merged in PR #19. +- [x] Canonical versioned UCNS bridge and factorization-evidence producer records — merged in `The-Interdependency/ucns` PR #108. +- [x] EDCM consumes actual UCNS bridge and factorization records as objects, canonical JSON, or canonical mappings through producer constructors — active PR #20. +- [x] Live UCNS objects and serialized bridge records share one `ucns.bridge_record()` identity path — active PR #20. +- [x] Factorization evidence is stable-hash-bound to geometry; mismatched, tampered, coerced, unknown, or unsupported records fail closed — active PR #20. +- [x] Object, bridge, scope, factorization, negative-certification, and theorem-status attachment are independent; package availability alone attaches nothing — active PR #20. +- [x] Certified, uncertified, factor-found, and unit-domain UCNS evidence remain distinguishable and never promote EDCM measurement validity — active PR #20. +- [x] Result schema `edcm.shared-stack-result/1.1.0` preserves canonical UCNS factorization evidence and binds it into result identity — active PR #20. ## Not yet complete -- [ ] Add official serialized UCNS bridge-record ingestion beyond live `UCNSObject` / `object_record` attachment. -- [ ] Attach negative-certification and theorem-status evidence only through validated evidence-bearing envelopes. - [ ] Reconcile remaining MODULE_BUILD, DOCS, CAPABILITIES, BOUNDARIES, CONTRACTS, DEPENDENCIES, OWNERS, and skill-lib declarations. - [ ] Install repo-local skill-lib and add real drift/msdmd gates; EDCM currently has no `.agents/skills/` tree or callable local runner. @@ -32,4 +36,4 @@ Contact convergence, DA geometry correlation, cadence admission from text, and s ## hmmm -The official serialized UCNS bridge-record schema and validated negative-certification/theorem-status evidence envelopes must come from canonical UCNS surfaces rather than being invented inside EDCM. Repo-local skill-lib checks remain unavailable until the actual skill installation and runner are added. +Version 1 UCNS evidence digests establish canonical content identity but not cryptographic producer signatures. Signed producer or transport authentication remains unresolved. Repo-local skill-lib checks remain unavailable until the actual skill installation and runner are added. diff --git a/docs/shared-stack-result.md b/docs/shared-stack-result.md index 60cd2b4..4ad4d38 100644 --- a/docs/shared-stack-result.md +++ b/docs/shared-stack-result.md @@ -4,8 +4,6 @@ `edcm.shared_stack` emits one deterministic review record without collapsing the identities of the systems that contributed to it. -The contract is available at: - ```python result = edcm.build_default_layers().run(payload) contract = result["edcm_result"] @@ -15,9 +13,11 @@ Schema: ```text schema_id: edcm.shared-stack-result -schema_version: 1.0.0 +schema_version: 1.1.0 ``` +Version 1.1.0 adds an explicit canonical UCNS factorization-evidence compartment and binds that evidence into result identity. + ## Compartments ### `source_evidence` @@ -44,9 +44,39 @@ No field is interpreted as an EDCM metric value. ### `ucns_geometry_identity` -Contains actual UCNS geometry evidence derived through `ucns.object_record`, including stable hash, serialization schema, structural facts, and typed domain prerequisite metadata. +Contains one validated canonical UCNS bridge record projected into EDCM's read-only evidence view: + +```text +bridge schema and producer identity +bridge evidence digest +canonical UCNS serialization version +stable object hash +canonical JSON +typed domain statuses and completeness prerequisite +SEQ-PRIME claim scope +structural facts and unit/frontier flags +``` + +A live `UCNSObject` is converted through `ucns.bridge_record()`. Serialized records are validated through the producer's own constructors. -It does not certify a concrete negative factorization result and does not promote EDCM measurement validity. +### `ucns_factorization_evidence` + +Contains one optional authoritative `ucns.UCNSFactorizationEvidence` view: + +```text +factorization evidence schema and producer identity +evidence digest and product hash +result kind and factor stable hashes +negative-certification state and claim scope +certification policy version +search exhaustion and truncation +catalogue source, sizes, and fingerprints +coverage validation and search-report binding +pruning rule/version and coverage preservation +explicit uncertified reasons +``` + +The producer record must bind to the same object hash as `ucns_geometry_identity`. Absence is typed `NA`. An attached but uncertified record remains evidence while `ucns_negative_certification_attached` stays false. ### `edcm_policy_manifest` @@ -73,24 +103,37 @@ Contains deterministic transcript readouts when a non-empty transcript was measu ### `status_evidence` -Keeps attachment states independent and pins the firewalls: +Keeps attachment states independent: ```text +ucns_bridge_record_attached +ucns_factorization_evidence_attached +ucns_theorem_status_attached +ucns_negative_certification_attached +metapat_theorem_status_attached proof_status_transfers_to_measurement_validity = false semantic_labels_are_measurement_values = false ``` +Content digests are verified. Version 1 records do not claim cryptographic producer signatures. + ## Identity rules -`epoch_identity` changes when any readout-governing context changes: +`epoch_identity` changes when readout-governing context changes: -- METAPAT canon digest; -- METAPAT provenance digest; -- UCNS stable hash or serialization schema; +- METAPAT canon or provenance digest; +- UCNS stable hash, canonical schema, or bridge evidence digest; - EDCM policy-manifest hash; - selected semantic, geometry, or measurement implementation. -`result_identity` additionally binds source evidence and measured readouts. +`result_identity` additionally binds: + +- source evidence; +- measured readouts; +- attached UCNS factorization evidence; +- status-evidence attachment states. + +Factorization evidence changes result identity but not measurement epoch identity because it is status evidence rather than readout-governing geometry or policy. Changing a METAPAT canon digest or EDCM manifest creates a new identity epoch. Historical results are not rewritten in place. @@ -99,6 +142,7 @@ Changing a METAPAT canon digest or EDCM manifest creates a new identity epoch. H ```python import edcm import metapat +import ucns envelope = metapat.root_spine_module_envelope() adaptation = metapat.adapt_envelope_to_ucns(envelope) @@ -111,22 +155,48 @@ result = edcm.build_default_layers().run({ }) contract = result["edcm_result"] +assert contract["ucns_geometry_identity"]["stable_hash"] == ucns.stable_hash( + adaptation.ucns_object +) +assert contract["ucns_factorization_evidence"]["state"] == "NA" +``` + +## Certified-evidence usage + +```python +bridge = ucns.bridge_record(ucns.S2) +evidence = ucns.factorization_evidence(ucns.S2) + +result = edcm.build_default_layers().run({ + "transcript": "A: Preserve authoritative status evidence.", + "ucns_bridge_record_json": bridge.to_json(), + "ucns_factorization_evidence_json": evidence.to_json(), +}) + +contract = result["edcm_result"] +assert contract["ucns_factorization_evidence"]["negative_result_certified"] is True +assert contract["status_evidence"]["ucns_negative_certification_attached"] is True +assert contract["status_evidence"]["proof_status_transfers_to_measurement_validity"] is False ``` ## Failure behavior The pipeline fails closed for: -- multiple METAPAT envelope forms in one payload; -- non-METAPAT objects supplied as `metapat_envelope`; +- multiple METAPAT envelope forms; - malformed or unknown serialized METAPAT fields; - invalid METAPAT provenance digest; +- multiple UCNS geometry forms; +- multiple UCNS factorization-evidence forms; +- factorization evidence without geometry; +- factorization product hash different from geometry stable hash; +- unknown, missing, coerced, tampered, or unsupported UCNS producer fields; +- non-METAPAT, non-UCNS, or wrong record object types; - unsupported METAPAT or UCNS schema versions; -- non-UCNS objects supplied as `ucns_object`; - transitive import failures inside optional sibling packages. Only direct absence of an optional sibling becomes typed unavailability. ## hmmm -Official serialized UCNS bridge-record ingestion and validated negative-certification/theorem-status evidence envelopes remain unresolved. Until canonical schemas exist, their attachment flags remain false. +UCNS evidence digests are content identities, not signed producer attestations. Signed transport or producer authentication remains unresolved without weakening canonical record validation or the proof-transfer firewall. diff --git a/docs/ucns-adapter.md b/docs/ucns-adapter.md index 857a4e7..668b7c1 100644 --- a/docs/ucns-adapter.md +++ b/docs/ucns-adapter.md @@ -2,43 +2,99 @@ ## Purpose -EDCM owns the adapter contract it needs. UCNS does not need to expose an EDCM-specific `SemanticsLayer`. +EDCM owns the consumer contract it needs. UCNS owns the algebra, canonical serialization, bridge-record schema, factorization policy, and certification evidence. -The adapter consumes the actual public UCNS package surface: +EDCM consumes these actual public UCNS surfaces: -- `ucns.UCNSObject`; -- `ucns.object_record`; -- `ucns.stable_hash`; -- `ucns.CANONICAL_SERIALIZATION_VERSION`; -- typed domain prerequisite metadata carried by the object record. +```text +ucns.UCNSObject +ucns.UCNSBridgeRecord +ucns.UCNSFactorizationEvidence +ucns.bridge_record +ucns.CANONICAL_SERIALIZATION_VERSION +ucns.BRIDGE_RECORD_SCHEMA_ID / VERSION +ucns.FACTORIZATION_EVIDENCE_SCHEMA_ID / VERSION +``` -## Usage +EDCM does not expect UCNS to expose an EDCM-specific `SemanticsLayer` and does not duplicate producer schemas. -With UCNS installed: +## Install -```python -from fractions import Fraction +```bash +python -m pip install -e ".[dev,ucns]" +``` + +The `ucns` extra is pinned to the verified producer commit that introduced canonical evidence envelopes. + +## Geometry input + +Supply exactly one geometry form: + +```text +ucns_object +ucns_bridge_record +ucns_bridge_record_json +ucns_bridge_record_dict +``` +### Live object + +```python import edcm import ucns -obj = ucns.UCNSObject(1, 1, [(Fraction(0), None)], [0]) +obj = ucns.S2 result = edcm.build_default_layers().run({"ucns_object": obj}) assert result["ucns_geometry"]["stable_hash"] == ucns.stable_hash(obj) assert result["ucns_integration"]["ucns_object_attached"] is True +assert result["ucns_integration"]["ucns_bridge_record_attached"] is True ``` -Without UCNS installed: +The live object is immediately converted through `ucns.bridge_record()`. EDCM does not maintain an alternate object inspector. + +### Serialized bridge record ```python -import edcm +bridge = ucns.bridge_record(ucns.S2) +result = edcm.build_default_layers().run({ + "ucns_bridge_record_json": bridge.to_json(), +}) + +assert result["ucns_geometry"]["bridge_evidence_digest"] == bridge.evidence_digest +assert result["ucns_integration"]["ucns_object_attached"] is False +assert result["ucns_integration"]["ucns_bridge_record_attached"] is True +``` + +JSON and mapping forms are validated through UCNS's own `from_json()` and `from_dict()` constructors. The producer verifies canonical JSON, stable hash, exact fields, strict types, schema identity, producer identity, and evidence digest. + +## Factorization evidence input + +After attaching geometry, optionally supply exactly one: + +```text +ucns_factorization_evidence +ucns_factorization_evidence_json +ucns_factorization_evidence_dict +``` -result = edcm.build_default_layers().run({"transcript": "A: We need to decide."}) -assert result["semantics"] == "edcm.transcript_only" -assert result["ucns_integration"]["ucns_package_available"] is False +```python +bridge = ucns.bridge_record(ucns.S2) +evidence = ucns.factorization_evidence(ucns.S2) + +result = edcm.build_default_layers().run({ + "transcript": "A: Preserve the evidence boundary.", + "ucns_bridge_record": bridge, + "ucns_factorization_evidence": evidence, +}) + +assert result["ucns_integration"]["ucns_factorization_evidence_attached"] is True +assert result["ucns_integration"]["ucns_negative_certification_attached"] is True +assert result["ucns_factorization_evidence"]["evidence_digest"] == evidence.evidence_digest ``` +The factorization record must have the same `product_hash` as the attached geometry `stable_hash`. A mismatch fails closed. + ## Independent status fields Every integration report distinguishes: @@ -47,32 +103,67 @@ Every integration report distinguishes: ucns_package_available ucns_adapter_active ucns_object_attached +ucns_bridge_record_attached ucns_scope_metadata_attached +ucns_factorization_evidence_attached ucns_negative_certification_attached ucns_theorem_status_attached ``` -Package import alone sets only package availability and, after successful adapter construction, adapter activation. It does not claim that an object or evidence record was attached. +Package import alone sets only package availability and adapter activation. No object, bridge, scope, theorem, factorization, or negative-certification attachment is inferred. + +A bridge record attaches typed UCNS domain-status evidence. Negative certification attaches only when a matching authoritative factorization record states `negative_result_certified = true` after producer validation. + +An uncertified result remains attached evidence while the certification flag stays false: + +```python +evidence = ucns.factorization_evidence(ucns.S2, catalogue=[]) +assert not evidence.negative_result_certified +``` + +## Result contract + +Result schema `edcm.shared-stack-result/1.1.0` includes separate compartments: + +```text +ucns_geometry_identity +ucns_factorization_evidence +status_evidence +readouts +``` + +Factorization evidence changes `result_identity`, not measurement `epoch_identity`, because it is attached status evidence rather than a readout-governing geometry or policy change. ## Failure behavior -- Direct absence of the optional `ucns` package selects explicit transcript-only mode. -- A transitive import failure is raised. -- Missing public surfaces fail adapter construction. -- Unsupported canonical serialization versions fail closed. -- A value under `ucns_object` that is not an actual `ucns.UCNSObject` raises `TypeError`. +The adapter fails closed for: + +- multiple geometry forms; +- multiple factorization-evidence forms; +- factorization evidence without geometry; +- factorization `product_hash` different from geometry `stable_hash`; +- wrong live object or record types; +- unknown, missing, coerced, tampered, or unsupported producer fields; +- unsupported UCNS serialization, bridge, or factorization-evidence schemas; +- transitive UCNS import failures. + +Only direct absence of the optional `ucns` package becomes typed transcript-only geometry mode. ## Proof and measurement firewall -The geometry evidence record preserves the UCNS stable hash and domain prerequisite metadata. It deliberately sets: +Geometry and factorization records deliberately preserve: ```text theorem_status_transfer = false measurement_validity_claim = false ``` -Domain metadata is attached evidence, not validation of an EDCM empirical readout and not certification of a concrete negative factorization result. +UCNS domain status and certified negative search evidence do not validate EDCM readouts, METAPAT ontology, external truth, diagnosis, intent, or consciousness. + +## Trust boundary + +UCNS evidence digests are verified content identities. Version 1 records do not carry cryptographic producer signatures or transport authentication. ## hmmm -Live `UCNSObject` / `object_record` ingestion is implemented. Official serialized bridge-record ingestion remains unresolved until its canonical schema is identified and pinned from UCNS rather than invented locally. +Signed producer attestations remain unresolved. Their absence does not reopen the canonical schema, stable-hash binding, certification policy, or proof-transfer firewall. diff --git a/edcm/__init__.py b/edcm/__init__.py index 60f5d73..dec3711 100644 --- a/edcm/__init__.py +++ b/edcm/__init__.py @@ -2,29 +2,30 @@ EDCM owns the maintained measurement implementation and the consumer adapter protocols used for canonical METAPAT semantic authority and actual UCNS -geometry. Optional package absence remains explicit typed absence; no sibling -package silently replaces EDCM measurement or supplies invented semantics. +geometry and status evidence. Optional package absence remains explicit typed +absence; no sibling package silently replaces EDCM measurement or supplies +invented semantics or certification. """ # === MODULE_BUILD === # id: edcm_package # module_name: edcm # module_kind: engine -# summary: EDCM package root — declares package identity and re-exports provenance-bearing shared-stack layers, canonical METAPAT consumer surfaces, actual-UCNS adapter surfaces, final result contracts, frozen-canon/authority integrity gates, energy audit, EDCM objects, edcmucns architecture, and canonical maintained measurement. +# summary: EDCM package root — declares package identity and re-exports provenance-bearing shared-stack layers, canonical METAPAT consumer surfaces, actual-UCNS bridge and factorization-evidence consumer surfaces, final result contracts, frozen-canon/authority integrity gates, energy audit, EDCM objects, edcmucns architecture, and canonical maintained measurement. # owner: Erin Spencer -# public_surface: __version__, build_default_layers, EDCMLayers, LayerProvenance, ConsolidatedMeasurementLayer, CompositeSemanticsLayer, MissingMetapatSemanticAuthorityLayer, MetapatSemanticAuthorityLayer, TranscriptOnlySemanticsLayer, UCNSSemanticsLayer, SharedStackCompositionLayer, SharedStackDeliveryLayer, ActualMetapatAdapter, MetapatIntegrationStatus, MetapatSemanticEvidence, select_metapat_adapter, inspect_metapat_adapter, ActualUCNSAdapter, UCNSIntegrationStatus, UCNSGeometryEvidence, select_ucns_adapter, inspect_ucns_adapter, EDCMResultContract, build_result_contract, RESULT_SCHEMA_ID, RESULT_SCHEMA_VERSION, IntegrityFinding, IntegrityReport, run_integrity_gate, verify_frozen_canon, verify_measurement_authority, verify_orthogonality_alias, audit_energy_text, audit_energy_claim, extract_energy_claim_candidates, audit_falsifiability_preservation, EnergyAuditReport, AuditFlag, EnergyClaim, EDCMBONE_FAILURE_TAXONOMY, BOUNDARY_NOTE, AxisState, MetricAxis, MetricReadout, ConstraintField, FieldMotion, canonical_axes, field_motion_fixture, FIELD_MOTION_FIXTURE_MATRIX, SIGNED_TERNARY, GRAINS, CONTACT_SIGN, RESOLUTION_SIGN, measurement, edcmucns, CanonLoader, parse_transcript, ParsedTranscript, compute_transcript, RoundMetrics, project_transcript, AgentMetrics, fire_alerts +# public_surface: __version__, build_default_layers, EDCMLayers, LayerProvenance, ConsolidatedMeasurementLayer, CompositeSemanticsLayer, MissingMetapatSemanticAuthorityLayer, MetapatSemanticAuthorityLayer, TranscriptOnlySemanticsLayer, UCNSSemanticsLayer, SharedStackCompositionLayer, SharedStackDeliveryLayer, ActualMetapatAdapter, MetapatIntegrationStatus, MetapatSemanticEvidence, select_metapat_adapter, inspect_metapat_adapter, ActualUCNSAdapter, UCNSIntegrationStatus, UCNSGeometryEvidence, UCNSFactorizationEvidenceRecord, select_ucns_adapter, inspect_ucns_adapter, EDCMResultContract, build_result_contract, RESULT_SCHEMA_ID, RESULT_SCHEMA_VERSION, IntegrityFinding, IntegrityReport, run_integrity_gate, verify_frozen_canon, verify_measurement_authority, verify_orthogonality_alias, audit_energy_text, audit_energy_claim, extract_energy_claim_candidates, audit_falsifiability_preservation, EnergyAuditReport, AuditFlag, EnergyClaim, EDCMBONE_FAILURE_TAXONOMY, BOUNDARY_NOTE, AxisState, MetricAxis, MetricReadout, ConstraintField, FieldMotion, canonical_axes, field_motion_fixture, FIELD_MOTION_FIXTURE_MATRIX, SIGNED_TERNARY, GRAINS, CONTACT_SIGN, RESOLUTION_SIGN, measurement, edcmucns, CanonLoader, parse_transcript, ParsedTranscript, compute_transcript, RoundMetrics, project_transcript, AgentMetrics, fire_alerts # internal_surface: none # auth_boundary: none # storage_boundary: none # network_boundary: none # user_data_boundary: none # admin_only: false -# tests: tests.test_measurement, tests.test_ucns_adapter, tests.test_metapat_adapter, tests.test_shared_stack_contract, tests.test_integrity, tests.test_ucns_objects, tests.test_energy_claims, tests.test_packaging +# tests: tests.test_measurement, tests.test_ucns_adapter, tests.test_ucns_evidence_consumer, tests.test_metapat_adapter, tests.test_shared_stack_contract, tests.test_integrity, tests.test_ucns_objects, tests.test_energy_claims, tests.test_packaging # rollout: default_enabled -# rollback: remove new exports and restore prior adapter-only package root +# rollback: remove new exports and restore prior package root only with a result-schema migration # requires: edcm_layers, edcm_metapat_adapter, edcm_ucns_adapter, edcm_shared_stack, edcm_integrity, edcm_energy_claims, edcm_falsifiability_bridge, edcm_ucns_objects, edcmucns_package # since: 2026-06-02 -# unresolved: official negative-certification and theorem-status evidence envelopes remain unattached until validated schemas exist +# unresolved: UCNS evidence digests provide content identity but not cryptographic producer authentication # === END MODULE_BUILD === __version__ = "0.1.0" @@ -56,6 +57,7 @@ from .ucns_adapter import ( ActualUCNSAdapter, UCNSAdapterConstructionError, + UCNSFactorizationEvidenceRecord, UCNSGeometryEvidence, UCNSIntegrationStatus, UnsupportedUCNSSchemaError, @@ -125,6 +127,7 @@ "select_metapat_adapter", "ActualUCNSAdapter", "UCNSAdapterConstructionError", + "UCNSFactorizationEvidenceRecord", "UCNSGeometryEvidence", "UCNSIntegrationStatus", "UnsupportedUCNSSchemaError", diff --git a/edcm/shared_stack.py b/edcm/shared_stack.py index f0d2491..5537478 100644 --- a/edcm/shared_stack.py +++ b/edcm/shared_stack.py @@ -4,20 +4,22 @@ -------------- The supported layer pipeline calls :func:`build_result_contract` after semantic and measurement stages. The resulting ``edcm_result`` record keeps source -evidence, METAPAT constraints, UCNS geometry identity, EDCM policy identity, -implementation selection, measured readouts, typed absence, unresolved fields, -and attached status evidence in separate compartments. +evidence, METAPAT constraints, UCNS geometry identity, authoritative UCNS +factorization evidence, EDCM policy identity, implementation selection, +measured readouts, typed absence, unresolved fields, and attachment states in +separate compartments. ``epoch_identity`` changes when the METAPAT canon/provenance identity, UCNS geometry identity, EDCM policy manifest, or selected implementation changes. -``result_identity`` additionally binds the measured source and readouts. +``result_identity`` additionally binds source evidence, readouts, and attached +UCNS factorization evidence. """ # === MODULE_BUILD === # id: edcm_shared_stack # module_name: shared_stack # module_kind: schema -# summary: deterministic final EDCM result contract separating source evidence, METAPAT semantic authority, UCNS geometry, EDCM policy identity, implementation provenance, readouts/NA, unresolved constraints, and attached status evidence. +# summary: deterministic final EDCM result contract separating source evidence, METAPAT semantic authority, UCNS geometry, authoritative UCNS factorization evidence, EDCM policy identity, implementation provenance, readouts/NA, unresolved constraints, and attachment states. # owner: Erin Spencer # public_surface: RESULT_SCHEMA_ID, RESULT_SCHEMA_VERSION, EDCMResultContract, build_result_contract # internal_surface: _canonical_bytes, _digest, _source_evidence, _typed_absence, _readouts, _collect_unresolved @@ -26,12 +28,12 @@ # network_boundary: none # user_data_boundary: hashes caller transcript content and preserves caller source reference without external transmission # admin_only: false -# tests: tests.test_shared_stack_contract +# tests: tests.test_shared_stack_contract, tests.test_ucns_evidence_consumer # rollout: default_enabled -# rollback: remove edcm_result assembly and restore local composition fallback +# rollback: remove factorization-evidence compartment and restore prior result schema only with a versioned migration # requires: edcmucns_manifest, edcm_metapat_adapter, edcm_ucns_adapter, edcm_measurement # since: 2026-07-12 -# unresolved: official negative-certification and theorem-status envelopes remain unattached until their validated schemas are supplied +# unresolved: UCNS evidence digests provide content identity but not signed producer authentication # === END MODULE_BUILD === from __future__ import annotations @@ -44,7 +46,7 @@ from .edcmucns.manifest import PolicyManifest RESULT_SCHEMA_ID = "edcm.shared-stack-result" -RESULT_SCHEMA_VERSION = "1.0.0" +RESULT_SCHEMA_VERSION = "1.1.0" def _canonical_bytes(value: Any) -> bytes: @@ -118,7 +120,9 @@ def _collect_unresolved(payload: Mapping[str, Any]) -> tuple[str, ...]: unresolved: list[str] = [] semantics = payload.get("metapat_semantics") if isinstance(semantics, Mapping): - unresolved.extend(str(value) for value in semantics.get("unresolved_constraints", ())) + unresolved.extend( + str(value) for value in semantics.get("unresolved_constraints", ()) + ) provenance = payload.get("layer_provenance") if isinstance(provenance, Mapping): for record in provenance.values(): @@ -138,6 +142,7 @@ class EDCMResultContract: source_evidence: dict[str, Any] metapat_semantic_constraints: dict[str, Any] ucns_geometry_identity: dict[str, Any] + ucns_factorization_evidence: dict[str, Any] edcm_policy_manifest: dict[str, Any] implementation_provenance: dict[str, Any] readouts: dict[str, Any] @@ -176,6 +181,15 @@ def build_result_contract( else: ucns_record = {"state": "attached", **dict(ucns)} + factorization = payload.get("ucns_factorization_evidence") + if not isinstance(factorization, Mapping): + factorization_record = _typed_absence( + "ucns_factorization_evidence", + "no validated UCNS factorization evidence was attached", + ) + else: + factorization_record = {"state": "attached", **dict(factorization)} + manifest_record = { "schema": "edcm.policy-manifest.v031", "manifest_hash": manifest.manifest_hash(), @@ -189,6 +203,12 @@ def build_result_contract( status_evidence = { "metapat": metapat_status, "ucns": ucns_status, + "ucns_bridge_record_attached": bool( + ucns_status.get("ucns_bridge_record_attached", False) + ), + "ucns_factorization_evidence_attached": bool( + ucns_status.get("ucns_factorization_evidence_attached", False) + ), "ucns_theorem_status_attached": bool( ucns_status.get("ucns_theorem_status_attached", False) ), @@ -201,6 +221,9 @@ def build_result_contract( "proof_status_transfers_to_measurement_validity": False, "semantic_labels_are_measurement_values": False, "measurement_validity_basis": "EDCM declared measurement contract only", + "evidence_authentication": ( + "content digests verified; cryptographic producer signature not supplied" + ), } unresolved = _collect_unresolved(payload) @@ -209,6 +232,7 @@ def build_result_contract( "metapat_provenance_digest": metapat_record.get("provenance_digest"), "ucns_stable_hash": ucns_record.get("stable_hash"), "ucns_schema": ucns_record.get("ucns_serialization_version"), + "ucns_bridge_evidence_digest": ucns_record.get("bridge_evidence_digest"), "edcm_manifest_hash": manifest_record["manifest_hash"], "semantic_authority_implementation": implementation.get("semantic_authority"), "geometry_implementation": implementation.get("geometry"), @@ -220,6 +244,8 @@ def build_result_contract( "epoch_identity": epoch_identity, "source_evidence": source, "readouts": readouts, + "ucns_factorization_evidence": factorization_record, + "status_evidence": status_evidence, } ) @@ -231,6 +257,7 @@ def build_result_contract( source_evidence=source, metapat_semantic_constraints=metapat_record, ucns_geometry_identity=ucns_record, + ucns_factorization_evidence=factorization_record, edcm_policy_manifest=manifest_record, implementation_provenance=implementation, readouts=readouts, diff --git a/edcm/ucns_adapter.py b/edcm/ucns_adapter.py index 5b20971..5fe5cd9 100644 --- a/edcm/ucns_adapter.py +++ b/edcm/ucns_adapter.py @@ -1,38 +1,49 @@ -"""Explicit adapter from EDCM to the public UCNS package surface. +"""Explicit EDCM consumer for canonical UCNS geometry and status evidence. Usage guidance -------------- -Call :func:`select_ucns_adapter` during pipeline construction. A missing -optional ``ucns`` package returns a typed unavailable selection. If ``ucns`` -is importable but its required public surface is malformed, construction -fails visibly; EDCM must not silently fall back. - -When an actual ``ucns.UCNSObject`` is supplied under ``ucns_object``, -:class:`ActualUCNSAdapter` attaches an EDCM-owned geometry evidence record -containing the UCNS stable hash, canonical serialization version, structural -facts, and domain prerequisite metadata. None of that evidence promotes an -EDCM measurement claim or certifies a concrete negative factorization result. +Call :func:`select_ucns_adapter` during pipeline construction. Direct absence +of the optional ``ucns`` package returns a typed unavailable selection. An +importable but malformed or unsupported UCNS package fails visibly. + +Supply exactly one geometry form: + +- ``ucns_object`` — an actual ``ucns.UCNSObject``; +- ``ucns_bridge_record`` — an actual ``ucns.UCNSBridgeRecord``; +- ``ucns_bridge_record_json`` — canonical producer JSON; or +- ``ucns_bridge_record_dict`` — the producer's canonical mapping. + +Optionally supply exactly one factorization-evidence form: + +- ``ucns_factorization_evidence``; +- ``ucns_factorization_evidence_json``; or +- ``ucns_factorization_evidence_dict``. + +Serialized forms are validated by UCNS's own ``from_json`` / ``from_dict`` +constructors. Factorization evidence must bind to the same stable object hash +as the geometry record. UCNS statuses remain evidence only and never promote +EDCM empirical validity. """ # === MODULE_BUILD === # id: edcm_ucns_adapter # module_name: ucns_adapter # module_kind: adapter -# summary: Explicit EDCM-owned adapter over actual UCNS public objects, stable identity, and typed domain prerequisite metadata. +# summary: EDCM-owned consumer over actual UCNS objects, canonical bridge records, and authoritative factorization evidence with stable-hash binding and no proof-status transfer. # owner: Erin Spencer -# public_surface: UCNSAdapter, ActualUCNSAdapter, UCNSAdapterSelection, UCNSIntegrationStatus, UCNSGeometryEvidence, UCNSAdapterConstructionError, UnsupportedUCNSSchemaError, select_ucns_adapter, inspect_ucns_adapter, missing_ucns_status -# internal_surface: _module_version, _failed_status +# public_surface: UCNSAdapter, ActualUCNSAdapter, UCNSAdapterSelection, UCNSIntegrationStatus, UCNSGeometryEvidence, UCNSFactorizationEvidenceRecord, UCNSAdapterConstructionError, UnsupportedUCNSSchemaError, select_ucns_adapter, inspect_ucns_adapter, missing_ucns_status +# internal_surface: _module_version, _failed_status, _one_present, _geometry_from_record, _factorization_from_record # auth_boundary: none # storage_boundary: none # network_boundary: none -# user_data_boundary: accepts caller-supplied UCNS objects and returns deterministic structural evidence +# user_data_boundary: accepts caller-supplied UCNS objects or canonical producer records and returns deterministic evidence # admin_only: false -# tests: tests.test_ucns_adapter, tests.test_ucns_dependency, tests.test_measurement +# tests: tests.test_ucns_adapter, tests.test_ucns_dependency, tests.test_ucns_evidence_consumer, tests.test_shared_stack_contract # rollout: default_enabled -# rollback: remove module, restore transcript-only semantics selection, and remove its public exports -# requires: optional ucns package public surface +# rollback: restore live-object-only adapter and mark serialized evidence unavailable +# requires: optional ucns package public surface including UCNSBridgeRecord and UCNSFactorizationEvidence # since: 2026-07-12 -# unresolved: official serialized bridge-record ingestion beyond live UCNSObject/object_record +# unresolved: evidence digests are content identities, not cryptographic producer signatures # === END MODULE_BUILD === from __future__ import annotations @@ -44,14 +55,37 @@ from typing import Any, Mapping, Protocol UCNS_SOURCE_REPOSITORY = "https://github.com/The-Interdependency/ucns" -UCNS_BRIDGE_SCHEMA_VERSION = "edcm-ucns-object-record-v1" SUPPORTED_SERIALIZATION_VERSIONS = frozenset({"ucns-canonical-json-v1"}) -INSTALL_HINT = "Install the sibling ucns package with: python -m pip install -e ../ucns" +SUPPORTED_BRIDGE_SCHEMAS = frozenset({("ucns.bridge-record", "1.0.0")}) +SUPPORTED_FACTORIZATION_EVIDENCE_SCHEMAS = frozenset( + {("ucns.factorization-evidence", "1.0.0")} +) +INSTALL_HINT = ( + "Install the canonical UCNS package with: " + "python -m pip install 'ucns @ git+https://github.com/" + "The-Interdependency/ucns.git@27c004b21b6d02bf3873c280ebd3158131ef87fe'" +) +_GEOMETRY_INPUT_KEYS = ( + "ucns_object", + "ucns_bridge_record", + "ucns_bridge_record_json", + "ucns_bridge_record_dict", +) +_FACTORIZATION_INPUT_KEYS = ( + "ucns_factorization_evidence", + "ucns_factorization_evidence_json", + "ucns_factorization_evidence_dict", +) _REQUIRED_PUBLIC_SURFACE = ( "UCNSObject", - "object_record", - "stable_hash", + "UCNSBridgeRecord", + "UCNSFactorizationEvidence", + "bridge_record", + "BRIDGE_RECORD_SCHEMA_ID", + "BRIDGE_RECORD_SCHEMA_VERSION", + "FACTORIZATION_EVIDENCE_SCHEMA_ID", + "FACTORIZATION_EVIDENCE_SCHEMA_VERSION", "CANONICAL_SERIALIZATION_VERSION", ) @@ -61,7 +95,7 @@ class UCNSAdapterConstructionError(RuntimeError): class UnsupportedUCNSSchemaError(UCNSAdapterConstructionError): - """Raised when UCNS exposes an unsupported canonical serialization schema.""" + """Raised when UCNS exposes an unsupported producer schema.""" @dataclass(frozen=True) @@ -69,13 +103,16 @@ class UCNSIntegrationStatus: """Independent UCNS integration-state flags. Package availability never implies adapter activation, object attachment, - scope evidence, negative certification, or theorem-status attachment. + bridge attachment, scope evidence, factorization evidence, negative + certification, or theorem-status attachment. """ ucns_package_available: bool ucns_adapter_active: bool ucns_object_attached: bool + ucns_bridge_record_attached: bool ucns_scope_metadata_attached: bool + ucns_factorization_evidence_attached: bool ucns_negative_certification_attached: bool ucns_theorem_status_attached: bool implementation_id: str @@ -91,9 +128,12 @@ def as_dict(self) -> dict[str, Any]: @dataclass(frozen=True) class UCNSGeometryEvidence: - """EDCM-owned evidence record derived from an actual UCNS object.""" + """EDCM-owned view of one validated canonical UCNS bridge record.""" + bridge_schema_id: str bridge_schema_version: str + bridge_producer_id: str + bridge_evidence_digest: str ucns_serialization_version: str stable_hash: str domain_label: str @@ -103,6 +143,10 @@ class UCNSGeometryEvidence: depth: int n_min: int length: int + is_unit: bool + is_verified_domain: bool + is_frontier: bool + note: str canonical_json: str theorem_status_transfer: bool = False measurement_validity_claim: bool = False @@ -111,8 +155,53 @@ def as_dict(self) -> dict[str, Any]: return asdict(self) +@dataclass(frozen=True) +class UCNSFactorizationEvidenceRecord: + """EDCM-owned view of authoritative UCNS factorization evidence.""" + + schema_id: str + schema_version: str + producer_id: str + evidence_digest: str + product_hash: str + product_domain_label: str + product_domain_statuses: tuple[str, ...] + completeness_guaranteed: bool + result_kind: str + factor_hashes: tuple[str, ...] + negative_result_certified: bool + seq_prime_is_absolute: bool + claim_scope: str + note: str + certification_policy_version: str + search_exhausted: bool + truncation_occurred: bool + catalogue_source: str + supplied_catalogue_size: int + supplied_catalogue_fingerprint: str + effective_catalogue_size: int + effective_catalogue_fingerprint: str + catalogue_coverage_status: str + catalogue_coverage_reason: str + catalogue_coverage_rule_version: str + required_catalogue_rule_version: str + required_catalogue_fingerprint: str + coverage_record_validated: bool + coverage_bound_to_search_report: bool + pruning_applied: bool + pruning_rule: str + pruning_rule_version: str + pruning_preserves_coverage: bool + uncertified_reasons: tuple[str, ...] + theorem_status_transfer: bool = False + measurement_validity_claim: bool = False + + def as_dict(self) -> dict[str, Any]: + return asdict(self) + + class UCNSAdapter(Protocol): - """The narrow geometry/identity behavior EDCM requires from UCNS.""" + """The narrow geometry and evidence behavior EDCM requires from UCNS.""" @property def status(self) -> UCNSIntegrationStatus: @@ -136,19 +225,31 @@ def _module_version(module: ModuleType) -> str | None: return str(value) if value is not None else None +def _one_present(state: Mapping[str, Any], keys: tuple[str, ...], label: str) -> str | None: + present = [key for key in keys if key in state] + if len(present) > 1: + raise ValueError( + f"supply exactly one {label} form; got " + ", ".join(present) + ) + return present[0] if present else None + + def missing_ucns_status() -> UCNSIntegrationStatus: return UCNSIntegrationStatus( ucns_package_available=False, ucns_adapter_active=False, ucns_object_attached=False, + ucns_bridge_record_attached=False, ucns_scope_metadata_attached=False, + ucns_factorization_evidence_attached=False, ucns_negative_certification_attached=False, ucns_theorem_status_attached=False, implementation_id="edcm.ucns_adapter.unavailable", implementation_version=None, source_repository=UCNS_SOURCE_REPOSITORY, selection="unavailable", - unresolved_constraints=("ucns package is not installed",), + unresolved_constraints=("canonical ucns package is not installed",), + errors=(INSTALL_HINT,), ) @@ -157,7 +258,9 @@ def _failed_status(error: BaseException) -> UCNSIntegrationStatus: ucns_package_available=True, ucns_adapter_active=False, ucns_object_attached=False, + ucns_bridge_record_attached=False, ucns_scope_metadata_attached=False, + ucns_factorization_evidence_attached=False, ucns_negative_certification_attached=False, ucns_theorem_status_attached=False, implementation_id="edcm.ucns_adapter.failed", @@ -170,25 +273,55 @@ def _failed_status(error: BaseException) -> UCNSIntegrationStatus: class ActualUCNSAdapter: - """Adapter over UCNS's actual public object and inspection surfaces.""" + """Adapter over UCNS's actual object and evidence-envelope surfaces.""" def __init__(self, module: ModuleType) -> None: - missing = tuple(name for name in _REQUIRED_PUBLIC_SURFACE if not hasattr(module, name)) + missing = tuple( + name for name in _REQUIRED_PUBLIC_SURFACE if not hasattr(module, name) + ) if missing: raise UCNSAdapterConstructionError( "Importable ucns package is missing required public surfaces: " + ", ".join(missing) ) - schema_version = str(module.CANONICAL_SERIALIZATION_VERSION) - if schema_version not in SUPPORTED_SERIALIZATION_VERSIONS: + serialization_version = str(module.CANONICAL_SERIALIZATION_VERSION) + if serialization_version not in SUPPORTED_SERIALIZATION_VERSIONS: raise UnsupportedUCNSSchemaError( - f"Unsupported UCNS serialization schema {schema_version!r}; " + f"Unsupported UCNS serialization schema {serialization_version!r}; " f"supported={sorted(SUPPORTED_SERIALIZATION_VERSIONS)!r}" ) + bridge_schema = ( + str(module.BRIDGE_RECORD_SCHEMA_ID), + str(module.BRIDGE_RECORD_SCHEMA_VERSION), + ) + if bridge_schema not in SUPPORTED_BRIDGE_SCHEMAS: + raise UnsupportedUCNSSchemaError( + f"Unsupported UCNS bridge schema {bridge_schema!r}; " + f"supported={sorted(SUPPORTED_BRIDGE_SCHEMAS)!r}" + ) + factor_schema = ( + str(module.FACTORIZATION_EVIDENCE_SCHEMA_ID), + str(module.FACTORIZATION_EVIDENCE_SCHEMA_VERSION), + ) + if factor_schema not in SUPPORTED_FACTORIZATION_EVIDENCE_SCHEMAS: + raise UnsupportedUCNSSchemaError( + f"Unsupported UCNS factorization evidence schema {factor_schema!r}; " + "supported=" + f"{sorted(SUPPORTED_FACTORIZATION_EVIDENCE_SCHEMAS)!r}" + ) + for producer_type, label in ( + (module.UCNSBridgeRecord, "UCNSBridgeRecord"), + (module.UCNSFactorizationEvidence, "UCNSFactorizationEvidence"), + ): + for constructor in ("from_dict", "from_json"): + if not callable(getattr(producer_type, constructor, None)): + raise UCNSAdapterConstructionError( + f"{label}.{constructor} is required" + ) self._module = module - self._schema_version = schema_version + self._serialization_version = serialization_version self._version = _module_version(module) @property @@ -197,7 +330,9 @@ def status(self) -> UCNSIntegrationStatus: ucns_package_available=True, ucns_adapter_active=True, ucns_object_attached=False, + ucns_bridge_record_attached=False, ucns_scope_metadata_attached=False, + ucns_factorization_evidence_attached=False, ucns_negative_certification_attached=False, ucns_theorem_status_attached=False, implementation_id="edcm.ucns_adapter.actual", @@ -206,57 +341,196 @@ def status(self) -> UCNSIntegrationStatus: selection="canonical_adapter", ) + def _coerce_bridge_record( + self, + state: Mapping[str, Any], + geometry_key: str, + ) -> tuple[Any, bool]: + value = state[geometry_key] + if geometry_key == "ucns_object": + if not isinstance(value, self._module.UCNSObject): + raise TypeError( + "ucns_object must be an actual ucns.UCNSObject; " + f"got {type(value).__module__}.{type(value).__qualname__}" + ) + return self._module.bridge_record(value), True + if geometry_key == "ucns_bridge_record": + if not isinstance(value, self._module.UCNSBridgeRecord): + raise TypeError( + "ucns_bridge_record must be an actual ucns.UCNSBridgeRecord; " + f"got {type(value).__module__}.{type(value).__qualname__}" + ) + record = value + elif geometry_key == "ucns_bridge_record_json": + if not isinstance(value, str): + raise TypeError("ucns_bridge_record_json must be a string") + record = self._module.UCNSBridgeRecord.from_json(value) + else: + if not isinstance(value, Mapping): + raise TypeError("ucns_bridge_record_dict must be a mapping") + record = self._module.UCNSBridgeRecord.from_dict(value) + return self._module.UCNSBridgeRecord.from_dict(record.to_dict()), False + + def _coerce_factorization_evidence( + self, + state: Mapping[str, Any], + factor_key: str, + ) -> Any: + value = state[factor_key] + if factor_key == "ucns_factorization_evidence": + if not isinstance(value, self._module.UCNSFactorizationEvidence): + raise TypeError( + "ucns_factorization_evidence must be an actual " + "ucns.UCNSFactorizationEvidence; got " + f"{type(value).__module__}.{type(value).__qualname__}" + ) + evidence = value + elif factor_key == "ucns_factorization_evidence_json": + if not isinstance(value, str): + raise TypeError( + "ucns_factorization_evidence_json must be a string" + ) + evidence = self._module.UCNSFactorizationEvidence.from_json(value) + else: + if not isinstance(value, Mapping): + raise TypeError( + "ucns_factorization_evidence_dict must be a mapping" + ) + evidence = self._module.UCNSFactorizationEvidence.from_dict(value) + return self._module.UCNSFactorizationEvidence.from_dict(evidence.to_dict()) + + @staticmethod + def _geometry_from_record(record: Any) -> UCNSGeometryEvidence: + return UCNSGeometryEvidence( + bridge_schema_id=str(record.schema_id), + bridge_schema_version=str(record.schema_version), + bridge_producer_id=str(record.producer_id), + bridge_evidence_digest=str(record.evidence_digest), + ucns_serialization_version=str(record.ucns_serialization_version), + stable_hash=str(record.object_hash), + domain_label=str(record.domain_label), + domain_statuses=tuple(record.domain_statuses), + completeness_guaranteed=bool(record.completeness_guaranteed), + seq_prime_claim_scope=str(record.seq_prime_claim_scope), + depth=int(record.depth), + n_min=int(record.n_min), + length=int(record.length), + is_unit=bool(record.is_unit), + is_verified_domain=bool(record.is_verified_domain), + is_frontier=bool(record.is_frontier), + note=str(record.note), + canonical_json=str(record.canonical_json), + ) + + @staticmethod + def _factorization_from_record(record: Any) -> UCNSFactorizationEvidenceRecord: + return UCNSFactorizationEvidenceRecord( + schema_id=str(record.schema_id), + schema_version=str(record.schema_version), + producer_id=str(record.producer_id), + evidence_digest=str(record.evidence_digest), + product_hash=str(record.product_hash), + product_domain_label=str(record.product_domain_label), + product_domain_statuses=tuple(record.product_domain_statuses), + completeness_guaranteed=bool(record.completeness_guaranteed), + result_kind=str(record.result_kind), + factor_hashes=tuple(record.factor_hashes), + negative_result_certified=bool(record.negative_result_certified), + seq_prime_is_absolute=bool(record.seq_prime_is_absolute), + claim_scope=str(record.claim_scope), + note=str(record.note), + certification_policy_version=str(record.certification_policy_version), + search_exhausted=bool(record.search_exhausted), + truncation_occurred=bool(record.truncation_occurred), + catalogue_source=str(record.catalogue_source), + supplied_catalogue_size=int(record.supplied_catalogue_size), + supplied_catalogue_fingerprint=str(record.supplied_catalogue_fingerprint), + effective_catalogue_size=int(record.effective_catalogue_size), + effective_catalogue_fingerprint=str(record.effective_catalogue_fingerprint), + catalogue_coverage_status=str(record.catalogue_coverage_status), + catalogue_coverage_reason=str(record.catalogue_coverage_reason), + catalogue_coverage_rule_version=str( + record.catalogue_coverage_rule_version + ), + required_catalogue_rule_version=str( + record.required_catalogue_rule_version + ), + required_catalogue_fingerprint=str( + record.required_catalogue_fingerprint + ), + coverage_record_validated=bool(record.coverage_record_validated), + coverage_bound_to_search_report=bool( + record.coverage_bound_to_search_report + ), + pruning_applied=bool(record.pruning_applied), + pruning_rule=str(record.pruning_rule), + pruning_rule_version=str(record.pruning_rule_version), + pruning_preserves_coverage=bool(record.pruning_preserves_coverage), + uncertified_reasons=tuple(record.uncertified_reasons), + ) + def normalize(self, payload: Mapping[str, Any]) -> dict[str, Any]: state = dict(payload) state["semantics"] = "ucns.geometry_adapter" + geometry_key = _one_present(state, _GEOMETRY_INPUT_KEYS, "UCNS geometry") + factor_key = _one_present( + state, + _FACTORIZATION_INPUT_KEYS, + "UCNS factorization evidence", + ) - if "ucns_object" not in state: + if geometry_key is None: + if factor_key is not None: + raise ValueError( + "UCNS factorization evidence requires an attached geometry " + "record with the same stable object hash" + ) state["ucns_integration"] = self.status.as_dict() state.pop("ucns_geometry", None) + state.pop("ucns_factorization_evidence", None) return state - obj = state["ucns_object"] - if not isinstance(obj, self._module.UCNSObject): - raise TypeError( - "ucns_object must be an actual ucns.UCNSObject; " - f"got {type(obj).__module__}.{type(obj).__qualname__}" - ) - - record = self._module.object_record(obj) - metadata = record.domain_metadata - statuses = tuple( - status.value if hasattr(status, "value") else str(status) - for status in metadata.statuses - ) - evidence = UCNSGeometryEvidence( - bridge_schema_version=UCNS_BRIDGE_SCHEMA_VERSION, - ucns_serialization_version=self._schema_version, - stable_hash=str(record.object_hash), - domain_label=str(record.domain_label), - domain_statuses=statuses, - completeness_guaranteed=bool(metadata.completeness_guaranteed), - seq_prime_claim_scope=str(metadata.seq_prime_claim_scope), - depth=int(record.depth), - n_min=int(record.n_min), - length=int(record.length), - canonical_json=str(record.canonical_json), - ) - attached = replace( + bridge_record, live_object = self._coerce_bridge_record(state, geometry_key) + geometry = self._geometry_from_record(bridge_record) + status = replace( self.status, - ucns_object_attached=True, + ucns_object_attached=live_object, + ucns_bridge_record_attached=True, ucns_scope_metadata_attached=True, + ucns_theorem_status_attached=True, ) - state["ucns_geometry"] = evidence.as_dict() - state["ucns_integration"] = attached.as_dict() + state["ucns_geometry"] = geometry.as_dict() + + if factor_key is not None: + factor_record = self._coerce_factorization_evidence(state, factor_key) + if str(factor_record.product_hash) != geometry.stable_hash: + raise ValueError( + "UCNS factorization evidence product_hash does not match " + "attached geometry stable_hash" + ) + factorization = self._factorization_from_record(factor_record) + state["ucns_factorization_evidence"] = factorization.as_dict() + status = replace( + status, + ucns_factorization_evidence_attached=True, + ucns_negative_certification_attached=( + factorization.negative_result_certified + ), + ucns_theorem_status_attached=True, + ) + else: + state.pop("ucns_factorization_evidence", None) + + state["ucns_integration"] = status.as_dict() return state def select_ucns_adapter() -> UCNSAdapterSelection: """Select the actual adapter or a typed unavailable state. - Only direct absence of the optional ``ucns`` package becomes an unavailable - selection. Transitive import failures, malformed public surfaces, and - unsupported schemas remain visible exceptions. + Only direct absence of the optional ``ucns`` package becomes unavailable. + Transitive import failures, malformed public surfaces, unsupported schemas, + and invalid producer evidence remain visible exceptions. """ try: @@ -272,7 +546,7 @@ def select_ucns_adapter() -> UCNSAdapterSelection: def inspect_ucns_adapter() -> UCNSIntegrationStatus: - """Return an explicit status report without silently activating fallback.""" + """Return explicit adapter status without activating fallback silently.""" try: return select_ucns_adapter().status @@ -283,10 +557,13 @@ def inspect_ucns_adapter() -> UCNSIntegrationStatus: __all__ = [ "ActualUCNSAdapter", "INSTALL_HINT", + "SUPPORTED_BRIDGE_SCHEMAS", + "SUPPORTED_FACTORIZATION_EVIDENCE_SCHEMAS", "SUPPORTED_SERIALIZATION_VERSIONS", "UCNSAdapter", "UCNSAdapterConstructionError", "UCNSAdapterSelection", + "UCNSFactorizationEvidenceRecord", "UCNSGeometryEvidence", "UCNSIntegrationStatus", "UnsupportedUCNSSchemaError", diff --git a/pyproject.toml b/pyproject.toml index c27fd96..3b53688 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,13 +42,13 @@ dev = [ "twine>=5.0", ] ucns = [ - "ucns @ git+https://github.com/The-Interdependency/ucns.git@3c6c37f41fadba699331e8b1632a52aee9364503", + "ucns @ git+https://github.com/The-Interdependency/ucns.git@27c004b21b6d02bf3873c280ebd3158131ef87fe", ] metapat = [ "metapat @ git+https://github.com/The-Interdependency/metapat.git@3a096f1789432fdb931d4f1659eebf7ef321fbaa", ] full-stack = [ - "ucns @ git+https://github.com/The-Interdependency/ucns.git@3c6c37f41fadba699331e8b1632a52aee9364503", + "ucns @ git+https://github.com/The-Interdependency/ucns.git@27c004b21b6d02bf3873c280ebd3158131ef87fe", "metapat @ git+https://github.com/The-Interdependency/metapat.git@3a096f1789432fdb931d4f1659eebf7ef321fbaa", ] diff --git a/tests/test_shared_stack_contract.py b/tests/test_shared_stack_contract.py index a78db78..62bcc7e 100644 --- a/tests/test_shared_stack_contract.py +++ b/tests/test_shared_stack_contract.py @@ -36,12 +36,14 @@ def test_base_mode_is_explicit_and_na_is_not_zero(monkeypatch): result = layers_module.build_default_layers().run({"input": "no transcript"}) contract = result["edcm_result"] + assert contract["schema_version"] == "1.1.0" assert contract["source_evidence"]["state"] == "NA" assert contract["readouts"]["state"] == "NA" assert contract["readouts"]["structural_density"] is None assert contract["readouts"]["structural_density"] != 0 assert contract["metapat_semantic_constraints"]["state"] == "NA" assert contract["ucns_geometry_identity"]["state"] == "NA" + assert contract["ucns_factorization_evidence"]["state"] == "NA" assert result["metapat_integration"]["metapat_package_available"] is False assert result["ucns_integration"]["ucns_package_available"] is False @@ -112,6 +114,7 @@ def test_full_stack_fixture_preserves_all_identity_boundaries(): contract = result["edcm_result"] assert contract["schema_id"] == "edcm.shared-stack-result" + assert contract["schema_version"] == "1.1.0" assert contract["metapat_semantic_constraints"]["canon_digest"] == envelope.canon_digest assert ( contract["metapat_semantic_constraints"]["provenance_digest"] @@ -119,12 +122,18 @@ def test_full_stack_fixture_preserves_all_identity_boundaries(): ) assert contract["metapat_semantic_constraints"]["source_statements"] == envelope.source_statements assert contract["ucns_geometry_identity"]["stable_hash"] == ucns.stable_hash(obj) + assert contract["ucns_geometry_identity"]["bridge_schema_id"] == "ucns.bridge-record" + assert contract["ucns_geometry_identity"]["bridge_evidence_digest"] + assert contract["ucns_factorization_evidence"]["state"] == "NA" assert result["ucns_geometry"]["stable_hash"] == adaptation.record.ucns_object_hash assert contract["edcm_policy_manifest"]["manifest_hash"] == PolicyManifest().manifest_hash() assert contract["readouts"]["state"] == "measured" assert contract["status_evidence"]["proof_status_transfers_to_measurement_validity"] is False assert contract["status_evidence"]["semantic_labels_are_measurement_values"] is False - assert contract["status_evidence"]["ucns_theorem_status_attached"] is False + assert contract["status_evidence"]["ucns_bridge_record_attached"] is True + assert contract["status_evidence"]["ucns_factorization_evidence_attached"] is False + assert contract["status_evidence"]["ucns_theorem_status_attached"] is True + assert contract["status_evidence"]["ucns_negative_certification_attached"] is False assert contract["status_evidence"]["metapat_theorem_status_attached"] is False @@ -138,9 +147,79 @@ def test_ucns_equality_and_stable_hash_survive_integration_path(): assert result["ucns_geometry"]["stable_hash"] == ucns.stable_hash(obj) assert result["edcm_result"]["ucns_geometry_identity"]["stable_hash"] == ucns.stable_hash(obj) + assert result["edcm_result"]["status_evidence"]["ucns_theorem_status_attached"] is True assert obj == obj +def test_certified_factorization_evidence_is_preserved_but_does_not_promote_validity(): + ucns = pytest.importorskip("ucns") + + bridge = ucns.bridge_record(ucns.S2) + factorization = ucns.factorization_evidence(ucns.S2) + result = layers_module.build_default_layers().run( + { + "transcript": TRANSCRIPT, + "ucns_bridge_record_json": bridge.to_json(), + "ucns_factorization_evidence_json": factorization.to_json(), + } + ) + contract = result["edcm_result"] + evidence = contract["ucns_factorization_evidence"] + + assert evidence["state"] == "attached" + assert evidence["product_hash"] == bridge.object_hash + assert evidence["evidence_digest"] == factorization.evidence_digest + assert evidence["negative_result_certified"] is True + assert evidence["search_exhausted"] is True + assert evidence["coverage_record_validated"] is True + assert evidence["coverage_bound_to_search_report"] is True + assert evidence["theorem_status_transfer"] is False + assert evidence["measurement_validity_claim"] is False + assert contract["status_evidence"]["ucns_factorization_evidence_attached"] is True + assert contract["status_evidence"]["ucns_negative_certification_attached"] is True + assert contract["status_evidence"]["proof_status_transfers_to_measurement_validity"] is False + + +def test_factorization_evidence_changes_result_identity_not_measurement_epoch(): + ucns = pytest.importorskip("ucns") + + bridge = ucns.bridge_record(ucns.S2) + factorization = ucns.factorization_evidence(ucns.S2) + without = layers_module.build_default_layers().run( + {"transcript": TRANSCRIPT, "ucns_bridge_record": bridge} + ) + with_evidence = layers_module.build_default_layers().run( + { + "transcript": TRANSCRIPT, + "ucns_bridge_record": bridge, + "ucns_factorization_evidence": factorization, + } + ) + + assert without["rounds"] == with_evidence["rounds"] + assert without["edcm_result"]["epoch_identity"] == with_evidence["edcm_result"]["epoch_identity"] + assert without["edcm_result"]["result_identity"] != with_evidence["edcm_result"]["result_identity"] + + +def test_uncertified_factorization_evidence_is_explicitly_not_certification(): + ucns = pytest.importorskip("ucns") + + bridge = ucns.bridge_record(ucns.S2) + factorization = ucns.factorization_evidence(ucns.S2, catalogue=[]) + result = layers_module.build_default_layers().run( + { + "ucns_bridge_record": bridge, + "ucns_factorization_evidence": factorization, + } + ) + + evidence = result["edcm_result"]["ucns_factorization_evidence"] + assert evidence["state"] == "attached" + assert evidence["negative_result_certified"] is False + assert evidence["uncertified_reasons"] + assert result["edcm_result"]["status_evidence"]["ucns_negative_certification_attached"] is False + + def test_importable_siblings_without_evidence_do_not_claim_attachment(): pytest.importorskip("metapat") pytest.importorskip("ucns") @@ -152,8 +231,12 @@ def test_importable_siblings_without_evidence_do_not_claim_attachment(): assert result["ucns_integration"]["ucns_package_available"] is True assert result["ucns_integration"]["ucns_adapter_active"] is True assert result["ucns_integration"]["ucns_object_attached"] is False + assert result["ucns_integration"]["ucns_bridge_record_attached"] is False + assert result["ucns_integration"]["ucns_factorization_evidence_attached"] is False + assert result["ucns_integration"]["ucns_theorem_status_attached"] is False assert result["edcm_result"]["metapat_semantic_constraints"]["state"] == "NA" assert result["edcm_result"]["ucns_geometry_identity"]["state"] == "NA" + assert result["edcm_result"]["ucns_factorization_evidence"]["state"] == "NA" def test_canon_rotation_creates_new_epoch_identity(): diff --git a/tests/test_ucns_adapter.py b/tests/test_ucns_adapter.py index 76b7295..f67863b 100644 --- a/tests/test_ucns_adapter.py +++ b/tests/test_ucns_adapter.py @@ -1,8 +1,9 @@ from __future__ import annotations +import json from dataclasses import dataclass from fractions import Fraction -from types import ModuleType, SimpleNamespace +from types import ModuleType import pytest @@ -19,35 +20,118 @@ select_ucns_adapter, ) +HASH_A = "a" * 64 +HASH_B = "b" * 64 -def _fake_ucns(*, schema: str = "ucns-canonical-json-v1") -> tuple[ModuleType, type]: + +def _fake_ucns( + *, + serialization: str = "ucns-canonical-json-v1", + bridge_version: str = "1.0.0", + factor_version: str = "1.0.0", +) -> tuple[ModuleType, type, type, type]: module = ModuleType("ucns") class UCNSObject: pass @dataclass(frozen=True) - class DomainMetadata: - statuses: tuple[object, ...] = (SimpleNamespace(value="DEFENDED"),) + class UCNSBridgeRecord: + schema_id: str = "ucns.bridge-record" + schema_version: str = bridge_version + producer_id: str = "ucns.object_record" + evidence_digest: str = "c" * 64 + ucns_serialization_version: str = serialization + object_hash: str = HASH_A + domain_label: str = "depth-1" + domain_statuses: tuple[str, ...] = ("DEFENDED", "TEST_BACKED") completeness_guaranteed: bool = True seq_prime_claim_scope: str = "defended-domain-relative" - - @dataclass(frozen=True) - class Record: - object_hash: str = "abc123" - domain_label: str = "depth-1" - domain_metadata: DomainMetadata = DomainMetadata() depth: int = 1 n_min: int = 1 length: int = 1 + is_unit: bool = False + is_verified_domain: bool = True + is_frontier: bool = False + note: str = "typed domain prerequisite evidence" canonical_json: str = '{"kind":"object","version":"ucns-canonical-json-v1"}' + def to_dict(self): + return { + name: getattr(self, name) + for name in self.__dataclass_fields__ + } + + @classmethod + def from_dict(cls, data): + return cls(**dict(data)) + + @classmethod + def from_json(cls, value): + return cls.from_dict(json.loads(value)) + + @dataclass(frozen=True) + class UCNSFactorizationEvidence: + schema_id: str = "ucns.factorization-evidence" + schema_version: str = factor_version + producer_id: str = "ucns.factorization_result" + evidence_digest: str = "d" * 64 + product_hash: str = HASH_A + product_domain_label: str = "depth-1" + product_domain_statuses: tuple[str, ...] = ("DEFENDED", "TEST_BACKED") + completeness_guaranteed: bool = True + result_kind: str = "SEQ_PRIME" + factor_hashes: tuple[str, ...] = () + negative_result_certified: bool = True + seq_prime_is_absolute: bool = True + claim_scope: str = "absolute-certified-negative" + note: str = "authoritative negative evidence" + certification_policy_version: str = "ucns-negative-certification-v2" + search_exhausted: bool = True + truncation_occurred: bool = False + catalogue_source: str = "canonical-generated" + supplied_catalogue_size: int = 2 + supplied_catalogue_fingerprint: str = "e" * 64 + effective_catalogue_size: int = 2 + effective_catalogue_fingerprint: str = "e" * 64 + catalogue_coverage_status: str = "canonical-exact" + catalogue_coverage_reason: str = "validated" + catalogue_coverage_rule_version: str = "coverage-v1" + required_catalogue_rule_version: str = "catalogue-v1" + required_catalogue_fingerprint: str = "f" * 64 + coverage_record_validated: bool = True + coverage_bound_to_search_report: bool = True + pruning_applied: bool = True + pruning_rule: str = "carrier-support" + pruning_rule_version: str = "pruning-v1" + pruning_preserves_coverage: bool = True + uncertified_reasons: tuple[str, ...] = () + + def to_dict(self): + return { + name: getattr(self, name) + for name in self.__dataclass_fields__ + } + + @classmethod + def from_dict(cls, data): + return cls(**dict(data)) + + @classmethod + def from_json(cls, value): + return cls.from_dict(json.loads(value)) + module.UCNSObject = UCNSObject - module.CANONICAL_SERIALIZATION_VERSION = schema - module.stable_hash = lambda obj: "abc123" - module.object_record = lambda obj: Record() + module.UCNSBridgeRecord = UCNSBridgeRecord + module.UCNSFactorizationEvidence = UCNSFactorizationEvidence + module.CANONICAL_SERIALIZATION_VERSION = serialization + module.BRIDGE_RECORD_SCHEMA_ID = "ucns.bridge-record" + module.BRIDGE_RECORD_SCHEMA_VERSION = bridge_version + module.FACTORIZATION_EVIDENCE_SCHEMA_ID = "ucns.factorization-evidence" + module.FACTORIZATION_EVIDENCE_SCHEMA_VERSION = factor_version + module.bridge_record = lambda obj: UCNSBridgeRecord() module.__version__ = "0.test" - return module, UCNSObject + return module, UCNSObject, UCNSBridgeRecord, UCNSFactorizationEvidence def _force_missing_metapat(monkeypatch): @@ -70,6 +154,8 @@ def missing(name: str): assert selection.adapter is None assert selection.status.ucns_package_available is False assert selection.status.ucns_adapter_active is False + assert selection.status.ucns_bridge_record_attached is False + assert selection.status.ucns_factorization_evidence_attached is False assert selection.status.selection == "unavailable" @@ -83,52 +169,190 @@ def broken(name: str): def test_importable_malformed_ucns_fails_adapter_construction(): - module, _ = _fake_ucns() - del module.object_record - with pytest.raises(UCNSAdapterConstructionError, match="object_record"): + module, _, _, _ = _fake_ucns() + del module.UCNSBridgeRecord + with pytest.raises(UCNSAdapterConstructionError, match="UCNSBridgeRecord"): ActualUCNSAdapter(module) -def test_unsupported_ucns_schema_fails_closed(): - module, _ = _fake_ucns(schema="ucns-canonical-json-v99") - with pytest.raises(UnsupportedUCNSSchemaError, match="v99"): +@pytest.mark.parametrize( + ("kwargs", "message"), + [ + ({"serialization": "ucns-canonical-json-v99"}, "v99"), + ({"bridge_version": "99.0.0"}, "bridge schema"), + ({"factor_version": "99.0.0"}, "factorization evidence schema"), + ], +) +def test_unsupported_ucns_schemas_fail_closed(kwargs, message): + module, _, _, _ = _fake_ucns(**kwargs) + with pytest.raises(UnsupportedUCNSSchemaError, match=message): ActualUCNSAdapter(module) -def test_package_and_adapter_do_not_imply_object_or_scope_attachment(): - module, _ = _fake_ucns() +def test_package_and_adapter_do_not_imply_any_attachment(): + module, _, _, _ = _fake_ucns() result = ActualUCNSAdapter(module).normalize({"transcript": "A: hello"}) status = result["ucns_integration"] assert status["ucns_package_available"] is True assert status["ucns_adapter_active"] is True assert status["ucns_object_attached"] is False + assert status["ucns_bridge_record_attached"] is False assert status["ucns_scope_metadata_attached"] is False + assert status["ucns_factorization_evidence_attached"] is False assert status["ucns_negative_certification_attached"] is False assert status["ucns_theorem_status_attached"] is False assert "ucns_geometry" not in result + assert "ucns_factorization_evidence" not in result -def test_actual_ucns_object_attaches_stable_geometry_evidence_only(): - module, object_type = _fake_ucns() +def test_live_ucns_object_is_converted_through_canonical_bridge_record(): + module, object_type, _, _ = _fake_ucns() result = ActualUCNSAdapter(module).normalize({"ucns_object": object_type()}) status = result["ucns_integration"] geometry = result["ucns_geometry"] assert status["ucns_object_attached"] is True + assert status["ucns_bridge_record_attached"] is True assert status["ucns_scope_metadata_attached"] is True + assert status["ucns_theorem_status_attached"] is True assert status["ucns_negative_certification_attached"] is False - assert status["ucns_theorem_status_attached"] is False - assert geometry["stable_hash"] == "abc123" - assert geometry["ucns_serialization_version"] == "ucns-canonical-json-v1" - assert geometry["domain_statuses"] == ("DEFENDED",) + assert geometry["stable_hash"] == HASH_A + assert geometry["bridge_schema_id"] == "ucns.bridge-record" + assert geometry["bridge_evidence_digest"] == "c" * 64 + assert geometry["domain_statuses"] == ("DEFENDED", "TEST_BACKED") assert geometry["theorem_status_transfer"] is False assert geometry["measurement_validity_claim"] is False -def test_wrong_object_type_fails_closed(): - module, _ = _fake_ucns() +@pytest.mark.parametrize( + "key", + [ + "ucns_bridge_record", + "ucns_bridge_record_json", + "ucns_bridge_record_dict", + ], +) +def test_bridge_record_object_json_and_mapping_are_accepted(key): + module, _, record_type, _ = _fake_ucns() + record = record_type() + if key.endswith("_json"): + value = json.dumps(record.to_dict()) + elif key.endswith("_dict"): + value = record.to_dict() + else: + value = record + result = ActualUCNSAdapter(module).normalize({key: value}) + + assert result["ucns_geometry"]["stable_hash"] == HASH_A + assert result["ucns_integration"]["ucns_object_attached"] is False + assert result["ucns_integration"]["ucns_bridge_record_attached"] is True + assert result["ucns_integration"]["ucns_theorem_status_attached"] is True + + +def test_multiple_geometry_forms_fail_closed(): + module, object_type, record_type, _ = _fake_ucns() + with pytest.raises(ValueError, match="exactly one UCNS geometry"): + ActualUCNSAdapter(module).normalize( + { + "ucns_object": object_type(), + "ucns_bridge_record": record_type(), + } + ) + + +def test_wrong_geometry_types_fail_closed(): + module, _, _, _ = _fake_ucns() with pytest.raises(TypeError, match="actual ucns.UCNSObject"): ActualUCNSAdapter(module).normalize({"ucns_object": object()}) + with pytest.raises(TypeError, match="actual ucns.UCNSBridgeRecord"): + ActualUCNSAdapter(module).normalize({"ucns_bridge_record": object()}) + + +def test_factorization_evidence_requires_matching_geometry(): + module, _, record_type, factor_type = _fake_ucns() + adapter = ActualUCNSAdapter(module) + + with pytest.raises(ValueError, match="requires an attached geometry"): + adapter.normalize({"ucns_factorization_evidence": factor_type()}) + + mismatch = factor_type(product_hash=HASH_B) + with pytest.raises(ValueError, match="product_hash does not match"): + adapter.normalize( + { + "ucns_bridge_record": record_type(), + "ucns_factorization_evidence": mismatch, + } + ) + + +@pytest.mark.parametrize( + "key", + [ + "ucns_factorization_evidence", + "ucns_factorization_evidence_json", + "ucns_factorization_evidence_dict", + ], +) +def test_certified_factorization_evidence_forms_attach_exact_record(key): + module, _, record_type, factor_type = _fake_ucns() + factor = factor_type() + if key.endswith("_json"): + value = json.dumps(factor.to_dict()) + elif key.endswith("_dict"): + value = factor.to_dict() + else: + value = factor + result = ActualUCNSAdapter(module).normalize( + {"ucns_bridge_record": record_type(), key: value} + ) + + status = result["ucns_integration"] + evidence = result["ucns_factorization_evidence"] + assert status["ucns_factorization_evidence_attached"] is True + assert status["ucns_negative_certification_attached"] is True + assert status["ucns_theorem_status_attached"] is True + assert evidence["product_hash"] == HASH_A + assert evidence["negative_result_certified"] is True + assert evidence["search_exhausted"] is True + assert evidence["coverage_record_validated"] is True + assert evidence["theorem_status_transfer"] is False + assert evidence["measurement_validity_claim"] is False + + +def test_uncertified_factorization_evidence_attaches_without_certification_claim(): + module, _, record_type, factor_type = _fake_ucns() + factor = factor_type( + negative_result_certified=False, + seq_prime_is_absolute=False, + claim_scope="domain-relative-uncertified", + uncertified_reasons=("catalogue-coverage-uncertified",), + ) + result = ActualUCNSAdapter(module).normalize( + { + "ucns_bridge_record": record_type(), + "ucns_factorization_evidence": factor, + } + ) + + status = result["ucns_integration"] + assert status["ucns_factorization_evidence_attached"] is True + assert status["ucns_negative_certification_attached"] is False + assert result["ucns_factorization_evidence"]["uncertified_reasons"] == ( + "catalogue-coverage-uncertified", + ) + + +def test_multiple_factorization_forms_fail_closed(): + module, _, record_type, factor_type = _fake_ucns() + factor = factor_type() + with pytest.raises(ValueError, match="exactly one UCNS factorization evidence"): + ActualUCNSAdapter(module).normalize( + { + "ucns_bridge_record": record_type(), + "ucns_factorization_evidence": factor, + "ucns_factorization_evidence_dict": factor.to_dict(), + } + ) def test_transcript_only_pipeline_is_explicit(monkeypatch): @@ -150,15 +374,8 @@ def test_transcript_only_pipeline_is_explicit(monkeypatch): assert result["layer_provenance"]["geometry"]["selection"] == "local_fallback" assert result["layer_provenance"]["semantic_authority"]["selection"] == "unavailable" assert result["layer_provenance"]["measurement"]["canonical"] is True - assert set(result["layer_provenance"]) == { - "semantic_authority", - "geometry", - "semantics", - "measurement", - "composition", - "delivery", - } assert result["edcm_result"]["ucns_geometry_identity"]["state"] == "NA" + assert result["edcm_result"]["ucns_factorization_evidence"]["state"] == "NA" def test_installed_edcmbone_cannot_override_canonical_edcm_measurement(monkeypatch): @@ -170,17 +387,31 @@ def test_installed_edcmbone_cannot_override_canonical_edcm_measurement(monkeypat lambda: UCNSAdapterSelection(adapter=None, status=status), ) monkeypatch.setitem(__import__("sys").modules, "edcmbone", ModuleType("edcmbone")) - assert isinstance(layers_module.build_default_layers().measurement, ConsolidatedMeasurementLayer) + assert isinstance( + layers_module.build_default_layers().measurement, + ConsolidatedMeasurementLayer, + ) -def test_live_ucns_package_roundtrip_when_integration_is_installed(): +def test_live_ucns_package_bridge_and_certification_roundtrip(): ucns = pytest.importorskip("ucns") - obj = ucns.UCNSObject(1, 1, [(Fraction(0), None)], [0]) - result = ActualUCNSAdapter(ucns).normalize({"ucns_object": obj}) + obj = ucns.S2 + bridge = ucns.bridge_record(obj) + factorization = ucns.factorization_evidence(obj) + result = ActualUCNSAdapter(ucns).normalize( + { + "ucns_bridge_record_json": bridge.to_json(), + "ucns_factorization_evidence_json": factorization.to_json(), + } + ) assert result["ucns_geometry"]["stable_hash"] == ucns.stable_hash(obj) - assert result["ucns_geometry"]["ucns_serialization_version"] == ( - ucns.CANONICAL_SERIALIZATION_VERSION + assert result["ucns_geometry"]["bridge_evidence_digest"] == bridge.evidence_digest + assert result["ucns_integration"]["ucns_object_attached"] is False + assert result["ucns_integration"]["ucns_bridge_record_attached"] is True + assert result["ucns_integration"]["ucns_factorization_evidence_attached"] is True + assert result["ucns_integration"]["ucns_negative_certification_attached"] is True + assert result["ucns_integration"]["ucns_theorem_status_attached"] is True + assert result["ucns_factorization_evidence"]["evidence_digest"] == ( + factorization.evidence_digest ) - assert result["ucns_integration"]["ucns_object_attached"] is True - assert result["ucns_integration"]["ucns_theorem_status_attached"] is False diff --git a/tests/test_ucns_dependency.py b/tests/test_ucns_dependency.py index 22eed2a..1a4487b 100644 --- a/tests/test_ucns_dependency.py +++ b/tests/test_ucns_dependency.py @@ -7,7 +7,9 @@ "ucns_package_available", "ucns_adapter_active", "ucns_object_attached", + "ucns_bridge_record_attached", "ucns_scope_metadata_attached", + "ucns_factorization_evidence_attached", "ucns_negative_certification_attached", "ucns_theorem_status_attached", } @@ -19,7 +21,9 @@ def test_ucns_dependency_report_separates_package_from_evidence(): report = dep.ucns_dependency_report() assert EXPLICIT_UCNS_FIELDS.issubset(report) assert report["ucns_object_attached"] is False + assert report["ucns_bridge_record_attached"] is False assert report["ucns_scope_metadata_attached"] is False + assert report["ucns_factorization_evidence_attached"] is False assert report["ucns_negative_certification_attached"] is False assert report["ucns_theorem_status_attached"] is False @@ -28,14 +32,16 @@ def test_ucns_dependency_report_separates_package_from_evidence(): assert report["dependency"] in {"available", "failed"} else: assert report["dependency"] == "missing" - assert "python -m pip install -e ../ucns" in report["install_hint"] + assert "The-Interdependency/ucns.git@27c004b" in report["install_hint"] def test_energy_report_does_not_convert_import_into_scope_attachment(): report = audit_energy_text("D_f has a hard ceiling at 2.4999.") assert EXPLICIT_UCNS_FIELDS.issubset(report.ucns_dependency) assert report.ucns_dependency["ucns_object_attached"] is False + assert report.ucns_dependency["ucns_bridge_record_attached"] is False assert report.ucns_dependency["ucns_scope_metadata_attached"] is False + assert report.ucns_dependency["ucns_factorization_evidence_attached"] is False assert "attached no UCNS" in report.ucns_scope_note or "no UCNS object" in report.ucns_scope_note diff --git a/tests/test_ucns_evidence_consumer.py b/tests/test_ucns_evidence_consumer.py new file mode 100644 index 0000000..9821117 --- /dev/null +++ b/tests/test_ucns_evidence_consumer.py @@ -0,0 +1,123 @@ +from __future__ import annotations + +import pytest + +from edcm.ucns_adapter import ActualUCNSAdapter + +ucns = pytest.importorskip("ucns") + + +def test_live_object_and_serialized_bridge_resolve_same_geometry_identity(): + obj = ucns.S2 + bridge = ucns.bridge_record(obj) + adapter = ActualUCNSAdapter(ucns) + + live = adapter.normalize({"ucns_object": obj}) + serialized = adapter.normalize({"ucns_bridge_record_json": bridge.to_json()}) + + assert live["ucns_geometry"] == serialized["ucns_geometry"] + assert live["ucns_geometry"]["stable_hash"] == ucns.stable_hash(obj) + assert live["ucns_geometry"]["bridge_evidence_digest"] == bridge.evidence_digest + assert live["ucns_integration"]["ucns_object_attached"] is True + assert serialized["ucns_integration"]["ucns_object_attached"] is False + assert serialized["ucns_integration"]["ucns_bridge_record_attached"] is True + + +def test_producer_bridge_deserializer_rejects_unknown_and_tampered_fields(): + bridge = ucns.bridge_record(ucns.S2) + unknown = bridge.to_dict() + unknown["invented"] = True + with pytest.raises(ValueError, match="unknown bridge record fields"): + ActualUCNSAdapter(ucns).normalize({"ucns_bridge_record_dict": unknown}) + + tampered = bridge.to_dict() + tampered["canonical_json"] = tampered["canonical_json"] + " " + with pytest.raises(ValueError): + ActualUCNSAdapter(ucns).normalize({"ucns_bridge_record_dict": tampered}) + + +def test_certified_negative_evidence_attaches_exact_search_and_coverage_record(): + obj = ucns.S2 + bridge = ucns.bridge_record(obj) + evidence = ucns.factorization_evidence(obj) + result = ActualUCNSAdapter(ucns).normalize( + { + "ucns_bridge_record": bridge, + "ucns_factorization_evidence": evidence, + } + ) + + status = result["ucns_integration"] + attached = result["ucns_factorization_evidence"] + assert status["ucns_factorization_evidence_attached"] is True + assert status["ucns_negative_certification_attached"] is True + assert status["ucns_theorem_status_attached"] is True + assert attached["evidence_digest"] == evidence.evidence_digest + assert attached["product_hash"] == bridge.object_hash + assert attached["negative_result_certified"] is True + assert attached["search_exhausted"] is True + assert attached["truncation_occurred"] is False + assert attached["coverage_record_validated"] is True + assert attached["coverage_bound_to_search_report"] is True + assert attached["pruning_preserves_coverage"] is True + assert attached["uncertified_reasons"] == () + assert attached["theorem_status_transfer"] is False + assert attached["measurement_validity_claim"] is False + + +def test_uncertified_evidence_is_attached_without_negative_certification(): + bridge = ucns.bridge_record(ucns.S2) + evidence = ucns.factorization_evidence(ucns.S2, catalogue=[]) + result = ActualUCNSAdapter(ucns).normalize( + { + "ucns_bridge_record_json": bridge.to_json(), + "ucns_factorization_evidence_json": evidence.to_json(), + } + ) + + assert result["ucns_integration"]["ucns_factorization_evidence_attached"] is True + assert result["ucns_integration"]["ucns_negative_certification_attached"] is False + assert result["ucns_factorization_evidence"]["negative_result_certified"] is False + assert result["ucns_factorization_evidence"]["uncertified_reasons"] + + +def test_unit_domain_evidence_never_becomes_prime_certification(): + bridge = ucns.bridge_record(ucns.UNIT) + evidence = ucns.factorization_evidence(ucns.UNIT) + result = ActualUCNSAdapter(ucns).normalize( + { + "ucns_bridge_record": bridge, + "ucns_factorization_evidence": evidence, + } + ) + + assert result["ucns_geometry"]["is_unit"] is True + assert result["ucns_factorization_evidence"]["claim_scope"] == ( + "not-prime-unit-domain" + ) + assert result["ucns_factorization_evidence"]["negative_result_certified"] is False + assert result["ucns_integration"]["ucns_negative_certification_attached"] is False + + +def test_factorization_evidence_for_different_object_fails_binding(): + bridge = ucns.bridge_record(ucns.S2) + other = ucns.factorization_evidence(ucns.UNIT) + with pytest.raises(ValueError, match="product_hash does not match"): + ActualUCNSAdapter(ucns).normalize( + { + "ucns_bridge_record": bridge, + "ucns_factorization_evidence": other, + } + ) + + +def test_package_availability_without_records_does_not_attach_status(): + result = ActualUCNSAdapter(ucns).normalize({"transcript": "A: evidence absent"}) + status = result["ucns_integration"] + assert status["ucns_package_available"] is True + assert status["ucns_adapter_active"] is True + assert status["ucns_bridge_record_attached"] is False + assert status["ucns_scope_metadata_attached"] is False + assert status["ucns_factorization_evidence_attached"] is False + assert status["ucns_negative_certification_attached"] is False + assert status["ucns_theorem_status_attached"] is False