Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion tests/test_paper_admission.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest

from alpaca_platform import paper_admission
from alpaca_platform import paper_admission, shadow_ledger


def sha(character: str) -> str:
Expand Down Expand Up @@ -68,6 +68,23 @@ def test_non_paper_environment_is_rejected(environment: str):
paper_admission.validate_paper_admission(admission)


def test_shadow_ledger_schema_is_not_paper_admission():
admission = valid_admission()
admission["schema"] = shadow_ledger.RECEIPT_SCHEMA
admission["admission_sha256"] = paper_admission.calculate_paper_admission_sha256(admission)

with pytest.raises(paper_admission.PaperAdmissionError, match="schema is unsupported"):
paper_admission.validate_paper_admission(admission)


def test_missing_paper_provenance_is_rejected():
admission = valid_admission()
del admission["environment"]

with pytest.raises(paper_admission.PaperAdmissionError, match="missing required field"):
paper_admission.validate_paper_admission(admission)


@pytest.mark.parametrize("forbidden_field", ["shadow_receipt", "account_id", "order_id", "credential"])
def test_shadow_and_sensitive_material_cannot_be_added(forbidden_field: str):
admission = valid_admission()
Expand Down
29 changes: 28 additions & 1 deletion tests/test_shadow_ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import pytest

from alpaca_platform import shadow_ledger
from alpaca_platform import paper_admission, shadow_ledger


def sha(character: str) -> str:
Expand Down Expand Up @@ -134,6 +134,33 @@ def test_genesis_receipt_is_chain_linked_and_contains_only_virtual_weight_change
assert forbidden not in rendered.lower()


def test_paper_admission_is_not_shadow_input_or_receipt():
admission = paper_admission.build_paper_admission(
environment="PAPER_DRY_RUN",
cycle_id="alpaca_paper_20260904_001",
valid_from="2026-09-04T00:00:00Z",
valid_until="2026-09-05T00:00:00Z",
paper_endpoint_sha256=sha("1"),
config_sha256=sha("2"),
strategy_sha256=sha("3"),
deployment_sha256=sha("4"),
risk_sha256=sha("5"),
)

with pytest.raises(shadow_ledger.ShadowLedgerError):
shadow_ledger.validate_shadow_cycle_input(admission)
with pytest.raises(shadow_ledger.ShadowLedgerError):
shadow_ledger.validate_shadow_ledger_receipt(admission)


def test_missing_shadow_lane_provenance_is_rejected():
payload = cycle_input()
del payload["risk_control"]

with pytest.raises(shadow_ledger.ShadowLedgerError, match="missing required field"):
shadow_ledger.validate_shadow_cycle_input(payload)


def test_next_session_links_to_previous_virtual_allocation_without_broker_state():
first = shadow_ledger.build_shadow_ledger_receipt(cycle_input())
second = shadow_ledger.build_shadow_ledger_receipt(
Expand Down
12 changes: 12 additions & 0 deletions tests/test_shadow_receipt_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,18 @@ def test_ready_controller_outcome_becomes_a_closed_sanitized_admission():
shadow_receipt_store.validate_shadow_receipt_admission(tampered)


def test_scheduler_receipt_digest_mismatch_is_rejected_before_admission():
outcome = ready_outcome()
mismatched = copy.deepcopy(outcome)
mismatched.result["shadow_receipt_sha256"] = sha("0")

with pytest.raises(shadow_receipt_store.ShadowReceiptStoreError, match="bind ledger receipt digest"):
shadow_receipt_store.build_shadow_receipt_admission(
mismatched,
risk_gate_decision=risk_gate_decision_envelope(mismatched),
)


def test_in_memory_store_is_create_only_and_reconciles_identical_admission():
store = shadow_receipt_store.InMemoryShadowReceiptStore()
outcome = ready_outcome()
Expand Down