capsule-engine 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- capsule_engine/__init__.py +17 -0
- capsule_engine/bundle_viewer/__init__.py +21 -0
- capsule_engine/bundle_viewer/static/offline_shell.html +1509 -0
- capsule_engine/bundle_viewer/viewer.py +57 -0
- capsule_engine/cli/__init__.py +5 -0
- capsule_engine/cli/bundle_cmd.py +269 -0
- capsule_engine/cli/console_cmd.py +70 -0
- capsule_engine/cli/constraints_cmd.py +74 -0
- capsule_engine/cli/format.py +173 -0
- capsule_engine/cli/guard_cmds.py +361 -0
- capsule_engine/cli/init_cmds.py +169 -0
- capsule_engine/cli/main.py +120 -0
- capsule_engine/cli/packs_cmds.py +96 -0
- capsule_engine/cli/telemetry_cmd.py +80 -0
- capsule_engine/cli/tenant_cmds.py +199 -0
- capsule_engine/cli/verify_cmd.py +110 -0
- capsule_engine/compiler/__init__.py +13 -0
- capsule_engine/compiler/effect_model.py +79 -0
- capsule_engine/compiler/vocabulary.py +253 -0
- capsule_engine/console/__init__.py +10 -0
- capsule_engine/console/api.py +251 -0
- capsule_engine/console/components.css +406 -0
- capsule_engine/console/console.css +130 -0
- capsule_engine/console/console.html +51 -0
- capsule_engine/console/console.js +330 -0
- capsule_engine/console/gallery.html +274 -0
- capsule_engine/console/server.py +137 -0
- capsule_engine/console/tokens.css +68 -0
- capsule_engine/conversation/__init__.py +88 -0
- capsule_engine/conversation/capsules.py +268 -0
- capsule_engine/conversation/exchange.py +279 -0
- capsule_engine/conversation/merkle.py +80 -0
- capsule_engine/conversation/session.py +101 -0
- capsule_engine/envcompat.py +15 -0
- capsule_engine/events/__init__.py +14 -0
- capsule_engine/events/capsule.py +133 -0
- capsule_engine/examples/__init__.py +9 -0
- capsule_engine/examples/data/tau2_airline/LICENSE-tau2-bench +21 -0
- capsule_engine/examples/data/tau2_airline/PROVENANCE.json +70 -0
- capsule_engine/examples/data/tau2_airline/hand_labels.json +893 -0
- capsule_engine/examples/data/tau2_airline/pilot1_live_gemini-2-5-flash_airline_shift1.jsonl +190 -0
- capsule_engine/examples/data/tau2_airline/tau2_committed_claude-3-7-sonnet_airline_trial0.jsonl +556 -0
- capsule_engine/examples/data/tau2_airline/tau2_committed_gpt-4-1-mini_airline_trial0.jsonl +480 -0
- capsule_engine/examples/data/tau2_airline/tau2_committed_gpt-4-1_airline_trial0.jsonl +496 -0
- capsule_engine/examples/data/tau2_airline/tau2_committed_o4-mini_airline_trial0.jsonl +392 -0
- capsule_engine/examples/data/tau2_airline/tau2_conversations_claude-3-7-sonnet_airline_4trials.jsonl +200 -0
- capsule_engine/examples/tau2_airline_reference.py +460 -0
- capsule_engine/examples/tau2_conversation_exchange.py +92 -0
- capsule_engine/folds/__init__.py +104 -0
- capsule_engine/folds/account_core.py +89 -0
- capsule_engine/folds/approval_latency.py +86 -0
- capsule_engine/folds/catalog.py +79 -0
- capsule_engine/folds/catalog_defs/actions.count_by_developer.yaml +10 -0
- capsule_engine/folds/catalog_defs/actions.executed_count.yaml +16 -0
- capsule_engine/folds/catalog_defs/actions.last_decision.yaml +12 -0
- capsule_engine/folds/catalog_defs/counterparty.seen_before.v2.yaml +34 -0
- capsule_engine/folds/catalog_defs/counterparty.seen_before.v3.yaml +38 -0
- capsule_engine/folds/catalog_defs/counterparty.seen_before.yaml +28 -0
- capsule_engine/folds/catalog_defs/disclosure.class_seen.yaml +29 -0
- capsule_engine/folds/catalog_defs/disclosure.statement_seen.yaml +32 -0
- capsule_engine/folds/catalog_defs/hold.active_exposure.yaml +44 -0
- capsule_engine/folds/catalog_defs/spend.weekly.v2.yaml +38 -0
- capsule_engine/folds/catalog_defs/spend.weekly.v3.1.yaml +71 -0
- capsule_engine/folds/catalog_defs/spend.weekly.v3.yaml +76 -0
- capsule_engine/folds/catalog_defs/spend.weekly.yaml +33 -0
- capsule_engine/folds/counterparty_signals.py +179 -0
- capsule_engine/folds/definition.py +421 -0
- capsule_engine/folds/duration.py +16 -0
- capsule_engine/folds/engine.py +436 -0
- capsule_engine/folds/errors.py +44 -0
- capsule_engine/folds/loader.py +24 -0
- capsule_engine/folds/ordering.py +143 -0
- capsule_engine/folds/paths.py +25 -0
- capsule_engine/folds/record_type_coverage.py +58 -0
- capsule_engine/folds/reducers.py +75 -0
- capsule_engine/folds/retention_continuity.py +117 -0
- capsule_engine/folds/set_membership.py +59 -0
- capsule_engine/folds/taxonomy.py +231 -0
- capsule_engine/guards/__init__.py +59 -0
- capsule_engine/guards/action.py +446 -0
- capsule_engine/guards/action_taxonomy.json +27 -0
- capsule_engine/guards/action_taxonomy_v2.json +27 -0
- capsule_engine/guards/action_taxonomy_v3.json +27 -0
- capsule_engine/guards/action_taxonomy_v4.json +27 -0
- capsule_engine/guards/action_taxonomy_v5.json +27 -0
- capsule_engine/guards/capsule.py +377 -0
- capsule_engine/guards/checks/__init__.py +268 -0
- capsule_engine/guards/checks/action_class_gate.py +199 -0
- capsule_engine/guards/checks/base.py +33 -0
- capsule_engine/guards/checks/caps.py +517 -0
- capsule_engine/guards/checks/channel_change.py +64 -0
- capsule_engine/guards/checks/commitment.py +41 -0
- capsule_engine/guards/checks/counterparty_identity_change.py +95 -0
- capsule_engine/guards/checks/counterparty_list.py +176 -0
- capsule_engine/guards/checks/counterparty_seen_before.py +160 -0
- capsule_engine/guards/checks/credential_pattern.py +73 -0
- capsule_engine/guards/checks/dedupe.py +259 -0
- capsule_engine/guards/checks/destination_rail.py +120 -0
- capsule_engine/guards/checks/field_change_count.py +100 -0
- capsule_engine/guards/checks/offer_expiry.py +134 -0
- capsule_engine/guards/checks/plan_containment.py +180 -0
- capsule_engine/guards/checks/price_floor.py +211 -0
- capsule_engine/guards/checks/promise_never.py +236 -0
- capsule_engine/guards/checks/promise_requires_approval.py +214 -0
- capsule_engine/guards/checks/recipient_role.py +117 -0
- capsule_engine/guards/checks/recurring_charge.py +49 -0
- capsule_engine/guards/checks/refundability.py +46 -0
- capsule_engine/guards/checks/release_on_acceptance.py +286 -0
- capsule_engine/guards/checks/required_disclosure.py +233 -0
- capsule_engine/guards/checks/single_commitment.py +221 -0
- capsule_engine/guards/checks/task_authority.py +182 -0
- capsule_engine/guards/checks/upfront_amount.py +71 -0
- capsule_engine/guards/checks/verify_before_dispatch.py +75 -0
- capsule_engine/guards/classes.py +393 -0
- capsule_engine/guards/engine.py +926 -0
- capsule_engine/guards/history_state.py +127 -0
- capsule_engine/guards/plan.py +237 -0
- capsule_engine/guards/revocation.py +120 -0
- capsule_engine/guards/signing.py +60 -0
- capsule_engine/guards/statements.py +62 -0
- capsule_engine/guards/tool_call.py +83 -0
- capsule_engine/guards/wickets/__init__.py +23 -0
- capsule_engine/guards/wickets/catalog.py +75 -0
- capsule_engine/guards/wickets/catalog_defs/action_class_gate.v1.1.yaml +38 -0
- capsule_engine/guards/wickets/catalog_defs/action_class_gate.v1.2.yaml +52 -0
- capsule_engine/guards/wickets/catalog_defs/action_class_gate.yaml +34 -0
- capsule_engine/guards/wickets/catalog_defs/caps.v2.yaml +30 -0
- capsule_engine/guards/wickets/catalog_defs/caps.v3.yaml +49 -0
- capsule_engine/guards/wickets/catalog_defs/caps.v4.yaml +45 -0
- capsule_engine/guards/wickets/catalog_defs/caps.v5.1.yaml +53 -0
- capsule_engine/guards/wickets/catalog_defs/caps.v5.yaml +43 -0
- capsule_engine/guards/wickets/catalog_defs/caps.yaml +17 -0
- capsule_engine/guards/wickets/catalog_defs/caps_holds.yaml +18 -0
- capsule_engine/guards/wickets/catalog_defs/channel_change.v1.1.yaml +18 -0
- capsule_engine/guards/wickets/catalog_defs/channel_change.yaml +10 -0
- capsule_engine/guards/wickets/catalog_defs/counterparty_identity_change.yaml +9 -0
- capsule_engine/guards/wickets/catalog_defs/counterparty_list.yaml +20 -0
- capsule_engine/guards/wickets/catalog_defs/counterparty_seen_before.v2.yaml +15 -0
- capsule_engine/guards/wickets/catalog_defs/counterparty_seen_before.v3.yaml +23 -0
- capsule_engine/guards/wickets/catalog_defs/counterparty_seen_before.v4.yaml +26 -0
- capsule_engine/guards/wickets/catalog_defs/counterparty_seen_before.yaml +14 -0
- capsule_engine/guards/wickets/catalog_defs/credential_pattern.yaml +14 -0
- capsule_engine/guards/wickets/catalog_defs/dedupe.yaml +19 -0
- capsule_engine/guards/wickets/catalog_defs/destination_rail.seller.v1.1.yaml +32 -0
- capsule_engine/guards/wickets/catalog_defs/destination_rail.seller.yaml +10 -0
- capsule_engine/guards/wickets/catalog_defs/destination_rail.yaml +9 -0
- capsule_engine/guards/wickets/catalog_defs/hold_reconcile.yaml +14 -0
- capsule_engine/guards/wickets/catalog_defs/material_fields_changed.v1.1.yaml +22 -0
- capsule_engine/guards/wickets/catalog_defs/material_fields_changed.yaml +14 -0
- capsule_engine/guards/wickets/catalog_defs/offer_expiry.v1.1.yaml +31 -0
- capsule_engine/guards/wickets/catalog_defs/offer_expiry.yaml +24 -0
- capsule_engine/guards/wickets/catalog_defs/offer_fields_changed.v1.1.yaml +22 -0
- capsule_engine/guards/wickets/catalog_defs/offer_fields_changed.yaml +10 -0
- capsule_engine/guards/wickets/catalog_defs/price_floor.yaml +32 -0
- capsule_engine/guards/wickets/catalog_defs/promise_never.v1.1.yaml +64 -0
- capsule_engine/guards/wickets/catalog_defs/promise_never.yaml +16 -0
- capsule_engine/guards/wickets/catalog_defs/promise_requires_approval.v1.1.yaml +26 -0
- capsule_engine/guards/wickets/catalog_defs/promise_requires_approval.yaml +21 -0
- capsule_engine/guards/wickets/catalog_defs/recipient_role.seller.v1.1.yaml +23 -0
- capsule_engine/guards/wickets/catalog_defs/recipient_role.seller.v1.2.yaml +24 -0
- capsule_engine/guards/wickets/catalog_defs/recipient_role.seller.yaml +10 -0
- capsule_engine/guards/wickets/catalog_defs/recipient_role.v1.1.yaml +26 -0
- capsule_engine/guards/wickets/catalog_defs/recipient_role.yaml +11 -0
- capsule_engine/guards/wickets/catalog_defs/recipient_seen_before.yaml +16 -0
- capsule_engine/guards/wickets/catalog_defs/recurring_charge.yaml +9 -0
- capsule_engine/guards/wickets/catalog_defs/refundability.v1.1.yaml +15 -0
- capsule_engine/guards/wickets/catalog_defs/refundability.yaml +7 -0
- capsule_engine/guards/wickets/catalog_defs/release_on_acceptance.seller.v1.1.yaml +44 -0
- capsule_engine/guards/wickets/catalog_defs/release_on_acceptance.seller.v1.2.yaml +63 -0
- capsule_engine/guards/wickets/catalog_defs/release_on_acceptance.seller.yaml +36 -0
- capsule_engine/guards/wickets/catalog_defs/required_disclosure.v1.1.yaml +36 -0
- capsule_engine/guards/wickets/catalog_defs/required_disclosure.v1.2.yaml +42 -0
- capsule_engine/guards/wickets/catalog_defs/required_disclosure.yaml +25 -0
- capsule_engine/guards/wickets/catalog_defs/single_commitment.seller.yaml +14 -0
- capsule_engine/guards/wickets/catalog_defs/task_authority.v1.1.yaml +20 -0
- capsule_engine/guards/wickets/catalog_defs/task_authority.yaml +8 -0
- capsule_engine/guards/wickets/catalog_defs/upfront_amount.v1.1.yaml +19 -0
- capsule_engine/guards/wickets/catalog_defs/upfront_amount.yaml +11 -0
- capsule_engine/guards/wickets/catalog_defs/verify_before_dispatch.yaml +9 -0
- capsule_engine/guards/wickets/definition.py +164 -0
- capsule_engine/guards/wickets/errors.py +18 -0
- capsule_engine/guards/wickets/loader.py +26 -0
- capsule_engine/guards/wickets/retired.py +62 -0
- capsule_engine/holds/__init__.py +35 -0
- capsule_engine/holds/capsules.py +266 -0
- capsule_engine/holds/engine.py +476 -0
- capsule_engine/holds/errors.py +29 -0
- capsule_engine/holds/policy.py +62 -0
- capsule_engine/holds/scope.py +47 -0
- capsule_engine/mcp/__init__.py +16 -0
- capsule_engine/mcp/config.py +117 -0
- capsule_engine/mcp/server.py +338 -0
- capsule_engine/mcp/tools.py +424 -0
- capsule_engine/packaging.py +60 -0
- capsule_engine/packs/__init__.py +45 -0
- capsule_engine/packs/backfill_coverage.py +238 -0
- capsule_engine/packs/catalog/airline-engagement/AI-BOOTSTRAP.md +53 -0
- capsule_engine/packs/catalog/airline-engagement/folds/session_close.yaml +8 -0
- capsule_engine/packs/catalog/airline-engagement/pack.yaml +146 -0
- capsule_engine/packs/catalog/eu-ai-act/fixtures/trace/good_execution.json +36 -0
- capsule_engine/packs/catalog/eu-ai-act/fixtures/trace/oversight_declared.json +36 -0
- capsule_engine/packs/catalog/eu-ai-act/fixtures/trace/tampered_execution.json +36 -0
- capsule_engine/packs/catalog/eu-ai-act/fixtures/trace/trusted_issuer.jwk.json +5 -0
- capsule_engine/packs/catalog/eu-ai-act/obligations-pack-note.md +68 -0
- capsule_engine/packs/catalog/eu-ai-act/obligations-register.yaml +761 -0
- capsule_engine/packs/catalog/eu-ai-act/pack.yaml +88 -0
- capsule_engine/packs/catalog/eu-ai-act/register.yaml +96 -0
- capsule_engine/packs/catalog/eu-ai-act-deterministic/fixtures/synthetic_internal_assist_sample.jsonl +6 -0
- capsule_engine/packs/catalog/eu-ai-act-deterministic/pack.yaml +580 -0
- capsule_engine/packs/catalog/everyday/AI-BOOTSTRAP.md +194 -0
- capsule_engine/packs/catalog/everyday/fixtures/mini_ledger.jsonl +45 -0
- capsule_engine/packs/catalog/everyday/pack.yaml +480 -0
- capsule_engine/packs/catalog/payments-safety/AI-BOOTSTRAP.md +83 -0
- capsule_engine/packs/catalog/payments-safety/fixtures/mini_ledger.jsonl +8 -0
- capsule_engine/packs/catalog/payments-safety/folds/spend_weekly.yaml +29 -0
- capsule_engine/packs/catalog/payments-safety/pack.yaml +112 -0
- capsule_engine/packs/catalog/seller/fixtures/mini_ledger.jsonl +83 -0
- capsule_engine/packs/catalog/seller/pack.yaml +503 -0
- capsule_engine/packs/catalog/standard-vendor/AI-BOOTSTRAP.md +70 -0
- capsule_engine/packs/catalog/standard-vendor/folds/session_close.yaml +8 -0
- capsule_engine/packs/catalog/standard-vendor/pack.yaml +466 -0
- capsule_engine/packs/contract_diff.py +809 -0
- capsule_engine/packs/contract_validate.py +185 -0
- capsule_engine/packs/corpus_verify.py +126 -0
- capsule_engine/packs/enforce.py +81 -0
- capsule_engine/packs/errors.py +159 -0
- capsule_engine/packs/eu_ai_act_trace_field_map.py +46 -0
- capsule_engine/packs/install.py +266 -0
- capsule_engine/packs/loader.py +1462 -0
- capsule_engine/packs/measurability_report.py +280 -0
- capsule_engine/packs/obligation_results.py +72 -0
- capsule_engine/packs/pins.py +92 -0
- capsule_engine/packs/schema.py +1053 -0
- capsule_engine/packs/thresholds.py +146 -0
- capsule_engine/packs/trace_attainment.py +188 -0
- capsule_engine/packs/trace_reader.py +104 -0
- capsule_engine/policy/__init__.py +37 -0
- capsule_engine/policy/activation.py +87 -0
- capsule_engine/policy/catalog_defs/default.yaml +23 -0
- capsule_engine/policy/catalog_defs/holds.yaml +27 -0
- capsule_engine/policy/errors.py +46 -0
- capsule_engine/policy/limits.py +287 -0
- capsule_engine/policy/loader.py +26 -0
- capsule_engine/policy/manifest.py +289 -0
- capsule_engine/policy/profile.py +281 -0
- capsule_engine/policy/resolve.py +224 -0
- capsule_engine/register/__init__.py +39 -0
- capsule_engine/register/compiler.py +219 -0
- capsule_engine/register/errors.py +40 -0
- capsule_engine/register/loader.py +247 -0
- capsule_engine/register/schema.py +129 -0
- capsule_engine/registry/__init__.py +19 -0
- capsule_engine/registry/conventions.json +162 -0
- capsule_engine/registry/conventions.py +188 -0
- capsule_engine/registry/cpb_registry.json +78 -0
- capsule_engine/report/__init__.py +62 -0
- capsule_engine/report/build.py +267 -0
- capsule_engine/report/coverage.py +777 -0
- capsule_engine/report/errors.py +35 -0
- capsule_engine/report/live_check.py +126 -0
- capsule_engine/report/live_history.py +420 -0
- capsule_engine/report/model.py +95 -0
- capsule_engine/report/render.py +467 -0
- capsule_engine/report/replay.py +1677 -0
- capsule_engine/report/result.py +504 -0
- capsule_engine/report/result_from_folds.py +222 -0
- capsule_engine/report/result_from_layers.py +670 -0
- capsule_engine/report/sale_bundle.py +864 -0
- capsule_engine/report/static/verify.js +451 -0
- capsule_engine/schemas/evidence-contract-v0.json +383 -0
- capsule_engine/schemas/vendor/epistemic-types.json +21 -0
- capsule_engine/schemas/vendor/evidence-result-v0.json +463 -0
- capsule_engine/telemetry/__init__.py +9 -0
- capsule_engine/telemetry/consent.py +39 -0
- capsule_engine/telemetry/events.py +93 -0
- capsule_engine/telemetry/fixtures/synthetic_events.jsonl +45 -0
- capsule_engine/telemetry/funnel.py +147 -0
- capsule_engine/telemetry/record.py +106 -0
- capsule_engine/telemetry/sink.py +61 -0
- capsule_engine/telemetry/state.py +60 -0
- capsule_engine/tenants.py +327 -0
- capsule_engine-0.1.0.dist-info/METADATA +47 -0
- capsule_engine-0.1.0.dist-info/RECORD +288 -0
- capsule_engine-0.1.0.dist-info/WHEEL +5 -0
- capsule_engine-0.1.0.dist-info/entry_points.txt +2 -0
- capsule_engine-0.1.0.dist-info/licenses/LICENSE +202 -0
- capsule_engine-0.1.0.dist-info/licenses/capsule_engine/examples/data/tau2_airline/LICENSE-tau2-bench +21 -0
- capsule_engine-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Backfill provenance mode: per-requirement evidence
|
|
3
|
+
sufficiency over a capsule stream that may mix contemporaneous and
|
|
4
|
+
backfilled records (AAC -05 ``draft-mih-scitt-agent-action-capsule-05``
|
|
5
|
+
§provenancemode, "Provenance mode and backfilled records").
|
|
6
|
+
|
|
7
|
+
Two rules from that section, mechanically enforced here rather than left to
|
|
8
|
+
a caller to remember (RULED 2026-09-22, decisions-log §6.4):
|
|
9
|
+
|
|
10
|
+
1. **Status cap.** A backfilled record's occurrence-time claim can never
|
|
11
|
+
satisfy a requirement whose ``minimum_assurance`` includes
|
|
12
|
+
``"committed"`` -- log-witnessed time assurance -- unless a
|
|
13
|
+
``references[]`` entry cites, by digest, a corroborating witnessed
|
|
14
|
+
timestamp (``citation_purpose: "corroborates_source_time"``). The cap is
|
|
15
|
+
REDERIVED from that evidence, never trusted off a claimed
|
|
16
|
+
``provenance_mode.time_rung`` field, mirroring
|
|
17
|
+
``agent_action_capsule.verify``'s own check 9 discipline.
|
|
18
|
+
2. **Duplicates count once.** A record chained ``chain.relation:
|
|
19
|
+
"duplicates"`` to a parent present in the same stream is excluded from
|
|
20
|
+
independent counting; the contemporaneous parent's own status governs.
|
|
21
|
+
|
|
22
|
+
**Statuses use the schema's own vocabulary, not the fold verdict
|
|
23
|
+
vocabulary.** ``capsule_engine/schemas/evidence-contract-v0.json``'s ``bundleAssertionStatus``
|
|
24
|
+
(``SATISFIED``/``INSUFFICIENT``/``NOT_FOUND``/...) is about **evidence
|
|
25
|
+
sufficiency and availability** -- the question this module answers.
|
|
26
|
+
``met``/``not_met``/``insufficient_evidence`` (``folds/ordering.py`` and
|
|
27
|
+
siblings) is the DIFFERENT, judged-OUTCOME axis and is not reused here. Its
|
|
28
|
+
authority is the judged-outcome axis: claim.verdict, met | not_met |
|
|
29
|
+
not_evaluable (agent-action-capsule spec/evidence-result-v0.md §1, Verdict;
|
|
30
|
+
read at agent-action-capsule commit ee7888df15f1db7eecfe9da62626d290eeabcce6).
|
|
31
|
+
|
|
32
|
+
**Trusted-dict input, same as every fold in this package.** This module
|
|
33
|
+
re-derives only the ``provenance_mode``/duplicate facts it needs directly
|
|
34
|
+
off already-verified capsule dicts (the ``folds/engine.py`` assumption);
|
|
35
|
+
it does not re-run full structural verification via
|
|
36
|
+
``agent_action_capsule.verify_store``, which requires complete,
|
|
37
|
+
cryptographically valid capsules and is redundant with verification already
|
|
38
|
+
done upstream at ingest.
|
|
39
|
+
|
|
40
|
+
**Scope, held hard.** This is a coverage/sufficiency primitive for ONE
|
|
41
|
+
requirement's already-identified candidate evidence (the ``matches``
|
|
42
|
+
predicate) -- not a general Evidence Contract evaluator that resolves which
|
|
43
|
+
records answer which requirement (no such engine exists in this package
|
|
44
|
+
today; see the GRC folds -- ``ordering.py``, ``retention_continuity.py``,
|
|
45
|
+
``set_membership.py``, ``record_type_coverage.py`` -- for the same
|
|
46
|
+
narrow-primitive-over-monolith precedent).
|
|
47
|
+
"""
|
|
48
|
+
from __future__ import annotations
|
|
49
|
+
|
|
50
|
+
import hashlib
|
|
51
|
+
import json
|
|
52
|
+
from collections.abc import Callable, Mapping
|
|
53
|
+
from dataclasses import dataclass
|
|
54
|
+
from typing import Any
|
|
55
|
+
|
|
56
|
+
from agent_action_capsule.canonical import FloatInDigestError, UnsafeIntegerError, json_digest
|
|
57
|
+
from agent_action_capsule.contracts import TIME_RUNGS # noqa: F401 -- re-exported for callers
|
|
58
|
+
|
|
59
|
+
__all__ = [
|
|
60
|
+
"STATUS_SATISFIED",
|
|
61
|
+
"STATUS_INSUFFICIENT",
|
|
62
|
+
"STATUS_NOT_FOUND",
|
|
63
|
+
"MODE_CONTEMPORANEOUS",
|
|
64
|
+
"MODE_BACKFILLED",
|
|
65
|
+
"RequirementCoverageResult",
|
|
66
|
+
"evaluate_requirement_coverage",
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
# capsule_engine/schemas/evidence-contract-v0.json $defs.bundleAssertionStatus (the three
|
|
70
|
+
# values a coverage/sufficiency check can produce; SATISFIED/GAP/UNKNOWN's
|
|
71
|
+
# other bundle-level siblings -- NOT_COMMITTED, WITHHELD, CONTRADICTED,
|
|
72
|
+
# NOT_APPLICABLE, UNKNOWN -- are a different check's business, not this one's).
|
|
73
|
+
STATUS_SATISFIED = "SATISFIED"
|
|
74
|
+
STATUS_INSUFFICIENT = "INSUFFICIENT"
|
|
75
|
+
STATUS_NOT_FOUND = "NOT_FOUND"
|
|
76
|
+
|
|
77
|
+
MODE_CONTEMPORANEOUS = "contemporaneous"
|
|
78
|
+
MODE_BACKFILLED = "backfilled"
|
|
79
|
+
|
|
80
|
+
# AAC -05 §provenancemode; REGISTRY.md §11 -- the one citation_purpose that
|
|
81
|
+
# can raise a backfilled record's time_rung above self_attested.
|
|
82
|
+
_CORROBORATES_SOURCE_TIME = "corroborates_source_time"
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _record_id(record: Mapping[str, Any]) -> str:
|
|
86
|
+
"""A real capsule's own ``capsule_id`` when present, else a content
|
|
87
|
+
digest over the record -- mirrors ``folds/engine.py``'s
|
|
88
|
+
``_record_identity`` exactly, so a synthetic/fixture record with no
|
|
89
|
+
``capsule_id`` still gets a stable, deterministic identity rather than
|
|
90
|
+
``None``."""
|
|
91
|
+
capsule_id = record.get("capsule_id")
|
|
92
|
+
if isinstance(capsule_id, str) and capsule_id:
|
|
93
|
+
return capsule_id
|
|
94
|
+
try:
|
|
95
|
+
return json_digest(dict(record))
|
|
96
|
+
except (FloatInDigestError, UnsafeIntegerError):
|
|
97
|
+
return hashlib.sha256(json.dumps(dict(record), sort_keys=True, default=str).encode("utf-8")).hexdigest()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _provenance_mode(record: Mapping[str, Any]) -> str:
|
|
101
|
+
pm = record.get("provenance_mode")
|
|
102
|
+
if isinstance(pm, Mapping) and pm.get("mode") in (MODE_CONTEMPORANEOUS, MODE_BACKFILLED):
|
|
103
|
+
return pm["mode"]
|
|
104
|
+
return MODE_CONTEMPORANEOUS # absent block => contemporaneous (AAC -05 §provenancemode)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _has_witnessed_corroboration(record: Mapping[str, Any]) -> bool:
|
|
108
|
+
refs = record.get("references")
|
|
109
|
+
if not isinstance(refs, list):
|
|
110
|
+
return False
|
|
111
|
+
for r in refs:
|
|
112
|
+
if (
|
|
113
|
+
isinstance(r, Mapping)
|
|
114
|
+
and r.get("citation_purpose") == _CORROBORATES_SOURCE_TIME
|
|
115
|
+
and isinstance(r.get("type"), str) and r.get("type")
|
|
116
|
+
and isinstance(r.get("digest_alg"), str) and r.get("digest_alg")
|
|
117
|
+
and isinstance(r.get("digest"), str) and r.get("digest")
|
|
118
|
+
):
|
|
119
|
+
return True
|
|
120
|
+
return False
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _time_rung(record: Mapping[str, Any]) -> str:
|
|
124
|
+
"""``"witnessed"`` for a contemporaneous record (``sealed_at`` IS the
|
|
125
|
+
witnessable time, AAC -05 §provenancemode "Time semantics, normative");
|
|
126
|
+
for a backfilled record, ``"witnessed"`` only with a well-formed
|
|
127
|
+
corroborating reference, else ``"self_attested"`` -- never trusts a
|
|
128
|
+
claimed ``provenance_mode.time_rung`` by itself."""
|
|
129
|
+
if _provenance_mode(record) != MODE_BACKFILLED:
|
|
130
|
+
return "witnessed"
|
|
131
|
+
return "witnessed" if _has_witnessed_corroboration(record) else "self_attested"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _duplicate_parent_id(record: Mapping[str, Any]) -> str | None:
|
|
135
|
+
chain = record.get("chain")
|
|
136
|
+
if isinstance(chain, Mapping) and chain.get("relation") == "duplicates":
|
|
137
|
+
parent = chain.get("parent_capsule_id")
|
|
138
|
+
if isinstance(parent, str) and parent:
|
|
139
|
+
return parent
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@dataclass(frozen=True)
|
|
144
|
+
class RequirementCoverageResult:
|
|
145
|
+
status: str # STATUS_SATISFIED | STATUS_INSUFFICIENT | STATUS_NOT_FOUND
|
|
146
|
+
detail: str
|
|
147
|
+
considered_count: int
|
|
148
|
+
matched_count: int # candidates before duplicate collapse
|
|
149
|
+
duplicates_collapsed_count: int
|
|
150
|
+
contemporaneous_count: int # surviving, post-collapse
|
|
151
|
+
backfilled_count: int # surviving, post-collapse
|
|
152
|
+
matched_capsule_ids: tuple[str, ...]
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def evaluate_requirement_coverage(
|
|
156
|
+
records: list[dict],
|
|
157
|
+
*,
|
|
158
|
+
matches: Callable[[dict], bool],
|
|
159
|
+
minimum_assurance: frozenset[str] = frozenset(),
|
|
160
|
+
) -> RequirementCoverageResult:
|
|
161
|
+
"""Walk ``records`` (ledger order, never re-sorted -- same discipline
|
|
162
|
+
``folds/engine.py`` documents), select the ``matches`` predicate's
|
|
163
|
+
candidates, collapse ``chain.relation: "duplicates"`` pairs to their
|
|
164
|
+
contemporaneous parent, then report sufficiency.
|
|
165
|
+
|
|
166
|
+
``minimum_assurance`` containing ``"committed"`` applies the status cap:
|
|
167
|
+
a requirement needing Committed-or-higher assurance is
|
|
168
|
+
``STATUS_INSUFFICIENT`` when every surviving candidate is a backfilled
|
|
169
|
+
record capped at ``self_attested`` -- evidence exists, it just cannot
|
|
170
|
+
clear the bar, which is a different, more specific fact than
|
|
171
|
+
``STATUS_NOT_FOUND`` (no evidence at all).
|
|
172
|
+
|
|
173
|
+
``matches`` is REQUIRED, no default, the same explicit-injection
|
|
174
|
+
convention ``folds/ordering.py``'s ``before``/``after`` and
|
|
175
|
+
``packs/measurability_report.py``'s ``entity_key`` use: this module has
|
|
176
|
+
no built-in notion of which records answer which requirement.
|
|
177
|
+
"""
|
|
178
|
+
candidates = [r for r in records if matches(r)]
|
|
179
|
+
by_id = {rid: r for r in records if (rid := _record_id(r)) is not None}
|
|
180
|
+
|
|
181
|
+
collapsed = 0
|
|
182
|
+
surviving: list[dict] = []
|
|
183
|
+
for record in candidates:
|
|
184
|
+
parent_id = _duplicate_parent_id(record)
|
|
185
|
+
if parent_id is not None and parent_id in by_id:
|
|
186
|
+
collapsed += 1
|
|
187
|
+
continue
|
|
188
|
+
surviving.append(record)
|
|
189
|
+
|
|
190
|
+
contemporaneous = [r for r in surviving if _provenance_mode(r) == MODE_CONTEMPORANEOUS]
|
|
191
|
+
backfilled = [r for r in surviving if _provenance_mode(r) == MODE_BACKFILLED]
|
|
192
|
+
|
|
193
|
+
if not surviving:
|
|
194
|
+
return RequirementCoverageResult(
|
|
195
|
+
status=STATUS_NOT_FOUND,
|
|
196
|
+
detail="no evidence record satisfies this requirement's matcher",
|
|
197
|
+
considered_count=len(records),
|
|
198
|
+
matched_count=len(candidates),
|
|
199
|
+
duplicates_collapsed_count=collapsed,
|
|
200
|
+
contemporaneous_count=0,
|
|
201
|
+
backfilled_count=0,
|
|
202
|
+
matched_capsule_ids=(),
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
if "committed" in minimum_assurance:
|
|
206
|
+
committed_eligible = [r for r in surviving if _time_rung(r) == "witnessed"]
|
|
207
|
+
if not committed_eligible:
|
|
208
|
+
return RequirementCoverageResult(
|
|
209
|
+
status=STATUS_INSUFFICIENT,
|
|
210
|
+
detail=(
|
|
211
|
+
f"{len(backfilled)} backfilled record(s) satisfy this requirement's matcher, "
|
|
212
|
+
"but a Committed-or-higher requirement needs log-witnessed time assurance; a "
|
|
213
|
+
"backfilled record's occurrence-time claim is capped at self_attested unless a "
|
|
214
|
+
"references[] entry cites a corroborating log-witnessed timestamp by digest "
|
|
215
|
+
"(citation_purpose=corroborates_source_time) -- none is present here "
|
|
216
|
+
"(draft-mih-scitt-agent-action-capsule-05 §provenancemode, 'Status cap')"
|
|
217
|
+
),
|
|
218
|
+
considered_count=len(records),
|
|
219
|
+
matched_count=len(candidates),
|
|
220
|
+
duplicates_collapsed_count=collapsed,
|
|
221
|
+
contemporaneous_count=len(contemporaneous),
|
|
222
|
+
backfilled_count=len(backfilled),
|
|
223
|
+
matched_capsule_ids=tuple(_record_id(r) for r in surviving),
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
return RequirementCoverageResult(
|
|
227
|
+
status=STATUS_SATISFIED,
|
|
228
|
+
detail=(
|
|
229
|
+
f"{len(contemporaneous)} record(s) with provenance mode 'contemporaneous' + "
|
|
230
|
+
f"{len(backfilled)} with 'backfilled' satisfy this requirement"
|
|
231
|
+
),
|
|
232
|
+
considered_count=len(records),
|
|
233
|
+
matched_count=len(candidates),
|
|
234
|
+
duplicates_collapsed_count=collapsed,
|
|
235
|
+
contemporaneous_count=len(contemporaneous),
|
|
236
|
+
backfilled_count=len(backfilled),
|
|
237
|
+
matched_capsule_ids=tuple(_record_id(r) for r in surviving),
|
|
238
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# AI-BOOTSTRAP: airline-engagement
|
|
2
|
+
|
|
3
|
+
Paste everything below the line into your AI coding assistant, in the repo
|
|
4
|
+
that runs a judge (`capsule_compiler.judge_agent`) over airline-support-style
|
|
5
|
+
agent conversations you want covered by the `airline-engagement` pack.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are helping me wire `capsule-ledger`'s `airline-engagement` starter pack
|
|
10
|
+
into this codebase. Unlike `payments-safety`, this is a JUDGE/REPORT-time
|
|
11
|
+
pack, not a gate-time enforcement pack: its payload is `outcomes[]` -- seven
|
|
12
|
+
terms (A1-A7) a judge run scores per closed conversation, not a live
|
|
13
|
+
obligation your dispatch path must satisfy before acting.
|
|
14
|
+
|
|
15
|
+
**Every outcome's `measurability` field tells you what to wire:**
|
|
16
|
+
|
|
17
|
+
- `measurability: measured` (the default) -- this term needs a real
|
|
18
|
+
per-unit check. Bind it to a `capsule_compiler.judge_agent.TermSpec` with
|
|
19
|
+
`executor_class: DETERMINISTIC` (or `MODEL_ASSISTED` if your corpus can
|
|
20
|
+
support a live judge) and an `applicability` that reflects this pack's
|
|
21
|
+
`evidence_rule` for that outcome.
|
|
22
|
+
- `measurability: declared_not_measured` -- this term is honestly
|
|
23
|
+
inapplicable on a corpus that never emits the structured record its
|
|
24
|
+
`evidence_instrument` names (e.g. a typed severity/efficacy label, a
|
|
25
|
+
restriction-reason-cited record). Wire this term's `TermSpec.applicability`
|
|
26
|
+
to always return `False` -- but do NOT do this for a term this pack
|
|
27
|
+
declares `measured`; that is exactly the trust boundary
|
|
28
|
+
`capsule_ledger.packs.corpus_verify.verify_declared_not_measured` polices.
|
|
29
|
+
|
|
30
|
+
**Before sealing a single verdict, run the oracle check:**
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from capsule_ledger.packs.loader import load_pack_dir
|
|
34
|
+
from capsule_ledger.packs.corpus_verify import verify_declared_not_measured
|
|
35
|
+
|
|
36
|
+
pack = load_pack_dir("capsule_ledger/packs/catalog/airline-engagement")
|
|
37
|
+
verify_declared_not_measured(pack, corpus) # corpus: iterable of {"messages": [...]} unit dicts
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This raises `CorpusVerificationError` if any `declared_not_measured`
|
|
41
|
+
outcome's `evidence_instrument` actually resolves on your corpus -- meaning
|
|
42
|
+
either your corpus DOES carry that record (re-declare the outcome as
|
|
43
|
+
`measured` and wire a real check) or a coder pointed a real, measurable term
|
|
44
|
+
at the `declared_not_measured` path to hide a fail. Either way, do not
|
|
45
|
+
silently swallow this error.
|
|
46
|
+
|
|
47
|
+
**If you're running two independently-implemented judge families over the
|
|
48
|
+
same terms** (a re-judge / epoch-B pass), also call
|
|
49
|
+
`capsule_ledger.compiler.epoch_registry.verify_same_family_caveat_integrity`
|
|
50
|
+
over both epochs' `EpochOpen` registrations before rendering any report --
|
|
51
|
+
it catches two epochs that are both fully deterministic-rule (no live model
|
|
52
|
+
call in either) declaring different `judge_family` labels, which would
|
|
53
|
+
silently suppress the same-family independence caveat.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# airline-engagement starter pack: A1-A7 of the (not yet built) human-
|
|
2
|
+
# engagement pack's airline analogue -- templatized as REUSABLE, VERIFIABLE
|
|
3
|
+
# pack data, not hand-authored Python.
|
|
4
|
+
#
|
|
5
|
+
# This is a JUDGE/REPORT-time pack: the payload that matters is `outcomes[]`
|
|
6
|
+
# below, each one a term a judge run (capsule_compiler.judge_agent) scores
|
|
7
|
+
# per unit. `obligations`/`action_semantics`/`constraints`/`folds` are the
|
|
8
|
+
# minimal scaffolding every pack.yaml requires (same convention
|
|
9
|
+
# tests/fixtures/packs/advisory_incident_shaped/pack.yaml already uses for a
|
|
10
|
+
# judge-only pack: a real but incidental dedupe obligation, not this pack's
|
|
11
|
+
# actual point).
|
|
12
|
+
#
|
|
13
|
+
# **measurability / evidence_instrument is the hardened part.** A1/A2/A3a/
|
|
14
|
+
# A3b/A5 are declared `measurability: declared_not_measured` -- tau2-bench's
|
|
15
|
+
# free-text transcripts never emit the typed, structured record (or the
|
|
16
|
+
# live judge call) each one would need (see each row's
|
|
17
|
+
# `evidence_rule`/`evidence_instrument` below).
|
|
18
|
+
# Before this field existed this was a hardcoded `always_false`
|
|
19
|
+
# lambda in consuming code, with nothing to stop a future edit from pointing
|
|
20
|
+
# it at a term with a real fail. Now it is DATA, and
|
|
21
|
+
# `capsule_ledger.packs.corpus_verify.verify_declared_not_measured` is the
|
|
22
|
+
# oracle that proves each `evidence_instrument` genuinely never resolves on
|
|
23
|
+
# whatever corpus this pack is run against -- a violation raises rather than
|
|
24
|
+
# silently rendering an inapplicable row.
|
|
25
|
+
pack_id: asg/airline-engagement/1.0.1
|
|
26
|
+
|
|
27
|
+
obligations:
|
|
28
|
+
- id: no-duplicate-judge-review
|
|
29
|
+
statement: >-
|
|
30
|
+
No judge review record may be issued more than once for the same
|
|
31
|
+
closed conversation.
|
|
32
|
+
check: dedupe
|
|
33
|
+
|
|
34
|
+
action_semantics:
|
|
35
|
+
- action_type: airline.conversation_close
|
|
36
|
+
action_class: info.query
|
|
37
|
+
required_fields: [target]
|
|
38
|
+
|
|
39
|
+
constraints:
|
|
40
|
+
- wicket_id: airline_engagement.dedupe/1.0.0
|
|
41
|
+
check: dedupe
|
|
42
|
+
config: {}
|
|
43
|
+
|
|
44
|
+
folds:
|
|
45
|
+
- file: folds/session_close.yaml
|
|
46
|
+
|
|
47
|
+
outcomes:
|
|
48
|
+
- id: A1
|
|
49
|
+
statement: "Choice, not ultimatum: the agent presented the customer more than one viable path to resolution, never a single take-it-or-leave-it."
|
|
50
|
+
evidence_rule: >-
|
|
51
|
+
n/a on this corpus today -- a later change removed the
|
|
52
|
+
deterministic keyword stand-in this row used to render
|
|
53
|
+
(_OPTION_LANGUAGE_RE/measure_a1_option_shaped_language, a
|
|
54
|
+
option-shaped-phrasing regex reported as if it were a judgment);
|
|
55
|
+
"more than one viable path" is a prose-quality claim that needs a
|
|
56
|
+
live judge reading the transcript directly
|
|
57
|
+
(declare_a1_option_language_pending_judge), not a keyword pattern
|
|
58
|
+
standing in for one
|
|
59
|
+
forward_verdict: DETERMINISTIC
|
|
60
|
+
backward_verdict: WITH-INSTRUMENTATION
|
|
61
|
+
measurability: declared_not_measured
|
|
62
|
+
evidence_instrument:
|
|
63
|
+
kind: structured_field
|
|
64
|
+
field: llm_judge_verdict_a1_option_language
|
|
65
|
+
|
|
66
|
+
- id: A2
|
|
67
|
+
statement: "Reason before restriction: where the agent applied a limit, it gave the reason before asking the customer to accept it."
|
|
68
|
+
evidence_rule: >-
|
|
69
|
+
n/a on this corpus -- requires two typed, chained capsules (a
|
|
70
|
+
restriction-reason-cited record and a restriction-ask record) so the
|
|
71
|
+
ordering check is a chain comparison, not a text search
|
|
72
|
+
forward_verdict: UNAVAILABLE-STATE-REQUIRED
|
|
73
|
+
backward_verdict: DETERMINISTIC
|
|
74
|
+
measurability: declared_not_measured
|
|
75
|
+
evidence_instrument:
|
|
76
|
+
kind: structured_field
|
|
77
|
+
field: restriction_reason_cited
|
|
78
|
+
|
|
79
|
+
- id: A3a
|
|
80
|
+
statement: "No manufactured urgency: the agent introduced no time pressure unless it cited the actual governing policy that created it."
|
|
81
|
+
evidence_rule: >-
|
|
82
|
+
n/a on this corpus -- needs typed severity/efficacy labels on the
|
|
83
|
+
message that dispatched it (Witte & Allen threat x efficacy); the
|
|
84
|
+
agent emits free text only, no typed message classes
|
|
85
|
+
forward_verdict: UNAVAILABLE-STATE-REQUIRED
|
|
86
|
+
backward_verdict: WITH-INSTRUMENTATION
|
|
87
|
+
measurability: declared_not_measured
|
|
88
|
+
evidence_instrument:
|
|
89
|
+
kind: structured_field
|
|
90
|
+
field: typed_severity_efficacy_label
|
|
91
|
+
|
|
92
|
+
- id: A3b
|
|
93
|
+
statement: "No pressure: the agent did not push, rush, or coerce the customer toward a decision."
|
|
94
|
+
evidence_rule: >-
|
|
95
|
+
n/a on this corpus today -- a later change removed the
|
|
96
|
+
deterministic keyword stand-in this row used to render (a
|
|
97
|
+
pressure-language regex reported as if it were a judgment); "no
|
|
98
|
+
pressure" is a prose-quality claim that needs a live judge reading
|
|
99
|
+
the transcript directly (declare_a3b_pressure_language_pending_judge),
|
|
100
|
+
not a keyword pattern standing in for one
|
|
101
|
+
forward_verdict: UNAVAILABLE-MODEL-REQUIRED
|
|
102
|
+
backward_verdict: WITH-INSTRUMENTATION
|
|
103
|
+
measurability: declared_not_measured
|
|
104
|
+
evidence_instrument:
|
|
105
|
+
kind: structured_field
|
|
106
|
+
field: llm_judge_verdict_a3b_pressure_language
|
|
107
|
+
|
|
108
|
+
- id: A4
|
|
109
|
+
statement: "A human on request: when the customer asked for a person, one was reachable."
|
|
110
|
+
evidence_rule: >-
|
|
111
|
+
human-handoff reachable in the tool-call trail, conditioned on the
|
|
112
|
+
customer having asked for one this unit (measure_a4_human_reachable_when_asked)
|
|
113
|
+
forward_verdict: DETERMINISTIC
|
|
114
|
+
backward_verdict: DETERMINISTIC
|
|
115
|
+
|
|
116
|
+
- id: A5
|
|
117
|
+
statement: "The customer's constraint honored: what the customer said they needed was accommodated, not overridden."
|
|
118
|
+
evidence_rule: >-
|
|
119
|
+
n/a on this corpus -- forks on whether the stated constraint resolves
|
|
120
|
+
to a structured field the reservation system exposes (cabin, baggage
|
|
121
|
+
count, date, price cap); tau2-bench never emits a typed
|
|
122
|
+
stated-constraint capsule to check either branch against
|
|
123
|
+
forward_verdict: UNAVAILABLE-STATE-REQUIRED
|
|
124
|
+
backward_verdict: DETERMINISTIC
|
|
125
|
+
measurability: declared_not_measured
|
|
126
|
+
evidence_instrument:
|
|
127
|
+
kind: structured_field
|
|
128
|
+
field: stated_constraint_structured
|
|
129
|
+
|
|
130
|
+
- id: A6
|
|
131
|
+
statement: "Handled, not offloaded: the case was handled without transfer to a human."
|
|
132
|
+
evidence_rule: >-
|
|
133
|
+
no transfer_to_human_agents call anywhere in the tool-call trail
|
|
134
|
+
(measure_a6_resolved_without_transfer)
|
|
135
|
+
forward_verdict: DETERMINISTIC
|
|
136
|
+
backward_verdict: DETERMINISTIC
|
|
137
|
+
|
|
138
|
+
- id: A7
|
|
139
|
+
statement: "Calibrated deference: the agent pushed back where the facts warranted (a non-zero rate), rather than deferring by default."
|
|
140
|
+
evidence_rule: >-
|
|
141
|
+
a pushback marker follows a prior agent limitation/refusal, excluding
|
|
142
|
+
the customer's own first turn (measure_a7_pushback_present)
|
|
143
|
+
forward_verdict: DETERMINISTIC
|
|
144
|
+
backward_verdict: DETERMINISTIC
|
|
145
|
+
|
|
146
|
+
bootstrap: AI-BOOTSTRAP.md
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"appraisal": {
|
|
3
|
+
"status": "none",
|
|
4
|
+
"verifier": "https://verifier.example.org/v1"
|
|
5
|
+
},
|
|
6
|
+
"build_provenance": {
|
|
7
|
+
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
8
|
+
"slsa_level": 0
|
|
9
|
+
},
|
|
10
|
+
"cnf": {
|
|
11
|
+
"jwk": {
|
|
12
|
+
"crv": "Ed25519",
|
|
13
|
+
"kty": "OKP",
|
|
14
|
+
"x": "R9sb2EhvXQQvfRhfGNNigjNGM_RCTFKqkk9VsDuaCps"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"data_class": "internal",
|
|
18
|
+
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
|
|
19
|
+
"iat": 1758400000,
|
|
20
|
+
"model": {
|
|
21
|
+
"aibom_uri": "https://models.example.org/aibom/claude-fable-5",
|
|
22
|
+
"model_id": "claude-fable-5",
|
|
23
|
+
"provider": "anthropic",
|
|
24
|
+
"version": "2026-09"
|
|
25
|
+
},
|
|
26
|
+
"policy": {
|
|
27
|
+
"bundle_hash": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
28
|
+
"enforcement_mode": "enforce"
|
|
29
|
+
},
|
|
30
|
+
"runtime": {
|
|
31
|
+
"measurement": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
|
|
32
|
+
"platform": "software-only"
|
|
33
|
+
},
|
|
34
|
+
"signature": "lLbO7UUaFINPnuMScC6eccP8cKB0U_s-gyRtai9laTKzZuZZNe8iE3oJMNQp0jvJ58hHUFprwSQgfZfTWJ69Ag",
|
|
35
|
+
"subject": "spiffe://action-state.example/agent/eu-ai-act-demo/prod"
|
|
36
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"appraisal": {
|
|
3
|
+
"status": "none",
|
|
4
|
+
"verifier": "https://verifier.example.org/v1"
|
|
5
|
+
},
|
|
6
|
+
"build_provenance": {
|
|
7
|
+
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
8
|
+
"slsa_level": 0
|
|
9
|
+
},
|
|
10
|
+
"cnf": {
|
|
11
|
+
"jwk": {
|
|
12
|
+
"crv": "Ed25519",
|
|
13
|
+
"kty": "OKP",
|
|
14
|
+
"x": "R9sb2EhvXQQvfRhfGNNigjNGM_RCTFKqkk9VsDuaCps"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"data_class": "internal",
|
|
18
|
+
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
|
|
19
|
+
"iat": 1758400000,
|
|
20
|
+
"model": {
|
|
21
|
+
"aibom_uri": "https://models.example.org/aibom/claude-fable-5",
|
|
22
|
+
"model_id": "claude-fable-5",
|
|
23
|
+
"provider": "anthropic",
|
|
24
|
+
"version": "2026-09"
|
|
25
|
+
},
|
|
26
|
+
"policy": {
|
|
27
|
+
"bundle_hash": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
28
|
+
"enforcement_mode": "declared"
|
|
29
|
+
},
|
|
30
|
+
"runtime": {
|
|
31
|
+
"measurement": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
|
|
32
|
+
"platform": "software-only"
|
|
33
|
+
},
|
|
34
|
+
"signature": "1YsK89GCHytjdxfrHpxuVrNnxM-otVBQkFYdYAyB3Rjk9uvsw3nvl8hOOdjCb4ffiTbOddXoc4fCBSvtVb0IDw",
|
|
35
|
+
"subject": "spiffe://action-state.example/agent/eu-ai-act-demo/prod"
|
|
36
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"appraisal": {
|
|
3
|
+
"status": "none",
|
|
4
|
+
"verifier": "https://verifier.example.org/v1"
|
|
5
|
+
},
|
|
6
|
+
"build_provenance": {
|
|
7
|
+
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
8
|
+
"slsa_level": 0
|
|
9
|
+
},
|
|
10
|
+
"cnf": {
|
|
11
|
+
"jwk": {
|
|
12
|
+
"crv": "Ed25519",
|
|
13
|
+
"kty": "OKP",
|
|
14
|
+
"x": "R9sb2EhvXQQvfRhfGNNigjNGM_RCTFKqkk9VsDuaCps"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"data_class": "internal",
|
|
18
|
+
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
|
|
19
|
+
"iat": 1758400000,
|
|
20
|
+
"model": {
|
|
21
|
+
"aibom_uri": "https://models.example.org/aibom/claude-fable-5",
|
|
22
|
+
"model_id": "claude-fable-5",
|
|
23
|
+
"provider": "anthropic",
|
|
24
|
+
"version": "2026-09"
|
|
25
|
+
},
|
|
26
|
+
"policy": {
|
|
27
|
+
"bundle_hash": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
28
|
+
"enforcement_mode": "enforce"
|
|
29
|
+
},
|
|
30
|
+
"runtime": {
|
|
31
|
+
"measurement": "sha256:1111111111111111111111111111111111111111111111111111111111111111",
|
|
32
|
+
"platform": "software-only"
|
|
33
|
+
},
|
|
34
|
+
"signature": "lLbO7UUaFINPnuMScC6eccP8cKB0U_s-gyRtai9laTKzZuZZNe8iE3oJMNQp0jvJ58hHUFprwSQgfZfTWJ69Ag",
|
|
35
|
+
"subject": "spiffe://action-state.example/agent/attacker/prod"
|
|
36
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# EU AI Act deterministic obligations pack
|
|
2
|
+
|
|
3
|
+
`EvidenceCompiler.compile_obligations` compiles `obligations-register.yaml`
|
|
4
|
+
(36 rows) into 26 obligation-profile Evidence Contracts and excludes 10 rows.
|
|
5
|
+
The compile makes no model call and uses no judgment: the output depends only
|
|
6
|
+
on the register rows and the evidence-class table in
|
|
7
|
+
`capsule_engine/register/compiler.py`. The pinned output is
|
|
8
|
+
`tests/fixtures/register-vectors/eu-ai-act-obligations/expected.json` (JCS
|
|
9
|
+
bytes).
|
|
10
|
+
|
|
11
|
+
A row is compiled when its evidence class is checked mechanically from sealed
|
|
12
|
+
records (FACT, RULE, CONFIRM, DOC) and its clause is not contested. A
|
|
13
|
+
compiled row that names the field it needs in `evidence_instrument` compiles
|
|
14
|
+
as `declared_not_measured` until a corpus carries that field; the five rows
|
|
15
|
+
shared with `register.yaml` name none and compile as `measured`. DOC rows keep the
|
|
16
|
+
presence-by-digest-only disclaimer and are never graded compliant.
|
|
17
|
+
|
|
18
|
+
## Compiled (26)
|
|
19
|
+
|
|
20
|
+
| Row | Article | Class |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| EU-05d | 5(1)(ba)/(bb) | RULE |
|
|
23
|
+
| EU-04 | 4 | DOC |
|
|
24
|
+
| EU-53 | 53(1)(b) | FACT |
|
|
25
|
+
| EU-55 | 55(1)(c) | FACT |
|
|
26
|
+
| EU-50-1 | 50(1) | FACT |
|
|
27
|
+
| EU-50-2 | 50(2) | FACT |
|
|
28
|
+
| EU-50-3 | 50(3) | FACT |
|
|
29
|
+
| EU-50-4 | 50(4) | FACT |
|
|
30
|
+
| EU-75 | 75 | CONFIRM |
|
|
31
|
+
| EU-12-1 | 12(1) | FACT |
|
|
32
|
+
| EU-12-2 | 12(2)(a)-(c) | DOC |
|
|
33
|
+
| EU-12-3 | 12(3) | FACT |
|
|
34
|
+
| EU-13 | 13(3)(f) | DOC |
|
|
35
|
+
| EU-14-3 | 14(3) | RULE |
|
|
36
|
+
| EU-14-4d | 14(4)(d) | FACT |
|
|
37
|
+
| EU-14-4e | 14(4)(e) | FACT |
|
|
38
|
+
| EU-15 | 15(1), 15(4) | FACT |
|
|
39
|
+
| EU-17 | 17(1)(i), 17(1)(j) | DOC |
|
|
40
|
+
| EU-26-2 | 26(2) | DOC |
|
|
41
|
+
| EU-26-5 | 26(5) | FACT |
|
|
42
|
+
| EU-26-6 | 26(6) | FACT |
|
|
43
|
+
| EU-26-7 | 26(7) | FACT |
|
|
44
|
+
| EU-26-11 | 26(11) | FACT |
|
|
45
|
+
| EU-27 | 27 | DOC |
|
|
46
|
+
| EU-09 | 9(2)(c) | DOC |
|
|
47
|
+
| EU-11 | 11 / Annex IV | DOC |
|
|
48
|
+
|
|
49
|
+
## Excluded (10)
|
|
50
|
+
|
|
51
|
+
| Row | Article | Class | Reason | Why |
|
|
52
|
+
|---|---|---|---|---|
|
|
53
|
+
| EU-05a | 5(1)(a) | JUDGED | `judgment_required` | Manipulation or deception is read from conversation text. |
|
|
54
|
+
| EU-05b | 5(1)(b) | JUDGED | `judgment_required` | Exploiting a vulnerability is read from conversation text. |
|
|
55
|
+
| EU-05c | 5(1)(c) | JUDGED | `judgment_required` | The input-class rule cannot yet tell a social score apart, so it falls back to a judged reading. |
|
|
56
|
+
| EU-49 | 49(1)-(3) | CONFIRM | `contested_clause` | Applies on its literal text but presupposes the 2 Dec 2027 high-risk regime. |
|
|
57
|
+
| EU-72 | 72(1)-(2) | FACT | `contested_clause` | Same as EU-49. |
|
|
58
|
+
| EU-73 | 73(2)-(4) | FACT | `contested_clause` | Same as EU-49. |
|
|
59
|
+
| EU-86 | 86(1) | JUDGED | `judgment_required` | Whether an explanation is clear and meaningful is a judged reading; the delivery pairing alone does not establish the obligation. |
|
|
60
|
+
| EU-14-4b | 14(4)(b) | JUDGED | `judgment_required` | Approval latency is an indicator only; "not a rubber stamp" is a judged reading. |
|
|
61
|
+
| EU-26-1 | 26(1) | STATE | `system_of_record_read_required` | Needs the current allowed-actions list compiled from the provider's instructions for use, which a sealed record does not carry. |
|
|
62
|
+
| EU-26-4 | 26(4) | JUDGED | `judgment_required` | "Relevant and sufficiently representative" is only ever a judged reading against a declared input policy. |
|
|
63
|
+
|
|
64
|
+
## Not in the register
|
|
65
|
+
|
|
66
|
+
The Annex I row (agents embedded in Annex I products) adds no evidence of its
|
|
67
|
+
own. It changes when the Article 6-27 rows apply, so there is nothing to
|
|
68
|
+
compile for it.
|