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.0.11 (authoritative source: src/icsd/_version.py). As of 2026-03-16, v1.0.11 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 artifact.
  • 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

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.0.11
  • 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, schema/integrity failure)

Verify and Lint Output

  • 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.

  • 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.

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

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"],
        }


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}

For a deterministic refusal-report pattern when an adapter proposes impossible state, see tests/test_trustless_authority_refusal.py.

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,
)

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.
  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

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 required evidence fields and hash format. For CI/audit automation, icsd-dpa verify <evidence.json> --format json emits a stable canonical report envelope separate from the evidence payload being verified. 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.0.11.tar.gz (103.7 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.0.11-py3-none-any.whl (57.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: dpa_icsd-1.0.11.tar.gz
  • Upload date:
  • Size: 103.7 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.0.11.tar.gz
Algorithm Hash digest
SHA256 0dcae1bafd97f8854981a867af88829a437eb0af65a7e98eb67273173a172bc4
MD5 2138c29ec917b7cd0f254f86e848106c
BLAKE2b-256 19f153c912a05f25fb823c10c7d68d6a570d58f1c30940b617be3f79bc4e5490

See more details on using hashes here.

File details

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

File metadata

  • Download URL: dpa_icsd-1.0.11-py3-none-any.whl
  • Upload date:
  • Size: 57.4 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.0.11-py3-none-any.whl
Algorithm Hash digest
SHA256 708a9c7e8a134389bb381471066bbca5255ab411ffebe66f6fa55afe3ae0d6cf
MD5 673f9338710ba9751efddf55b775c54d
BLAKE2b-256 3960f820004b7f81809e78fa7d5619a35c207fe82c5e1050dcdf72d5cee34816

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