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-icsdis the published package name on PyPI.icsdis the Python import namespace.icsd-dpais the CLI command for CI and local checks.- ICSD focuses on invariant-safe state transitions and deterministic evidence.
- The
v1.xcontract 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/lintJSON 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 demowrites deterministic quick-start evidence to./quickstart.evidence.json.icsd-dpa demo custom.evidence.jsonwrites the same deterministic payload to a different path.icsd-dpa verify quickstart.evidence.jsonvalidates 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 fromexamples/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.mdunder[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-dpaas the CLI entry point in scripts/CI (verify,lint, and exit codes0/1/2are stable acrossv1.x). - Keep package-root usage minimal (
icsd.__version__); import runtime primitives fromicsd.coreand CLI internals fromicsd.cli. - Compatibility retained in
v1.x: evidence schema0.1and lint profile namepolicy-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 (
Standardtier) - trustless D&D dice-plugin proposal refusal demo (
Standardtier) - 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.pypython 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
InvariantProfileRegistrytemplates. - 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.pytests/test_conformance_legal.pytests/test_conformance_construction.pytests/test_conformance_schema.pytests/test_conformance_supply_chain.pytests/test_conformance_iam.pytests/test_conformance_lab.pytests/test_conformance_robotics.pytests/test_conformance_agent_guardrails.pytests/test_conformance_event_pipeline.pytests/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(...)orAgentExecutionContext - 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 EvidenceBundleis 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 findings1: lint findings2: tool error (invalid args, unreadable file, invalid JSON, or evidence-envelope/schema/hash-field failure)
Verify and Lint Output
-
icsd-dpa verifyvalidates the evidence envelope only: required fields, UTC/hash-field format, and nested signature/provenance record shape accepted byvalidate_evidence_payload(...). -
icsd-dpa verify <evidence.json> --format json: machine-readable report on stdout withcommand,path,status,exit_code,error_count, anderrors. -
icsd-dpa lint <path> --format json: machine-readable report on stdout withcommand,path,profile,status,exit_code,finding_count, andfindings. -
verifyandlintJSON reports use canonical compact JSON with sorted keys so CI/audit consumers can rely on stable wire output. -
icsd-dpa verifydoes not perform cryptographic signature verification, reconstructbefore_hash/after_hashfrom 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.1suffix for backward compatibility in v1.x.
- Blocks dynamic execution calls (
-
--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:
- Transparency Feed Deployment Recipe
- Auditor Subscription Guide
- ICSD Domain Index
- ICSD Adoption Ladder
- FastAPI Integration Pattern
- Whitepaper Integration
Operational pattern:
- A transition emits deterministic evidence and a stream event payload.
- A stream adapter publishes the event payload to subscriber infrastructure.
- 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.
- 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.xreleases follow semantic versioning: breaking changes to documented public contracts require a2.xrelease.- Package root API guarantee in v1.x remains intentionally narrow:
icsd.__version__. icsd.core.*andicsd.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.1and lint profilepolicy-v0.1remain supported in v1.x for compatibility. - Breaking behavior changes should be labelled
Kind/Breakingin issue/commit metadata.
Credits
- Framework: https://datatracker.ietf.org/doc/draft-dpa-icsd/
- Author: Benjamin Anthony Fisher
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3dcbccb957a45faf7462da512fd31cbf3f3d2b4296c4a5cb71a0cbbdfd3d2a08
|
|
| MD5 |
5fd99dd423cc211e6d966f818634e3f1
|
|
| BLAKE2b-256 |
a882ef9a8919e4db4da5125fcd3cf7fa65aa78ecccd4d989c9218884aa3a7ffd
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e2de1fe79038606454347abf1055df7266798332d61511e40599e7ad5e809d4
|
|
| MD5 |
22cbfdf01dd5732154b1df6f060d9f26
|
|
| BLAKE2b-256 |
3a750fa9983f12e88697207321c5e4ae7dc5cbad335c95bf1a1863b4f2298182
|