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,424 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""The MCP tool implementations: plain functions returning plain, JSON-serializable
|
|
3
|
+
dicts, each one a thin wrapper over an existing module -- ``LedgerAPI``, the fold
|
|
4
|
+
engine, or the guard engine/checks. No business logic is reimplemented here.
|
|
5
|
+
|
|
6
|
+
Kept independent of ``mcp.server.fastmcp`` (no import of it anywhere in this
|
|
7
|
+
module) so every tool is directly unit-testable with a plain ``LedgerStore`` and
|
|
8
|
+
no MCP session/transport in the loop -- ``server.py`` is the only module that
|
|
9
|
+
knows FastMCP exists.
|
|
10
|
+
|
|
11
|
+
Every read tool returns an ``envelope`` (or, for ``record.verify``, a
|
|
12
|
+
verification result) alongside its answer -- never a bare number or a bare
|
|
13
|
+
yes/no with nothing behind it. This is deliberate: an agent calling these tools
|
|
14
|
+
must never need to fall back to raw ledger rows to check a tool's own claim.
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from datetime import datetime, timedelta, timezone
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from cll.ledger.api import LedgerAPI, ScanQuery
|
|
23
|
+
|
|
24
|
+
from ..cli.constraints_cmd import CHECKS, DEFAULT_CAPS_FOLD_ID
|
|
25
|
+
from ..cli.format import summarize_action
|
|
26
|
+
from ..folds.catalog import Catalog
|
|
27
|
+
from ..folds.engine import evaluate_one
|
|
28
|
+
from ..folds.errors import FoldDefinitionError, FoldDeterminismError
|
|
29
|
+
from ..folds.loader import load_definition_file
|
|
30
|
+
from ..guards import Action, GuardEngine
|
|
31
|
+
from ..guards.checks.caps import cap_for, resolve_caps_minor
|
|
32
|
+
from ..guards.checks.dedupe import check_dedupe
|
|
33
|
+
from ..guards.classes import TAXONOMY, UNCLASSIFIED_DEFAULT
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"ledger_query",
|
|
37
|
+
"fold_list",
|
|
38
|
+
"fold_get",
|
|
39
|
+
"budget_remaining",
|
|
40
|
+
"action_been_done",
|
|
41
|
+
"constraints_list",
|
|
42
|
+
"decision_explain",
|
|
43
|
+
"record_get",
|
|
44
|
+
"record_verify",
|
|
45
|
+
"intent_declare",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
_DEDUPE_WINDOW_DAYS = 30 # matches GuardEngine's own default (guards/engine.py)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _error(reason: str, message: str) -> dict[str, Any]:
|
|
52
|
+
return {"error": {"reason": reason, "message": message}}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _record_dict(record) -> dict[str, Any]:
|
|
56
|
+
return {
|
|
57
|
+
"seq": record.seq,
|
|
58
|
+
"capsule_id": record.capsule_id,
|
|
59
|
+
"capsule": record.capsule,
|
|
60
|
+
"consequential": record.consequential,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _shift(ts: str, *, days: int) -> str:
|
|
65
|
+
text = ts[:-1] + "+00:00" if ts.endswith("Z") else ts
|
|
66
|
+
dt = datetime.fromisoformat(text) - timedelta(days=days)
|
|
67
|
+
return dt.isoformat().replace("+00:00", "Z")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# ---------------------------------------------------------------------------
|
|
71
|
+
# ledger.query
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def ledger_query(
|
|
76
|
+
ledger: LedgerAPI,
|
|
77
|
+
*,
|
|
78
|
+
agent: str | None = None,
|
|
79
|
+
since: str | None = None,
|
|
80
|
+
until: str | None = None,
|
|
81
|
+
counterparty: str | None = None,
|
|
82
|
+
verdict: str | None = None,
|
|
83
|
+
action_type: str | None = None,
|
|
84
|
+
limit: int | None = None,
|
|
85
|
+
) -> dict[str, Any]:
|
|
86
|
+
"""The same filtered scan `capsule log` runs: every matching record, plus the
|
|
87
|
+
honest total (a filtered view is never mistaken for the whole ledger) and
|
|
88
|
+
the chain-gap count `capsule log`'s own footer reports."""
|
|
89
|
+
total = sum(1 for _ in ledger.scan(ScanQuery()))
|
|
90
|
+
query = ScanQuery(
|
|
91
|
+
agent=agent,
|
|
92
|
+
since=since,
|
|
93
|
+
until=until,
|
|
94
|
+
counterparty=counterparty,
|
|
95
|
+
verdict=verdict,
|
|
96
|
+
action_type=action_type,
|
|
97
|
+
limit=limit,
|
|
98
|
+
)
|
|
99
|
+
records = list(ledger.scan(query))
|
|
100
|
+
gaps = ledger.find_gaps()
|
|
101
|
+
return {
|
|
102
|
+
"records": [_record_dict(r) for r in records],
|
|
103
|
+
"matched": len(records),
|
|
104
|
+
"total": total,
|
|
105
|
+
"range": [records[0].seq, records[-1].seq] if records else [0, -1],
|
|
106
|
+
"checkpoint": {"tree_size": total},
|
|
107
|
+
"staleness": {"checkpoint_age_ms": 0},
|
|
108
|
+
"chain_gaps": len(gaps),
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# ---------------------------------------------------------------------------
|
|
113
|
+
# fold.list / fold.get
|
|
114
|
+
# ---------------------------------------------------------------------------
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def fold_list(catalog_dir: str | Path) -> dict[str, Any]:
|
|
118
|
+
"""The fold catalog: every declared fold's id, definition digest, and
|
|
119
|
+
source path, matching `capsule fold list` exactly (same `Catalog`)."""
|
|
120
|
+
catalog = Catalog(catalog_dir)
|
|
121
|
+
entries = catalog.list_entries()
|
|
122
|
+
errors = catalog.list_errors()
|
|
123
|
+
return {
|
|
124
|
+
"folds": [
|
|
125
|
+
{"fold_id": e.definition.fold_id, "digest": e.digest, "source_path": str(e.source_path)}
|
|
126
|
+
for e in entries
|
|
127
|
+
],
|
|
128
|
+
"errors": [
|
|
129
|
+
{"source_path": str(e.source_path), "reason": e.reason, "message": e.message} for e in errors
|
|
130
|
+
],
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def fold_get(
|
|
135
|
+
ledger: LedgerAPI,
|
|
136
|
+
catalog_dir: str | Path,
|
|
137
|
+
*,
|
|
138
|
+
fold: str,
|
|
139
|
+
key: str | None = None,
|
|
140
|
+
as_of: str | None = None,
|
|
141
|
+
) -> dict[str, Any]:
|
|
142
|
+
"""Evaluate one fold over the current ledger and return its full result
|
|
143
|
+
envelope -- the same replay `capsule fold test` runs, against the live
|
|
144
|
+
ledger instead of a one-off `--ledger` file.
|
|
145
|
+
|
|
146
|
+
``fold`` is a fold_id, a definition digest, or a path to a definition
|
|
147
|
+
YAML file (checked in that order). Rolling-window folds require
|
|
148
|
+
``as_of``: this tool, like the fold engine underneath it, refuses to
|
|
149
|
+
invent a time anchor from the wall clock -- supply one derived from real
|
|
150
|
+
data (e.g. the timestamp of the record you care about).
|
|
151
|
+
"""
|
|
152
|
+
path = Path(fold)
|
|
153
|
+
try:
|
|
154
|
+
if path.exists():
|
|
155
|
+
definition = load_definition_file(path)
|
|
156
|
+
else:
|
|
157
|
+
entry = Catalog(catalog_dir).get(fold)
|
|
158
|
+
if entry is None:
|
|
159
|
+
return _error("not_found", f"no such fold {fold!r} in catalog {catalog_dir}")
|
|
160
|
+
definition = entry.definition
|
|
161
|
+
except FoldDefinitionError as exc:
|
|
162
|
+
return _error(exc.reason, str(exc))
|
|
163
|
+
|
|
164
|
+
records = [r.capsule for r in ledger.scan(ScanQuery())]
|
|
165
|
+
try:
|
|
166
|
+
trace = evaluate_one(definition, records, key_value=key, as_of=as_of)
|
|
167
|
+
except FoldDeterminismError as exc:
|
|
168
|
+
return _error(exc.reason, str(exc))
|
|
169
|
+
|
|
170
|
+
return {"fold_id": definition.fold_id, "key": key, **trace.to_envelope()}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
# ---------------------------------------------------------------------------
|
|
174
|
+
# budget.remaining
|
|
175
|
+
# ---------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def budget_remaining(
|
|
179
|
+
ledger: LedgerAPI,
|
|
180
|
+
catalog_dir: str | Path,
|
|
181
|
+
caps_minor: dict[str, int],
|
|
182
|
+
*,
|
|
183
|
+
agent: str,
|
|
184
|
+
action_class: str = "money.transfer",
|
|
185
|
+
as_of: str | None = None,
|
|
186
|
+
) -> dict[str, Any]:
|
|
187
|
+
"""How much of ``action_class``'s configured weekly cap ``agent`` has left,
|
|
188
|
+
evaluated the same way the guard's own `caps` check does (T1's
|
|
189
|
+
`spend.weekly` fold, replayed for real -- never a number this tool
|
|
190
|
+
computes by summing raw records itself).
|
|
191
|
+
|
|
192
|
+
If no cap is configured for ``action_class`` (this deployment's own
|
|
193
|
+
`--cap CLASS=MINOR_UNITS` / `$CAPSULE_MCP_CAPS_MINOR`), returns
|
|
194
|
+
``cap_configured: false`` rather than a fabricated remaining amount --
|
|
195
|
+
matching the caps check's own `n/a` result for an unconfigured class.
|
|
196
|
+
"""
|
|
197
|
+
cap_minor = cap_for(resolve_caps_minor(caps_minor), action_class)
|
|
198
|
+
if cap_minor is None:
|
|
199
|
+
return {
|
|
200
|
+
"agent": agent,
|
|
201
|
+
"action_class": action_class,
|
|
202
|
+
"cap_configured": False,
|
|
203
|
+
"reason": "no cap configured for this action class",
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
entry = Catalog(catalog_dir).get(DEFAULT_CAPS_FOLD_ID)
|
|
207
|
+
if entry is None:
|
|
208
|
+
return _error("not_found", f"caps fold {DEFAULT_CAPS_FOLD_ID!r} not found in catalog {catalog_dir}")
|
|
209
|
+
|
|
210
|
+
records = [r.capsule for r in ledger.scan(ScanQuery(agent=agent))]
|
|
211
|
+
resolved_as_of = as_of or datetime.now(timezone.utc).isoformat()
|
|
212
|
+
trace = evaluate_one(entry.definition, records, key_value=agent, as_of=resolved_as_of)
|
|
213
|
+
spent_minor = trace.result or 0
|
|
214
|
+
remaining_minor = cap_minor - spent_minor
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
"agent": agent,
|
|
218
|
+
"action_class": action_class,
|
|
219
|
+
"cap_configured": True,
|
|
220
|
+
"cap_minor": cap_minor,
|
|
221
|
+
"spent_minor": spent_minor,
|
|
222
|
+
"remaining_minor": remaining_minor,
|
|
223
|
+
"over_cap": remaining_minor < 0,
|
|
224
|
+
"envelope": trace.to_envelope(),
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
# ---------------------------------------------------------------------------
|
|
229
|
+
# action.been_done
|
|
230
|
+
# ---------------------------------------------------------------------------
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def action_been_done(
|
|
234
|
+
ledger: LedgerAPI,
|
|
235
|
+
*,
|
|
236
|
+
verb: str,
|
|
237
|
+
operator: str,
|
|
238
|
+
developer: str,
|
|
239
|
+
action_type: str = "decide",
|
|
240
|
+
target: str | None = None,
|
|
241
|
+
equivalence_key: str | None = None,
|
|
242
|
+
since_days: int = _DEDUPE_WINDOW_DAYS,
|
|
243
|
+
timestamp: str | None = None,
|
|
244
|
+
) -> dict[str, Any]:
|
|
245
|
+
"""Has an equivalent action already been recorded? Wraps the guard's own
|
|
246
|
+
`dedupe` check (exact-match equivalence index, see `guards/checks/dedupe.py`)
|
|
247
|
+
-- the same check `GuardEngine.check` runs before dispatch, run here as a
|
|
248
|
+
standalone query rather than as a gate.
|
|
249
|
+
"""
|
|
250
|
+
action = Action(
|
|
251
|
+
verb=verb,
|
|
252
|
+
operator=operator,
|
|
253
|
+
developer=developer,
|
|
254
|
+
action_type=action_type,
|
|
255
|
+
target=target,
|
|
256
|
+
equivalence_key=equivalence_key,
|
|
257
|
+
timestamp=timestamp,
|
|
258
|
+
)
|
|
259
|
+
since = _shift(action.resolved_timestamp(), days=since_days)
|
|
260
|
+
outcome = check_dedupe(action, ledger, since=since)
|
|
261
|
+
c = outcome.constraint
|
|
262
|
+
return {
|
|
263
|
+
"verb": verb,
|
|
264
|
+
"operator": operator,
|
|
265
|
+
"developer": developer,
|
|
266
|
+
"action_type": action_type,
|
|
267
|
+
"target": target,
|
|
268
|
+
"been_done": c.result == "fail",
|
|
269
|
+
"reason": c.reason,
|
|
270
|
+
"evidence": c.evidence,
|
|
271
|
+
"checked_window_days": since_days,
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
# ---------------------------------------------------------------------------
|
|
276
|
+
# constraints.list
|
|
277
|
+
# ---------------------------------------------------------------------------
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def constraints_list(catalog_dir: str | Path) -> dict[str, Any]:
|
|
281
|
+
"""The registered guard checks and the action-class taxonomy -- the same
|
|
282
|
+
static catalog `capsule constraints list` prints, structured instead of
|
|
283
|
+
formatted for a terminal."""
|
|
284
|
+
caps_entry = Catalog(catalog_dir).get(DEFAULT_CAPS_FOLD_ID)
|
|
285
|
+
caps_method = caps_entry.definition.fold_id if caps_entry is not None else None
|
|
286
|
+
|
|
287
|
+
checks = [
|
|
288
|
+
{
|
|
289
|
+
"id": check_id,
|
|
290
|
+
"type": check_type,
|
|
291
|
+
"method": caps_method if check_id == "caps" else method,
|
|
292
|
+
"description": description,
|
|
293
|
+
}
|
|
294
|
+
for check_id, check_type, method, description in CHECKS
|
|
295
|
+
]
|
|
296
|
+
action_classes = [
|
|
297
|
+
{"name": ac.name, "consequential": ac.consequential, "fail_open_allowed": ac.fail_open_allowed}
|
|
298
|
+
for ac in (*TAXONOMY.values(), UNCLASSIFIED_DEFAULT)
|
|
299
|
+
]
|
|
300
|
+
return {"checks": checks, "action_classes": action_classes}
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
# ---------------------------------------------------------------------------
|
|
304
|
+
# decision.explain / record.get / record.verify
|
|
305
|
+
# ---------------------------------------------------------------------------
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def decision_explain(ledger: LedgerAPI, *, capsule_id: str) -> dict[str, Any]:
|
|
309
|
+
"""Why a decision came out the way it did: the capsule's own constraints
|
|
310
|
+
breakdown (`id`/`result`/`method` per check that ran) plus its verdict --
|
|
311
|
+
the same information `capsule show` prints, never a separately-generated
|
|
312
|
+
explanation. A capsule's constraints ARE the explanation; there is no
|
|
313
|
+
other reasoning to fetch."""
|
|
314
|
+
record = ledger.fetch(capsule_id)
|
|
315
|
+
if record is None:
|
|
316
|
+
return _error("not_found", f"no such capsule {capsule_id!r}")
|
|
317
|
+
|
|
318
|
+
capsule = record.capsule
|
|
319
|
+
disposition = capsule.get("disposition") or {}
|
|
320
|
+
return {
|
|
321
|
+
"capsule_id": record.capsule_id,
|
|
322
|
+
"agent": capsule.get("developer"),
|
|
323
|
+
"operator": capsule.get("operator"),
|
|
324
|
+
"action": summarize_action(capsule),
|
|
325
|
+
"action_type": capsule.get("action_type"),
|
|
326
|
+
"timestamp": capsule.get("timestamp"),
|
|
327
|
+
"decision": disposition.get("decision"),
|
|
328
|
+
"verdict_class": disposition.get("verdict_class"),
|
|
329
|
+
"constraints": [
|
|
330
|
+
{
|
|
331
|
+
"id": c.get("id"),
|
|
332
|
+
"result": c.get("result"),
|
|
333
|
+
"check_type": c.get("check_type"),
|
|
334
|
+
"method": c.get("method"),
|
|
335
|
+
}
|
|
336
|
+
for c in (capsule.get("constraints") or [])
|
|
337
|
+
],
|
|
338
|
+
"chain": capsule.get("chain"),
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def record_get(ledger: LedgerAPI, *, capsule_id: str) -> dict[str, Any]:
|
|
343
|
+
"""The full raw capsule by id or unambiguous prefix -- `capsule show --json`'s
|
|
344
|
+
own output, unchanged."""
|
|
345
|
+
record = ledger.fetch(capsule_id)
|
|
346
|
+
if record is None:
|
|
347
|
+
return _error("not_found", f"no such capsule {capsule_id!r}")
|
|
348
|
+
return _record_dict(record)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def record_verify(ledger: LedgerAPI, *, capsule_id: str) -> dict[str, Any]:
|
|
352
|
+
"""Independently re-verify one capsule's digest and chain -- `capsule verify`'s
|
|
353
|
+
own check, run against the live ledger. Returns `ok` plus every finding
|
|
354
|
+
(never just a bare boolean) so a `False` always comes with a reason."""
|
|
355
|
+
record = ledger.fetch(capsule_id)
|
|
356
|
+
if record is None:
|
|
357
|
+
return _error("not_found", f"no such capsule {capsule_id!r}")
|
|
358
|
+
result = ledger.verify(capsule_id)
|
|
359
|
+
if result is None:
|
|
360
|
+
return _error("not_found", f"no such capsule {capsule_id!r}")
|
|
361
|
+
return {
|
|
362
|
+
"capsule_id": record.capsule_id,
|
|
363
|
+
"ok": result.ok,
|
|
364
|
+
"findings": [
|
|
365
|
+
{"code": f.code, "detail": f.detail, "severity": f.severity} for f in result.findings
|
|
366
|
+
],
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
# ---------------------------------------------------------------------------
|
|
371
|
+
# intent.declare -- the only write tool
|
|
372
|
+
# ---------------------------------------------------------------------------
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def intent_declare(
|
|
376
|
+
ledger: LedgerAPI,
|
|
377
|
+
guard: GuardEngine,
|
|
378
|
+
*,
|
|
379
|
+
verb: str,
|
|
380
|
+
operator: str,
|
|
381
|
+
developer: str,
|
|
382
|
+
action_class: str | None = None,
|
|
383
|
+
amount_minor: int | None = None,
|
|
384
|
+
currency: str | None = None,
|
|
385
|
+
target: str | None = None,
|
|
386
|
+
cited_mandate_capsule_id: str | None = None,
|
|
387
|
+
equivalence_key: str | None = None,
|
|
388
|
+
) -> dict[str, Any]:
|
|
389
|
+
"""Declare an intended action and run it through the guard for a real
|
|
390
|
+
decision -- allow, deny, or escalate. THE ONLY WRITE TOOL on this server:
|
|
391
|
+
every other tool only reads. On anything but an infra-level failure, the
|
|
392
|
+
decision is appended to the ledger as a signed capsule (`GuardEngine.check`,
|
|
393
|
+
same as a live `capsule guard` call would do) -- `capsule_id` in the response
|
|
394
|
+
is directly queryable afterward via `record.get` or `ledger.query`.
|
|
395
|
+
|
|
396
|
+
``action_class`` is looked up in the starter taxonomy
|
|
397
|
+
(`capsule constraints list` shows it); absent or unrecognized both resolve to
|
|
398
|
+
the consequential, fail-closed default -- there is no silent bypass for
|
|
399
|
+
an unclassified action.
|
|
400
|
+
"""
|
|
401
|
+
action = Action(
|
|
402
|
+
verb=verb,
|
|
403
|
+
operator=operator,
|
|
404
|
+
developer=developer,
|
|
405
|
+
action_class=action_class,
|
|
406
|
+
amount_minor=amount_minor,
|
|
407
|
+
currency=currency,
|
|
408
|
+
target=target,
|
|
409
|
+
cited_mandate_capsule_id=cited_mandate_capsule_id,
|
|
410
|
+
equivalence_key=equivalence_key,
|
|
411
|
+
)
|
|
412
|
+
decision = guard.check(action)
|
|
413
|
+
return {
|
|
414
|
+
"outcome": decision.outcome,
|
|
415
|
+
"capsule_id": (decision.capsule or {}).get("capsule_id"),
|
|
416
|
+
"dry_run": decision.dry_run,
|
|
417
|
+
"degraded": decision.degraded,
|
|
418
|
+
"degradation_kind": decision.degradation_kind,
|
|
419
|
+
"reason": decision.reason,
|
|
420
|
+
"checkpoint": decision.checkpoint,
|
|
421
|
+
"constraints": [
|
|
422
|
+
{"id": c.id, "result": c.result, "reason": c.reason} for c in decision.constraints
|
|
423
|
+
],
|
|
424
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Packaging
|
|
3
|
+
|
|
4
|
+
One wheel, one codebase. ``guards-only`` keeps the
|
|
5
|
+
caps/dedupe/verify-before-dispatch checks and ``dry_run`` fully functional;
|
|
6
|
+
the evidence machinery underneath (capsules, permalinks, verify surfaces)
|
|
7
|
+
stays present in the code but is not surfaced: no capsule vocabulary in CLI
|
|
8
|
+
output, no share/verify links printed or rendered, and the record-query verbs
|
|
9
|
+
(``log``/``show``/``verify``/``bundle``) are not registered at all. ``full``
|
|
10
|
+
is today's existing behavior, unchanged.
|
|
11
|
+
|
|
12
|
+
``guards-only`` changes what is shown, never what is recorded:
|
|
13
|
+
every check still seals its record to the ledger;
|
|
14
|
+
the CLI simply doesn't register the record-query verbs or print capsule
|
|
15
|
+
vocabulary and links. Switching to full at any time surfaces the complete
|
|
16
|
+
history recorded all along.
|
|
17
|
+
|
|
18
|
+
Mechanism, and why: an environment variable rather than a pip extra, a
|
|
19
|
+
persistent config file, or a per-invocation CLI flag.
|
|
20
|
+
|
|
21
|
+
* A pip extra (``capsule-ledger[evidence]``) implies a *dependency* difference --
|
|
22
|
+
something extra gets installed. Nothing does: both arms import the exact
|
|
23
|
+
same modules, the only difference is what's registered/rendered. An extra
|
|
24
|
+
would misdescribe what actually changed.
|
|
25
|
+
* A per-invocation flag (``--minimal``/``--full``) has to be remembered on
|
|
26
|
+
every command, which is exactly the kind of friction that would confound
|
|
27
|
+
the very activation/enforcement metrics this packaging split exists to
|
|
28
|
+
measure honestly.
|
|
29
|
+
* A persistent config file needs an init step before first use, which adds
|
|
30
|
+
friction to the "clean install" acceptance test this task is measured
|
|
31
|
+
against.
|
|
32
|
+
* An env var can be set once (in the environment an operator already
|
|
33
|
+
controls for their agent runtime) and then every ``capsule`` invocation in
|
|
34
|
+
that environment picks it up consistently, with zero extra state and zero
|
|
35
|
+
per-command overhead.
|
|
36
|
+
"""
|
|
37
|
+
from __future__ import annotations
|
|
38
|
+
|
|
39
|
+
from .envcompat import env_get
|
|
40
|
+
|
|
41
|
+
__all__ = ["GUARDS_ONLY", "FULL", "current_arm", "evidence_visible"]
|
|
42
|
+
|
|
43
|
+
GUARDS_ONLY = "guards-only"
|
|
44
|
+
FULL = "full"
|
|
45
|
+
_VALID = (GUARDS_ONLY, FULL)
|
|
46
|
+
_ENV_VAR = "CAPSULE_LEDGER_ARM"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def current_arm() -> str:
|
|
50
|
+
"""The active packaging arm for this process: ``$CAPSULE_LEDGER_ARM``
|
|
51
|
+
if it names a valid arm, else ``full``
|
|
52
|
+
(today's existing, unchanged behavior)."""
|
|
53
|
+
value = env_get(_ENV_VAR, FULL).strip().lower()
|
|
54
|
+
return value if value in _VALID else FULL
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def evidence_visible(arm: str | None = None) -> bool:
|
|
58
|
+
"""Whether evidence (capsule vocabulary, permalinks, verify surfaces)
|
|
59
|
+
should be surfaced to the user for the given (or current) arm."""
|
|
60
|
+
return (arm or current_arm()) == FULL
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Starter packs: installable obligation -> deterministic-check -> capsule
|
|
3
|
+
recipes, layered on top of the existing guard/fold/manifest primitives.
|
|
4
|
+
|
|
5
|
+
See the module docstrings in ``schema.py`` (the parsed pack shape),
|
|
6
|
+
``loader.py`` (``pack.yaml`` -> ``PackDefinition``), ``install.py``
|
|
7
|
+
(``PackDefinition`` -> an installed, manifest-governed ``GuardEngine``), and
|
|
8
|
+
``pins.py`` (fail-closed registry-pin verification before install) for the
|
|
9
|
+
pieces. ``catalog/`` holds the packs this repo ships (``payments-safety``
|
|
10
|
+
today).
|
|
11
|
+
"""
|
|
12
|
+
from .enforce import accept_thresholds, enforce_pack, profile_for_accepted
|
|
13
|
+
from .errors import PackDefinitionError, RegistryPinError
|
|
14
|
+
from .install import InstalledPack, build_engine, install_pack, record_pack_activation
|
|
15
|
+
from .loader import load_pack_dir
|
|
16
|
+
from .obligation_results import ObligationResult, obligation_results
|
|
17
|
+
from .pins import load_pins_file, verify_pins
|
|
18
|
+
from .schema import ActionSemantic, Obligation, PackDefinition, PackFixtures, ProposerStub
|
|
19
|
+
from .thresholds import ThresholdProposal, load_proposals_file, propose_thresholds, write_proposals_file
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"PackDefinition",
|
|
23
|
+
"Obligation",
|
|
24
|
+
"ActionSemantic",
|
|
25
|
+
"ProposerStub",
|
|
26
|
+
"PackFixtures",
|
|
27
|
+
"load_pack_dir",
|
|
28
|
+
"ObligationResult",
|
|
29
|
+
"obligation_results",
|
|
30
|
+
"PackDefinitionError",
|
|
31
|
+
"InstalledPack",
|
|
32
|
+
"install_pack",
|
|
33
|
+
"build_engine",
|
|
34
|
+
"record_pack_activation",
|
|
35
|
+
"load_pins_file",
|
|
36
|
+
"verify_pins",
|
|
37
|
+
"RegistryPinError",
|
|
38
|
+
"ThresholdProposal",
|
|
39
|
+
"propose_thresholds",
|
|
40
|
+
"write_proposals_file",
|
|
41
|
+
"load_proposals_file",
|
|
42
|
+
"accept_thresholds",
|
|
43
|
+
"enforce_pack",
|
|
44
|
+
"profile_for_accepted",
|
|
45
|
+
]
|