Skip to main content

Reference Python implementation and tooling baseline for ICSD.

Project description

ICSD Python Tooling

Reference Python implementation for Invariant-Closed System Design (ICSD). 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.

Status

As of 2026-03-04, v1.0.0 includes implemented core modules and CLI commands:

  • icsd-dpa verify <evidence.json>
  • icsd-dpa lint <path>
  • icsd-dpa lint profile selection and 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.0.0 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]"

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

  • Upgrade or pin to the stable release:
python -m pip install --upgrade dpa-icsd==1.0.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.0.0: evidence schema 0.1 and lint profile name policy-v0.1.
  • Breaking-change policy: documented public-contract breaks require a major release (2.0.0).

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 docs/domains.md (legal, construction, schema governance, supply chain, IAM, healthcare, robotics, and event pipelines).

Regulated Systems Guides

High-signal docs for domain mapping and rollout:

  • docs/domains.md: domain index mapping invariants, evidence/provenance sources, and policy-cutover patterns to runnable examples.
  • docs/adoption_ladder.md: progressive adoption tiers (Lite -> Standard -> Full) with feature-to-tier mapping and concrete exit criteria.
  • docs/ai_agents.md: AI-agent guardrail integration workflow (proposal -> context -> transition -> evidence/refusal) with refusal handling and anti-pattern guidance.
  • docs/fastapi_integration.md: docs-only wrapper pattern for request schema validation, authority proposal ingestion, and deterministic evidence/refusal API responses.
  • docs/adoption_metrics.md: manual-first PyPI download snapshot workflow via pypistats (dpa-icsd, daily/weekly/monthly counts).

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

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.

PyPI Name Decision and Claim Checklist

Name decision (WS-0022, checked on 2026-03-03):

  • Keep distribution name as dpa-icsd for first publish.
  • Keep import module as icsd and CLI command as icsd-dpa.
  • Treat the distribution name as sticky after first successful PyPI upload.

Availability check references:

  • https://pypi.org/pypi/icsd/json returns 200 (name already occupied).
  • https://pypi.org/pypi/dpa-icsd/json returns 404 (name available at check time).

Pre-release namespace checklist:

  1. Re-run the JSON endpoint check immediately before creating a release tag.
  2. If dpa-icsd returns 200 before first publish, stop the release and open a new workstream to select and apply a new distribution name.
  3. After first successful publish, do not rename the distribution.

Baseline validation:

python -c "import icsd; print(icsd.__version__)"
icsd-dpa --version
ruff format --check .
ruff check .
pytest -q

Deterministic CI/local parity validation:

python -m pip install -e ".[dev]"
python -m pip check
python -m ruff format --check .
python -m ruff check .
python -c "from pathlib import Path; Path('.ci_tmp').mkdir(exist_ok=True)"
python -m pytest --basetemp .ci_tmp/pytest

Release Rehearsal (TestPyPI Readiness)

This project keeps release verification manual-first for the v1.0.0 release flow. For a local one-command rehearsal (without upload), run scripts/release_check.sh.

  1. Install release tooling.
python -m pip install --upgrade build twine
  1. Build source and wheel distributions.
python -m build
  1. Validate built metadata before upload.
python -m twine check dist/*
  1. Smoke-test install from the built wheel in an isolated virtual environment.
python -m venv .rehearsal-venv
.rehearsal-venv/bin/python -m pip install --upgrade pip
.rehearsal-venv/bin/python -m pip install --force-reinstall dist/dpa_icsd-*.whl
.rehearsal-venv/bin/icsd-dpa --version
.rehearsal-venv/bin/python -c "import icsd; print(icsd.__version__)"

PowerShell equivalent:

$PY = ".\.rehearsal-venv\Scripts\python.exe"
& $PY -m pip install --upgrade pip
& $PY -m pip install --force-reinstall dist\dpa_icsd-*.whl
& ".\.rehearsal-venv\Scripts\icsd-dpa.exe" --version
& $PY -c "import icsd; print(icsd.__version__)"
  1. Upload rehearsal artifacts to TestPyPI.
export TWINE_USERNAME="__token__"
export TWINE_PASSWORD="<testpypi-token>"
python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*

PowerShell equivalent:

$env:TWINE_USERNAME = "__token__"
$env:TWINE_PASSWORD = "<testpypi-token>"
python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
  1. Verify installation from TestPyPI.
python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple dpa-icsd==1.0.0
icsd-dpa --version

Release Automation (Gitea Tags)

Release publishing is separated from normal CI:

  • CI workflow: .gitea/workflows/ci.yml (branches/PRs only).
  • Release workflow: .gitea/workflows/release.yml (tag push v* and manual workflow_dispatch).

Release workflow stages:

  1. Build distributions and run twine check.
  2. Publish artifacts to TestPyPI.
  3. Install from TestPyPI and smoke-test icsd-dpa.
  4. Publish the same validated artifacts to PyPI (publish mode only).

Dry-run gate (no PyPI publish):

  • Trigger Release Publish manually (workflow_dispatch) with release_mode=dry-run (default).
  • Optional input tag_name can be set to a target release tag (vX.Y.Z).
  • If tag_name is omitted in dry-run mode, the workflow derives v<package_version> from src/icsd/_version.py.
  • Dry-run mode still executes build, TestPyPI publish, and TestPyPI install verification.
  • Dry-run mode skips the publish-pypi job, so no live PyPI upload occurs.

Tagging rule:

  • Create tags matching package version with a v prefix, for example v1.0.0.
  • The release workflow validates that tag[1:] == icsd._version.__version__ before any publish flow.
  • Release workflow tag resolution prefers GITEA_REF_NAME, falls back to GITHUB_REF_NAME, then falls back to parsing GITEA_REF / GITHUB_REF, then workflow_dispatch input tag_name.
  • In manual publish mode, a release tag (or tag_name) is required; in dry-run mode, missing tag input is auto-derived from package version.

Required Gitea secrets:

  • TESTPYPI_API_TOKEN: API token for TestPyPI (__token__ user).
  • PYPI_API_TOKEN: API token for PyPI (__token__ user, required only for publish mode).

CLI Quick Reference

icsd-dpa --version
icsd-dpa verify <evidence.json>
icsd-dpa lint <path>
icsd-dpa lint <path> --profile policy-v0.1 --format json

Exit codes:

  • 0: success / no findings
  • 1: lint findings
  • 2: tool error (invalid args, unreadable file, invalid JSON, schema/integrity failure)

Lint Profiles and 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 findings.
  • --format json: machine-readable report on stdout with profile, status, exit code, and findings.

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: 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"

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 docs/whitepaper_integration.md 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.

{
  "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"
}

Philosophy Linkouts

Stability Policy (v1.x)

  • 1.x releases follow semantic versioning: breaking changes to documented public contracts require a 2.0.0 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, 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.

Changelog Discipline

  • Add all user-visible changes to the [Unreleased] section in CHANGELOG.md.
  • Use categories (Added, Changed, Fixed, Removed, Security) consistently.
  • Keep entries concrete, short, and scoped to behavior, API, or operational impact.

Repository Layout

icsd-python/
  AGENTS.md
  WORKSTREAMS.md
  README.md
  CHANGELOG.md
  pyproject.toml
  ruff.toml
  src/icsd/
  tests/

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.7.tar.gz (76.4 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.7-py3-none-any.whl (44.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: dpa_icsd-1.0.7.tar.gz
  • Upload date:
  • Size: 76.4 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.7.tar.gz
Algorithm Hash digest
SHA256 eb763d86bdf9ff94d3672bd768894bd73ad2223b973740d5e530a8122b3ae471
MD5 5ca94e6ff2170d6933ae371afa0fe77a
BLAKE2b-256 72a32af7015e5754b7bae065c899833eb14542e17614a96984dcd8a4abc2a5de

See more details on using hashes here.

File details

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

File metadata

  • Download URL: dpa_icsd-1.0.7-py3-none-any.whl
  • Upload date:
  • Size: 44.0 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.7-py3-none-any.whl
Algorithm Hash digest
SHA256 b003632753ba505b0d6b1298a9b24c173cb5dd61e06d79a64cc8702c6d5a8d5a
MD5 059ec8f9922e44aebd00fa7cc7db47d8
BLAKE2b-256 42d4bf5dbee1ce0ad068767977268b084beed96b8808ab97468fdee4c54d866b

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