diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c57e0e3..5f53acb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -21,3 +21,19 @@ updates: directory: / schedule: interval: weekly + + - package-ecosystem: pip + directory: /ports/python + schedule: + interval: weekly + groups: + python: + patterns: + - "*" + update-types: + - minor + - patch + ignore: + - dependency-name: "*" + update-types: + - version-update:semver-major diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc36293..7e56c6a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,6 +82,67 @@ jobs: - run: go test -race ./... - run: go vet ./... + python: + name: Python ${{ matrix.python }} + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + python: + - "3.11" + - "3.12" + - "3.13" + - "3.14" + defaults: + run: + working-directory: ports/python + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + with: + python-version: ${{ matrix.python }} + cache: pip + cache-dependency-path: ports/python/pyproject.toml + - run: python -m pip install ".[dev]" + - run: ruff format --check . + - run: ruff check . + - run: mypy src + - run: pytest + + python-package: + name: Python package + runs-on: ubuntu-latest + timeout-minutes: 15 + defaults: + run: + working-directory: ports/python + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + with: + python-version: "3.12" + cache: pip + cache-dependency-path: ports/python/pyproject.toml + - run: python -m pip install build twine + - run: python -m build + - run: twine check dist/* + - name: Test wheel installation + run: | + python -m venv .wheel-venv + .wheel-venv/bin/python -m pip install dist/*.whl + .wheel-venv/bin/python -c "from importlib.resources import files; import worldcut; assert files('worldcut').joinpath('py.typed').is_file(); assert worldcut.ENGINE_VERSION == '0.1.2'" + .wheel-venv/bin/worldcut-py --help + .wheel-venv/bin/worldcut-py ../../examples/coherent-deployment.json + - name: Test source distribution independently + run: | + mkdir .sdist-test + tar -xzf dist/*.tar.gz -C .sdist-test --strip-components=1 + python -m venv .sdist-venv + .sdist-venv/bin/python -m pip install "./.sdist-test[dev]" + cd .sdist-test + ../.sdist-venv/bin/pytest + required: name: Required checks if: always() @@ -89,6 +150,8 @@ jobs: - node - benchmark - go + - python + - python-package runs-on: ubuntu-latest steps: - name: Require successful CI @@ -96,7 +159,11 @@ jobs: NODE_RESULT: ${{ needs.node.result }} BENCHMARK_RESULT: ${{ needs.benchmark.result }} GO_RESULT: ${{ needs.go.result }} + PYTHON_RESULT: ${{ needs.python.result }} + PYTHON_PACKAGE_RESULT: ${{ needs.python-package.result }} run: | test "$NODE_RESULT" = "success" test "$BENCHMARK_RESULT" = "success" test "$GO_RESULT" = "success" + test "$PYTHON_RESULT" = "success" + test "$PYTHON_PACKAGE_RESULT" = "success" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index fbfcf0b..e1e071f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -21,6 +21,6 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4 with: - languages: javascript-typescript + languages: javascript-typescript,python - name: Analyze uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4 diff --git a/README.md b/README.md index b99dfc6..5c09997 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ Language-neutral protocol semantics and golden vectors are under | --- | --- | --- | | TypeScript | 0.1 / 0.1.2 | Reference package with documented integrations | | [Go](ports/go) | 0.1 / 0.1.2 | Independent conformant verifier and CLI; integrations not yet included | +| [Python](ports/python) | 0.1 / 0.1.2 | Independent conformant verifier and CLI; integrations not yet included | ## Run the examples diff --git a/ports/python/.gitignore b/ports/python/.gitignore new file mode 100644 index 0000000..bbc8b2c --- /dev/null +++ b/ports/python/.gitignore @@ -0,0 +1,12 @@ +/.venv/ +/.wheel-venv/ +/.sdist-venv/ +/.sdist-test/ +/dist/ +/.pytest_cache/ +/.mypy_cache/ +/.ruff_cache/ +/.hypothesis/ +*.egg-info/ +__pycache__/ +*.py[cod] diff --git a/ports/python/README.md b/ports/python/README.md new file mode 100644 index 0000000..727a916 --- /dev/null +++ b/ports/python/README.md @@ -0,0 +1,53 @@ +# WorldCut Python + +Independent Python implementation of WorldCut protocol **0.1**, engine +**0.1.2**, and canonicalization **worldcut-json-v1**. Python 3.11 or newer is +required. + +## Install + +```sh +python -m pip install worldcut +``` + +## Library + +```python +from pathlib import Path + +from worldcut import parse_input, verify + +parsed = parse_input(Path("verification.json").read_bytes()) +result = verify(parsed) +print(result["verdict"]) +print(result["verificationRecordDigest"]) +``` + +`ParsedInput` is an immutable validated snapshot. Every verification returns a +fresh result, so mutating one result cannot affect later verification. + +## CLI + +```sh +worldcut-py verification.json +worldcut-py --require-satisfied verification.json +``` + +The second form exits with status 2 unless the verdict is +`CONTRACT_SATISFIED`. + +## Validate + +```sh +python -m pip install -e ".[dev]" +ruff format --check . +ruff check . +mypy src +pytest +python -m build +twine check dist/* +``` + +The source distribution includes the complete mirrored conformance corpus and +can run its tests without files from the parent repository. This port includes +the verifier and CLI only; integrations are intentionally not included yet. diff --git a/ports/python/pyproject.toml b/ports/python/pyproject.toml new file mode 100644 index 0000000..44a459e --- /dev/null +++ b/ports/python/pyproject.toml @@ -0,0 +1,70 @@ +[build-system] +requires = ["hatchling>=1.27"] +build-backend = "hatchling.build" + +[project] +name = "worldcut" +version = "0.1.0" +description = "Independent Python verifier for the WorldCut decision-coherence protocol" +readme = "README.md" +requires-python = ">=3.11" +license = "Apache-2.0" +authors = [{ name = "Jason Doyle" }] +keywords = ["consistency", "distributed-systems", "provenance", "verification"] +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Typing :: Typed", +] +dependencies = ["rfc8785==0.1.4"] + +[project.optional-dependencies] +dev = [ + "build>=1.2.2", + "hypothesis>=6.130", + "mypy>=1.15", + "pytest>=8.3", + "ruff>=0.11", + "twine>=6.1", +] + +[project.scripts] +worldcut-py = "worldcut.cli:main" + +[project.urls] +Homepage = "https://github.com/Jason-Doyle/WorldCut" +Issues = "https://github.com/Jason-Doyle/WorldCut/issues" +Repository = "https://github.com/Jason-Doyle/WorldCut" + +[tool.hatch.build.targets.wheel] +packages = ["src/worldcut"] + +[tool.hatch.build.targets.sdist] +include = [ + "/src/worldcut", + "/tests", + "/README.md", + "/pyproject.toml", +] + +[tool.pytest.ini_options] +addopts = "-ra --strict-config --strict-markers" +testpaths = ["tests"] + +[tool.mypy] +python_version = "3.11" +strict = true +files = ["src"] + +[tool.ruff] +target-version = "py311" +line-length = 88 + +[tool.ruff.lint] +select = ["B", "E", "F", "I", "RUF", "SIM", "UP"] diff --git a/ports/python/src/worldcut/__init__.py b/ports/python/src/worldcut/__init__.py new file mode 100644 index 0000000..63a3336 --- /dev/null +++ b/ports/python/src/worldcut/__init__.py @@ -0,0 +1,30 @@ +"""Independent Python implementation of the WorldCut 0.1 verifier.""" + +from .canonicalization import canonical_json, sha256_digest +from .errors import WorldCutError, WorldCutErrorCode, WorldCutInputError +from .models import ParsedInput, VerificationResult +from .validation import PROTOCOL_VERSION, parse_input +from .verifier import ( + CANONICALIZATION, + ENGINE_VERSION, + verify, + verify_json, +) + +__all__ = [ + "CANONICALIZATION", + "ENGINE_VERSION", + "PROTOCOL_VERSION", + "ParsedInput", + "VerificationResult", + "WorldCutError", + "WorldCutErrorCode", + "WorldCutInputError", + "canonical_json", + "parse_input", + "sha256_digest", + "verify", + "verify_json", +] + +__version__ = "0.1.0" diff --git a/ports/python/src/worldcut/canonicalization.py b/ports/python/src/worldcut/canonicalization.py new file mode 100644 index 0000000..bcf6664 --- /dev/null +++ b/ports/python/src/worldcut/canonicalization.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +import hashlib +import math + +import rfc8785 + +from .models import JsonValue + +_MAX_SAFE_INTEGER = 9_007_199_254_740_991 + + +def _assert_valid_unicode(value: str, field: str) -> None: + for character in value: + code_point = ord(character) + if 0xD800 <= code_point <= 0xDFFF: + raise TypeError(f"{field} contains an unpaired surrogate") + + +def _snapshot_json(value: object, field: str, ancestors: set[int]) -> JsonValue: + if value is None or isinstance(value, (str, bool)): + if isinstance(value, str): + _assert_valid_unicode(value, field) + return value + if isinstance(value, int) and not isinstance(value, bool): + if abs(value) > _MAX_SAFE_INTEGER: + raise TypeError(f"{field} contains an integer outside the safe domain") + return value + if isinstance(value, float): + if not math.isfinite(value): + raise TypeError(f"{field} contains a non-finite number") + return value + if type(value) is list: + identity = id(value) + if identity in ancestors: + raise TypeError(f"{field} must not contain cycles") + ancestors.add(identity) + array_result = [ + _snapshot_json(item, f"{field}[{index}]", ancestors) + for index, item in enumerate(value) + ] + ancestors.remove(identity) + return array_result + if type(value) is dict: + identity = id(value) + if identity in ancestors: + raise TypeError(f"{field} must not contain cycles") + ancestors.add(identity) + object_result: dict[str, JsonValue] = {} + for raw_key, item in value.items(): + if not isinstance(raw_key, str): + raise TypeError(f"{field} must use string object keys") + _assert_valid_unicode(raw_key, f"{field} key") + object_result[raw_key] = _snapshot_json( + item, f"{field}.{raw_key}", ancestors + ) + ancestors.remove(identity) + return object_result + raise TypeError(f"{field} contains unsupported {type(value).__name__} data") + + +def canonical_json(value: JsonValue) -> str: + """Return the worldcut-json-v1 canonical representation of JSON data.""" + + snapshot = _snapshot_json(value, "value", set()) + try: + return rfc8785.dumps(snapshot).decode("utf-8") + except (rfc8785.CanonicalizationError, UnicodeError) as error: + raise TypeError(f"cannot canonicalize JSON data: {error}") from error + + +def sha256_digest(value: JsonValue) -> str: + """Return the lowercase SHA-256 digest of canonical JSON data.""" + + return hashlib.sha256(canonical_json(value).encode("utf-8")).hexdigest() + + +def utf16_sort_key(value: str) -> bytes: + """Produce the protocol's raw UTF-16 code-unit ordering key.""" + + _assert_valid_unicode(value, "text") + return value.encode("utf-16-be") diff --git a/ports/python/src/worldcut/cli.py b/ports/python/src/worldcut/cli.py new file mode 100644 index 0000000..9200a69 --- /dev/null +++ b/ports/python/src/worldcut/cli.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +import json +import sys +from pathlib import Path + +from .errors import WorldCutError +from .verifier import verify_json + + +def _usage() -> str: + return "\n".join( + [ + "Usage: worldcut-py [--require-satisfied] ", + "", + "Options:", + " --require-satisfied Exit with code 2 unless the contract is satisfied", + " --help Show this help", + ] + ) + + +def _write_error(code: str, message: str) -> None: + print( + json.dumps({"error": {"code": code, "message": message}}), + file=sys.stderr, + ) + + +def run(arguments: list[str] | None = None) -> int: + """Run the WorldCut CLI and return its process exit status.""" + + arguments = list(sys.argv[1:] if arguments is None else arguments) + if "--help" in arguments: + print(_usage()) + return 0 + require_satisfied = False + positional: list[str] = [] + for argument in arguments: + if argument == "--require-satisfied": + require_satisfied = True + elif argument.startswith("-"): + _write_error("WORLDCUT_INVALID_ARGUMENT", f"Unknown option: {argument}") + return 1 + else: + positional.append(argument) + if len(positional) != 1: + _write_error( + "WORLDCUT_INVALID_ARGUMENT", + "Exactly one verification JSON file is required", + ) + return 1 + path = Path(positional[0]).resolve() + try: + source = path.read_bytes() + except OSError: + _write_error("WORLDCUT_FILE_READ_FAILED", f"Unable to read {path}") + return 1 + try: + result = verify_json(source) + except WorldCutError as error: + _write_error(error.code, str(error)) + return 1 + print(json.dumps(result, indent=2)) + if require_satisfied and result["verdict"] != "CONTRACT_SATISFIED": + return 2 + return 0 + + +def main() -> None: + """Console-script entry point.""" + + raise SystemExit(run()) + + +if __name__ == "__main__": + main() diff --git a/ports/python/src/worldcut/errors.py b/ports/python/src/worldcut/errors.py new file mode 100644 index 0000000..8954eca --- /dev/null +++ b/ports/python/src/worldcut/errors.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +from typing import Literal, TypeAlias + +WorldCutErrorCode: TypeAlias = Literal[ + "WORLDCUT_INVALID_INPUT", + "WORLDCUT_INVALID_ARGUMENT", + "WORLDCUT_FILE_READ_FAILED", + "WORLDCUT_RUNTIME_ERROR", +] + + +class WorldCutError(Exception): + """Base exception carrying a stable WorldCut error code.""" + + code: WorldCutErrorCode + + def __init__(self, code: WorldCutErrorCode, message: str) -> None: + super().__init__(message) + self.code = code + + +class WorldCutInputError(WorldCutError): + """Raised when transport data violates the WorldCut protocol.""" + + def __init__(self, message: str) -> None: + super().__init__("WORLDCUT_INVALID_INPUT", message) diff --git a/ports/python/src/worldcut/models.py b/ports/python/src/worldcut/models.py new file mode 100644 index 0000000..a531baa --- /dev/null +++ b/ports/python/src/worldcut/models.py @@ -0,0 +1,259 @@ +from __future__ import annotations + +from collections.abc import Mapping +from dataclasses import dataclass, field +from types import MappingProxyType +from typing import Literal, NotRequired, TypeAlias, TypedDict + +JsonPrimitive: TypeAlias = str | int | float | bool | None +JsonValue: TypeAlias = JsonPrimitive | list["JsonValue"] | dict[str, "JsonValue"] +FrozenJson: TypeAlias = ( + JsonPrimitive | tuple["FrozenJson", ...] | Mapping[str, "FrozenJson"] +) + +Provenance: TypeAlias = Literal[ + "provider_asserted", + "client_observed", + "derived", + "operator_supplied", +] +RequirementStatus: TypeAlias = Literal["SATISFIED", "VIOLATED", "UNKNOWN"] +ContractVerdict: TypeAlias = Literal[ + "CONTRACT_SATISFIED", + "CONTRACT_VIOLATED", + "INSUFFICIENT_EVIDENCE", +] +RequirementType: TypeAlias = Literal["dependency", "common_valid_time", "value_equals"] +AcquisitionActionType: TypeAlias = Literal[ + "REFRESH_OBSERVATION", + "FETCH_REQUIRED_METADATA", + "ACQUIRE_COMPATIBLE_EVIDENCE", +] + + +class AcquisitionAction(TypedDict): + id: str + type: AcquisitionActionType + role: str + cost: int + description: str + expected: JsonValue + + +class AcquisitionOption(TypedDict): + id: str + description: str + actions: list[AcquisitionAction] + + +class RequirementResult(TypedDict): + requirementId: str + requirementType: RequirementType + required: bool + status: RequirementStatus + summary: str + details: JsonValue + acquisitionOptions: list[AcquisitionOption] + + +class AcquisitionPlan(TypedDict): + status: Literal["NOT_NEEDED", "AVAILABLE", "INCOMPLETE"] + reason: str | None + actions: list[AcquisitionAction] + selectedOptionIds: list[str] + totalCost: int + coveredRequirementIds: list[str] + unresolvedRequirementIds: list[str] + + +class VerificationCoverage(TypedDict): + required: int + satisfied: int + violated: int + unknown: int + advisory: int + + +class VerificationResult(TypedDict): + protocolVersion: Literal["0.1"] + engineVersion: str + canonicalization: Literal["worldcut-json-v1"] + contractId: str + contractVersion: str + verdict: ContractVerdict + coverage: VerificationCoverage + requirementResults: list[RequirementResult] + acquisitionPlan: AcquisitionPlan + verificationRecordDigest: str + + +class ResourceInput(TypedDict): + provider: str + account: str + kind: str + key: str + + +class ValidityInput(TypedDict): + from_: str + until: str | None + + +class DependencyInput(TypedDict): + name: str + resource: ResourceInput + relation: Literal["exact"] + provenance: Provenance + version: NotRequired[str] + + +@dataclass(frozen=True, slots=True) +class ResourceIdentity: + provider: str + account: str + kind: str + key: str + + +@dataclass(frozen=True, slots=True, order=True) +class NormalizedTimestamp: + order: int + text: str = field(compare=False) + + +@dataclass(frozen=True, slots=True) +class ValidityInterval: + from_text: str + until_text: str | None + start: NormalizedTimestamp + end: NormalizedTimestamp | None + + +@dataclass(frozen=True, slots=True) +class DependencyWitness: + name: str + resource: ResourceIdentity + relation: Literal["exact"] + version: str | None + provenance: Provenance + + +@dataclass(frozen=True, slots=True) +class ObservationWitness: + provenance: Provenance + version: str | None + validity: ValidityInterval | None + dependencies: tuple[DependencyWitness, ...] + + +@dataclass(frozen=True, slots=True) +class Observation: + id: str + role: str + resource: ResourceIdentity + value: FrozenJson + observed_at_text: str + observed_at: NormalizedTimestamp + acquisition_cost: int + witness: ObservationWitness + raw: Mapping[str, FrozenJson] + + +@dataclass(frozen=True, slots=True) +class RequirementBase: + id: str + description: str + required: bool + raw: Mapping[str, FrozenJson] + + +@dataclass(frozen=True, slots=True) +class DependencyRequirement(RequirementBase): + type: Literal["dependency"] + dependent_role: str + target_role: str + dependency_name: str + + +@dataclass(frozen=True, slots=True) +class CommonValidTimeRequirement(RequirementBase): + type: Literal["common_valid_time"] + roles: tuple[str, ...] + within: ValidityInterval + + +@dataclass(frozen=True, slots=True) +class ValueEqualsRequirement(RequirementBase): + type: Literal["value_equals"] + role: str + path: tuple[str, ...] + expected: FrozenJson + + +Requirement: TypeAlias = ( + DependencyRequirement | CommonValidTimeRequirement | ValueEqualsRequirement +) + + +@dataclass(frozen=True, slots=True) +class Contract: + id: str + version: str + decision_time_text: str + decision_time: NormalizedTimestamp + requirements: tuple[Requirement, ...] + raw: Mapping[str, FrozenJson] + + +@dataclass(frozen=True, slots=True) +class _VerificationInput: + protocol_version: Literal["0.1"] + contract: Contract + observations: tuple[Observation, ...] + + +_PARSED_INPUT_TOKEN = object() + + +class ParsedInput: + """Opaque immutable handle returned by :func:`worldcut.parse_input`.""" + + __slots__ = ("__value",) + __value: _VerificationInput + + def __init__(self, value: _VerificationInput, token: object) -> None: + if token is not _PARSED_INPUT_TOKEN: + raise TypeError("ParsedInput must be produced by parse_input") + object.__setattr__(self, "_ParsedInput__value", value) + + def __setattr__(self, name: str, value: object) -> None: + raise AttributeError("ParsedInput is immutable") + + def _unwrap(self) -> _VerificationInput: + return self.__value + + +def _new_parsed_input(value: _VerificationInput) -> ParsedInput: + return ParsedInput(value, _PARSED_INPUT_TOKEN) + + +def _unwrap_parsed_input(value: ParsedInput) -> _VerificationInput: + if not isinstance(value, ParsedInput): + raise TypeError("verification input must be produced by parse_input") + return value._unwrap() + + +def freeze_json(value: JsonValue) -> FrozenJson: + if isinstance(value, dict): + return MappingProxyType({key: freeze_json(item) for key, item in value.items()}) + if isinstance(value, list): + return tuple(freeze_json(item) for item in value) + return value + + +def thaw_json(value: FrozenJson) -> JsonValue: + if isinstance(value, Mapping): + return {key: thaw_json(item) for key, item in value.items()} + if isinstance(value, tuple): + return [thaw_json(item) for item in value] + return value diff --git a/ports/python/src/worldcut/planning.py b/ports/python/src/worldcut/planning.py new file mode 100644 index 0000000..84e706e --- /dev/null +++ b/ports/python/src/worldcut/planning.py @@ -0,0 +1,181 @@ +from __future__ import annotations + +from dataclasses import dataclass + +from .canonicalization import utf16_sort_key +from .errors import WorldCutInputError +from .models import AcquisitionAction, AcquisitionPlan, RequirementResult + +MAX_UNRESOLVED_REQUIREMENTS = 64 +MAX_OPTION_COMBINATIONS = 65_536 +MAX_SEARCH_STATES = (MAX_UNRESOLVED_REQUIREMENTS + 1) * MAX_OPTION_COMBINATIONS +MAX_ACQUISITION_COST = 1_000_000_000 +MAX_PLAN_TOTAL_COST = 64_000_000_000 + + +@dataclass(slots=True) +class _SearchState: + index: int + option_ids: list[str] + actions: dict[str, AcquisitionAction] + cost: int + + +@dataclass(slots=True) +class _Candidate: + option_ids: list[str] + actions: list[AcquisitionAction] + cost: int + + +def _candidate_key(candidate: _Candidate) -> tuple[int, int, bytes]: + return ( + candidate.cost, + len(candidate.actions), + utf16_sort_key("\0".join(candidate.option_ids)), + ) + + +def _incomplete(reason: str, unresolved: list[RequirementResult]) -> AcquisitionPlan: + return { + "status": "INCOMPLETE", + "reason": reason, + "actions": [], + "selectedOptionIds": [], + "totalCost": 0, + "coveredRequirementIds": [], + "unresolvedRequirementIds": [result["requirementId"] for result in unresolved], + } + + +def _add_option( + state: _SearchState, option_id: str, option_actions: list[AcquisitionAction] +) -> _SearchState: + actions = dict(state.actions) + cost = state.cost + for action in option_actions: + action_cost = action["cost"] + if action_cost < 0 or action_cost > MAX_ACQUISITION_COST: + raise WorldCutInputError( + f"Acquisition action {action['id']} cost must be between 0 and " + f"{MAX_ACQUISITION_COST}" + ) + existing = actions.get(action["id"]) + if existing is not None: + if existing["cost"] != action_cost: + raise RuntimeError( + f"Acquisition action {action['id']} has conflicting declared costs" + ) + continue + if cost > MAX_PLAN_TOTAL_COST - action_cost: + raise WorldCutInputError( + f"Acquisition plan cost exceeds {MAX_PLAN_TOTAL_COST}" + ) + actions[action["id"]] = action + cost += action_cost + return _SearchState( + index=state.index + 1, + option_ids=[*state.option_ids, option_id], + actions=actions, + cost=cost, + ) + + +def select_acquisition_plan( + requirement_results: list[RequirementResult], +) -> AcquisitionPlan: + """Select the exact minimum-cost acquisition plan within protocol limits.""" + + unresolved = sorted( + ( + result + for result in requirement_results + if result["required"] and result["status"] != "SATISFIED" + ), + key=lambda result: utf16_sort_key(result["requirementId"]), + ) + if not unresolved: + return { + "status": "NOT_NEEDED", + "reason": None, + "actions": [], + "selectedOptionIds": [], + "totalCost": 0, + "coveredRequirementIds": [], + "unresolvedRequirementIds": [], + } + if len(unresolved) > MAX_UNRESOLVED_REQUIREMENTS: + return _incomplete( + "Acquisition planning supports at most 64 unresolved requirements.", + unresolved, + ) + + coverable: list[RequirementResult] = [] + impossible: list[str] = [] + combinations = 1 + for result in unresolved: + options = result["acquisitionOptions"] + if not options: + impossible.append(result["requirementId"]) + continue + if combinations > MAX_OPTION_COMBINATIONS // len(options): + return _incomplete( + "Acquisition search exceeds the 65536 combination limit.", + unresolved, + ) + combinations *= len(options) + coverable.append(result) + + stack = [_SearchState(index=0, option_ids=[], actions={}, cost=0)] + best: _Candidate | None = None + visited = 0 + while stack: + visited += 1 + if visited > MAX_SEARCH_STATES: + return _incomplete( + "Acquisition search exceeds the 4259840 state limit.", + unresolved, + ) + state = stack.pop() + if best is not None and state.cost > best.cost: + continue + if state.index >= len(coverable): + candidate = _Candidate( + option_ids=sorted(state.option_ids, key=utf16_sort_key), + actions=sorted( + state.actions.values(), + key=lambda action: utf16_sort_key(action["id"]), + ), + cost=state.cost, + ) + if best is None or _candidate_key(candidate) < _candidate_key(best): + best = candidate + continue + options = sorted( + coverable[state.index]["acquisitionOptions"], + key=lambda option: utf16_sort_key(option["id"]), + ) + for option in reversed(options): + next_state = _add_option(state, option["id"], option["actions"]) + if best is None or next_state.cost <= best.cost: + stack.append(next_state) + + if best is None: + return _incomplete( + "Acquisition search completed without a valid option set.", + unresolved, + ) + impossible.sort(key=utf16_sort_key) + return { + "status": "AVAILABLE" if not impossible else "INCOMPLETE", + "reason": ( + None + if not impossible + else (f"No acquisition option is available for: {', '.join(impossible)}.") + ), + "actions": best.actions, + "selectedOptionIds": best.option_ids, + "totalCost": best.cost, + "coveredRequirementIds": [result["requirementId"] for result in coverable], + "unresolvedRequirementIds": impossible, + } diff --git a/ports/python/src/worldcut/py.typed b/ports/python/src/worldcut/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/ports/python/src/worldcut/requirements.py b/ports/python/src/worldcut/requirements.py new file mode 100644 index 0000000..2d8d2bb --- /dev/null +++ b/ports/python/src/worldcut/requirements.py @@ -0,0 +1,600 @@ +from __future__ import annotations + +import re +from collections.abc import Mapping +from typing import cast + +from .canonicalization import canonical_json, sha256_digest +from .models import ( + AcquisitionAction, + AcquisitionActionType, + AcquisitionOption, + CommonValidTimeRequirement, + DependencyRequirement, + FrozenJson, + JsonValue, + NormalizedTimestamp, + Observation, + Requirement, + RequirementResult, + ResourceIdentity, + ValidityInterval, + ValueEqualsRequirement, + thaw_json, +) + +_CANONICAL_ARRAY_INDEX = re.compile(r"^(0|[1-9][0-9]*)$") + + +def _resource_json(resource: ResourceIdentity) -> JsonValue: + return { + "provider": resource.provider, + "account": resource.account, + "kind": resource.kind, + "key": resource.key, + } + + +def _interval_json(interval: ValidityInterval) -> JsonValue: + return {"from": interval.from_text, "until": interval.until_text} + + +def _action( + action_type: AcquisitionActionType, + observation: Observation | None, + role: str, + description: str, + expected: JsonValue, +) -> AcquisitionAction: + if observation is None: + cost = 1 + elif action_type == "FETCH_REQUIRED_METADATA": + cost = max(1, (observation.acquisition_cost + 3) // 4) + else: + cost = observation.acquisition_cost + expected_digest = "none" if expected is None else sha256_digest(expected)[:12] + return { + "id": f"{action_type.lower()}:{role}:{expected_digest}", + "type": action_type, + "role": role, + "cost": cost, + "description": description, + "expected": expected, + } + + +def _option( + requirement_id: str, + suffix: str, + description: str, + actions: list[AcquisitionAction], +) -> AcquisitionOption: + return { + "id": f"{requirement_id}:{suffix}", + "description": description, + "actions": actions, + } + + +def _missing_roles_result( + requirement: Requirement, roles: list[str] +) -> RequirementResult: + actions = [ + _action( + "REFRESH_OBSERVATION", + None, + role, + f"Acquire an observation for role {role}.", + None, + ) + for role in roles + ] + return { + "requirementId": requirement.id, + "requirementType": requirement.type, + "required": requirement.required, + "status": "UNKNOWN", + "summary": ( + f"No observations are bound to required role(s): {', '.join(roles)}." + ), + "details": {"missingRoles": cast(list[JsonValue], roles)}, + "acquisitionOptions": [ + _option( + requirement.id, + "acquire-missing-roles", + "Acquire every missing role required to evaluate this requirement.", + actions, + ) + ], + } + + +def evaluate_dependency( + requirement: DependencyRequirement, + observations: Mapping[str, Observation], +) -> RequirementResult: + missing_roles = [ + role + for role in (requirement.dependent_role, requirement.target_role) + if role not in observations + ] + if missing_roles: + return _missing_roles_result(requirement, missing_roles) + dependent = observations[requirement.dependent_role] + target = observations[requirement.target_role] + dependency = next( + ( + candidate + for candidate in dependent.witness.dependencies + if candidate.name == requirement.dependency_name + ), + None, + ) + if dependency is None: + actions = [ + _action( + "FETCH_REQUIRED_METADATA", + dependent, + dependent.role, + f"Fetch dependency metadata for {dependent.role}.", + { + "dependencyName": requirement.dependency_name, + "targetResource": _resource_json(target.resource), + }, + ) + ] + if target.witness.version is None: + actions.append( + _action( + "FETCH_REQUIRED_METADATA", + target, + target.role, + f"Fetch the resource version for {target.role}.", + None, + ) + ) + return { + "requirementId": requirement.id, + "requirementType": requirement.type, + "required": requirement.required, + "status": "UNKNOWN", + "summary": ( + f"{dependent.role} does not expose dependency " + f"{requirement.dependency_name}." + ), + "details": { + "dependentRole": dependent.role, + "targetRole": target.role, + "missingDependency": requirement.dependency_name, + }, + "acquisitionOptions": [ + _option( + requirement.id, + "fetch-dependency-metadata", + "Fetch all metadata required to compare the dependency.", + actions, + ) + ], + } + if dependency.resource != target.resource: + return { + "requirementId": requirement.id, + "requirementType": requirement.type, + "required": requirement.required, + "status": "VIOLATED", + "summary": ( + f"{dependent.role} is bound to a different resource than {target.role}." + ), + "details": { + "dependentResource": _resource_json(dependency.resource), + "targetResource": _resource_json(target.resource), + }, + "acquisitionOptions": [ + _option( + requirement.id, + "acquire-compatible-resource", + ( + "Acquire dependent evidence bound to the selected " + "target resource." + ), + [ + _action( + "ACQUIRE_COMPATIBLE_EVIDENCE", + dependent, + dependent.role, + ( + f"Acquire {dependent.role} evidence for the " + f"selected {target.role} resource." + ), + {"targetResource": _resource_json(target.resource)}, + ) + ], + ) + ], + } + if dependency.version is None or target.witness.version is None: + actions = [] + if dependency.version is None: + actions.append( + _action( + "FETCH_REQUIRED_METADATA", + dependent, + dependent.role, + f"Fetch the dependency version for {dependent.role}.", + {"dependencyName": requirement.dependency_name}, + ) + ) + if target.witness.version is None: + actions.append( + _action( + "FETCH_REQUIRED_METADATA", + target, + target.role, + f"Fetch the resource version for {target.role}.", + None, + ) + ) + return { + "requirementId": requirement.id, + "requirementType": requirement.type, + "required": requirement.required, + "status": "UNKNOWN", + "summary": ( + f"Version evidence is incomplete for {requirement.description}." + ), + "details": { + "dependencyVersion": dependency.version, + "targetVersion": target.witness.version, + }, + "acquisitionOptions": [ + _option( + requirement.id, + "fetch-all-version-metadata", + "Fetch every missing version needed for this comparison.", + actions, + ) + ], + } + dependency_version = dependency.version + target_version = target.witness.version + if dependency_version != target_version: + return { + "requirementId": requirement.id, + "requirementType": requirement.type, + "required": requirement.required, + "status": "VIOLATED", + "summary": ( + f"{requirement.description}: {dependency_version} does not equal " + f"{target_version}." + ), + "details": { + "dependentRole": dependent.role, + "dependencyVersion": dependency_version, + "targetRole": target.role, + "targetVersion": target_version, + "relation": dependency.relation, + }, + "acquisitionOptions": [ + _option( + requirement.id, + "acquire-compatible-dependent", + ( + "Acquire dependent evidence bound to the selected " + "target version." + ), + [ + _action( + "ACQUIRE_COMPATIBLE_EVIDENCE", + dependent, + dependent.role, + ( + f"Acquire {dependent.role} evidence bound to " + f"{target_version}." + ), + { + "targetRole": target.role, + "targetVersion": target_version, + }, + ) + ], + ), + _option( + requirement.id, + "refresh-target", + "Refresh the target before selecting compatible evidence.", + [ + _action( + "REFRESH_OBSERVATION", + target, + target.role, + ( + f"Refresh {target.role} before selecting " + "compatible evidence." + ), + { + "dependentRole": dependent.role, + "dependentVersion": dependency_version, + }, + ) + ], + ), + ], + } + return { + "requirementId": requirement.id, + "requirementType": requirement.type, + "required": requirement.required, + "status": "SATISFIED", + "summary": ( + f"{requirement.description}: both roles are bound to {dependency_version}." + ), + "details": { + "dependentRole": dependent.role, + "targetRole": target.role, + "version": dependency_version, + }, + "acquisitionOptions": [], + } + + +def evaluate_common_valid_time( + requirement: CommonValidTimeRequirement, + observations_by_role: Mapping[str, Observation], +) -> RequirementResult: + missing_roles = [ + role for role in requirement.roles if role not in observations_by_role + ] + observations = [ + observations_by_role[role] + for role in requirement.roles + if role in observations_by_role + ] + missing_validity = [ + observation + for observation in observations + if observation.witness.validity is None + ] + prerequisite_actions = [ + _action( + "REFRESH_OBSERVATION", + None, + role, + f"Acquire an observation for role {role}.", + None, + ) + for role in missing_roles + ] + prerequisite_actions.extend( + _action( + "FETCH_REQUIRED_METADATA", + observation, + observation.role, + f"Fetch validity metadata for {observation.role}.", + {"within": _interval_json(requirement.within)}, + ) + for observation in missing_validity + ) + + latest_start = requirement.within.start + earliest_end = requirement.within.end + for observation in observations: + validity = observation.witness.validity + if validity is None: + continue + latest_start = max(latest_start, validity.start) + if validity.end is not None: + earliest_end = ( + validity.end + if earliest_end is None + else min(earliest_end, validity.end) + ) + + missing_validity_roles = [observation.role for observation in missing_validity] + if earliest_end is not None and latest_start >= earliest_end: + options = [] + for observation in observations: + refresh = _action( + "REFRESH_OBSERVATION", + observation, + observation.role, + (f"Refresh {observation.role} to seek a compatible validity window."), + {"within": _interval_json(requirement.within)}, + ) + options.append( + _option( + requirement.id, + f"refresh-{observation.role}", + ( + f"Refresh {observation.role} and acquire every other " + "missing prerequisite." + ), + [refresh, *prerequisite_actions], + ) + ) + return { + "requirementId": requirement.id, + "requirementType": requirement.type, + "required": requirement.required, + "status": "VIOLATED", + "summary": ( + f"{requirement.description}: the known validity intervals " + "do not overlap." + ), + "details": { + "roles": cast(list[JsonValue], list(requirement.roles)), + "latestStart": _format_timestamp(latest_start), + "earliestEnd": _format_timestamp(earliest_end), + "missingRoles": cast(list[JsonValue], missing_roles), + "missingValidityRoles": cast(list[JsonValue], missing_validity_roles), + }, + "acquisitionOptions": options, + } + + end_text = _format_timestamp(earliest_end) if earliest_end is not None else None + if missing_roles or missing_validity: + return { + "requirementId": requirement.id, + "requirementType": requirement.type, + "required": requirement.required, + "status": "UNKNOWN", + "summary": f"{requirement.description}: validity evidence is incomplete.", + "details": { + "roles": cast(list[JsonValue], list(requirement.roles)), + "missingRoles": cast(list[JsonValue], missing_roles), + "missingValidityRoles": cast(list[JsonValue], missing_validity_roles), + "possibleKnownWindow": { + "from": _format_timestamp(latest_start), + "until": end_text, + }, + }, + "acquisitionOptions": [ + _option( + requirement.id, + "acquire-all-validity-prerequisites", + "Acquire every missing observation and validity witness.", + prerequisite_actions, + ) + ], + } + return { + "requirementId": requirement.id, + "requirementType": requirement.type, + "required": requirement.required, + "status": "SATISFIED", + "summary": f"{requirement.description}: a common valid time exists.", + "details": { + "roles": list(requirement.roles), + "commonWindow": { + "from": _format_timestamp(latest_start), + "until": end_text, + }, + }, + "acquisitionOptions": [], + } + + +def _format_timestamp(value: NormalizedTimestamp) -> str: + return value.text + + +def _value_at_path(value: FrozenJson, path: tuple[str, ...]) -> tuple[bool, FrozenJson]: + current = value + for segment in path: + if isinstance(current, tuple): + if _CANONICAL_ARRAY_INDEX.fullmatch(segment) is None: + return False, None + index = int(segment) + if index >= len(current): + return False, None + current = current[index] + elif isinstance(current, Mapping): + if segment not in current: + return False, None + current = current[segment] + else: + return False, None + return True, current + + +def evaluate_value_equals( + requirement: ValueEqualsRequirement, + observations: Mapping[str, Observation], +) -> RequirementResult: + if requirement.role not in observations: + return _missing_roles_result(requirement, [requirement.role]) + observation = observations[requirement.role] + display_path = ".".join(requirement.path) + found, frozen_actual = _value_at_path(observation.value, requirement.path) + expected = thaw_json(requirement.expected) + if not found: + return { + "requirementId": requirement.id, + "requirementType": requirement.type, + "required": requirement.required, + "status": "UNKNOWN", + "summary": ( + f"{requirement.description}: value path {display_path} is missing." + ), + "details": { + "role": requirement.role, + "path": list(requirement.path), + "expected": expected, + }, + "acquisitionOptions": [ + _option( + requirement.id, + "acquire-value", + "Acquire evidence containing the required value path.", + [ + _action( + "ACQUIRE_COMPATIBLE_EVIDENCE", + observation, + observation.role, + ( + f"Acquire {observation.role} evidence containing " + f"{display_path}." + ), + { + "path": list(requirement.path), + "expected": thaw_json(requirement.expected), + }, + ) + ], + ) + ], + } + actual = thaw_json(frozen_actual) + if canonical_json(actual) != canonical_json(expected): + return { + "requirementId": requirement.id, + "requirementType": requirement.type, + "required": requirement.required, + "status": "VIOLATED", + "summary": ( + f"{requirement.description}: observed value does not equal " + "the required value." + ), + "details": { + "role": requirement.role, + "path": list(requirement.path), + "expected": expected, + "actual": actual, + }, + "acquisitionOptions": [ + _option( + requirement.id, + "refresh-value", + "Refresh the observation before evaluating the value again.", + [ + _action( + "REFRESH_OBSERVATION", + observation, + observation.role, + ( + f"Refresh {observation.role} before evaluating " + f"{display_path}." + ), + { + "path": list(requirement.path), + "expected": thaw_json(requirement.expected), + }, + ) + ], + ) + ], + } + return { + "requirementId": requirement.id, + "requirementType": requirement.type, + "required": requirement.required, + "status": "SATISFIED", + "summary": ( + f"{requirement.description}: observed value matches the requirement." + ), + "details": { + "role": requirement.role, + "path": list(requirement.path), + "expected": expected, + }, + "acquisitionOptions": [], + } diff --git a/ports/python/src/worldcut/validation.py b/ports/python/src/worldcut/validation.py new file mode 100644 index 0000000..00d2390 --- /dev/null +++ b/ports/python/src/worldcut/validation.py @@ -0,0 +1,524 @@ +from __future__ import annotations + +import json +import math +import re +from collections.abc import Mapping +from typing import Literal, cast + +from .errors import WorldCutInputError +from .models import ( + CommonValidTimeRequirement, + Contract, + DependencyRequirement, + DependencyWitness, + FrozenJson, + JsonValue, + NormalizedTimestamp, + Observation, + ObservationWitness, + ParsedInput, + Provenance, + Requirement, + ResourceIdentity, + ValidityInterval, + ValueEqualsRequirement, + _new_parsed_input, + _VerificationInput, + freeze_json, +) + +PROTOCOL_VERSION: Literal["0.1"] = "0.1" +MAX_ACQUISITION_COST = 1_000_000_000 +_MAX_SAFE_INTEGER = 9_007_199_254_740_991 +_TIMESTAMP = re.compile( + r"^(?P\d{4})-(?P\d{2})-(?P\d{2})T" + r"(?P\d{2}):(?P\d{2}):(?P\d{2})\." + r"(?P\d{3})Z$" +) +_PROVENANCE = { + "provider_asserted", + "client_observed", + "derived", + "operator_supplied", +} + + +def _validate_raw_unicode(source: bytes) -> str: + try: + text = source.decode("utf-8", errors="strict") + except UnicodeDecodeError as error: + raise ValueError("input is not valid UTF-8") from error + + in_string = False + index = 0 + while index < len(text): + character = text[index] + if not in_string: + if character == '"': + in_string = True + index += 1 + continue + if character == '"': + in_string = False + index += 1 + continue + if character != "\\": + if 0xD800 <= ord(character) <= 0xDFFF: + raise ValueError("input contains an unpaired surrogate") + index += 1 + continue + index += 1 + if index >= len(text): + raise ValueError("unterminated JSON escape") + if text[index] != "u": + index += 1 + continue + escape_start = index + 1 + escape_end = escape_start + 4 + if escape_end > len(text): + raise ValueError("incomplete Unicode escape") + try: + code_unit = int(text[escape_start:escape_end], 16) + except ValueError as error: + raise ValueError("invalid Unicode escape") from error + index = escape_end + if 0xD800 <= code_unit <= 0xDBFF: + if text[index : index + 2] != "\\u" or index + 6 > len(text): + raise ValueError("unpaired high surrogate") + try: + low = int(text[index + 2 : index + 6], 16) + except ValueError as error: + raise ValueError("unpaired high surrogate") from error + if not 0xDC00 <= low <= 0xDFFF: + raise ValueError("unpaired high surrogate") + index += 6 + elif 0xDC00 <= code_unit <= 0xDFFF: + raise ValueError("unpaired low surrogate") + return text + + +def _parse_number(text: str) -> int | float: + number = float(text) + if not math.isfinite(number): + raise ValueError(f"invalid JSON number {text!r}") + if number.is_integer() and abs(number) <= _MAX_SAFE_INTEGER: + return int(number) + return number + + +def _reject_constant(text: str) -> JsonValue: + raise ValueError(f"invalid JSON constant {text}") + + +def _decode_json(source: bytes) -> JsonValue: + text = _validate_raw_unicode(source) + value = json.loads( + text, + parse_int=_parse_number, + parse_float=_parse_number, + parse_constant=_reject_constant, + ) + return cast(JsonValue, value) + + +def _record(value: JsonValue, field: str) -> dict[str, JsonValue]: + if type(value) is not dict: + raise ValueError(f"{field} must be a plain object") + return value + + +def _array(value: JsonValue, field: str) -> list[JsonValue]: + if type(value) is not list: + raise ValueError(f"{field} must be an array") + return value + + +def _exact_keys(record: Mapping[str, JsonValue], allowed: set[str], field: str) -> None: + unknown = [key for key in record if key not in allowed] + if unknown: + raise ValueError(f"{field} contains unsupported field(s): {', '.join(unknown)}") + + +def _required_keys( + record: Mapping[str, JsonValue], required: tuple[str, ...], field: str +) -> None: + missing = [key for key in required if key not in record] + if missing: + raise ValueError(f"{field} is missing required field(s): {', '.join(missing)}") + + +def _non_empty_string(value: JsonValue, field: str) -> str: + if not isinstance(value, str) or not value: + raise ValueError(f"{field} must not be empty") + return value + + +def _timestamp(value: JsonValue, field: str) -> tuple[str, NormalizedTimestamp]: + text = _non_empty_string(value, field) + match = _TIMESTAMP.fullmatch(text) + if match is None: + raise ValueError( + f"{field} must use normalized ISO-8601 UTC form with milliseconds" + ) + parts = {name: int(raw) for name, raw in match.groupdict().items()} + year = parts["year"] + month = parts["month"] + leap = year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) + month_lengths = (31, 29 if leap else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) + if ( + month < 1 + or month > 12 + or parts["day"] < 1 + or parts["day"] > month_lengths[month - 1] + or parts["hour"] > 23 + or parts["minute"] > 59 + or parts["second"] > 59 + ): + raise ValueError( + f"{field} must use normalized ISO-8601 UTC form with milliseconds" + ) + order = year + for component, radix in ( + (month, 13), + (parts["day"], 32), + (parts["hour"], 24), + (parts["minute"], 60), + (parts["second"], 60), + (parts["millisecond"], 1000), + ): + order = order * radix + component + return text, NormalizedTimestamp(order=order, text=text) + + +def _resource(value: JsonValue, field: str) -> ResourceIdentity: + record = _record(value, field) + keys = {"provider", "account", "kind", "key"} + _exact_keys(record, keys, field) + _required_keys(record, ("provider", "account", "kind", "key"), field) + return ResourceIdentity( + provider=_non_empty_string(record["provider"], f"{field}.provider"), + account=_non_empty_string(record["account"], f"{field}.account"), + kind=_non_empty_string(record["kind"], f"{field}.kind"), + key=_non_empty_string(record["key"], f"{field}.key"), + ) + + +def _interval(value: JsonValue, field: str) -> ValidityInterval: + record = _record(value, field) + _exact_keys(record, {"from", "until"}, field) + _required_keys(record, ("from", "until"), field) + from_text, start = _timestamp(record["from"], f"{field}.from") + until_value = record["until"] + if until_value is None: + return ValidityInterval(from_text, None, start, None) + until_text, end = _timestamp(until_value, f"{field}.until") + if end <= start: + raise ValueError(f"{field} must be a non-empty half-open interval") + return ValidityInterval(from_text, until_text, start, end) + + +def _provenance(value: JsonValue, field: str) -> Provenance: + text = _non_empty_string(value, field) + if text not in _PROVENANCE: + raise ValueError(f"{field} is not a supported provenance category") + return cast(Provenance, text) + + +def _dependency(value: JsonValue, role: str) -> DependencyWitness: + field = f"{role}.dependency" + record = _record(value, field) + _exact_keys( + record, {"name", "resource", "relation", "version", "provenance"}, field + ) + _required_keys(record, ("name", "resource", "relation", "provenance"), field) + name = _non_empty_string(record["name"], "dependency.name") + relation = _non_empty_string( + record["relation"], f"{role}.dependency.{name}.relation" + ) + if relation != "exact": + raise ValueError(f"{role}.dependency.{name}.relation is unsupported") + version = ( + _non_empty_string(record["version"], f"{role}.dependency.{name}.version") + if "version" in record + else None + ) + return DependencyWitness( + name=name, + resource=_resource(record["resource"], f"{role}.dependency.{name}.resource"), + relation="exact", + version=version, + provenance=_provenance( + record["provenance"], f"{role}.dependency.{name}.provenance" + ), + ) + + +def _witness(value: JsonValue, role: str) -> ObservationWitness: + field = f"{role}.witness" + record = _record(value, field) + _exact_keys(record, {"provenance", "version", "validity", "dependencies"}, field) + _required_keys(record, ("provenance",), field) + version = ( + _non_empty_string(record["version"], f"{field}.version") + if "version" in record + else None + ) + validity = ( + _interval(record["validity"], f"{field}.validity") + if "validity" in record + else None + ) + dependencies: list[DependencyWitness] = [] + names: set[str] = set() + if "dependencies" in record: + for raw_dependency in _array(record["dependencies"], f"{field}.dependencies"): + dependency = _dependency(raw_dependency, role) + if dependency.name in names: + raise ValueError( + f"Duplicate dependency {dependency.name} on role {role}" + ) + names.add(dependency.name) + dependencies.append(dependency) + return ObservationWitness( + provenance=_provenance(record["provenance"], f"{field}.provenance"), + version=version, + validity=validity, + dependencies=tuple(dependencies), + ) + + +def _observation(value: JsonValue) -> Observation: + record = _record(value, "observation") + allowed = { + "id", + "role", + "resource", + "value", + "observedAt", + "acquisitionCost", + "witness", + } + _exact_keys(record, allowed, "observation") + _required_keys(record, tuple(sorted(allowed)), "observation") + identifier = _non_empty_string(record["id"], "observation.id") + role = _non_empty_string(record["role"], "observation.role") + observed_at_text, observed_at = _timestamp( + record["observedAt"], f"{role}.observedAt" + ) + cost = record["acquisitionCost"] + if isinstance(cost, bool) or not isinstance(cost, int): + raise ValueError( + f"{role}.acquisitionCost must be between 0 and {MAX_ACQUISITION_COST}" + ) + if cost < 0 or cost > MAX_ACQUISITION_COST: + raise ValueError( + f"{role}.acquisitionCost must be between 0 and {MAX_ACQUISITION_COST}" + ) + return Observation( + id=identifier, + role=role, + resource=_resource(record["resource"], f"{role}.resource"), + value=freeze_json(record["value"]), + observed_at_text=observed_at_text, + observed_at=observed_at, + acquisition_cost=cost, + witness=_witness(record["witness"], role), + raw=cast(Mapping[str, FrozenJson], freeze_json(record)), + ) + + +def _required_flag(record: Mapping[str, JsonValue], identifier: str) -> bool: + if "required" not in record: + return True + required = record["required"] + if not isinstance(required, bool): + raise ValueError(f"{identifier}.required must be boolean") + return required + + +def _requirement(value: JsonValue) -> Requirement: + record = _record(value, "requirement") + _required_keys(record, ("id", "description", "type"), "requirement") + identifier = _non_empty_string(record["id"], "requirement.id") + description = _non_empty_string(record["description"], f"{identifier}.description") + requirement_type = _non_empty_string(record["type"], f"{identifier}.type") + required = _required_flag(record, identifier) + frozen_raw = cast(Mapping[str, FrozenJson], freeze_json(record)) + if requirement_type == "dependency": + _exact_keys( + record, + { + "id", + "description", + "required", + "type", + "dependentRole", + "targetRole", + "dependencyName", + }, + identifier, + ) + _required_keys( + record, ("dependentRole", "targetRole", "dependencyName"), identifier + ) + return DependencyRequirement( + id=identifier, + description=description, + required=required, + raw=frozen_raw, + type="dependency", + dependent_role=_non_empty_string( + record["dependentRole"], f"{identifier}.dependentRole" + ), + target_role=_non_empty_string( + record["targetRole"], f"{identifier}.targetRole" + ), + dependency_name=_non_empty_string( + record["dependencyName"], f"{identifier}.dependencyName" + ), + ) + if requirement_type == "common_valid_time": + _exact_keys( + record, + {"id", "description", "required", "type", "roles", "within"}, + identifier, + ) + _required_keys(record, ("roles", "within"), identifier) + role_values = _array(record["roles"], f"{identifier}.roles") + if len(role_values) < 2: + raise ValueError(f"{identifier} must reference at least two roles") + roles: list[str] = [] + seen: set[str] = set() + for raw_role in role_values: + role = _non_empty_string(raw_role, f"{identifier}.role") + if role in seen: + raise ValueError(f"{identifier} contains duplicate role {role}") + seen.add(role) + roles.append(role) + return CommonValidTimeRequirement( + id=identifier, + description=description, + required=required, + raw=frozen_raw, + type="common_valid_time", + roles=tuple(roles), + within=_interval(record["within"], f"{identifier}.within"), + ) + if requirement_type == "value_equals": + _exact_keys( + record, + {"id", "description", "required", "type", "role", "path", "expected"}, + identifier, + ) + _required_keys(record, ("role", "path", "expected"), identifier) + path_values = _array(record["path"], f"{identifier}.path") + if not path_values: + raise ValueError(f"{identifier}.path must contain at least one segment") + path = tuple( + _non_empty_string(segment, f"{identifier}.path segment") + for segment in path_values + ) + return ValueEqualsRequirement( + id=identifier, + description=description, + required=required, + raw=frozen_raw, + type="value_equals", + role=_non_empty_string(record["role"], f"{identifier}.role"), + path=path, + expected=freeze_json(record["expected"]), + ) + raise ValueError(f"Unsupported requirement type: {requirement_type}") + + +def _contract(value: JsonValue) -> Contract: + record = _record(value, "contract") + allowed = {"id", "version", "decisionTime", "assumptions", "requirements"} + _exact_keys(record, allowed, "contract") + _required_keys(record, tuple(sorted(allowed)), "contract") + identifier = _non_empty_string(record["id"], "contract.id") + version = _non_empty_string(record["version"], "contract.version") + decision_time_text, decision_time = _timestamp( + record["decisionTime"], "contract.decisionTime" + ) + assumptions = _record(record["assumptions"], "contract.assumptions") + assumption_keys = {"clockModel", "intervalModel", "metadataModel"} + _exact_keys(assumptions, assumption_keys, "contract.assumptions") + _required_keys(assumptions, tuple(sorted(assumption_keys)), "contract.assumptions") + if ( + assumptions["clockModel"] != "trusted_normalized" + or assumptions["intervalModel"] != "half_open" + or assumptions["metadataModel"] != "honest_but_possibly_incomplete" + ): + raise ValueError("contract assumptions are not supported by this engine") + requirements: list[Requirement] = [] + identifiers: set[str] = set() + required_count = 0 + for raw_requirement in _array(record["requirements"], "contract.requirements"): + requirement = _requirement(raw_requirement) + if requirement.id in identifiers: + raise ValueError(f"Duplicate requirement id: {requirement.id}") + identifiers.add(requirement.id) + required_count += int(requirement.required) + requirements.append(requirement) + if required_count == 0: + raise ValueError( + "A decision contract must contain at least one required requirement" + ) + return Contract( + id=identifier, + version=version, + decision_time_text=decision_time_text, + decision_time=decision_time, + requirements=tuple(requirements), + raw=cast(Mapping[str, FrozenJson], freeze_json(record)), + ) + + +def _validate_input(value: JsonValue) -> _VerificationInput: + root = _record(value, "input") + allowed = {"protocolVersion", "contract", "observations"} + _exact_keys(root, allowed, "input") + _required_keys(root, tuple(sorted(allowed)), "input") + if root["protocolVersion"] != PROTOCOL_VERSION: + raise ValueError("input.protocolVersion must equal 0.1") + contract = _contract(root["contract"]) + observations: list[Observation] = [] + identifiers: set[str] = set() + roles: set[str] = set() + for raw_observation in _array(root["observations"], "observations"): + observation = _observation(raw_observation) + if observation.id in identifiers: + raise ValueError(f"Duplicate observation id: {observation.id}") + if observation.role in roles: + raise ValueError(f"Duplicate observation role: {observation.role}") + if observation.observed_at > contract.decision_time: + raise ValueError( + f"{observation.role}.observedAt must not be after contract.decisionTime" + ) + identifiers.add(observation.id) + roles.add(observation.role) + observations.append(observation) + return _VerificationInput( + protocol_version="0.1", + contract=contract, + observations=tuple(observations), + ) + + +def parse_input(source: str | bytes | bytearray) -> ParsedInput: + """Parse, validate, and immutably snapshot one WorldCut verification input.""" + + if isinstance(source, str): + raw = source.encode("utf-8", errors="surrogatepass") + elif isinstance(source, bytes): + raw = source + elif isinstance(source, bytearray): + raw = bytes(source) + else: + raise TypeError("source must be str, bytes, or bytearray") + try: + return _new_parsed_input(_validate_input(_decode_json(raw))) + except (ValueError, json.JSONDecodeError, RecursionError) as error: + raise WorldCutInputError(str(error)) from error diff --git a/ports/python/src/worldcut/verifier.py b/ports/python/src/worldcut/verifier.py new file mode 100644 index 0000000..36cf5ff --- /dev/null +++ b/ports/python/src/worldcut/verifier.py @@ -0,0 +1,116 @@ +from __future__ import annotations + +from typing import Literal, cast + +from .canonicalization import sha256_digest, utf16_sort_key +from .errors import WorldCutInputError +from .models import ( + CommonValidTimeRequirement, + ContractVerdict, + DependencyRequirement, + JsonValue, + ParsedInput, + RequirementResult, + ValueEqualsRequirement, + VerificationCoverage, + VerificationResult, + _unwrap_parsed_input, + thaw_json, +) +from .planning import select_acquisition_plan +from .requirements import ( + evaluate_common_valid_time, + evaluate_dependency, + evaluate_value_equals, +) +from .validation import parse_input + +ENGINE_VERSION = "0.1.2" +CANONICALIZATION: Literal["worldcut-json-v1"] = "worldcut-json-v1" + + +def verify(parsed_input: ParsedInput) -> VerificationResult: + """Verify a parsed WorldCut input and return a fresh mutable result.""" + + try: + value = _unwrap_parsed_input(parsed_input) + except TypeError as error: + raise WorldCutInputError(str(error)) from error + observations = {observation.role: observation for observation in value.observations} + requirements = sorted( + value.contract.requirements, key=lambda item: utf16_sort_key(item.id) + ) + results: list[RequirementResult] = [] + for requirement in requirements: + if isinstance(requirement, DependencyRequirement): + results.append(evaluate_dependency(requirement, observations)) + elif isinstance(requirement, CommonValidTimeRequirement): + results.append(evaluate_common_valid_time(requirement, observations)) + elif isinstance(requirement, ValueEqualsRequirement): + results.append(evaluate_value_equals(requirement, observations)) + + coverage: VerificationCoverage = { + "required": 0, + "satisfied": 0, + "violated": 0, + "unknown": 0, + "advisory": 0, + } + for result in results: + if not result["required"]: + coverage["advisory"] += 1 + continue + coverage["required"] += 1 + if result["status"] == "SATISFIED": + coverage["satisfied"] += 1 + elif result["status"] == "VIOLATED": + coverage["violated"] += 1 + else: + coverage["unknown"] += 1 + + verdict: ContractVerdict + if coverage["violated"]: + verdict = "CONTRACT_VIOLATED" + elif coverage["unknown"]: + verdict = "INSUFFICIENT_EVIDENCE" + else: + verdict = "CONTRACT_SATISFIED" + plan = select_acquisition_plan(results) + + contract = cast(dict[str, JsonValue], thaw_json(value.contract.raw)) + contract["requirements"] = [ + thaw_json(requirement.raw) for requirement in requirements + ] + record: JsonValue = { + "protocolVersion": value.protocol_version, + "engineVersion": ENGINE_VERSION, + "canonicalization": CANONICALIZATION, + "contract": contract, + "observations": [ + thaw_json(observation.raw) + for observation in sorted( + value.observations, key=lambda item: utf16_sort_key(item.role) + ) + ], + "verdict": verdict, + "requirementResults": cast(list[JsonValue], results), + "acquisitionPlan": cast(JsonValue, plan), + } + return { + "protocolVersion": value.protocol_version, + "engineVersion": ENGINE_VERSION, + "canonicalization": CANONICALIZATION, + "contractId": value.contract.id, + "contractVersion": value.contract.version, + "verdict": verdict, + "coverage": coverage, + "requirementResults": results, + "acquisitionPlan": plan, + "verificationRecordDigest": sha256_digest(record), + } + + +def verify_json(source: str | bytes | bytearray) -> VerificationResult: + """Parse and verify one WorldCut JSON document.""" + + return verify(parse_input(source)) diff --git a/ports/python/tests/data/conformance/0.1/canonicalization-vectors.json b/ports/python/tests/data/conformance/0.1/canonicalization-vectors.json new file mode 100644 index 0000000..9374a45 --- /dev/null +++ b/ports/python/tests/data/conformance/0.1/canonicalization-vectors.json @@ -0,0 +1,60 @@ +{ + "canonicalization": "worldcut-json-v1", + "cases": [ + { + "name": "object-key-order", + "value": { + "z": 1, + "a": 2 + }, + "expectedCanonicalJson": "{\"a\":2,\"z\":1}", + "expectedSha256": "c2985c5ba6f7d2a55e768f92490ca09388e95bc4cccb9fdf11b15f4d42f93e73" + }, + { + "name": "nested", + "value": { + "b": [ + true, + null, + { + "y": "two", + "x": "one" + } + ], + "a": 0 + }, + "expectedCanonicalJson": "{\"a\":0,\"b\":[true,null,{\"x\":\"one\",\"y\":\"two\"}]}", + "expectedSha256": "c7b434323f6442528834059ff019ce0155446ab48085829dcfeb497934c89e61" + }, + { + "name": "unicode-key-order", + "value": { + "1": "one", + "\r": "cr", + "€": "euro", + "😀": "face", + "ö": "o" + }, + "expectedCanonicalJson": "{\"\\r\":\"cr\",\"1\":\"one\",\"ö\":\"o\",\"€\":\"euro\",\"😀\":\"face\"}", + "expectedSha256": "7d173b0f794426c197248618236ad042c878322f16664325ee097a6c697fd60d" + }, + { + "name": "numbers", + "value": [ + 333333333.3333333, + 1e+30, + 4.5, + 0.002, + 1e-27 + ], + "expectedCanonicalJson": "[333333333.3333333,1e+30,4.5,0.002,1e-27]", + "expectedSha256": "7c6bc86d861387d823ae596b79ca0b26567dddc22a77acb1f4e06d441f555adf" + }, + { + "name": "escaped-string", + "value": "€$\u000f\nA'B\"\\\\\"/", + "expectedCanonicalJson": "\"€$\\u000f\\nA'B\\\"\\\\\\\\\\\"/\"", + "expectedSha256": "48caa679d7f31885aac4a400aa52732f9b304c1a417dfa6e75631e81ca2f785c" + } + ] +} diff --git a/ports/python/tests/data/conformance/0.1/invalid-vectors.json b/ports/python/tests/data/conformance/0.1/invalid-vectors.json new file mode 100644 index 0000000..ddd5d3f --- /dev/null +++ b/ports/python/tests/data/conformance/0.1/invalid-vectors.json @@ -0,0 +1,1833 @@ +{ + "protocolVersion": "0.1", + "cases": [ + { + "name": "unsupported-protocol", + "input": { + "protocolVersion": "1.0", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expectedErrorCode": "WORLDCUT_INVALID_INPUT" + }, + { + "name": "duplicate-role", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "head", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expectedErrorCode": "WORLDCUT_INVALID_INPUT" + }, + { + "name": "duplicate-observation-id", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-head-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expectedErrorCode": "WORLDCUT_INVALID_INPUT" + }, + { + "name": "invalid-interval", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T17:55:00.000Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expectedErrorCode": "WORLDCUT_INVALID_INPUT" + }, + { + "name": "future-observation", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T18:00:00.001Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expectedErrorCode": "WORLDCUT_INVALID_INPUT" + }, + { + "name": "excessive-acquisition-cost", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1000000001, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expectedErrorCode": "WORLDCUT_INVALID_INPUT" + }, + { + "name": "fractional-acquisition-cost", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1.2, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expectedErrorCode": "WORLDCUT_INVALID_INPUT" + }, + { + "name": "unsupported-field", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ], + "unsupported": true + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expectedErrorCode": "WORLDCUT_INVALID_INPUT" + }, + { + "name": "all-advisory", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head", + "required": false + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed", + "required": false + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + }, + "required": false + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expectedErrorCode": "WORLDCUT_INVALID_INPUT" + }, + { + "name": "duplicate-requirement-id", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-tested-current-head", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expectedErrorCode": "WORLDCUT_INVALID_INPUT" + }, + { + "name": "duplicate-dependency-name", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + }, + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expectedErrorCode": "WORLDCUT_INVALID_INPUT" + }, + { + "name": "invalid-timestamp", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expectedErrorCode": "WORLDCUT_INVALID_INPUT" + } + ] +} diff --git a/ports/python/tests/data/conformance/0.1/manifest.json b/ports/python/tests/data/conformance/0.1/manifest.json new file mode 100644 index 0000000..76e3259 --- /dev/null +++ b/ports/python/tests/data/conformance/0.1/manifest.json @@ -0,0 +1,27 @@ +{ + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "files": { + "verification-vectors.json": { + "sha256": "db6771b0bc3953dd74f0020ecabe72317a8a82879094c9ac1bc53f059e42e326", + "cases": 15 + }, + "invalid-vectors.json": { + "sha256": "cb91d4844e5405cf886427b0c7d42dfef9c09b82006991f65d6d6489cdda7bac", + "cases": 12 + }, + "canonicalization-vectors.json": { + "sha256": "bc63e52e23eb8d5e6d99142204158395098b0200d1e9f32a19a4755de2903987", + "cases": 5 + }, + "raw-vectors.json": { + "sha256": "b982317915adfe95761f889500fd553220edee5fe5205ed77dffa74e483e8e60", + "cases": 1 + }, + "raw/unpaired-high-surrogate.json": { + "sha256": "832c9023d610d289d60ef5a3c7d14f2bdff1a29d24bef0b7683c24efae1e4d23", + "bytes": 3635 + } + } +} diff --git a/ports/python/tests/data/conformance/0.1/raw-vectors.json b/ports/python/tests/data/conformance/0.1/raw-vectors.json new file mode 100644 index 0000000..c7bf051 --- /dev/null +++ b/ports/python/tests/data/conformance/0.1/raw-vectors.json @@ -0,0 +1,14 @@ +{ + "protocolVersion": "0.1", + "cases": [ + { + "name": "unpaired-high-surrogate", + "file": "raw/unpaired-high-surrogate.json", + "sha256": "832c9023d610d289d60ef5a3c7d14f2bdff1a29d24bef0b7683c24efae1e4d23", + "acceptedOutcomes": [ + "PARSE_ERROR", + "WORLDCUT_INVALID_INPUT" + ] + } + ] +} diff --git a/ports/python/tests/data/conformance/0.1/raw/unpaired-high-surrogate.json b/ports/python/tests/data/conformance/0.1/raw/unpaired-high-surrogate.json new file mode 100644 index 0000000..ad0c0c8 --- /dev/null +++ b/ports/python/tests/data/conformance/0.1/raw/unpaired-high-surrogate.json @@ -0,0 +1,145 @@ +{ + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": "\ud800", + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] +} diff --git a/ports/python/tests/data/conformance/0.1/verification-vectors.json b/ports/python/tests/data/conformance/0.1/verification-vectors.json new file mode 100644 index 0000000..4033472 --- /dev/null +++ b/ports/python/tests/data/conformance/0.1/verification-vectors.json @@ -0,0 +1,6422 @@ +{ + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "cases": [ + { + "name": "coherent", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "deploy-current-tested-release", + "contractVersion": "1", + "verdict": "CONTRACT_SATISFIED", + "coverage": { + "required": 3, + "satisfied": 3, + "violated": 0, + "unknown": 0, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "approval-and-quote-overlap", + "requirementType": "common_valid_time", + "required": true, + "status": "SATISFIED", + "summary": "The approval and quote were valid at a common time: a common valid time exists.", + "details": { + "roles": [ + "approval", + "quote" + ], + "commonWindow": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + }, + "acquisitionOptions": [] + }, + { + "requirementId": "ci-status-passed", + "requirementType": "value_equals", + "required": true, + "status": "SATISFIED", + "summary": "The CI status is passed: observed value matches the requirement.", + "details": { + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + "acquisitionOptions": [] + }, + { + "requirementId": "ci-tested-current-head", + "requirementType": "dependency", + "required": true, + "status": "SATISFIED", + "summary": "The passing CI run tested the selected branch head: both roles are bound to commit-B.", + "details": { + "dependentRole": "ci", + "targetRole": "head", + "version": "commit-B" + }, + "acquisitionOptions": [] + } + ], + "acquisitionPlan": { + "status": "NOT_NEEDED", + "reason": null, + "actions": [], + "selectedOptionIds": [], + "totalCost": 0, + "coveredRequirementIds": [], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "f402861e5df539f5ea4b69681431c2e2bcbd18e7cb5a02c63a7cfca3b9bb3eee" + } + }, + { + "name": "dependency-mismatch", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-head", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-a", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2040" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2040", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-A", + "provenance": "provider_asserted" + } + ] + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "deploy-current-tested-head", + "contractVersion": "1", + "verdict": "CONTRACT_VIOLATED", + "coverage": { + "required": 1, + "satisfied": 0, + "violated": 1, + "unknown": 0, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "ci-tested-current-head", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "The passing CI run tested the selected branch head: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "ci-tested-current-head:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "ci-tested-current-head:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + } + ], + "acquisitionPlan": { + "status": "AVAILABLE", + "reason": null, + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ], + "selectedOptionIds": [ + "ci-tested-current-head:refresh-target" + ], + "totalCost": 1, + "coveredRequirementIds": [ + "ci-tested-current-head" + ], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "8bb1ccb80d72dd8cd540c9abb6e377c47c28cbcf0ae7b4c169df63f5279ee790" + } + }, + { + "name": "temporal-gap", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "approved-price-window", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-approval-expired", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-7", + "validity": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T17:58:00.000Z" + } + } + }, + { + "id": "obs-quote-later", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.001Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "approved-price-window", + "contractVersion": "1", + "verdict": "CONTRACT_VIOLATED", + "coverage": { + "required": 1, + "satisfied": 0, + "violated": 1, + "unknown": 0, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "approval-and-quote-overlap", + "requirementType": "common_valid_time", + "required": true, + "status": "VIOLATED", + "summary": "The approval and quote were valid at a common time: the known validity intervals do not overlap.", + "details": { + "roles": [ + "approval", + "quote" + ], + "latestStart": "2026-09-02T17:58:00.001Z", + "earliestEnd": "2026-09-02T17:58:00.000Z", + "missingRoles": [], + "missingValidityRoles": [] + }, + "acquisitionOptions": [ + { + "id": "approval-and-quote-overlap:refresh-approval", + "description": "Refresh approval and acquire every other missing prerequisite.", + "actions": [ + { + "id": "refresh_observation:approval:03cb6375e080", + "type": "REFRESH_OBSERVATION", + "role": "approval", + "cost": 2, + "description": "Refresh approval to seek a compatible validity window.", + "expected": { + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + } + ] + }, + { + "id": "approval-and-quote-overlap:refresh-quote", + "description": "Refresh quote and acquire every other missing prerequisite.", + "actions": [ + { + "id": "refresh_observation:quote:03cb6375e080", + "type": "REFRESH_OBSERVATION", + "role": "quote", + "cost": 3, + "description": "Refresh quote to seek a compatible validity window.", + "expected": { + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + } + ] + } + ] + } + ], + "acquisitionPlan": { + "status": "AVAILABLE", + "reason": null, + "actions": [ + { + "id": "refresh_observation:approval:03cb6375e080", + "type": "REFRESH_OBSERVATION", + "role": "approval", + "cost": 2, + "description": "Refresh approval to seek a compatible validity window.", + "expected": { + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + } + ], + "selectedOptionIds": [ + "approval-and-quote-overlap:refresh-approval" + ], + "totalCost": 2, + "coveredRequirementIds": [ + "approval-and-quote-overlap" + ], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "da836f28a058ce0e3489637c743efe2617f873fab6600c5f2b1e839eb2779bdf" + } + }, + { + "name": "missing-dependency", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-head", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-unknown", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-unknown" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-unknown" + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "deploy-current-tested-head", + "contractVersion": "1", + "verdict": "INSUFFICIENT_EVIDENCE", + "coverage": { + "required": 1, + "satisfied": 0, + "violated": 0, + "unknown": 1, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "ci-tested-current-head", + "requirementType": "dependency", + "required": true, + "status": "UNKNOWN", + "summary": "ci does not expose dependency tested_head.", + "details": { + "dependentRole": "ci", + "targetRole": "head", + "missingDependency": "tested_head" + }, + "acquisitionOptions": [ + { + "id": "ci-tested-current-head:fetch-dependency-metadata", + "description": "Fetch all metadata required to compare the dependency.", + "actions": [ + { + "id": "fetch_required_metadata:ci:1e7092ae3f55", + "type": "FETCH_REQUIRED_METADATA", + "role": "ci", + "cost": 1, + "description": "Fetch dependency metadata for ci.", + "expected": { + "dependencyName": "tested_head", + "targetResource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + } + } + } + ] + } + ] + } + ], + "acquisitionPlan": { + "status": "AVAILABLE", + "reason": null, + "actions": [ + { + "id": "fetch_required_metadata:ci:1e7092ae3f55", + "type": "FETCH_REQUIRED_METADATA", + "role": "ci", + "cost": 1, + "description": "Fetch dependency metadata for ci.", + "expected": { + "dependencyName": "tested_head", + "targetResource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + } + } + } + ], + "selectedOptionIds": [ + "ci-tested-current-head:fetch-dependency-metadata" + ], + "totalCost": 1, + "coveredRequirementIds": [ + "ci-tested-current-head" + ], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "f5a8f5f853b9db0a36e54e9738d8b3aceb102d062659d73752c456e1b74d10f6" + } + }, + { + "name": "value-mismatch", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "value-mismatch", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "failed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "value-mismatch", + "contractVersion": "1", + "verdict": "CONTRACT_VIOLATED", + "coverage": { + "required": 3, + "satisfied": 2, + "violated": 1, + "unknown": 0, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "approval-and-quote-overlap", + "requirementType": "common_valid_time", + "required": true, + "status": "SATISFIED", + "summary": "The approval and quote were valid at a common time: a common valid time exists.", + "details": { + "roles": [ + "approval", + "quote" + ], + "commonWindow": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + }, + "acquisitionOptions": [] + }, + { + "requirementId": "ci-status-passed", + "requirementType": "value_equals", + "required": true, + "status": "VIOLATED", + "summary": "The CI status is passed: observed value does not equal the required value.", + "details": { + "role": "ci", + "path": [ + "status" + ], + "expected": "failed", + "actual": "passed" + }, + "acquisitionOptions": [ + { + "id": "ci-status-passed:refresh-value", + "description": "Refresh the observation before evaluating the value again.", + "actions": [ + { + "id": "refresh_observation:ci:b07de73b4894", + "type": "REFRESH_OBSERVATION", + "role": "ci", + "cost": 4, + "description": "Refresh ci before evaluating status.", + "expected": { + "path": [ + "status" + ], + "expected": "failed" + } + } + ] + } + ] + }, + { + "requirementId": "ci-tested-current-head", + "requirementType": "dependency", + "required": true, + "status": "SATISFIED", + "summary": "The passing CI run tested the selected branch head: both roles are bound to commit-B.", + "details": { + "dependentRole": "ci", + "targetRole": "head", + "version": "commit-B" + }, + "acquisitionOptions": [] + } + ], + "acquisitionPlan": { + "status": "AVAILABLE", + "reason": null, + "actions": [ + { + "id": "refresh_observation:ci:b07de73b4894", + "type": "REFRESH_OBSERVATION", + "role": "ci", + "cost": 4, + "description": "Refresh ci before evaluating status.", + "expected": { + "path": [ + "status" + ], + "expected": "failed" + } + } + ], + "selectedOptionIds": [ + "ci-status-passed:refresh-value" + ], + "totalCost": 4, + "coveredRequirementIds": [ + "ci-status-passed" + ], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "834df6c1741714f824dc6fca9f1001f075d7eeabe93512fa60148a93d90e5d92" + } + }, + { + "name": "value-path-missing", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "value-path-missing", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "missing" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "value-path-missing", + "contractVersion": "1", + "verdict": "INSUFFICIENT_EVIDENCE", + "coverage": { + "required": 3, + "satisfied": 2, + "violated": 0, + "unknown": 1, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "approval-and-quote-overlap", + "requirementType": "common_valid_time", + "required": true, + "status": "SATISFIED", + "summary": "The approval and quote were valid at a common time: a common valid time exists.", + "details": { + "roles": [ + "approval", + "quote" + ], + "commonWindow": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + }, + "acquisitionOptions": [] + }, + { + "requirementId": "ci-status-passed", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "The CI status is passed: value path missing is missing.", + "details": { + "role": "ci", + "path": [ + "missing" + ], + "expected": "passed" + }, + "acquisitionOptions": [ + { + "id": "ci-status-passed:acquire-value", + "description": "Acquire evidence containing the required value path.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:b6c8b2f486b3", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence containing missing.", + "expected": { + "path": [ + "missing" + ], + "expected": "passed" + } + } + ] + } + ] + }, + { + "requirementId": "ci-tested-current-head", + "requirementType": "dependency", + "required": true, + "status": "SATISFIED", + "summary": "The passing CI run tested the selected branch head: both roles are bound to commit-B.", + "details": { + "dependentRole": "ci", + "targetRole": "head", + "version": "commit-B" + }, + "acquisitionOptions": [] + } + ], + "acquisitionPlan": { + "status": "AVAILABLE", + "reason": null, + "actions": [ + { + "id": "acquire_compatible_evidence:ci:b6c8b2f486b3", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence containing missing.", + "expected": { + "path": [ + "missing" + ], + "expected": "passed" + } + } + ], + "selectedOptionIds": [ + "ci-status-passed:acquire-value" + ], + "totalCost": 4, + "coveredRequirementIds": [ + "ci-status-passed" + ], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "ce443403acf879a7487377a1bc1a127034dcf6d1634cfe75562b8fde1531fae2" + } + }, + { + "name": "array-index", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "array-index", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "first-status", + "type": "value_equals", + "description": "The first array value is passed", + "role": "ci", + "path": [ + "0" + ], + "expected": "passed" + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": [ + "passed" + ], + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "array-index", + "contractVersion": "1", + "verdict": "CONTRACT_SATISFIED", + "coverage": { + "required": 1, + "satisfied": 1, + "violated": 0, + "unknown": 0, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "first-status", + "requirementType": "value_equals", + "required": true, + "status": "SATISFIED", + "summary": "The first array value is passed: observed value matches the requirement.", + "details": { + "role": "ci", + "path": [ + "0" + ], + "expected": "passed" + }, + "acquisitionOptions": [] + } + ], + "acquisitionPlan": { + "status": "NOT_NEEDED", + "reason": null, + "actions": [], + "selectedOptionIds": [], + "totalCost": 0, + "coveredRequirementIds": [], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "cc96a3f93e6f03e8981437ae6801cb19bf7a1dce13709152632c3178512f65ec" + } + }, + { + "name": "array-length-is-not-a-value-path", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "array-length-is-not-a-value-path", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "first-status", + "type": "value_equals", + "description": "The first array value is passed", + "role": "ci", + "path": [ + "length" + ], + "expected": "passed" + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": [ + "passed" + ], + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "array-length-is-not-a-value-path", + "contractVersion": "1", + "verdict": "INSUFFICIENT_EVIDENCE", + "coverage": { + "required": 1, + "satisfied": 0, + "violated": 0, + "unknown": 1, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "first-status", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "The first array value is passed: value path length is missing.", + "details": { + "role": "ci", + "path": [ + "length" + ], + "expected": "passed" + }, + "acquisitionOptions": [ + { + "id": "first-status:acquire-value", + "description": "Acquire evidence containing the required value path.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:4674a7eae86d", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence containing length.", + "expected": { + "path": [ + "length" + ], + "expected": "passed" + } + } + ] + } + ] + } + ], + "acquisitionPlan": { + "status": "AVAILABLE", + "reason": null, + "actions": [ + { + "id": "acquire_compatible_evidence:ci:4674a7eae86d", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence containing length.", + "expected": { + "path": [ + "length" + ], + "expected": "passed" + } + } + ], + "selectedOptionIds": [ + "first-status:acquire-value" + ], + "totalCost": 4, + "coveredRequirementIds": [ + "first-status" + ], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "62b3ec27dbd060e6ac452ada327c45b847f889a7e35de6d528e4fbf5de7563d7" + } + }, + { + "name": "whitespace-object-path", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "whitespace-object-path", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "whitespace-key", + "type": "value_equals", + "description": "Whitespace object keys remain exact", + "role": "ci", + "path": [ + " " + ], + "expected": "passed" + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + " ": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "whitespace-object-path", + "contractVersion": "1", + "verdict": "CONTRACT_SATISFIED", + "coverage": { + "required": 1, + "satisfied": 1, + "violated": 0, + "unknown": 0, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "whitespace-key", + "requirementType": "value_equals", + "required": true, + "status": "SATISFIED", + "summary": "Whitespace object keys remain exact: observed value matches the requirement.", + "details": { + "role": "ci", + "path": [ + " " + ], + "expected": "passed" + }, + "acquisitionOptions": [] + } + ], + "acquisitionPlan": { + "status": "NOT_NEEDED", + "reason": null, + "actions": [], + "selectedOptionIds": [], + "totalCost": 0, + "coveredRequirementIds": [], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "87caf905e01765a6e27743c71899e9c2a5e8e7d4cc287c4940b00b4cc2ac903b" + } + }, + { + "name": "advisory-unknown", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "advisory-unknown", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + }, + { + "id": "optional-provider-note", + "type": "value_equals", + "description": "An optional provider note is present", + "required": false, + "role": "optional", + "path": [ + "note" + ], + "expected": "present" + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "advisory-unknown", + "contractVersion": "1", + "verdict": "CONTRACT_SATISFIED", + "coverage": { + "required": 3, + "satisfied": 3, + "violated": 0, + "unknown": 0, + "advisory": 1 + }, + "requirementResults": [ + { + "requirementId": "approval-and-quote-overlap", + "requirementType": "common_valid_time", + "required": true, + "status": "SATISFIED", + "summary": "The approval and quote were valid at a common time: a common valid time exists.", + "details": { + "roles": [ + "approval", + "quote" + ], + "commonWindow": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + }, + "acquisitionOptions": [] + }, + { + "requirementId": "ci-status-passed", + "requirementType": "value_equals", + "required": true, + "status": "SATISFIED", + "summary": "The CI status is passed: observed value matches the requirement.", + "details": { + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + "acquisitionOptions": [] + }, + { + "requirementId": "ci-tested-current-head", + "requirementType": "dependency", + "required": true, + "status": "SATISFIED", + "summary": "The passing CI run tested the selected branch head: both roles are bound to commit-B.", + "details": { + "dependentRole": "ci", + "targetRole": "head", + "version": "commit-B" + }, + "acquisitionOptions": [] + }, + { + "requirementId": "optional-provider-note", + "requirementType": "value_equals", + "required": false, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): optional.", + "details": { + "missingRoles": [ + "optional" + ] + }, + "acquisitionOptions": [ + { + "id": "optional-provider-note:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:optional:none", + "type": "REFRESH_OBSERVATION", + "role": "optional", + "cost": 1, + "description": "Acquire an observation for role optional.", + "expected": null + } + ] + } + ] + } + ], + "acquisitionPlan": { + "status": "NOT_NEEDED", + "reason": null, + "actions": [], + "selectedOptionIds": [], + "totalCost": 0, + "coveredRequirementIds": [], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "7addbae456670e1a91025ca45188a99e269f8186b547f13d3a1331f761153c5b" + } + }, + { + "name": "violation-dominates-unknown", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "violation-dominates-unknown", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "missing-optional-system", + "type": "value_equals", + "description": "A required external approval is present", + "role": "external-approval", + "path": [ + "approved" + ], + "expected": true + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-a", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2040" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2040", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-A", + "provenance": "provider_asserted" + } + ] + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "violation-dominates-unknown", + "contractVersion": "1", + "verdict": "CONTRACT_VIOLATED", + "coverage": { + "required": 2, + "satisfied": 0, + "violated": 1, + "unknown": 1, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "ci-tested-current-head", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "The passing CI run tested the selected branch head: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "ci-tested-current-head:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "ci-tested-current-head:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "missing-optional-system", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): external-approval.", + "details": { + "missingRoles": [ + "external-approval" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-optional-system:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:external-approval:none", + "type": "REFRESH_OBSERVATION", + "role": "external-approval", + "cost": 1, + "description": "Acquire an observation for role external-approval.", + "expected": null + } + ] + } + ] + } + ], + "acquisitionPlan": { + "status": "AVAILABLE", + "reason": null, + "actions": [ + { + "id": "refresh_observation:external-approval:none", + "type": "REFRESH_OBSERVATION", + "role": "external-approval", + "cost": 1, + "description": "Acquire an observation for role external-approval.", + "expected": null + }, + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ], + "selectedOptionIds": [ + "ci-tested-current-head:refresh-target", + "missing-optional-system:acquire-missing-roles" + ], + "totalCost": 2, + "coveredRequirementIds": [ + "ci-tested-current-head", + "missing-optional-system" + ], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "44079bb20c75a56734ed25106e80831627c837ab9bbf99ddc1cafdf27fc52dc2" + } + }, + { + "name": "open-ended-overlap", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "open-ended-overlap", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": null + } + } + }, + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "open-ended-overlap", + "contractVersion": "1", + "verdict": "CONTRACT_SATISFIED", + "coverage": { + "required": 3, + "satisfied": 3, + "violated": 0, + "unknown": 0, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "approval-and-quote-overlap", + "requirementType": "common_valid_time", + "required": true, + "status": "SATISFIED", + "summary": "The approval and quote were valid at a common time: a common valid time exists.", + "details": { + "roles": [ + "approval", + "quote" + ], + "commonWindow": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + }, + "acquisitionOptions": [] + }, + { + "requirementId": "ci-status-passed", + "requirementType": "value_equals", + "required": true, + "status": "SATISFIED", + "summary": "The CI status is passed: observed value matches the requirement.", + "details": { + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + "acquisitionOptions": [] + }, + { + "requirementId": "ci-tested-current-head", + "requirementType": "dependency", + "required": true, + "status": "SATISFIED", + "summary": "The passing CI run tested the selected branch head: both roles are bound to commit-B.", + "details": { + "dependentRole": "ci", + "targetRole": "head", + "version": "commit-B" + }, + "acquisitionOptions": [] + } + ], + "acquisitionPlan": { + "status": "NOT_NEEDED", + "reason": null, + "actions": [], + "selectedOptionIds": [], + "totalCost": 0, + "coveredRequirementIds": [], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "990cf61f725948e7ee7fd0a17c14cd5748a92c1ecbe5fad007475291178a1cee" + } + }, + { + "name": "planner-requirement-limit", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "planner-requirement-limit", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "missing-00", + "type": "value_equals", + "description": "Missing role 0", + "role": "missing-0", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-01", + "type": "value_equals", + "description": "Missing role 1", + "role": "missing-1", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-02", + "type": "value_equals", + "description": "Missing role 2", + "role": "missing-2", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-03", + "type": "value_equals", + "description": "Missing role 3", + "role": "missing-3", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-04", + "type": "value_equals", + "description": "Missing role 4", + "role": "missing-4", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-05", + "type": "value_equals", + "description": "Missing role 5", + "role": "missing-5", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-06", + "type": "value_equals", + "description": "Missing role 6", + "role": "missing-6", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-07", + "type": "value_equals", + "description": "Missing role 7", + "role": "missing-7", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-08", + "type": "value_equals", + "description": "Missing role 8", + "role": "missing-8", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-09", + "type": "value_equals", + "description": "Missing role 9", + "role": "missing-9", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-10", + "type": "value_equals", + "description": "Missing role 10", + "role": "missing-10", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-11", + "type": "value_equals", + "description": "Missing role 11", + "role": "missing-11", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-12", + "type": "value_equals", + "description": "Missing role 12", + "role": "missing-12", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-13", + "type": "value_equals", + "description": "Missing role 13", + "role": "missing-13", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-14", + "type": "value_equals", + "description": "Missing role 14", + "role": "missing-14", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-15", + "type": "value_equals", + "description": "Missing role 15", + "role": "missing-15", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-16", + "type": "value_equals", + "description": "Missing role 16", + "role": "missing-16", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-17", + "type": "value_equals", + "description": "Missing role 17", + "role": "missing-17", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-18", + "type": "value_equals", + "description": "Missing role 18", + "role": "missing-18", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-19", + "type": "value_equals", + "description": "Missing role 19", + "role": "missing-19", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-20", + "type": "value_equals", + "description": "Missing role 20", + "role": "missing-20", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-21", + "type": "value_equals", + "description": "Missing role 21", + "role": "missing-21", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-22", + "type": "value_equals", + "description": "Missing role 22", + "role": "missing-22", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-23", + "type": "value_equals", + "description": "Missing role 23", + "role": "missing-23", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-24", + "type": "value_equals", + "description": "Missing role 24", + "role": "missing-24", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-25", + "type": "value_equals", + "description": "Missing role 25", + "role": "missing-25", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-26", + "type": "value_equals", + "description": "Missing role 26", + "role": "missing-26", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-27", + "type": "value_equals", + "description": "Missing role 27", + "role": "missing-27", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-28", + "type": "value_equals", + "description": "Missing role 28", + "role": "missing-28", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-29", + "type": "value_equals", + "description": "Missing role 29", + "role": "missing-29", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-30", + "type": "value_equals", + "description": "Missing role 30", + "role": "missing-30", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-31", + "type": "value_equals", + "description": "Missing role 31", + "role": "missing-31", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-32", + "type": "value_equals", + "description": "Missing role 32", + "role": "missing-32", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-33", + "type": "value_equals", + "description": "Missing role 33", + "role": "missing-33", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-34", + "type": "value_equals", + "description": "Missing role 34", + "role": "missing-34", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-35", + "type": "value_equals", + "description": "Missing role 35", + "role": "missing-35", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-36", + "type": "value_equals", + "description": "Missing role 36", + "role": "missing-36", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-37", + "type": "value_equals", + "description": "Missing role 37", + "role": "missing-37", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-38", + "type": "value_equals", + "description": "Missing role 38", + "role": "missing-38", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-39", + "type": "value_equals", + "description": "Missing role 39", + "role": "missing-39", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-40", + "type": "value_equals", + "description": "Missing role 40", + "role": "missing-40", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-41", + "type": "value_equals", + "description": "Missing role 41", + "role": "missing-41", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-42", + "type": "value_equals", + "description": "Missing role 42", + "role": "missing-42", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-43", + "type": "value_equals", + "description": "Missing role 43", + "role": "missing-43", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-44", + "type": "value_equals", + "description": "Missing role 44", + "role": "missing-44", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-45", + "type": "value_equals", + "description": "Missing role 45", + "role": "missing-45", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-46", + "type": "value_equals", + "description": "Missing role 46", + "role": "missing-46", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-47", + "type": "value_equals", + "description": "Missing role 47", + "role": "missing-47", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-48", + "type": "value_equals", + "description": "Missing role 48", + "role": "missing-48", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-49", + "type": "value_equals", + "description": "Missing role 49", + "role": "missing-49", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-50", + "type": "value_equals", + "description": "Missing role 50", + "role": "missing-50", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-51", + "type": "value_equals", + "description": "Missing role 51", + "role": "missing-51", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-52", + "type": "value_equals", + "description": "Missing role 52", + "role": "missing-52", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-53", + "type": "value_equals", + "description": "Missing role 53", + "role": "missing-53", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-54", + "type": "value_equals", + "description": "Missing role 54", + "role": "missing-54", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-55", + "type": "value_equals", + "description": "Missing role 55", + "role": "missing-55", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-56", + "type": "value_equals", + "description": "Missing role 56", + "role": "missing-56", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-57", + "type": "value_equals", + "description": "Missing role 57", + "role": "missing-57", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-58", + "type": "value_equals", + "description": "Missing role 58", + "role": "missing-58", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-59", + "type": "value_equals", + "description": "Missing role 59", + "role": "missing-59", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-60", + "type": "value_equals", + "description": "Missing role 60", + "role": "missing-60", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-61", + "type": "value_equals", + "description": "Missing role 61", + "role": "missing-61", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-62", + "type": "value_equals", + "description": "Missing role 62", + "role": "missing-62", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-63", + "type": "value_equals", + "description": "Missing role 63", + "role": "missing-63", + "path": [ + "value" + ], + "expected": true + }, + { + "id": "missing-64", + "type": "value_equals", + "description": "Missing role 64", + "role": "missing-64", + "path": [ + "value" + ], + "expected": true + } + ] + }, + "observations": [] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "planner-requirement-limit", + "contractVersion": "1", + "verdict": "INSUFFICIENT_EVIDENCE", + "coverage": { + "required": 65, + "satisfied": 0, + "violated": 0, + "unknown": 65, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "missing-00", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-0.", + "details": { + "missingRoles": [ + "missing-0" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-00:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-0:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-0", + "cost": 1, + "description": "Acquire an observation for role missing-0.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-01", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-1.", + "details": { + "missingRoles": [ + "missing-1" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-01:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-1:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-1", + "cost": 1, + "description": "Acquire an observation for role missing-1.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-02", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-2.", + "details": { + "missingRoles": [ + "missing-2" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-02:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-2:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-2", + "cost": 1, + "description": "Acquire an observation for role missing-2.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-03", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-3.", + "details": { + "missingRoles": [ + "missing-3" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-03:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-3:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-3", + "cost": 1, + "description": "Acquire an observation for role missing-3.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-04", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-4.", + "details": { + "missingRoles": [ + "missing-4" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-04:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-4:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-4", + "cost": 1, + "description": "Acquire an observation for role missing-4.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-05", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-5.", + "details": { + "missingRoles": [ + "missing-5" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-05:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-5:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-5", + "cost": 1, + "description": "Acquire an observation for role missing-5.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-06", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-6.", + "details": { + "missingRoles": [ + "missing-6" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-06:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-6:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-6", + "cost": 1, + "description": "Acquire an observation for role missing-6.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-07", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-7.", + "details": { + "missingRoles": [ + "missing-7" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-07:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-7:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-7", + "cost": 1, + "description": "Acquire an observation for role missing-7.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-08", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-8.", + "details": { + "missingRoles": [ + "missing-8" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-08:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-8:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-8", + "cost": 1, + "description": "Acquire an observation for role missing-8.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-09", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-9.", + "details": { + "missingRoles": [ + "missing-9" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-09:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-9:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-9", + "cost": 1, + "description": "Acquire an observation for role missing-9.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-10", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-10.", + "details": { + "missingRoles": [ + "missing-10" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-10:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-10:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-10", + "cost": 1, + "description": "Acquire an observation for role missing-10.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-11", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-11.", + "details": { + "missingRoles": [ + "missing-11" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-11:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-11:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-11", + "cost": 1, + "description": "Acquire an observation for role missing-11.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-12", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-12.", + "details": { + "missingRoles": [ + "missing-12" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-12:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-12:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-12", + "cost": 1, + "description": "Acquire an observation for role missing-12.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-13", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-13.", + "details": { + "missingRoles": [ + "missing-13" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-13:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-13:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-13", + "cost": 1, + "description": "Acquire an observation for role missing-13.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-14", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-14.", + "details": { + "missingRoles": [ + "missing-14" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-14:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-14:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-14", + "cost": 1, + "description": "Acquire an observation for role missing-14.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-15", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-15.", + "details": { + "missingRoles": [ + "missing-15" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-15:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-15:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-15", + "cost": 1, + "description": "Acquire an observation for role missing-15.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-16", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-16.", + "details": { + "missingRoles": [ + "missing-16" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-16:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-16:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-16", + "cost": 1, + "description": "Acquire an observation for role missing-16.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-17", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-17.", + "details": { + "missingRoles": [ + "missing-17" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-17:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-17:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-17", + "cost": 1, + "description": "Acquire an observation for role missing-17.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-18", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-18.", + "details": { + "missingRoles": [ + "missing-18" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-18:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-18:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-18", + "cost": 1, + "description": "Acquire an observation for role missing-18.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-19", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-19.", + "details": { + "missingRoles": [ + "missing-19" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-19:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-19:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-19", + "cost": 1, + "description": "Acquire an observation for role missing-19.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-20", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-20.", + "details": { + "missingRoles": [ + "missing-20" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-20:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-20:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-20", + "cost": 1, + "description": "Acquire an observation for role missing-20.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-21", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-21.", + "details": { + "missingRoles": [ + "missing-21" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-21:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-21:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-21", + "cost": 1, + "description": "Acquire an observation for role missing-21.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-22", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-22.", + "details": { + "missingRoles": [ + "missing-22" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-22:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-22:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-22", + "cost": 1, + "description": "Acquire an observation for role missing-22.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-23", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-23.", + "details": { + "missingRoles": [ + "missing-23" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-23:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-23:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-23", + "cost": 1, + "description": "Acquire an observation for role missing-23.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-24", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-24.", + "details": { + "missingRoles": [ + "missing-24" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-24:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-24:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-24", + "cost": 1, + "description": "Acquire an observation for role missing-24.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-25", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-25.", + "details": { + "missingRoles": [ + "missing-25" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-25:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-25:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-25", + "cost": 1, + "description": "Acquire an observation for role missing-25.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-26", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-26.", + "details": { + "missingRoles": [ + "missing-26" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-26:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-26:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-26", + "cost": 1, + "description": "Acquire an observation for role missing-26.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-27", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-27.", + "details": { + "missingRoles": [ + "missing-27" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-27:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-27:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-27", + "cost": 1, + "description": "Acquire an observation for role missing-27.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-28", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-28.", + "details": { + "missingRoles": [ + "missing-28" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-28:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-28:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-28", + "cost": 1, + "description": "Acquire an observation for role missing-28.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-29", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-29.", + "details": { + "missingRoles": [ + "missing-29" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-29:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-29:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-29", + "cost": 1, + "description": "Acquire an observation for role missing-29.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-30", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-30.", + "details": { + "missingRoles": [ + "missing-30" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-30:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-30:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-30", + "cost": 1, + "description": "Acquire an observation for role missing-30.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-31", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-31.", + "details": { + "missingRoles": [ + "missing-31" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-31:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-31:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-31", + "cost": 1, + "description": "Acquire an observation for role missing-31.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-32", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-32.", + "details": { + "missingRoles": [ + "missing-32" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-32:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-32:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-32", + "cost": 1, + "description": "Acquire an observation for role missing-32.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-33", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-33.", + "details": { + "missingRoles": [ + "missing-33" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-33:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-33:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-33", + "cost": 1, + "description": "Acquire an observation for role missing-33.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-34", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-34.", + "details": { + "missingRoles": [ + "missing-34" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-34:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-34:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-34", + "cost": 1, + "description": "Acquire an observation for role missing-34.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-35", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-35.", + "details": { + "missingRoles": [ + "missing-35" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-35:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-35:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-35", + "cost": 1, + "description": "Acquire an observation for role missing-35.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-36", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-36.", + "details": { + "missingRoles": [ + "missing-36" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-36:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-36:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-36", + "cost": 1, + "description": "Acquire an observation for role missing-36.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-37", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-37.", + "details": { + "missingRoles": [ + "missing-37" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-37:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-37:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-37", + "cost": 1, + "description": "Acquire an observation for role missing-37.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-38", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-38.", + "details": { + "missingRoles": [ + "missing-38" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-38:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-38:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-38", + "cost": 1, + "description": "Acquire an observation for role missing-38.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-39", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-39.", + "details": { + "missingRoles": [ + "missing-39" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-39:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-39:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-39", + "cost": 1, + "description": "Acquire an observation for role missing-39.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-40", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-40.", + "details": { + "missingRoles": [ + "missing-40" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-40:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-40:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-40", + "cost": 1, + "description": "Acquire an observation for role missing-40.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-41", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-41.", + "details": { + "missingRoles": [ + "missing-41" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-41:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-41:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-41", + "cost": 1, + "description": "Acquire an observation for role missing-41.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-42", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-42.", + "details": { + "missingRoles": [ + "missing-42" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-42:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-42:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-42", + "cost": 1, + "description": "Acquire an observation for role missing-42.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-43", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-43.", + "details": { + "missingRoles": [ + "missing-43" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-43:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-43:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-43", + "cost": 1, + "description": "Acquire an observation for role missing-43.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-44", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-44.", + "details": { + "missingRoles": [ + "missing-44" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-44:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-44:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-44", + "cost": 1, + "description": "Acquire an observation for role missing-44.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-45", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-45.", + "details": { + "missingRoles": [ + "missing-45" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-45:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-45:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-45", + "cost": 1, + "description": "Acquire an observation for role missing-45.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-46", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-46.", + "details": { + "missingRoles": [ + "missing-46" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-46:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-46:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-46", + "cost": 1, + "description": "Acquire an observation for role missing-46.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-47", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-47.", + "details": { + "missingRoles": [ + "missing-47" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-47:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-47:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-47", + "cost": 1, + "description": "Acquire an observation for role missing-47.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-48", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-48.", + "details": { + "missingRoles": [ + "missing-48" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-48:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-48:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-48", + "cost": 1, + "description": "Acquire an observation for role missing-48.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-49", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-49.", + "details": { + "missingRoles": [ + "missing-49" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-49:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-49:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-49", + "cost": 1, + "description": "Acquire an observation for role missing-49.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-50", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-50.", + "details": { + "missingRoles": [ + "missing-50" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-50:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-50:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-50", + "cost": 1, + "description": "Acquire an observation for role missing-50.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-51", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-51.", + "details": { + "missingRoles": [ + "missing-51" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-51:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-51:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-51", + "cost": 1, + "description": "Acquire an observation for role missing-51.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-52", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-52.", + "details": { + "missingRoles": [ + "missing-52" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-52:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-52:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-52", + "cost": 1, + "description": "Acquire an observation for role missing-52.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-53", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-53.", + "details": { + "missingRoles": [ + "missing-53" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-53:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-53:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-53", + "cost": 1, + "description": "Acquire an observation for role missing-53.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-54", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-54.", + "details": { + "missingRoles": [ + "missing-54" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-54:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-54:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-54", + "cost": 1, + "description": "Acquire an observation for role missing-54.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-55", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-55.", + "details": { + "missingRoles": [ + "missing-55" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-55:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-55:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-55", + "cost": 1, + "description": "Acquire an observation for role missing-55.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-56", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-56.", + "details": { + "missingRoles": [ + "missing-56" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-56:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-56:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-56", + "cost": 1, + "description": "Acquire an observation for role missing-56.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-57", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-57.", + "details": { + "missingRoles": [ + "missing-57" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-57:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-57:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-57", + "cost": 1, + "description": "Acquire an observation for role missing-57.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-58", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-58.", + "details": { + "missingRoles": [ + "missing-58" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-58:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-58:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-58", + "cost": 1, + "description": "Acquire an observation for role missing-58.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-59", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-59.", + "details": { + "missingRoles": [ + "missing-59" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-59:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-59:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-59", + "cost": 1, + "description": "Acquire an observation for role missing-59.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-60", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-60.", + "details": { + "missingRoles": [ + "missing-60" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-60:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-60:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-60", + "cost": 1, + "description": "Acquire an observation for role missing-60.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-61", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-61.", + "details": { + "missingRoles": [ + "missing-61" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-61:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-61:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-61", + "cost": 1, + "description": "Acquire an observation for role missing-61.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-62", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-62.", + "details": { + "missingRoles": [ + "missing-62" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-62:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-62:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-62", + "cost": 1, + "description": "Acquire an observation for role missing-62.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-63", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-63.", + "details": { + "missingRoles": [ + "missing-63" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-63:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-63:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-63", + "cost": 1, + "description": "Acquire an observation for role missing-63.", + "expected": null + } + ] + } + ] + }, + { + "requirementId": "missing-64", + "requirementType": "value_equals", + "required": true, + "status": "UNKNOWN", + "summary": "No observations are bound to required role(s): missing-64.", + "details": { + "missingRoles": [ + "missing-64" + ] + }, + "acquisitionOptions": [ + { + "id": "missing-64:acquire-missing-roles", + "description": "Acquire every missing role required to evaluate this requirement.", + "actions": [ + { + "id": "refresh_observation:missing-64:none", + "type": "REFRESH_OBSERVATION", + "role": "missing-64", + "cost": 1, + "description": "Acquire an observation for role missing-64.", + "expected": null + } + ] + } + ] + } + ], + "acquisitionPlan": { + "status": "INCOMPLETE", + "reason": "Acquisition planning supports at most 64 unresolved requirements.", + "actions": [], + "selectedOptionIds": [], + "totalCost": 0, + "coveredRequirementIds": [], + "unresolvedRequirementIds": [ + "missing-00", + "missing-01", + "missing-02", + "missing-03", + "missing-04", + "missing-05", + "missing-06", + "missing-07", + "missing-08", + "missing-09", + "missing-10", + "missing-11", + "missing-12", + "missing-13", + "missing-14", + "missing-15", + "missing-16", + "missing-17", + "missing-18", + "missing-19", + "missing-20", + "missing-21", + "missing-22", + "missing-23", + "missing-24", + "missing-25", + "missing-26", + "missing-27", + "missing-28", + "missing-29", + "missing-30", + "missing-31", + "missing-32", + "missing-33", + "missing-34", + "missing-35", + "missing-36", + "missing-37", + "missing-38", + "missing-39", + "missing-40", + "missing-41", + "missing-42", + "missing-43", + "missing-44", + "missing-45", + "missing-46", + "missing-47", + "missing-48", + "missing-49", + "missing-50", + "missing-51", + "missing-52", + "missing-53", + "missing-54", + "missing-55", + "missing-56", + "missing-57", + "missing-58", + "missing-59", + "missing-60", + "missing-61", + "missing-62", + "missing-63", + "missing-64" + ] + }, + "verificationRecordDigest": "06818943c48b3bc9b1ccaa6431f29ea1b86f51ad2563fbe7e81a96095944cd10" + } + }, + { + "name": "planner-combination-limit", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "planner-combination-limit", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "mismatch-00", + "type": "dependency", + "description": "Mismatched dependency 0", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-01", + "type": "dependency", + "description": "Mismatched dependency 1", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-02", + "type": "dependency", + "description": "Mismatched dependency 2", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-03", + "type": "dependency", + "description": "Mismatched dependency 3", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-04", + "type": "dependency", + "description": "Mismatched dependency 4", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-05", + "type": "dependency", + "description": "Mismatched dependency 5", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-06", + "type": "dependency", + "description": "Mismatched dependency 6", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-07", + "type": "dependency", + "description": "Mismatched dependency 7", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-08", + "type": "dependency", + "description": "Mismatched dependency 8", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-09", + "type": "dependency", + "description": "Mismatched dependency 9", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-10", + "type": "dependency", + "description": "Mismatched dependency 10", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-11", + "type": "dependency", + "description": "Mismatched dependency 11", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-12", + "type": "dependency", + "description": "Mismatched dependency 12", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-13", + "type": "dependency", + "description": "Mismatched dependency 13", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-14", + "type": "dependency", + "description": "Mismatched dependency 14", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-15", + "type": "dependency", + "description": "Mismatched dependency 15", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + }, + { + "id": "mismatch-16", + "type": "dependency", + "description": "Mismatched dependency 16", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + } + ] + }, + "observations": [ + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + }, + { + "id": "obs-ci-a", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2040" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2040", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-A", + "provenance": "provider_asserted" + } + ] + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "planner-combination-limit", + "contractVersion": "1", + "verdict": "CONTRACT_VIOLATED", + "coverage": { + "required": 17, + "satisfied": 0, + "violated": 17, + "unknown": 0, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "mismatch-00", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 0: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-00:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-00:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-01", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 1: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-01:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-01:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-02", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 2: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-02:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-02:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-03", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 3: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-03:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-03:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-04", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 4: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-04:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-04:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-05", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 5: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-05:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-05:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-06", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 6: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-06:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-06:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-07", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 7: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-07:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-07:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-08", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 8: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-08:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-08:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-09", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 9: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-09:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-09:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-10", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 10: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-10:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-10:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-11", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 11: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-11:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-11:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-12", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 12: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-12:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-12:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-13", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 13: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-13:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-13:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-14", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 14: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-14:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-14:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-15", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 15: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-15:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-15:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + }, + { + "requirementId": "mismatch-16", + "requirementType": "dependency", + "required": true, + "status": "VIOLATED", + "summary": "Mismatched dependency 16: commit-A does not equal commit-B.", + "details": { + "dependentRole": "ci", + "dependencyVersion": "commit-A", + "targetRole": "head", + "targetVersion": "commit-B", + "relation": "exact" + }, + "acquisitionOptions": [ + { + "id": "mismatch-16:acquire-compatible-dependent", + "description": "Acquire dependent evidence bound to the selected target version.", + "actions": [ + { + "id": "acquire_compatible_evidence:ci:c969e13b988f", + "type": "ACQUIRE_COMPATIBLE_EVIDENCE", + "role": "ci", + "cost": 4, + "description": "Acquire ci evidence bound to commit-B.", + "expected": { + "targetRole": "head", + "targetVersion": "commit-B" + } + } + ] + }, + { + "id": "mismatch-16:refresh-target", + "description": "Refresh the target before selecting compatible evidence.", + "actions": [ + { + "id": "refresh_observation:head:6df94fb5680d", + "type": "REFRESH_OBSERVATION", + "role": "head", + "cost": 1, + "description": "Refresh head before selecting compatible evidence.", + "expected": { + "dependentRole": "ci", + "dependentVersion": "commit-A" + } + } + ] + } + ] + } + ], + "acquisitionPlan": { + "status": "INCOMPLETE", + "reason": "Acquisition search exceeds the 65536 combination limit.", + "actions": [], + "selectedOptionIds": [], + "totalCost": 0, + "coveredRequirementIds": [], + "unresolvedRequirementIds": [ + "mismatch-00", + "mismatch-01", + "mismatch-02", + "mismatch-03", + "mismatch-04", + "mismatch-05", + "mismatch-06", + "mismatch-07", + "mismatch-08", + "mismatch-09", + "mismatch-10", + "mismatch-11", + "mismatch-12", + "mismatch-13", + "mismatch-14", + "mismatch-15", + "mismatch-16" + ] + }, + "verificationRecordDigest": "c637dc64eddfccf6617fb47aad5bb4f9e1f33efd7ac31b8b038b155f54428969" + } + }, + { + "name": "reversed-ordering", + "input": { + "protocolVersion": "0.1", + "contract": { + "id": "deploy-current-tested-release", + "version": "1", + "decisionTime": "2026-09-02T18:00:00.000Z", + "assumptions": { + "clockModel": "trusted_normalized", + "intervalModel": "half_open", + "metadataModel": "honest_but_possibly_incomplete" + }, + "requirements": [ + { + "id": "approval-and-quote-overlap", + "type": "common_valid_time", + "description": "The approval and quote were valid at a common time", + "roles": [ + "approval", + "quote" + ], + "within": { + "from": "2026-09-02T17:55:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + }, + { + "id": "ci-status-passed", + "type": "value_equals", + "description": "The CI status is passed", + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + { + "id": "ci-tested-current-head", + "type": "dependency", + "description": "The passing CI run tested the selected branch head", + "dependentRole": "ci", + "targetRole": "head", + "dependencyName": "tested_head" + } + ] + }, + "observations": [ + { + "id": "obs-quote", + "role": "quote", + "resource": { + "provider": "pricing.example", + "account": "acme", + "kind": "quote", + "key": "release-2041" + }, + "value": { + "amount": 1250, + "currency": "USD" + }, + "observedAt": "2026-09-02T17:59:59.500Z", + "acquisitionCost": 3, + "witness": { + "provenance": "provider_asserted", + "version": "quote-17", + "validity": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:03:00.000Z" + } + } + }, + { + "id": "obs-approval", + "role": "approval", + "resource": { + "provider": "change.example", + "account": "acme", + "kind": "approval", + "key": "release-2041" + }, + "value": { + "approved": true + }, + "observedAt": "2026-09-02T17:59:59.000Z", + "acquisitionCost": 2, + "witness": { + "provenance": "provider_asserted", + "version": "approval-8", + "validity": { + "from": "2026-09-02T17:50:00.000Z", + "until": "2026-09-02T18:05:00.000Z" + } + } + }, + { + "id": "obs-ci-b", + "role": "ci", + "resource": { + "provider": "ci.example", + "account": "acme", + "kind": "ci_run", + "key": "run-2041" + }, + "value": { + "status": "passed" + }, + "observedAt": "2026-09-02T17:59:58.500Z", + "acquisitionCost": 4, + "witness": { + "provenance": "provider_asserted", + "version": "run-2041", + "dependencies": [ + { + "name": "tested_head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "relation": "exact", + "version": "commit-B", + "provenance": "provider_asserted" + } + ] + } + }, + { + "id": "obs-head-b", + "role": "head", + "resource": { + "provider": "github", + "account": "acme", + "kind": "branch_head", + "key": "payments/main" + }, + "value": { + "commit": "commit-B" + }, + "observedAt": "2026-09-02T17:59:58.000Z", + "acquisitionCost": 1, + "witness": { + "provenance": "provider_asserted", + "version": "commit-B" + } + } + ] + }, + "expected": { + "protocolVersion": "0.1", + "engineVersion": "0.1.2", + "canonicalization": "worldcut-json-v1", + "contractId": "deploy-current-tested-release", + "contractVersion": "1", + "verdict": "CONTRACT_SATISFIED", + "coverage": { + "required": 3, + "satisfied": 3, + "violated": 0, + "unknown": 0, + "advisory": 0 + }, + "requirementResults": [ + { + "requirementId": "approval-and-quote-overlap", + "requirementType": "common_valid_time", + "required": true, + "status": "SATISFIED", + "summary": "The approval and quote were valid at a common time: a common valid time exists.", + "details": { + "roles": [ + "approval", + "quote" + ], + "commonWindow": { + "from": "2026-09-02T17:58:00.000Z", + "until": "2026-09-02T18:00:00.001Z" + } + }, + "acquisitionOptions": [] + }, + { + "requirementId": "ci-status-passed", + "requirementType": "value_equals", + "required": true, + "status": "SATISFIED", + "summary": "The CI status is passed: observed value matches the requirement.", + "details": { + "role": "ci", + "path": [ + "status" + ], + "expected": "passed" + }, + "acquisitionOptions": [] + }, + { + "requirementId": "ci-tested-current-head", + "requirementType": "dependency", + "required": true, + "status": "SATISFIED", + "summary": "The passing CI run tested the selected branch head: both roles are bound to commit-B.", + "details": { + "dependentRole": "ci", + "targetRole": "head", + "version": "commit-B" + }, + "acquisitionOptions": [] + } + ], + "acquisitionPlan": { + "status": "NOT_NEEDED", + "reason": null, + "actions": [], + "selectedOptionIds": [], + "totalCost": 0, + "coveredRequirementIds": [], + "unresolvedRequirementIds": [] + }, + "verificationRecordDigest": "f402861e5df539f5ea4b69681431c2e2bcbd18e7cb5a02c63a7cfca3b9bb3eee" + } + } + ] +} diff --git a/ports/python/tests/test_cli.py b/ports/python/tests/test_cli.py new file mode 100644 index 0000000..72648c1 --- /dev/null +++ b/ports/python/tests/test_cli.py @@ -0,0 +1,93 @@ +from __future__ import annotations + +import io +import json +import sys +from pathlib import Path +from typing import Any + +import pytest + +from worldcut.cli import run + +DATA = Path(__file__).parent / "data" / "conformance" / "0.1" + + +def _case_with_verdict(verdict: str) -> dict[str, Any]: + vectors = json.loads( + (DATA / "verification-vectors.json").read_text(encoding="utf-8") + ) + return next( + case for case in vectors["cases"] if case["expected"]["verdict"] == verdict + ) + + +def _write_case(tmp_path: Path, verdict: str) -> tuple[Path, dict[str, Any]]: + case = _case_with_verdict(verdict) + path = tmp_path / f"{verdict.lower()}.json" + path.write_text(json.dumps(case["input"]), encoding="utf-8") + return path, case["expected"] + + +def test_cli_prints_the_complete_verification_result( + tmp_path: Path, capsys: pytest.CaptureFixture[str] +) -> None: + path, expected = _write_case(tmp_path, "CONTRACT_SATISFIED") + + assert run([str(path)]) == 0 + assert json.loads(capsys.readouterr().out) == expected + + +def test_cli_can_require_a_satisfied_contract( + tmp_path: Path, capsys: pytest.CaptureFixture[str] +) -> None: + path, expected = _write_case(tmp_path, "CONTRACT_VIOLATED") + + assert run(["--require-satisfied", str(path)]) == 2 + assert json.loads(capsys.readouterr().out) == expected + + +def test_cli_escapes_unicode_for_legacy_console_encodings( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + case = _case_with_verdict("CONTRACT_SATISFIED") + case["input"]["contract"]["requirements"][0]["id"] = "requirement-\U0001f40d" + path = tmp_path / "unicode.json" + path.write_text(json.dumps(case["input"]), encoding="utf-8") + output = io.BytesIO() + stream = io.TextIOWrapper(output, encoding="ascii") + monkeypatch.setattr(sys, "stdout", stream) + + assert run([str(path)]) == 0 + stream.flush() + result = json.loads(output.getvalue().decode("ascii")) + requirement_ids = {item["requirementId"] for item in result["requirementResults"]} + assert "requirement-\U0001f40d" in requirement_ids + + +@pytest.mark.parametrize("arguments", [[], ["--unknown"]]) +def test_cli_rejects_invalid_arguments( + arguments: list[str], capsys: pytest.CaptureFixture[str] +) -> None: + assert run(arguments) == 1 + error = json.loads(capsys.readouterr().err) + assert error["error"]["code"] == "WORLDCUT_INVALID_ARGUMENT" + + +def test_cli_reports_file_read_failures( + tmp_path: Path, capsys: pytest.CaptureFixture[str] +) -> None: + assert run([str(tmp_path / "missing.json")]) == 1 + error = json.loads(capsys.readouterr().err) + assert error["error"]["code"] == "WORLDCUT_FILE_READ_FAILED" + + +def test_cli_reports_invalid_protocol_input( + tmp_path: Path, capsys: pytest.CaptureFixture[str] +) -> None: + path = tmp_path / "invalid.json" + path.write_bytes(b"not json") + + assert run([str(path)]) == 1 + error = json.loads(capsys.readouterr().err) + assert error["error"]["code"] == "WORLDCUT_INVALID_INPUT" diff --git a/ports/python/tests/test_conformance.py b/ports/python/tests/test_conformance.py new file mode 100644 index 0000000..24db1c1 --- /dev/null +++ b/ports/python/tests/test_conformance.py @@ -0,0 +1,107 @@ +from __future__ import annotations + +import hashlib +import json +from pathlib import Path +from typing import Any + +import pytest + +from worldcut import ( + WorldCutError, + canonical_json, + parse_input, + sha256_digest, + verify, + verify_json, +) + +DATA = Path(__file__).parent / "data" / "conformance" / "0.1" + + +def _vectors(name: str) -> dict[str, Any]: + return json.loads((DATA / name).read_text(encoding="utf-8")) + + +@pytest.mark.parametrize( + "case", + _vectors("verification-vectors.json")["cases"], + ids=lambda case: str(case["name"]), +) +def test_verification_vectors(case: dict[str, Any]) -> None: + source = json.dumps( + case["input"], ensure_ascii=False, separators=(",", ":") + ).encode() + assert verify_json(source) == case["expected"] + + +@pytest.mark.parametrize( + "case", + _vectors("invalid-vectors.json")["cases"], + ids=lambda case: str(case["name"]), +) +def test_invalid_vectors(case: dict[str, Any]) -> None: + source = json.dumps( + case["input"], ensure_ascii=False, separators=(",", ":") + ).encode() + with pytest.raises(WorldCutError) as caught: + verify_json(source) + assert caught.value.code == case["expectedErrorCode"] + + +@pytest.mark.parametrize( + "case", + _vectors("canonicalization-vectors.json")["cases"], + ids=lambda case: str(case["name"]), +) +def test_canonicalization_vectors(case: dict[str, Any]) -> None: + assert canonical_json(case["value"]) == case["expectedCanonicalJson"] + assert sha256_digest(case["value"]) == case["expectedSha256"] + + +@pytest.mark.parametrize( + "case", + _vectors("raw-vectors.json")["cases"], + ids=lambda case: str(case["name"]), +) +def test_raw_vectors(case: dict[str, Any]) -> None: + source = (DATA / Path(case["file"])).read_bytes() + with pytest.raises(WorldCutError) as caught: + verify_json(source) + assert caught.value.code in case["acceptedOutcomes"] + + +def test_manifest_hashes_and_counts() -> None: + manifest = _vectors("manifest.json") + for name, metadata in manifest["files"].items(): + source = (DATA / Path(name)).read_bytes() + assert hashlib.sha256(source).hexdigest() == metadata["sha256"] + if "cases" in metadata: + assert len(_vectors(name)["cases"]) == metadata["cases"] + if "bytes" in metadata: + assert len(source) == metadata["bytes"] + + +def test_result_mutation_cannot_affect_later_verification() -> None: + case = _vectors("verification-vectors.json")["cases"][0] + parsed = parse_input(json.dumps(case["input"]).encode()) + first = verify(parsed) + first["requirementResults"][0]["details"] = {"mutated": True} + first["acquisitionPlan"]["actions"].append( + { + "id": "mutated", + "type": "REFRESH_OBSERVATION", + "role": "mutated", + "cost": 1, + "description": "mutated", + "expected": None, + } + ) + second = verify(parsed) + assert second == case["expected"] + + +def test_normalized_year_zero_timestamps_match_reference_domain() -> None: + case = _vectors("verification-vectors.json")["cases"][0] + source = json.dumps(case["input"]).replace("2026-", "0000-") + assert verify_json(source)["verdict"] == "CONTRACT_SATISFIED" diff --git a/ports/python/tests/test_planning.py b/ports/python/tests/test_planning.py new file mode 100644 index 0000000..84fc9b5 --- /dev/null +++ b/ports/python/tests/test_planning.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +from worldcut.models import AcquisitionAction, AcquisitionOption, RequirementResult +from worldcut.planning import select_acquisition_plan + + +def _action(identifier: str, cost: int) -> AcquisitionAction: + return { + "id": identifier, + "type": "REFRESH_OBSERVATION", + "role": identifier, + "cost": cost, + "description": identifier, + "expected": None, + } + + +def _option(identifier: str, actions: list[AcquisitionAction]) -> AcquisitionOption: + return {"id": identifier, "description": identifier, "actions": actions} + + +def _unresolved(identifier: str, options: list[AcquisitionOption]) -> RequirementResult: + return { + "requirementId": identifier, + "requirementType": "dependency", + "required": True, + "status": "UNKNOWN", + "summary": identifier, + "details": None, + "acquisitionOptions": options, + } + + +def test_planner_deduplicates_shared_actions() -> None: + shared = _action("shared", 3) + plan = select_acquisition_plan( + [ + _unresolved( + "r1", + [ + _option("r1-shared", [shared]), + _option("r1-only", [_action("r1", 2)]), + ], + ), + _unresolved( + "r2", + [ + _option("r2-shared", [shared]), + _option("r2-only", [_action("r2", 2)]), + ], + ), + ] + ) + assert plan["status"] == "AVAILABLE" + assert plan["totalCost"] == 3 + assert [action["id"] for action in plan["actions"]] == ["shared"] + + +def test_planner_tie_breaks_by_action_count_then_option_id() -> None: + plan = select_acquisition_plan( + [ + _unresolved( + "r", + [ + _option("r:b", [_action("one", 2)]), + _option("r:a", [_action("left", 1), _action("right", 1)]), + ], + ) + ] + ) + assert plan["selectedOptionIds"] == ["r:b"] diff --git a/ports/python/tests/test_properties.py b/ports/python/tests/test_properties.py new file mode 100644 index 0000000..9843efb --- /dev/null +++ b/ports/python/tests/test_properties.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +import json +import math +from contextlib import suppress +from typing import Any + +from hypothesis import given, settings +from hypothesis import strategies as st + +from worldcut import WorldCutError, canonical_json, sha256_digest, verify_json + +json_scalars = ( + st.none() + | st.booleans() + | st.text() + | st.integers(min_value=-(2**53) + 1, max_value=2**53 - 1) + | st.floats(allow_nan=False, allow_infinity=False) +) +json_values = st.recursive( + json_scalars, + lambda children: ( + st.lists(children, max_size=6) + | st.dictionaries(st.text(), children, max_size=6) + ), + max_leaves=25, +) + + +@given(json_values) +@settings(max_examples=250) +def test_canonicalization_is_deterministic(value: Any) -> None: + try: + first = canonical_json(value) + except TypeError: + return + assert first == canonical_json(value) + assert len(sha256_digest(value)) == 64 + + +@given(st.binary(max_size=1024)) +@settings(max_examples=500) +def test_arbitrary_transport_bytes_never_escape_as_unstructured_errors( + source: bytes, +) -> None: + with suppress(WorldCutError): + verify_json(source) + + +def test_excessive_json_nesting_is_a_structured_input_error() -> None: + source = "[" * 2000 + "0" + "]" * 2000 + try: + verify_json(source) + except WorldCutError: + return + raise AssertionError("excessively nested JSON unexpectedly verified") + + +@given(st.text(max_size=512)) +@settings(max_examples=300) +def test_json_values_without_protocol_shape_are_rejected(source: str) -> None: + try: + parsed: Any = json.loads(source) + except (json.JSONDecodeError, ValueError): + return + if ( + isinstance(parsed, dict) + and parsed.get("protocolVersion") == "0.1" + and "contract" in parsed + and "observations" in parsed + ): + return + try: + verify_json(source) + except WorldCutError: + return + raise AssertionError("non-protocol JSON unexpectedly verified") + + +@given(st.floats(allow_nan=True, allow_infinity=True)) +def test_non_finite_values_are_not_canonicalizable(value: float) -> None: + if math.isfinite(value): + canonical_json(value) + else: + try: + canonical_json(value) + except TypeError: + return + raise AssertionError("non-finite value unexpectedly canonicalized") diff --git a/ports/python/tests/test_public_api.py b/ports/python/tests/test_public_api.py new file mode 100644 index 0000000..da2dcfd --- /dev/null +++ b/ports/python/tests/test_public_api.py @@ -0,0 +1,30 @@ +from __future__ import annotations + +from importlib.resources import files + +import pytest + +import worldcut +from worldcut import ParsedInput +from worldcut.cli import run + + +def test_type_marker_is_installed() -> None: + assert files("worldcut").joinpath("py.typed").is_file() + + +def test_parsed_input_cannot_be_constructed_or_mutated() -> None: + with pytest.raises(TypeError): + ParsedInput(object(), object()) # type: ignore[arg-type] + + +def test_cli_help(capsys: pytest.CaptureFixture[str]) -> None: + assert run(["--help"]) == 0 + assert "worldcut-py" in capsys.readouterr().out + + +def test_public_versions() -> None: + assert worldcut.__version__ == "0.1.0" + assert worldcut.PROTOCOL_VERSION == "0.1" + assert worldcut.ENGINE_VERSION == "0.1.2" + assert worldcut.CANONICALIZATION == "worldcut-json-v1" diff --git a/scripts/generate-conformance.mjs b/scripts/generate-conformance.mjs index 1335917..ff1d831 100644 --- a/scripts/generate-conformance.mjs +++ b/scripts/generate-conformance.mjs @@ -13,6 +13,7 @@ const projectRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const outputDirectory = join(projectRoot, "conformance", "0.1"); const mirrorDirectories = [ join(projectRoot, "ports", "go", "testdata", "conformance", "0.1"), + join(projectRoot, "ports", "python", "tests", "data", "conformance", "0.1"), ]; const writeMode = process.argv.includes("--write");