File size: 2,558 Bytes
9ec4919
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#!/usr/bin/env python3
"""Preview a loop contract as a readable operating plan."""

from __future__ import annotations

import argparse
import json
from pathlib import Path
from typing import Any

from check_loop_contract_examples import SCHEMA_PATH, validate


def bullet_list(items: list[str]) -> str:
    return "\n".join(f"  - {item}" for item in items)


def render_contract(contract: dict[str, Any]) -> str:
    trigger = contract["trigger"]
    intake = contract["intake"]
    workspace = contract["workspace"]
    context = contract["context"]
    verification = contract["verification"]
    state = contract["state"]
    budget = contract["budget"]
    escalation = contract["escalation"]
    exit_rules = contract["exit"]

    agents = "\n".join(
        f"  - {agent['role']}: {agent['responsibility']}" for agent in contract["agents"]
    )

    return f"""# {contract['name']}

Objective:
  {contract['objective']}

Trigger:
  Type: {trigger['type']}
  Cadence or event: {trigger['cadence_or_event']}

Discover / Intake:
{bullet_list(intake['sources'])}
  Selection rule: {intake['selection_rule']}

Workspace:
  Isolation: {workspace['isolation']}
  Allowed actions:
{bullet_list(workspace['allowed_actions'])}
  Disallowed actions:
{bullet_list(workspace['disallowed_actions'])}

Context:
  Required files:
{bullet_list(context['required_files'])}
  Runtime sources:
{bullet_list(context['runtime_sources'])}

Agents:
{agents}

Verification:
  Gates:
{bullet_list(verification['gates'])}
  Receipts:
{bullet_list(verification['receipts'])}

State:
  Artifacts:
{bullet_list(state['artifacts'])}
  Update rule: {state['update_rule']}

Budget:
  Max retries: {budget['max_retries']}
  Max runtime minutes: {budget['max_runtime_minutes']}

Escalation:
  Conditions:
{bullet_list(escalation['conditions'])}
  Destination: {escalation['destination']}

Exit:
  Success: {exit_rules['success']}
  Stop without success: {exit_rules['stop_without_success']}
"""


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("contract", type=Path, help="Path to a loop contract JSON file.")
    args = parser.parse_args()

    schema = json.loads(SCHEMA_PATH.read_text(encoding="utf-8"))
    contract = json.loads(args.contract.read_text(encoding="utf-8"))
    errors = validate(contract, schema, str(args.contract))
    if errors:
        for error in errors:
            print(error)
        return 1

    print(render_contract(contract))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())