Skip to main content

Reference Python implementation and tooling baseline for Invariant-Closed System Design (ICSD).

Project description

ICSD Python Tooling

Reference Python implementation and tooling baseline for Invariant-Closed System Design (ICSD). ICSD is a deterministic state-transition framework designed for invariant validation, evidence generation, and auditable system behaviour. This repository provides:

  • Core primitives for invariant validation, transitions, and deterministic evidence.
  • A CI-friendly CLI with stable non-zero exit semantics.
  • A workstream-based collaboration model for concurrent contributors.

What Is dpa-icsd? (Skim)

  • dpa-icsd is the published package name on PyPI.
  • icsd is the Python import namespace.
  • icsd-dpa is the CLI command for CI and local checks.
  • ICSD focuses on invariant-safe state transitions and deterministic evidence.
  • The v1.x contract keeps CLI exit semantics and evidence schema compatibility stable.

Why ICSD?

ICSD is designed so invalid states are rejected structurally, not repaired after the fact. That reduces reactive error-handling complexity and makes evidence trails deterministic for audit and automation.

Status

Current package version: 1.1.0 (authoritative source: src/icsd/_version.py). As of 2026-03-16, v1.1.0 includes implemented core modules and CLI commands:

  • icsd-dpa demo [output.json]
  • icsd-dpa verify <evidence.json>
  • icsd-dpa lint <path>
  • Stable verify/lint JSON output for CI/audit pipelines.
  • Versioned invariant policy profiles selectable by profile name.
  • Authority-source metadata and transition-time authority validation hooks.
  • Transparency-log adapter hooks for append/verify workflows.

The package-level public API remains intentionally narrow at the v1.x boundary. See Stability Policy before depending on import paths.

Install

Published package identity:

  • Distribution name: dpa-icsd
  • Import module: icsd
  • CLI entry point: icsd-dpa

Install from PyPI:

python -m pip install dpa-icsd

Install from local source (development):

python -m pip install -e ".[dev]"

Quick Start (CLI)

python -m pip install dpa-icsd
icsd-dpa --version
icsd-dpa demo
icsd-dpa verify quickstart.evidence.json
icsd-dpa lint .

Notes:

  • icsd-dpa demo writes deterministic quick-start evidence to ./quickstart.evidence.json.
  • icsd-dpa demo custom.evidence.json writes the same deterministic payload to a different path.
  • icsd-dpa verify quickstart.evidence.json validates the generated evidence envelope, required fields, and hash-field format.
  • icsd-dpa lint . lints the current working directory.
  • For icsd-dpa verify <evidence.json>, you can use the generated quick-start artifact or an example evidence artifact from examples/out/.

Quick Start (Python)

from icsd.core import Invariant, InvariantSet, Transition


def positive_balance(state):
    return state["balance"] >= 0


inv = Invariant(name="balance_non_negative", check=positive_balance)
invset = InvariantSet([inv])

transition = Transition.simple(
    name="debit_demo",
    mutate=lambda state: state.update({"balance": state["balance"] - 1}),
    invariants=invset,
)

result = transition.apply(
    state={"balance": 10},
    entity_type="account",
    entity_id="acct-001",
    actor="user:quickstart",
    authority="policy/account-demo",
)

with open("quickstart.evidence.json", "w", encoding="utf-8") as f:
    f.write(result.evidence_json)

print("Evidence written to quickstart.evidence.json")
icsd-dpa verify quickstart.evidence.json

States and evidence metadata must remain JSON-compatible under ICSD's current Python-reference canonicalisation rules. Today that means json.dumps(..., sort_keys=True, separators=(",", ":"), ensure_ascii=False, allow_nan=False) followed by UTF-8 encoding where bytes are needed. If values such as Python datetime objects reach evidence hashing, signing, or result.evidence_json, ICSD raises EvidenceSerialisationError from icsd.core.errors. This is stable for the current implementation, but it is not RFC 8785 / JCS canonical JSON and does not by itself claim generic standards-based cross-language interoperability.

What Happens Next?

  • See the examples below for fuller invariant, profile, and adapter workflows.
  • Maintainers and contributors should use DEV_README.md.
  • Project changes are recorded in CHANGELOG.md under [Unreleased] first.

Optional Speed Extras (Contract)

Core install remains dependency-light (dependencies = [] in pyproject.toml). Optional acceleration extras are available as an explicit packaging contract and do not change ICSD behavior guarantees.

python -m pip install "dpa-icsd[speed-numpy]"
python -m pip install "dpa-icsd[speed-numba]"
python -m pip install "dpa-icsd[speed-extensions]"

For full contract details, see Performance Contract.

NumPy Batch Invariant Helper (Optional)

WS-0077 adds an optional NumPy-backed invariant helper for deterministic array-field validation in batch workflows. This helper is a deep import:

from icsd.adapters.numpy_invariants import NumpyBatchFieldInvariant
from icsd.core.invariants import Invariant, InvariantSet

invariants = InvariantSet(
    [
        Invariant(
            name="batch_values_numeric",
            check=NumpyBatchFieldInvariant(
                field="values",
                expected_ndim=1,
                min_value=0,
                require_finite=True,
            ),
        )
    ]
)

Install optional NumPy support with:

python -m pip install "dpa-icsd[speed-numpy]"

Behavior guarantees are unchanged. Missing NumPy returns a deterministic invariant failure at call-time, and boolean arrays are intentionally rejected by this numeric helper.

Numba JIT Invariant Helper (Optional Experiment)

WS-0078 adds NumbaBatchFieldInvariant as a deep-import experimental helper that preserves NumPy reference invariant outcomes and deterministic envelopes.

from icsd.adapters.numba_invariants import NumbaBatchFieldInvariant
from icsd.core.invariants import Invariant, InvariantSet

invariants = InvariantSet(
    [
        Invariant(
            name="batch_values_numeric",
            check=NumbaBatchFieldInvariant(
                field="values",
                expected_ndim=1,
                min_value=0,
                require_finite=True,
            ),
        )
    ]
)

Install optional Numba support with:

python -m pip install "dpa-icsd[speed-numba]"

If Numba is missing, unsupported, or its kernels fail, this helper falls back to the NumPy reference path. This is expected behavior for the experiment.

Cython Feasibility Harness (Optional Experiment)

WS-0079 adds an internal feasibility harness for Cython speedup exploration:

  • deterministic reference kernels and parity checks in icsd.adapters._cython_feasibility
  • optional probe extension source at icsd.adapters._cython_speedups.pyx
  • deterministic benchmark/profile scripts under benchmarks/

This workstream does not change runtime ICSD semantics.

Run feasibility benchmark (default: no build attempt):

python benchmarks/benchmark_cython_speedups.py --format json

Run best-effort build attempt:

python benchmarks/benchmark_cython_speedups.py --build-speedup --format json

Profile target selection:

python benchmarks/profile_cython_targets.py --format json

build=False speedup import is primarily useful when the extension has already been built locally. Without a prebuilt local extension, unavailable speedups are expected and reported as non-failing status.

v1.x Migration Guide (from v0.x prerelease)

  • Upgrade or pin to the stable release:
python -m pip install --upgrade dpa-icsd==1.1.0
  • Use icsd-dpa as the CLI entry point in scripts/CI (verify, lint, and exit codes 0/1/2 are stable across v1.x).
  • Keep package-root usage minimal (icsd.__version__); import runtime primitives from icsd.core and CLI internals from icsd.cli.
  • Compatibility retained in v1.x: evidence schema 0.1 and lint profile name policy-v0.1.
  • Breaking-change policy: documented public-contract breaks require the next major release (2.x).

Domain-Neutral Examples

Runnable non-finance examples live in examples/:

  • legal case lifecycle with statutory policy cutover and authority-backed audit trail
  • construction tolerance gating with inspection authority checks and evidence-level inspector/measurement provenance
  • schema contract evolution with migration and temporal policy cutover
  • supply-chain provenance with cold-chain custody continuity, per-hop provenance receipts, and out-of-range rejection
  • IAM access governance with least privilege, approval evidence enforcement, and trustless authority-proposal refusal
  • healthcare/lab sample custody with calibration-window policy cutover and release-authority gating
  • safety-critical robotics leash flow with agent-constrained execution and emergency-stop override
  • agent guardrails workflow with deterministic refusal reporting for unsafe autonomous actions
  • event-pipeline schema governance with v1->v2 cutover, migration/quarantine, and stream-event emission
  • D&D rules cutover demo with temporal profile provenance (Standard tier)
  • trustless D&D dice-plugin proposal refusal demo (Standard tier)
  • lite examples pack for minimal adoption (invariants + transition + one rejection)
  • fun D&D lite examples for combat and character-sheet invariant learning

Run from repository root:

python examples/legal_case_lifecycle.py
python examples/construction_tolerance_gate.py
python examples/schema_evolution_contracts.py
python examples/supply_chain_provenance.py
python examples/iam_access_governance.py
python examples/lab_sample_workflow.py
python examples/robotics_safety_leash.py
python examples/agent_guardrails.py
python examples/event_pipeline_schema_governance.py
python examples/dnd_rules_cutover_standard.py
python examples/dnd_trustless_dice_proposal.py
python examples/lite_supply_chain_temperature_gate.py
python examples/lite_legal_case_required_fields.py
python examples/lite_construction_tolerance.py
python examples/lite_schema_contracts.py
python examples/dnd_combat_lite.py
python examples/dnd_character_sheet_lite.py

Each script emits JSON artifacts under examples/out/ (gitignored).

Learning ICSD via Toy Domains

ICSD is not limited to compliance-heavy systems. To learn the invariant and refusal model quickly, start with toy game-state examples first:

  • python examples/dnd_combat_lite.py
  • python examples/dnd_character_sheet_lite.py

Then move to regulated-system examples and their conformance suites in ICSD Domain Index (legal, construction, schema governance, supply chain, IAM, healthcare, robotics, and event pipelines).

Regulated Systems Guides

High-signal docs for domain mapping and rollout:

  • ICSD Domain Index: domain index mapping invariants, evidence/provenance sources, and policy-cutover patterns to runnable examples.
  • ICSD Adoption Ladder: progressive adoption tiers (Lite -> Standard -> Full) with feature-to-tier mapping and concrete exit criteria.
  • AI Agent Integration Guide: AI-agent guardrail integration workflow (proposal -> context -> transition -> evidence/refusal) with refusal handling and anti-pattern guidance.
  • FastAPI Integration Pattern: docs-only wrapper pattern for request schema validation, authority proposal ingestion, and deterministic evidence/refusal API responses.
  • Policy Profile Authoring Guide: maintainer-facing guidance for naming, versioning, activation windows, cutover safety, and reusable InvariantProfileRegistry templates.
  • Adoption Metrics: manual-first PyPI download snapshot workflow via pypistats (dpa-icsd, daily/weekly/monthly counts).
  • Performance Contract: optional speed-extras dependency contract (speed-numpy, speed-numba, speed-extensions) and semantic equivalence guardrails.

Conformance Scenario Tests

Narrative non-finance conformance suites live in tests/:

  • tests/test_conformance_runner.py
  • tests/test_conformance_legal.py
  • tests/test_conformance_construction.py
  • tests/test_conformance_schema.py
  • tests/test_conformance_supply_chain.py
  • tests/test_conformance_iam.py
  • tests/test_conformance_lab.py
  • tests/test_conformance_robotics.py
  • tests/test_conformance_agent_guardrails.py
  • tests/test_conformance_event_pipeline.py
  • tests/test_conformance_dnd.py

These scenarios intentionally validate ICSD behaviour claims without asserting formal standards compliance:

  • valid-by-construction state setup via InvariantSet.construct_state(...)
  • transition application via Transition.apply_with_context(...) or AgentExecutionContext
  • deterministic evidence integrity + provenance verification
  • explicit rejection of invalid/unrepresentable transitions

Run only the conformance suites:

pytest -q tests/test_conformance_legal.py tests/test_conformance_construction.py tests/test_conformance_schema.py tests/test_conformance_supply_chain.py tests/test_conformance_iam.py tests/test_conformance_lab.py tests/test_conformance_robotics.py tests/test_conformance_agent_guardrails.py tests/test_conformance_event_pipeline.py tests/test_conformance_dnd.py

Single-entry umbrella conformance run:

pytest -q tests/test_conformance_runner.py

If your environment has restrictive temp-directory ACLs, pin pytest to a project-local temp path:

PYTEST_ADDOPTS="--basetemp .ci_tmp/pytest" pytest -q

Import Policy (v1.x)

  • Package root import contract remains intentionally narrow in v1.x: icsd.__version__.
  • Prefer deep imports for runtime primitives in v1.x, for example: from icsd.core import EvidenceBundle.
  • Do not assume from icsd import EvidenceBundle is part of the stable root-import contract.

Maintainer Docs

Release automation, PyPI namespace checks, and contributor workflow details live in DEV_README.md.

CLI Quick Reference

icsd-dpa --version
icsd-dpa demo [output.json]
icsd-dpa verify <evidence.json>
icsd-dpa verify <evidence.json> --format json
icsd-dpa lint <path>
icsd-dpa lint <path> --profile policy-v0.1 --format json
icsd-dpa lint <path> --jobs 4 --format json

Exit codes:

  • 0: success / no findings
  • 1: lint findings
  • 2: tool error (invalid args, unreadable file, invalid JSON, or evidence-envelope/schema/hash-field failure)

Verify and Lint Output

  • icsd-dpa verify validates the evidence envelope only: required fields, UTC/hash-field format, and nested signature/provenance record shape accepted by validate_evidence_payload(...).

  • icsd-dpa verify <evidence.json> --format json: machine-readable report on stdout with command, path, status, exit_code, error_count, and errors.

  • icsd-dpa lint <path> --format json: machine-readable report on stdout with command, path, profile, status, exit_code, finding_count, and findings.

  • verify and lint JSON reports use canonical compact JSON with sorted keys so CI/audit consumers can rely on stable wire output.

  • icsd-dpa verify does not perform cryptographic signature verification, reconstruct before_hash / after_hash from external states, authenticate provenance, or confirm transparency inclusion.

  • baseline (default): Python/JSON syntax checks only.

  • policy-v0.1: Adds stricter structural checks:

    • Blocks dynamic execution calls (eval, exec) in Python sources.
    • Requires JSON root objects and validates evidence-shaped JSON payloads.
    • Profile name retains the v0.1 suffix for backward compatibility in v1.x.
  • --format text (default): human-readable stderr errors/findings.

  • --jobs 1 (default): deterministic single-threaded lint traversal.

  • --jobs > 1: opt-in deterministic parallel lint traversal with stable output ordering.

  • The guarantee is deterministic ordering and stable output envelopes, not blanket speedup across all workloads.

  • Pure Python CPU-bound lint or invariant workloads may see limited or no improvement under thread-based parallelism.

Python Example: Invariants

from icsd.core.errors import InvariantFailure
from icsd.core.invariants import Invariant, InvariantSet


def owner_required(state: dict[str, str]) -> bool | InvariantFailure:
    owner = state.get("owner", "").strip()
    if owner:
        return True
    return InvariantFailure(
        invariant="owner_required",
        code="missing_owner",
        message="Owner must be set before transition execution.",
    )


invariants = InvariantSet(
    [
        Invariant(name="status_known", check=lambda s: s.get("status") in {"draft", "approved"}),
        Invariant(name="owner_required", check=owner_required),
    ]
)

failures = invariants.validate({"status": "draft", "owner": ""})
assert len(failures) == 1

Python Example: Batch Validation (Single-Process)

from icsd.core.batch import validate_states
from icsd.core.invariants import Invariant, InvariantSet

invariants = InvariantSet(
    [Invariant(name="non_negative_balance", check=lambda state: state["balance"] >= 0)]
)
report = validate_states(
    invariants,
    [{"balance": 100}, {"balance": -1}, {"balance": 50}],
    context={"batch_id": "batch-001"},
)
assert report.total_count == 3
assert report.passed_count == 2
assert report.failed_count == 1
assert report.as_dict()["results"][1]["status"] == "failed"

Batch validation in icsd.core.batch is deterministic and single-process by design.

Python Example: Batch Validation (Parallel Opt-In)

from icsd.core.invariants import Invariant, InvariantSet
from icsd.tools.parallel import validate_states_parallel

invariants = InvariantSet(
    [Invariant(name="non_negative_balance", check=lambda state: state["balance"] >= 0)]
)
report = validate_states_parallel(
    invariants,
    [{"balance": 100}, {"balance": -1}, {"balance": 50}],
    context={"batch_id": "batch-001"},
    workers=4,
)
assert report.total_count == 3
assert report.passed_count == 2
assert report.failed_count == 1

validate_states_parallel(...) is explicitly opt-in. workers=1 preserves the existing sequential validation path, while workers>1 uses deterministic threaded execution that preserves input order. The contract is stable ordering and report shape, not guaranteed faster execution for pure Python CPU-bound checks.

Python Example: Invariant-Safe Construction Helpers

from icsd.core.evidence import AuthoritySource
from icsd.core.invariants import Invariant, InvariantSet
from icsd.core.transition import Transition

invariants = InvariantSet(
    [Invariant(name="non_negative_balance", check=lambda state: state["balance"] >= 0)]
)

transition = Transition(
    name="debit_account",
    mutate=lambda state: state.update({"balance": state["balance"] - 20}),
    invariants=invariants,
    authority_validator=Transition.require_authority_sources(minimum=1),
)

# State objects are copied and validated before use.
safe_state = invariants.construct_state({"balance": 100})

# Authority/profile checks can be validated before apply-time.
context = transition.build_context(
    authority="policy/account-debit",
    authority_sources=[
        AuthoritySource(
            source_type="registry",
            source_id="uk-companies-house",
            reference="company/00000006",
        )
    ],
)
result = transition.apply_with_context(
    state=safe_state,
    entity_type="account",
    entity_id="acct-001",
    actor="user:ops",
    context=context,
)

Python Example: Legacy Migration and Quarantine

from icsd.core.invariants import Invariant, InvariantSet
from icsd.core.migration import migrate_legacy_states

invariants = InvariantSet(
    [
        Invariant(name="non_negative_balance", check=lambda state: state["balance"] >= 0),
        Invariant(name="owner_required", check=lambda state: bool(state["owner"].strip())),
    ]
)


def repair_legacy(state: dict[str, object]) -> None:
    if isinstance(state.get("balance"), int) and state["balance"] < 0:
        state["balance"] = 0
    if isinstance(state.get("owner"), str) and not state["owner"].strip():
        state["owner"] = "migrated-owner"


report = migrate_legacy_states(
    [{"balance": -10, "owner": ""}, {"balance": 50, "owner": "ops"}],
    invariants=invariants,
    transform=repair_legacy,
)
assert report.migrated_count == 2
assert report.quarantined_count == 0

Python Example: Versioned Invariant Profiles

from icsd.core.invariants import (
    Invariant,
    InvariantProfile,
    InvariantProfileRegistry,
    InvariantSet,
)
from icsd.core.transition import Transition

registry = InvariantProfileRegistry(
    [
        InvariantProfile(
            name="uk-payroll",
            policy="policy/payroll-tax",
            policy_version="2026.03",
            invariants=InvariantSet(
                [Invariant(name="non_negative_pay", check=lambda state: state["pay"] >= 0)]
            ),
        )
    ]
)

transition = Transition(
    name="apply_payroll_adjustment",
    mutate=lambda state: state.update({"pay": state["pay"] - 20}),
    profile_registry=registry,
    default_profile="uk-payroll",
)
result = transition.apply(
    state={"pay": 100},
    entity_type="payroll_record",
    entity_id="pay-001",
    actor="user:ops",
    policy_version="2026.03",
)

assert result.after_state == {"pay": 80}
assert result.evidence.authority == "policy/payroll-tax@2026.03"

Python Example: Temporal Policy Activation and Cutover

from icsd.core.invariants import Invariant, InvariantProfile, InvariantProfileRegistry, InvariantSet
from icsd.core.transition import Transition

registry = InvariantProfileRegistry(
    [
        InvariantProfile(
            name="uk-payroll",
            policy="policy/payroll-tax",
            policy_version="2026.03",
            active_from="2026-01-01T00:00:00Z",
            active_until="2026-06-01T00:00:00Z",
            invariants=InvariantSet(
                [Invariant(name="non_negative_pay", check=lambda state: state["pay"] >= 0)]
            ),
        ),
        InvariantProfile(
            name="uk-payroll",
            policy="policy/payroll-tax",
            policy_version="2026.06",
            active_from="2026-06-01T00:00:00Z",
            invariants=InvariantSet(
                [Invariant(name="non_negative_pay", check=lambda state: state["pay"] >= 0)]
            ),
        ),
    ]
)
transition = Transition(
    name="apply_payroll_adjustment",
    mutate=lambda state: state.update({"pay": state["pay"] - 20}),
    profile_registry=registry,
    default_profile="uk-payroll",
)
before_cutover = transition.apply(
    state={"pay": 100},
    entity_type="payroll_record",
    entity_id="pay-001",
    actor="user:ops",
    timestamp="2026-05-31T23:59:59Z",
)
after_cutover = transition.apply(
    state={"pay": 100},
    entity_type="payroll_record",
    entity_id="pay-001",
    actor="user:ops",
    timestamp="2026-06-01T00:00:00Z",
)
assert before_cutover.evidence.authority == "policy/payroll-tax@2026.03"
assert after_cutover.evidence.authority == "policy/payroll-tax@2026.06"

For profile naming, versioning, cutover-window authoring, and reusable registry templates, see docs/policy_profiles.md.

Python Example: Transition and Evidence

from datetime import datetime, timezone

from icsd.core.evidence import AuthoritySource
from icsd.core.invariants import Invariant, InvariantSet
from icsd.core.transition import Transition

invariants = InvariantSet(
    [Invariant(name="non_negative_balance", check=lambda state: state["balance"] >= 0)]
)


def debit(state: dict[str, int]) -> None:
    state["balance"] -= 20


transition = Transition(name="debit_account", mutate=debit, invariants=invariants)
result = transition.apply(
    state={"balance": 100},
    entity_type="account",
    entity_id="acct-001",
    actor="user:ops",
    authority="policy/account-debit",
    authority_sources=[
        AuthoritySource(
            source_type="registry",
            source_id="uk-companies-house",
            reference="company/00000006",
        )
    ],
    transition_id="11111111-1111-4111-8111-111111111111",
    timestamp=datetime(2026, 3, 3, 10, 0, tzinfo=timezone.utc),
)

assert result.before_state == {"balance": 100}
assert result.after_state == {"balance": 80}
assert result.evidence.verify_integrity(
    before_state=result.before_state,
    after_state=result.after_state,
)

Python Example: Minimal Transition Helper

from icsd.core.invariants import Invariant, InvariantSet
from icsd.core.transition import Transition

transition = Transition.simple(
    name="debit_account",
    mutate=lambda state: state.update({"balance": state["balance"] - 20}),
    invariants=InvariantSet(
        [Invariant(name="non_negative_balance", check=lambda state: state["balance"] >= 0)]
    ),
)

Transition.simple(...) is constructor sugar for direct-invariant transitions. It does not bypass invariant checks or authority validation hooks.

Python Example: Authority Validation Hook

from icsd.core.invariants import Invariant, InvariantSet
from icsd.core.transition import Transition

transition = Transition(
    name="debit_account",
    mutate=lambda state: state.update({"balance": state["balance"] - 20}),
    invariants=InvariantSet(
        [Invariant(name="non_negative_balance", check=lambda state: state["balance"] >= 0)]
    ),
    authority_validator=Transition.require_authority_sources(minimum=1),
)

Python Example: Authority Adapter (Trustless Proposal Verification)

from icsd.core.invariants import Invariant, InvariantSet
from icsd.core.transition import Transition


class ExternalAuthorityAdapter:
    def propose(self, *, current_state, authority_response):
        # External responses are proposal inputs, not direct truth.
        return {
            "changes": {
                "balance": authority_response["approved_balance"],
            },
            "source": "authority-api",
            "reference": authority_response["response_id"],
            "details": {"provider": "external-authority"},
        }


transition = Transition(
    name="debit_account",
    mutate=lambda state: state.update({"balance": state["balance"] - 5}),
    invariants=InvariantSet(
        [Invariant(name="non_negative_balance", check=lambda state: state["balance"] >= 0)]
    ),
    authority_adapter=ExternalAuthorityAdapter(),
)
result = transition.apply(
    state={"balance": 100},
    entity_type="account",
    entity_id="acct-001",
    actor="user:ops",
    authority="policy/account-debit",
    authority_response={"approved_balance": 60, "response_id": "resp-001"},
)
assert result.after_state == {"balance": 95}
assert result.evidence.provenance[0].source == "authority-api"

For a deterministic refusal-report pattern when an adapter proposes impossible state, see tests/test_trustless_authority_refusal.py. When an accepted adapter proposal includes both source and reference, ICSD persists that proposal context into evidence provenance with the validated proposal_changes and optional adapter proposal_details.

Python Example: Schema Contract Adapters (JSON Schema + Pydantic)

from pydantic import BaseModel, Field

from icsd.adapters import JsonSchemaInvariant, PydanticModelInvariant
from icsd.core.invariants import Invariant, InvariantSet

json_contract = JsonSchemaInvariant(
    schema={
        "type": "object",
        "required": ["status", "count"],
        "properties": {
            "status": {"type": "string", "enum": ["draft", "review", "approved"]},
            "count": {"type": "integer", "minimum": 0},
        },
        "additionalProperties": False,
    }
)


class ContractModel(BaseModel):
    status: str = Field(min_length=1)
    count: int = Field(ge=0)


pydantic_contract = PydanticModelInvariant(model=ContractModel)

invariants = InvariantSet(
    [
        Invariant(name="json_contract", check=json_contract),
        Invariant(name="pydantic_contract", check=pydantic_contract),
    ]
)
invariants.assert_valid({"status": "review", "count": 2})

JsonSchemaInvariant uses jsonschema when installed and falls back to a deterministic subset validator (type, required, properties, additionalProperties, enum, const, length/number bounds, and array item checks) when it is not. PydanticModelInvariant requires optional pydantic to be installed.

Python Example: Agent-Constrained Execution Context

from icsd.core.context import AgentExecutionContext, AgentPolicyEnforcement
from icsd.core.invariants import Invariant, InvariantProfile, InvariantProfileRegistry, InvariantSet
from icsd.core.transition import Transition

registry = InvariantProfileRegistry(
    [
        InvariantProfile(
            name="retail-banking",
            policy="policy/account-debit",
            policy_version="2026.03",
            invariants=InvariantSet(
                [Invariant(name="non_negative_balance", check=lambda state: state["balance"] >= 0)]
            ),
        )
    ]
)
transition = Transition(
    name="debit_account",
    mutate=lambda state: state.update({"balance": state["balance"] - 5}),
    profile_registry=registry,
)
agent_context = AgentExecutionContext(
    transition,
    enforcement=AgentPolicyEnforcement(
        require_profile=True,
        require_policy_version=True,
        minimum_authority_sources=1,
    ),
)
result = agent_context.apply(
    state={"balance": 100},
    entity_type="account",
    entity_id="acct-001",
    actor="user:ops",
    profile="retail-banking",
    policy_version="2026.03",
    authority_sources=[
        {
            "source_type": "registry",
            "source_id": "uk-companies-house",
            "reference": "company/00000006",
        }
    ],
)
assert result.after_state == {"balance": 95}

Python Example: Transparency Log Adapter

from icsd.adapters import TransparencyLogReceipt, TransparencyVerification
from icsd.core.invariants import Invariant, InvariantSet
from icsd.core.transition import Transition


class MemoryLogAdapter:
    def append(self, *, evidence_payload):
        return TransparencyLogReceipt(adapter="memory-log", reference="entry/1")

    def verify(self, *, evidence_payload, receipt=None):
        return TransparencyVerification(verified=True, checkpoint="checkpoint-1")


transition = Transition(
    name="debit_account",
    mutate=lambda state: state.update({"balance": state["balance"] - 20}),
    invariants=InvariantSet(
        [Invariant(name="non_negative_balance", check=lambda state: state["balance"] >= 0)]
    ),
    transparency_log=MemoryLogAdapter(),
    verify_transparency_after_append=True,
)

Transparency append and verify both bind to the same canonical evidence payload. If a transparency receipt is embedded back into evidence.provenance, that transparency-log/... record is treated as append metadata rather than part of the payload identity being verified.

Python Example: Real-time Evidence Stream Adapter

from icsd.adapters.transparency_stream import TransparencyStreamReceipt
from icsd.core.invariants import Invariant, InvariantSet
from icsd.core.transition import Transition


class AuditorFeedAdapter:
    def emit(self, *, event_payload):
        # event_payload includes evidence, signable_hash, and transition metadata.
        return TransparencyStreamReceipt(
            adapter="auditor-feed",
            event_id=f"evt/{event_payload['transition_id']}",
        )


transition = Transition(
    name="debit_account",
    mutate=lambda state: state.update({"balance": state["balance"] - 20}),
    invariants=InvariantSet(
        [Invariant(name="non_negative_balance", check=lambda state: state["balance"] >= 0)]
    ),
    transparency_stream=AuditorFeedAdapter(),
)

Invisible Compliance Layer Guides

Deployment-oriented guidance for evidence-stream and auditor workflows:

Operational pattern:

  1. A transition emits deterministic evidence and a stream event payload.
  2. A stream adapter publishes the event payload to subscriber infrastructure.
  3. A transparency-log adapter stores/returns inclusion receipts for later checks. Those receipt entries may be embedded in evidence provenance for audit convenience, but they are excluded from the canonical payload bound to the append/verify identity check.
  4. Auditors subscribe to the feed and verify evidence locally.

Concrete CLI walkthrough:

python examples/legal_case_lifecycle.py
icsd-dpa verify examples/out/legal_case_04_appealed.evidence.json

That CLI step validates the evidence envelope only. Transparency receipt verification, event/evidence correlation, and any signature or provenance trust checks remain separate auditor steps.

Whitepaper Integration (Non-Normative)

For whitepaper usage, see Whitepaper Integration for a ready-to-use "Reference Implementation and Conformance Testing" section and claim-to-test/example mapping.

The package is a reference implementation only; it does not define the ICSD normative specification.

Evidence Payload Shape (Schema v0.1, Supported in v1.x)

icsd-dpa verify validates the evidence JSON envelope, required fields, UTC/hash-field format, and nested record shape accepted by validate_evidence_payload(...). For CI/audit automation, icsd-dpa verify <evidence.json> --format json emits a stable canonical report envelope separate from the evidence payload being verified. It does not verify cryptographic signatures, recompute before_hash / after_hash from source states, authenticate provenance, or confirm transparency inclusion. The stored before_hash, after_hash, and signable-byte workflows are based on the repository's current Python-reference canonicalisation rules. Consumers in other languages must reproduce those exact bytes for parity today; the project does not currently claim RFC 8785 / JCS-style canonical JSON interoperability. The full implementation-aligned reference is available in docs/evidence_schema_v0_1.md, and the machine-readable artifact is published at docs/evidence_schema_v0_1.json. Within v1.x, evidence schema 0.1 remains stable and compatible extension keys remain permitted for forward-compatible consumers.

{
  "schema_version": "0.1",
  "transition_id": "11111111-1111-4111-8111-111111111111",
  "entity_type": "account",
  "entity_id": "acct-001",
  "actor": "user:ops",
  "authority": "policy/account-debit",
  "authority_sources": [
    {
      "source_type": "registry",
      "source_id": "uk-companies-house",
      "reference": "company/00000006"
    }
  ],
  "timestamp": "2026-03-03T10:00:00Z",
  "before_hash": "d2ec8f050e788f96279be8f1a1d7e56ce3f180ebea047a1bf6f019f06f5f0a18",
  "after_hash": "55459e863d1c8fcdaff7ac18549f96db4495ea3a74c4d659e410cd554d65ff43"
}

Stability Policy (v1.x)

  • 1.x releases follow semantic versioning: breaking changes to documented public contracts require a 2.x release.
  • Package root API guarantee in v1.x remains intentionally narrow: icsd.__version__.
  • icsd.core.* and icsd.cli.* are supported import paths in v1.x; incompatible changes require a major-version bump.
  • CLI command surface (icsd-dpa --version, demo, verify, lint) and exit-code semantics (0, 1, 2) are stable for v1.x automation.
  • Evidence schema 0.1 and lint profile policy-v0.1 remain supported in v1.x for compatibility.
  • Breaking behavior changes should be labelled Kind/Breaking in issue/commit metadata.

Credits

License

Apache-2.0. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dpa_icsd-1.1.0.tar.gz (113.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dpa_icsd-1.1.0-py3-none-any.whl (62.8 kB view details)

Uploaded Python 3

File details

Details for the file dpa_icsd-1.1.0.tar.gz.

File metadata

  • Download URL: dpa_icsd-1.1.0.tar.gz
  • Upload date:
  • Size: 113.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for dpa_icsd-1.1.0.tar.gz
Algorithm Hash digest
SHA256 3dcbccb957a45faf7462da512fd31cbf3f3d2b4296c4a5cb71a0cbbdfd3d2a08
MD5 5fd99dd423cc211e6d966f818634e3f1
BLAKE2b-256 a882ef9a8919e4db4da5125fcd3cf7fa65aa78ecccd4d989c9218884aa3a7ffd

See more details on using hashes here.

File details

Details for the file dpa_icsd-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: dpa_icsd-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 62.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for dpa_icsd-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8e2de1fe79038606454347abf1055df7266798332d61511e40599e7ad5e809d4
MD5 22cbfdf01dd5732154b1df6f060d9f26
BLAKE2b-256 3a750fa9983f12e88697207321c5e4ae7dc5cbad335c95bf1a1863b4f2298182

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page