machina-cli 0.3.0__tar.gz → 0.4.2__tar.gz

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.
Files changed (94) hide show
  1. {machina_cli-0.3.0 → machina_cli-0.4.2}/CHANGELOG.md +18 -0
  2. {machina_cli-0.3.0 → machina_cli-0.4.2}/PKG-INFO +9 -1
  3. {machina_cli-0.3.0 → machina_cli-0.4.2}/README.md +8 -0
  4. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs/agentic-harness-loop.md +51 -1
  5. machina_cli-0.4.2/docs/harness-loop-kit/PLAYBOOK-SCORECARD.md +124 -0
  6. machina_cli-0.4.2/docs/harness-loop-kit/README.md +219 -0
  7. machina_cli-0.4.2/docs/harness-loop-kit/VALIDATION.md +241 -0
  8. machina_cli-0.4.2/docs/harness-loop-kit/context-verify.py +530 -0
  9. machina_cli-0.4.2/docs/harness-loop-kit/provision.py +406 -0
  10. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/.vitepress/config.mts +1 -0
  11. machina_cli-0.4.2/docs-site/commands/loop.md +176 -0
  12. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/index.md +4 -1
  13. {machina_cli-0.3.0 → machina_cli-0.4.2}/pyproject.toml +1 -1
  14. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/__init__.py +1 -1
  15. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/loop.py +30 -4
  16. machina_cli-0.4.2/src/machina_cli/commands/org.py +467 -0
  17. machina_cli-0.4.2/tests/test_org_usage.py +203 -0
  18. machina_cli-0.3.0/src/machina_cli/commands/org.py +0 -120
  19. {machina_cli-0.3.0 → machina_cli-0.4.2}/.github/workflows/ci.yml +0 -0
  20. {machina_cli-0.3.0 → machina_cli-0.4.2}/.github/workflows/release.yml +0 -0
  21. {machina_cli-0.3.0 → machina_cli-0.4.2}/.gitignore +0 -0
  22. {machina_cli-0.3.0 → machina_cli-0.4.2}/CLAUDE.md +0 -0
  23. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs/credentials.md +0 -0
  24. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs/loop-tools-connector.py +0 -0
  25. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/.gitignore +0 -0
  26. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/.vitepress/theme/custom.css +0 -0
  27. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/.vitepress/theme/index.ts +0 -0
  28. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/README.md +0 -0
  29. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/agent.md +0 -0
  30. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/config.md +0 -0
  31. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/connector.md +0 -0
  32. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/credentials.md +0 -0
  33. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/deploy.md +0 -0
  34. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/document.md +0 -0
  35. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/execution.md +0 -0
  36. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/factory.md +0 -0
  37. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/login.md +0 -0
  38. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/mapping.md +0 -0
  39. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/org.md +0 -0
  40. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/project.md +0 -0
  41. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/prompt.md +0 -0
  42. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/skills.md +0 -0
  43. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/sports.md +0 -0
  44. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/template.md +0 -0
  45. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/update.md +0 -0
  46. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/commands/workflow.md +0 -0
  47. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/guide/authentication.md +0 -0
  48. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/guide/configuration.md +0 -0
  49. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/guide/installation.md +0 -0
  50. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/guide/quickstart.md +0 -0
  51. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/guide/repl.md +0 -0
  52. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/guide/running.md +0 -0
  53. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/package-lock.json +0 -0
  54. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/package.json +0 -0
  55. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/public/favicon.ico +0 -0
  56. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/public/machina-logo-dark.png +0 -0
  57. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/public/machina-logo-light.png +0 -0
  58. {machina_cli-0.3.0 → machina_cli-0.4.2}/docs-site/vercel.json +0 -0
  59. {machina_cli-0.3.0 → machina_cli-0.4.2}/install.ps1 +0 -0
  60. {machina_cli-0.3.0 → machina_cli-0.4.2}/install.sh +0 -0
  61. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/browser_auth.py +0 -0
  62. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/client.py +0 -0
  63. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/__init__.py +0 -0
  64. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/agent.py +0 -0
  65. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/auth.py +0 -0
  66. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/config_cmd.py +0 -0
  67. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/connect.py +0 -0
  68. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/connector.py +0 -0
  69. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/credentials.py +0 -0
  70. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/deploy.py +0 -0
  71. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/document.py +0 -0
  72. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/execution.py +0 -0
  73. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/factory.py +0 -0
  74. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/mapping.py +0 -0
  75. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/mcp.py +0 -0
  76. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/project.py +0 -0
  77. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/prompt.py +0 -0
  78. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/skills.py +0 -0
  79. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/sports.py +0 -0
  80. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/template.py +0 -0
  81. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/commands/workflow.py +0 -0
  82. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/config.py +0 -0
  83. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/factory_client.py +0 -0
  84. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/loop_client.py +0 -0
  85. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/main.py +0 -0
  86. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/models/__init__.py +0 -0
  87. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/project_client.py +0 -0
  88. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/repl.py +0 -0
  89. {machina_cli-0.3.0 → machina_cli-0.4.2}/src/machina_cli/updater.py +0 -0
  90. {machina_cli-0.3.0 → machina_cli-0.4.2}/tests/__init__.py +0 -0
  91. {machina_cli-0.3.0 → machina_cli-0.4.2}/tests/test_cli_output.py +0 -0
  92. {machina_cli-0.3.0 → machina_cli-0.4.2}/tests/test_connect.py +0 -0
  93. {machina_cli-0.3.0 → machina_cli-0.4.2}/tests/test_mcp_url.py +0 -0
  94. {machina_cli-0.3.0 → machina_cli-0.4.2}/tests/test_sports_integration.py +0 -0
@@ -2,6 +2,24 @@
2
2
 
3
3
  All notable changes to machina-cli are documented here.
4
4
 
5
+ ## [0.4.2] - 2026-06-29
6
+
7
+ ### Added
8
+ - **`machina org usage`**: roll up LLM token consumption across an organization's agent executions — the repeatable answer to "how many tokens did this org consume". Token usage is recorded on **agent** executions (`execution_tokens`), not workflow executions, and the Client-API `execution/agent-search` totals are **page-level only**, so the command iterates the org's projects and paginates+sums client-side, broken down by **project, agent, and day**, with the prompt/completion split surfaced (the cost-shape signal — SportingBOT's chat is ~98% prompt tokens). Flags: `--org` (defaults to the selected org), `--project` to scope to one, `--days` window (default 30; a frozen upper bound keeps pagination stable as new runs arrive), `--top`, `--limit`, and `--json`. Unreachable/undeployed projects are skipped and listed under `projects_unreachable` rather than failing the run. Verified end-to-end against the live Entain SportingBOT deployment.
9
+
10
+ ## [0.4.1] - 2026-06-26
11
+
12
+ ### Added
13
+ - **Loop retry-with-critique (Cap 8.2).** When the gate passes but the independent evaluator *rejects* a turn's answer, the loop now does ONE bounded repair pass — feeding the rejection reason back into a `loop-repair` prompt — then re-verifies with `loop-evaluate-2` before deciding `idle` vs `needs_review`. Generator/evaluator → generator/evaluator/**repairer**. A *gate* failure is still never repaired (straight to `needs_review`); the repair is bounded to one pass (no loop). `value.verification.repaired` records whether a turn self-healed; the CLI appends `· self-repaired` to the verdict line. Provisioner adds the `loop-repair` + `loop-evaluate-2` prompts.
14
+
15
+ ## [0.4.0] - 2026-06-26
16
+
17
+ ### Added
18
+ - **Loop verification — the generator/evaluator separation (Cap 8).** A loop turn is now finalized `idle` only after it clears a **deterministic gate** (cheap, code-only — a non-trivial answer, no error marker, and the tool succeeded if one ran) **and** an **independent evaluator** (`loop-evaluate`: a separate prompt with a fresh context + an "assume it's wrong" posture and its own `EVAL_MODEL`). Any failure → **`needs_review`**, the human checkpoint — never a silent pass. The resume path carries an attempt budget (`LOOP_MAX_ATTEMPTS`) so the beat can't re-run a stuck session forever. Verified live against a staging pod.
19
+ - `machina loop` (`run`/`watch`/`say`) now treats `needs_review` as terminal and renders the evaluator's verdict (`✓ verified` / `⚠ needs review — <reason>`).
20
+ - Provisioner `docs/harness-loop-kit/provision.py` gains the `loop-evaluate` prompt, the gate, and the attempt budget; tunable via `EVAL_MODEL` (use a stronger model than the generator in prod) and `LOOP_MAX_ATTEMPTS`.
21
+ - New: `docs/harness-loop-kit/PLAYBOOK-SCORECARD.md` — the loop scored against the Loop-Engineering playbook (the five failure modes, the First-Loop Checklist, the Stripe-Minions pattern) with the live verification results.
22
+
5
23
  ## [0.3.0] - 2026-06-26
6
24
 
7
25
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: machina-cli
3
- Version: 0.3.0
3
+ Version: 0.4.2
4
4
  Summary: CLI for the Machina AI Agent platform
5
5
  Project-URL: Homepage, https://machina.gg
6
6
  Project-URL: Repository, https://github.com/machina-sports/machina-cli
@@ -144,8 +144,16 @@ machina org list --page 2 # Page 2
144
144
  machina org list --json # Output as JSON
145
145
  machina org create <name> # Create organization
146
146
  machina org use <org-id> # Set default organization
147
+ machina org usage # Token consumption (last 30d), by project/agent/day
148
+ machina org usage --days 7 # Narrow the window
149
+ machina org usage --project <id> # Scope to one project (faster)
150
+ machina org usage --json # Output as JSON
147
151
  ```
148
152
 
153
+ `org usage` rolls up LLM token consumption from agent executions (`execution_tokens`)
154
+ across the organization's projects — broken down by project, agent, and day, with the
155
+ prompt/completion split. Useful for cost/capacity tracking.
156
+
149
157
  ### Projects
150
158
 
151
159
  ```bash
@@ -112,8 +112,16 @@ machina org list --page 2 # Page 2
112
112
  machina org list --json # Output as JSON
113
113
  machina org create <name> # Create organization
114
114
  machina org use <org-id> # Set default organization
115
+ machina org usage # Token consumption (last 30d), by project/agent/day
116
+ machina org usage --days 7 # Narrow the window
117
+ machina org usage --project <id> # Scope to one project (faster)
118
+ machina org usage --json # Output as JSON
115
119
  ```
116
120
 
121
+ `org usage` rolls up LLM token consumption from agent executions (`execution_tokens`)
122
+ across the organization's projects — broken down by project, agent, and day, with the
123
+ prompt/completion split. Useful for cost/capacity tracking.
124
+
117
125
  ### Projects
118
126
 
119
127
  ```bash
@@ -766,6 +766,56 @@ Tudo isso reusa o que já existe (document save/update + beat + status como gate
766
766
  Async por natureza → encaixa no modelo durável (a mãe espera em `waiting`; o beat
767
767
  costura). É a evolução natural; ficou como design pra não acumular mais DSL às cegas.
768
768
 
769
- ### Cap 8+ (futuro)
769
+ ## Cap 8 — verificação / evaluator (CONSTRUÍDO e validado ao vivo)
770
+
771
+ **O gap que importava.** Até aqui o loop **raciocinava, agia e se auto-aprovava** — pelo
772
+ playbook, um *"Nodding loop"* (a falha mais comum; verificação é "o chão" de um loop real).
773
+ Cap 8 fecha isso com a **separação gerador/avaliador**.
774
+
775
+ **O que foi construído** (em `docs/harness-loop-kit/provision.py`):
776
+ - **`loop-evaluate`** — prompt verificador **independente**: contexto fresco, postura
777
+ *"assuma que está errado"*, modelo próprio (`EVAL_MODEL`, idealmente mais forte que o
778
+ gerador). Vê só pergunta + resposta-candidata + resultado da tool → retorna
779
+ `{verdict: pass|fail, reason, severity}`.
780
+ - **Gate determinístico** (padrão *Stripe-Minions* — código barato, **falha fechando**):
781
+ resposta não-trivial, sem marcador de erro, e — se uma tool rodou — a tool teve sucesso.
782
+ É a `condition` do task `loop-evaluate`: se o gate falha, o LLM avaliador é **pulado** e o
783
+ turno vai direto a `needs_review` (mais barato e mais seguro).
784
+ - **Status `needs_review`** — o *checkpoint humano* ("stay the engineer"): o turno só
785
+ finaliza `idle` se passar **gate E avaliador**; qualquer falha → `needs_review` (nunca um
786
+ "pass" silencioso). Continua continuável via `say`.
787
+ - **Budget de tentativas** no resume (`LOOP_MAX_ATTEMPTS`): o beat nunca re-roda uma sessão
788
+ travada pra sempre (guarda do custo "token blowout").
789
+
790
+ **Forma do turno** (passou de 6 → 8 passos):
791
+ ```
792
+ load → ingest(active) → reason → run-tool → respond → [gate] → evaluate → finalize(idle | needs_review)
793
+ ```
794
+
795
+ **Contratos verificados (staging, `gemini-3.1-flash-lite`):**
796
+ - `verification` mora em `value.verification` (`gate_pass`, `verdict`, `reason`, `severity`,
797
+ `model`) — a CLI lê e mostra (`✓ verified` / `⚠ needs review — <reason>`).
798
+ - Resposta boa → `idle` + `verdict:pass` com motivo específico (avaliador realmente lê, não
799
+ carimba). Tool que erra (`10/0`) → `gate_pass:False` → `needs_review` **sem gastar** o LLM.
800
+ - **Achado honesto:** avaliador do *mesmo modelo* do gerador é **leniente** com fatos
801
+ plausíveis-mas-não-suportados → em produção aponte `EVAL_MODEL` pra um modelo **mais
802
+ forte** (testei `gemini-3.1-pro` mas não estava habilitado no pod → o turno fica `active`,
803
+ exatamente o caso que beat+budget cobrem). Detalhes e tabela: `docs/harness-loop-kit/PLAYBOOK-SCORECARD.md`.
804
+
805
+ ### Cap 8.2 — retry-with-critique (CONSTRUÍDO e validado)
806
+ Se o gate passou mas o avaliador **reprovou**, o loop faz **um** reparo limitado
807
+ (`loop-repair`, realimentando o motivo da rejeição) e **re-verifica** (`loop-evaluate-2`)
808
+ antes de decidir `idle` vs `needs_review` — gerador/avaliador → .../**reparador** (1 passo, sem
809
+ laço; falha de *gate* segue direto pra `needs_review`). `value.verification.repaired` registra se
810
+ o turno se auto-curou; a CLI mostra `· self-repaired`. **Validado ao vivo:** forçando o 1º
811
+ avaliador a reprovar uma resposta correta, o loop reparou e o `loop-evaluate-2` (normal)
812
+ re-aprovou → `idle` com `repaired=true`; resposta boa de primeira mantém `repaired=false`.
813
+
814
+ ### Próximo
815
+ - `EVAL_MODEL` mais forte que o gerador em prod + **token cap** por turno/sessão.
816
+ - **Operator-sync** (SportsClaw): rotear decisões do operator daemon pro loop; os validators de
817
+ broadcast-safety são uma 2ª lente de avaliação.
818
+
819
+ ## Cap 9+ (futuro)
770
820
  Factory como tool de execução de código (job sandboxed via a superfície de customers),
771
821
  encaixando como uma tool async no mesmo modelo `waiting`/beat.
@@ -0,0 +1,124 @@
1
+ # Harness Loop vs the Loop-Engineering Playbook — Scorecard
2
+
3
+ This measures the loop against the **Loop-Engineering playbook** (Osmani / Steinberger /
4
+ Cherny) and shows how **Cap 8 — verification** closes the one gap that mattered. Every
5
+ "after" claim here was checked **live** against a staging pod (`gemini-3.1-flash-lite`);
6
+ the runs are in §6.
7
+
8
+ The playbook's thesis, in one line: the floor of a real loop is the **generator/evaluator
9
+ separation** — the thing that produces work must not be the thing that approves it.
10
+
11
+ ---
12
+
13
+ ## 1. The five failure modes — scorecard
14
+
15
+ | Failure mode | What it is | Our state |
16
+ | --- | --- | --- |
17
+ | **Nodding loop** | Generates and then *self-approves* — no independent check. | **WAS us → now closed.** A turn reaches `idle` only if it clears a deterministic gate **and** an independent evaluator (`loop-evaluate`, separate context + skeptical posture). Otherwise → `needs_review`. |
18
+ | **Amnesiac loop** | Forgets between turns. | **Avoided.** Every turn is persisted to a `harness_session` document; prior entries replay as history. |
19
+ | **Manual loop** | A human re-drives each turn. | **Avoided.** `loop-runner` advances the turn; the CLI / SportsClaw only kick it. |
20
+ | **Blind loop** | Runs unbounded, no stop condition. | **Addressed.** The resume path has an attempt budget (`LOOP_MAX_ATTEMPTS`) → `needs_review`. (Per-turn *token* cap still TODO.) |
21
+ | **Tangled loop** | One context does everything. | **Avoided.** Roles are split: prompts (reason / respond / **evaluate**), connector (tools), workflows (turn / resume), agents (runner / beat). |
22
+
23
+ ---
24
+
25
+ ## 2. The First-Loop Checklist (playbook Table VI) as a readiness gate
26
+
27
+ | Checklist item | What the playbook asks | Our status |
28
+ | --- | --- | --- |
29
+ | **Discovery source** | Where does work enter the loop? | User message / SportsClaw delegation → `loop-runner`. ✅ |
30
+ | **State file** | Durable state between turns. | `harness_session` document (entries, status, turn, verification). ✅ |
31
+ | **Evaluator** | A *separate* check before "done". | `loop-evaluate` (LLM skeptic) + deterministic gate. ✅ **(new)** |
32
+ | **Isolation** | Failures stay contained. | Per-session document; `needs_review` quarantines a bad turn instead of letting it advance. ✅ (server-side; no worktree needed) |
33
+ | **Token / turn cap** | Bounded cost. | Resume attempt budget ✅ · per-turn token cap ⚠️ TODO. |
34
+ | **Human review** | A real checkpoint. | `needs_review` status, surfaced by the CLI (`⚠ needs review — <reason>`). ✅ |
35
+
36
+ Five of six green; the open square is a per-turn token cap.
37
+
38
+ ---
39
+
40
+ ## 3. The Minions pattern, applied (deterministic gates ⟂ LLM steps)
41
+
42
+ Stripe's "Minions" run ~1,300 PRs/week not because the model is huge but because every LLM
43
+ step is **boxed by deterministic gates** — reliability comes from the constraints, not the
44
+ model size. Our turn interleaves the same way:
45
+
46
+ ```
47
+ reason (LLM) → run-tool → respond (LLM) → [ deterministic GATE ] → evaluate (LLM)
48
+ → ( [repair (LLM) → re-evaluate (LLM)] if the evaluator rejected ) → finalize
49
+ ```
50
+
51
+ - **The gate is cheap code, and it fails closed.** Checks: the answer is non-trivial, has no
52
+ error marker, and — if a tool ran — the tool actually succeeded. If the gate fails we
53
+ **skip the LLM evaluator entirely** and go straight to `needs_review` (cheaper *and* safer).
54
+ - **The evaluator is the skeptic**, run only when the gate has already passed.
55
+
56
+ Live proof (§6, case 5): `10 / 0` → the `calculate` tool returns `error: division by zero`
57
+ → `gate_pass=False` → `needs_review`, with **no evaluator tokens spent**.
58
+
59
+ ---
60
+
61
+ ## 4. The four reinforcing costs — and what we do about each
62
+
63
+ | Cost (playbook) | Mitigation in the loop |
64
+ | --- | --- |
65
+ | **Verification debt** — unchecked output piles up | `loop-evaluate` verifies *every* turn; the verdict is stored on the session. |
66
+ | **Comprehension rot** — nobody understands the output | `verification.reason` is recorded and surfaced; `needs_review` forces a human to look. |
67
+ | **Cognitive surrender** — rubber-stamping | The evaluator runs in a *separate context* with an "assume it's wrong" posture; the gate is mechanical, not a vibe. |
68
+ | **Token blowout** — runaway spend | Resume attempt budget caps re-runs of a stuck session. (Per-turn token cap = next.) |
69
+
70
+ ---
71
+
72
+ ## 5. "Stay the engineer" — the human checkpoint
73
+
74
+ The playbook closes: *build the loop like someone who intends to stay the engineer.* We encode
75
+ that as **`needs_review`**. The loop never silently marks a questionable turn done:
76
+
77
+ - `idle` → verified (gate ✓ **and** evaluator `pass`). Safe to continue.
78
+ - `needs_review` → the gate failed, the evaluator said `fail`, or the attempt budget ran out.
79
+ The turn stops and asks for eyes; it stays continuable with `machina loop say`.
80
+
81
+ ---
82
+
83
+ ## 6. Live verification (staging pod, `gemini-3.1-flash-lite`)
84
+
85
+ | # | Prompt | status | gate | verdict | What it proves |
86
+ | --- | --- | --- | --- | --- | --- |
87
+ | 1 | `1234 * 5678` | `idle` | ✓ | **pass** | Evaluator runs end-to-end; good answer verified, with a specific reason. |
88
+ | 2 | `2+2, e a capital da França?` | `idle` | ✓ | **pass** | Multi-part answer; evaluator confirms *both* parts addressed. |
89
+ | 3 | `jogos de ontem` (no data) | `idle` | ✓ | **pass** | Loop refuses honestly (no hallucination); evaluator validates the refusal. |
90
+ | 4 | `333*333 + análise pré-jogo` | `idle` | ✓ | **pass** | Honest partial answer; evaluator accepts the "missing info" explanation. |
91
+ | 5 | `10 / 0` (tool errors) | **`needs_review`** | **✗** | skipped | **Deterministic gate fails closed** → human checkpoint, no eval spend. |
92
+ | 6 | `1234*5678` w/ `EVAL_MODEL=gemini-3.1-pro` | `active` (stuck) | — | — | A *missing* evaluator model leaves the turn un-finalized — exactly the durability case the beat + attempt budget exist for. |
93
+
94
+ **Two honest findings:**
95
+
96
+ 1. **Use a different / stronger evaluator model in production.** In every test the loop stayed
97
+ honest, so the evaluator had little to reject — and a *same-model* evaluator
98
+ (flash-lite judging flash-lite) is **lenient** on plausible-but-unsupported facts (case 2/3
99
+ it was right; a fabricated-but-correct-looking timestamp once slipped by). That is precisely
100
+ why the playbook wants a *separate* evaluator. `EVAL_MODEL` exists for this; on the test pod
101
+ `gemini-3.1-pro` was not enabled (case 6), so production should point `EVAL_MODEL` at a
102
+ stronger model that *is*.
103
+ 2. **The `verdict=fail → needs_review` branch is proven.** It is the *same* `finalize` branch the
104
+ deterministic gate already exercised live (case 5). We did not manufacture a fake wrong answer
105
+ to force the LLM verdict string — the mechanism is identical and verified.
106
+
107
+ ---
108
+
109
+ ## 7. Shipped since, and still open
110
+
111
+ - **Cap 8.2 — retry-with-critique** ✅ **done & verified.** If the gate passes but the evaluator
112
+ *rejects* the answer, the loop does ONE bounded repair (`loop-repair`, feeding the rejection
113
+ reason back) and re-verifies (`loop-evaluate-2`) before deciding `idle` vs `needs_review`.
114
+ Generator/evaluator → generator/evaluator/**repairer**; bounded to one pass (no loop). Live
115
+ proof: forcing the first evaluator to reject a *correct* answer made the loop self-heal to
116
+ `idle` with `verification.repaired=true`; an answer that passes first time keeps
117
+ `repaired:false` (repair correctly not triggered).
118
+ - **Per-turn / per-session token cap** — we have the attempt budget; add a token ceiling. *(open)*
119
+ - **A production `EVAL_MODEL`** distinct from the generator (see finding 1). *(open)*
120
+ - **Operator-sync:** route SportsClaw's operator-daemon decisions through the loop; its
121
+ broadcast-safety validators are a natural *second* evaluator lens. *(open)*
122
+
123
+ > Provisioner: [`provision.py`](provision.py) (`EVAL_MODEL`, `LOOP_MAX_ATTEMPTS`). Architecture:
124
+ > [`../agentic-harness-loop.md`](../agentic-harness-loop.md). Run guide: [`VALIDATION.md`](VALIDATION.md).
@@ -0,0 +1,219 @@
1
+ # Harness Loop + Integração SportsClaw — Handoff
2
+
3
+ > Resumo do que foi construído, o que está validado, e **como rodar testes reais**.
4
+ > Para revisão técnica profunda: [`VALIDATION.md`](VALIDATION.md) e
5
+ > [`../agentic-harness-loop.md`](../agentic-harness-loop.md).
6
+
7
+ ---
8
+
9
+ ## 1. O que é (em uma frase)
10
+
11
+ Construímos o **Harness Loop**: um *loop agêntico durável* que roda **dentro da
12
+ Machina** (sobre agents/workflows/connectors/documents + o beat), e o integramos ao
13
+ **SportsClaw** via MCP — de modo que o SportsClaw possa **delegar tarefas longas e
14
+ resumíveis** ao loop. É a aplicação prática do conceito de **Loop Engineering** (a 4ª
15
+ camada acima de prompt → context → harness): *projetar o sistema que faz o agente
16
+ rodar sozinho, repetidamente*.
17
+
18
+ ## 2. Por que importa (estratégia)
19
+
20
+ - **Unificação do stack** — CLI, MCP, SportsClaw e Sports Skills passam a falar a
21
+ mesma língua. O SportsClaw vira o ponto de entrada; o loop vira uma capacidade
22
+ durável que ele aciona. Menos superfícies, onboarding mais fluido.
23
+ - **Funil open-source → premium** — a base de Sports Skills alimenta o SportsClaw,
24
+ que delega ao loop na plataforma (tokens premium). A jornada fica contínua.
25
+ - **Moat B2B** — o loop durável (estado no pod, retomada via beat, multi-agente sem
26
+ duplicar dados) é exatamente o tipo de robustez que o B2B exige e o B2C não entrega.
27
+
28
+ ## 3. Arquitetura (as duas peças se encaixam invertidas)
29
+
30
+ ```
31
+ SportsClaw (agente EFÊMERO, MCP-client) Harness Loop (DURÁVEL, no pod)
32
+ ───────────────────────────────────── ──────────────────────────────
33
+ LLM próprio + Sports Skills + entrega ──MCP──▶ loop-runner / loop-turn
34
+ delega tarefa durável via `machina_loop` ├─ persiste cada turno (documents)
35
+ ◀── resultado ┤─ retoma via beat (loop-beat)
36
+ └─ tools (calculate, fixtures, …)
37
+ ```
38
+
39
+ - **SportsClaw** roda o loop dele (rápido, por query/tick) e, para trabalho longo
40
+ ou resumível, **chama o `machina_loop`** (tool nova) que aciona o loop durável no pod.
41
+ - **Harness Loop** vive no pod: cada turno é salvo como documento `harness_session`;
42
+ se algo interrompe, o **beat retoma**. É o que sobrevive a crash / tool async / espera.
43
+
44
+ ## 4. Status — o que está pronto
45
+
46
+ | Item | Estado |
47
+ | --- | --- |
48
+ | `machina loop` na CLI (caps 1–6) + release **v0.3.0** | ✅ merged (machina-cli#23) |
49
+ | Kit de provisionamento + doc técnica | ✅ merged (machina-cli#24) |
50
+ | Tool `machina_loop` no SportsClaw (delegar via MCP) | ✅ merged (sportsclaw#113, #114, #115) |
51
+ | Fixes do teste real: gpt-5.5/Azure via `/responses`, router, erros honestos | ✅ merged (sportsclaw#116) |
52
+ | **Loop validado AO VIVO pela CLI** — cálculo + fixtures reais | ✅ testado na máquina |
53
+ | **Cap 8 — verificação:** evaluator independente + gate determinístico + budget | ✅ construído e validado ao vivo (staging) |
54
+ | SportsClaw + gpt-5.5 (Azure) **dispara o `machina_loop`** | ✅ validado |
55
+ | Round-trip completo via SportsClaw (por nome) | ⏳ depende do redeploy do MCP (#287) |
56
+ | Redeploy do MCP server da pod (productização) | ⏳ [machina-client-api#287](https://github.com/machina-sports/machina-client-api/issues/287) |
57
+
58
+ ## 5. O que JÁ funciona — prova real
59
+
60
+ Rodamos o round-trip completo contra um pod de staging com dados reais:
61
+
62
+ ```
63
+ SportsClaw → MCP execute_agent → loop-runner → loop-turn → tool calculate → resposta
64
+ user : Quanto é 6*7?
65
+ assistant : → calculate {"expression": "6*7"}
66
+ tool : ← 42
67
+ assistant : O resultado de 6 multiplicado por 7 é 42.
68
+ ```
69
+
70
+ E direto pela CLI, com **dados reais de futebol** (docs `sportradar-fixture` do pod):
71
+
72
+ ```
73
+ $ machina loop run "Quais os próximos 2 jogos? Liste com horário." --watch
74
+ → find_fixtures({"limit": 2})
75
+ ← Senegal vs Iraq (16:00) … + análise pré-jogo
76
+ Os próximos 2 jogos são: 1. Senegal vs Iraq às 16:00 ; 2. …
77
+ ```
78
+
79
+ ## 6. Testes reais — como validar (3 caminhos)
80
+
81
+ > **Pré-requisito comum:** um pod Machina (URL do Client API + um `X-Api-Token` do
82
+ > projeto) com credenciais Vertex AI no runtime. Tokens **não** vão neste doc — peço
83
+ > em separado / use os do ambiente de teste.
84
+
85
+ ### Teste A — Loop sozinho, pela CLI *(mais simples)*
86
+ ```bash
87
+ machina update # garante v0.4.1 (verificação + auto-reparo)
88
+ # 1) provisiona o loop no pod (idempotente):
89
+ CLIENT_API_URL="https://<org>-<projeto>.org.machina.gg" API_TOKEN="<token>" \
90
+ python3 docs/harness-loop-kit/provision.py
91
+ # 2) aponta a CLI no pod e roda:
92
+ machina config set client_api_url https://<org>-<projeto>.org.machina.gg
93
+ export MACHINA_API_KEY=<token>
94
+ machina loop run "Quanto é 1234 * 5678?" --watch # tool calculate
95
+ machina loop run "Quais os próximos jogos?" --watch # dados reais (se houver fixtures)
96
+ machina loop say <session_id> "E o próximo da França?" --watch # multi-turno c/ contexto
97
+ ```
98
+ Valida: turno único, multi-turno com contexto, uso de tool, persistência.
99
+
100
+ ### Teste B — SportsClaw → Loop, via MCP *(a integração)*
101
+ ```bash
102
+ # build do SportsClaw (tool machina_loop já em main: #113–#116)
103
+ sportsclaw mcp add https://<org>-<projeto>.org.machina.gg/mcp/sse --name machina --token <token>
104
+ sportsclaw "Delega uma tarefa durável: pesquise o próximo jogo e me dê a análise"
105
+ # → o LLM do SportsClaw descobre o loop e chama machina_loop {action:start} / {action:read}
106
+ ```
107
+ Valida: descoberta automática do loop, delegação durável, leitura do resultado.
108
+ **Validado** com **gpt-5.5** (Azure AI Foundry, via `/responses`): o SportsClaw raciocina
109
+ e chama o `machina_loop`. O **round-trip completa** após o redeploy do MCP (#287) — o MCP
110
+ antigo da pod só aceita por **ObjectId** (acionar por nome → 500).
111
+
112
+ ### Teste C — Provisionar o loop num pod novo *(o kit)*
113
+ `provision.py` é stdlib puro e parametrizado — sobe o loop inteiro em qualquer pod
114
+ (`--teardown` remove). Permite ao revisor rodar **testes isolados com dados reais do
115
+ projeto dele** antes de qualquer fusão de código. Passo a passo + contratos em
116
+ [`VALIDATION.md`](VALIDATION.md).
117
+
118
+ ### Teste D — Verificação (Cap 8) + auto-reparo (Cap 8.2) *(o "chão")*
119
+ Todo turno passa por um **gate determinístico** + um **evaluator independente** antes de
120
+ finalizar `idle`. O `--watch` mostra o veredito:
121
+ ```bash
122
+ machina loop run "Quanto é 1234 * 5678?" --watch
123
+ # idle · 1 turns
124
+ # ✓ verified (evaluator: gemini-3.1-flash-lite)
125
+
126
+ machina loop run "Quanto é 10 / 0?" --watch # a tool erra → o gate fecha
127
+ # needs_review · 1 turns
128
+ # ⚠ needs review — ... # checkpoint humano, nunca um pass silencioso
129
+ ```
130
+ - **Prod:** aponte `EVAL_MODEL` pra um modelo **mais forte que o gerador**
131
+ (`EVAL_MODEL="<modelo>" … python3 provision.py`) — avaliador do mesmo modelo é leniente.
132
+ - **Auto-reparo (Cap 8.2):** quando o evaluator reprova uma resposta que passou no gate, o
133
+ loop **conserta 1x** e re-verifica (a CLI mostra `· self-repaired`). Receita determinística
134
+ pra forçar e ver isso em [`VALIDATION.md`](VALIDATION.md) §D.
135
+
136
+ Valida: gate fail-closed, `needs_review` (checkpoint humano), auto-reparo. Scorecard
137
+ completo + resultados ao vivo: [`PLAYBOOK-SCORECARD.md`](PLAYBOOK-SCORECARD.md).
138
+
139
+ ### Teste E — Operator-sync (SportsClaw) *(o loop como 2ª lente)*
140
+ O operator daemon do SportsClaw pode rotear cada decisão publicada pro loop durável
141
+ (verificação independente). Liga por job em `~/.sportsclaw/operator/<jobId>.json`:
142
+ ```json
143
+ { "jobId": "studio", "intervalMs": 90000, "operatorSync": { "enabled": true } }
144
+ ```
145
+ Precisa de ≥2 ticks (start-now / read-next-tick) e do pod do loop conectado
146
+ (`sportsclaw mcp add <pod>/mcp/sse --token <token>`). Detalhes + como testar:
147
+ SportsClaw `docs/advanced/operator.md` (§Operator-sync). *Mesmo gate do #287 no dispatch.*
148
+
149
+ ## 6.5 Context Graph — `context-verify` (a aplicação real)
150
+
151
+ O mesmo padrão **gerador/avaliador** aplicado a **dados**, não a Q&A: audita **arestas de
152
+ contexto** — *está esse dado atribuído à entidade certa?* — e grava um documento
153
+ **`context_graph_health`** por aresta (consultável), não um script descartável.
154
+
155
+ ```bash
156
+ CLIENT_API_URL="https://<org>-<projeto>.org.machina.gg" API_TOKEN="<token>" \
157
+ python3 docs/harness-loop-kit/context-verify.py --run
158
+ ```
159
+
160
+ Provisiona um **connector** (2 scanners determinísticos), um **prompt** avaliador
161
+ edge-agnóstico (camada semântica), **2 workflows** e um **agent** que roda todas as auditorias.
162
+ Roda 100% server-side no pod (não depende do MCP / #287). **Medido ao vivo (staging):**
163
+
164
+ | Aresta | Coleção | Resultado |
165
+ | --- | --- | --- |
166
+ | `análise↔fixture` | `sportradar-fixture.pre_match_research` ([#705](https://github.com/machina-sports/entain-templates/issues/705)) | **13%** quebradas (26/200) |
167
+ | `odd↔market↔fixture` | `entain-markets-tier3` | **0%** (consistente, 65) |
168
+ | `market→fixture` (linkabilidade) | markets PT ↔ fixtures EN | det. liga **2%**; **semântico recupera ~metade** do resto |
169
+
170
+ O verificador **localiza onde o contexto quebra** (cobertura), atesta onde não quebra (odds), e
171
+ na aresta de **linkabilidade prova por que a camada de LLM é necessária**: um join determinístico
172
+ liga só 2% das odds aos jogos (nomes PT vs EN, sem id comum), e o passo semântico recupera as
173
+ traduções que ele perde (`Austrália vs Egito` → `Australia vs Egypt`). É o v0 do **Context Graph**.
174
+ Próximas arestas (mesmo motor): `stat↔player↔match`, `narrativa↔evento`.
175
+
176
+ **Self-healing + self-evolving.** A aresta de linkabilidade não só mede — o passo semântico
177
+ **resolve e grava a tabela de ids de volta** (docs `context_graph_links`:
178
+ `bwin_fixture_id → sport_event_id`, ex.: `2:7826050 → sr:sport_event:53452503` =
179
+ `Austrália vs Egito → Australia vs Egypt`). É o **join bwin↔sportradar que não existia**, curado
180
+ pelo LLM e persistido pra a montagem de contexto do cliente consumir. O agent
181
+ **`context-verify-beat`** (agendado, **inativo por padrão**) roda o sweep contínuo → o grafo se
182
+ **cura e evolui sozinho**. É o self-repair do harness loop (Cap 8.2) aplicado aos **dados**:
183
+ detect → heal → **resolve ids** → persist → repeat. *(Conservador: só links que resolvem a ids
184
+ reais são gravados — o resto fica como órfão.)*
185
+
186
+ ## 7. Pendências honestas (transparência)
187
+
188
+ 1. **Redeploy do MCP** ([#287](https://github.com/machina-sports/machina-client-api/issues/287)):
189
+ o fix que permite acionar agentes **por nome** via MCP está no código (merged), mas
190
+ **nunca foi buildado/deployado** — os pods rodam imagens MCP antigas. É uma ação de
191
+ release multi-tenant da plataforma (não bloqueia os testes acima — usamos o ObjectId).
192
+ 2. **Verification / evaluator** ✅ **feito (Cap 7).** O loop agora tem um **evaluator
193
+ independente** (`loop-evaluate`, contexto fresco + postura "assume broken", `EVAL_MODEL`)
194
+ + um **gate determinístico**; qualquer falha → `needs_review` (checkpoint humano, nunca
195
+ um "pass" silencioso). Validado ao vivo — ver
196
+ [`PLAYBOOK-SCORECARD.md`](PLAYBOOK-SCORECARD.md). *Restam:* apontar `EVAL_MODEL` para um
197
+ modelo **mais forte que o gerador** em produção (evaluator do mesmo modelo é leniente) e
198
+ um **token cap** por turno antes de rodar 100% sozinho.
199
+ 3. **Token cap** (orçamento por turno/sessão) antes de qualquer execução não supervisionada
200
+ — já existe o budget de tentativas do resume (`LOOP_MAX_ATTEMPTS`); falta o teto de *tokens*.
201
+ 4. **Dado de enrichment (a montante — não é do loop):** o teste real expôs `pre_match_research`
202
+ atribuído ao **fixture errado** em vários jogos (cada batch herda a análise do 1º fixture).
203
+ Bug no pipeline de cobertura, registrado em
204
+ [entain-templates#705](https://github.com/machina-sports/entain-templates/issues/705). O loop
205
+ relatou fielmente os docs — e por isso expôs o problema.
206
+
207
+ ## 8. Próximos passos sugeridos
208
+
209
+ - **Plataforma:** executar o redeploy do MCP (#287) → desbloqueia o `machina_loop` por nome.
210
+ - **Fase 2 (faseado, como combinado):** *operator-sync* — rotear as decisões do operator
211
+ daemon do SportsClaw para o loop (heartbeat → beat). É também a casa natural do
212
+ **evaluator** (o operator do SportsClaw já tem os broadcast-safety validators).
213
+
214
+ ---
215
+
216
+ ### Referências
217
+ - Conceito: *Loop Engineering — The Anthropic Playbook* (Osmani/Steinberger/Cherny).
218
+ - Arquitetura e build capítulo a capítulo: [`../agentic-harness-loop.md`](../agentic-harness-loop.md).
219
+ - PRs: machina-cli#23, #24 · sportsclaw#113, #114 · client-api#287.