@crvouga/dev-fleet 0.0.0-stage → 0.1.0
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.
- package/.mise/locks/aws-cdk/2.1146.1/aube-lock.yaml +24 -0
- package/.mise/locks/aws-cdk/2.1146.1/package.json +7 -0
- package/.mise/locks/azure-cli/2.91.0~a837e014/pyproject.toml +5 -0
- package/.mise/locks/azure-cli/2.91.0~a837e014/uv.lock +2794 -0
- package/.mise/locks/gemini/0.66.0~84aac8e6/aube-lock.yaml +123 -0
- package/.mise/locks/gemini/0.66.0~84aac8e6/package.json +12 -0
- package/.mise/locks/npm-devcontainers-cli/0.90.0/aube-lock.yaml +24 -0
- package/.mise/locks/npm-devcontainers-cli/0.90.0/package.json +7 -0
- package/.mise/locks/npm-modelcontextprotocol-inspector/2.13.0~4c109bea/aube-lock.yaml +1432 -0
- package/.mise/locks/npm-modelcontextprotocol-inspector/2.13.0~4c109bea/package.json +7 -0
- package/.mise/locks/npm-vercel/65.8.0/aube-lock.yaml +3595 -0
- package/.mise/locks/npm-vercel/65.8.0/package.json +7 -0
- package/.mise/locks/npm-wrangler/4.156.0/aube-lock.yaml +895 -0
- package/.mise/locks/npm-wrangler/4.156.0/package.json +7 -0
- package/.mise/locks/npm-yarnpkg-cli-dist/4.18.1/aube-lock.yaml +24 -0
- package/.mise/locks/npm-yarnpkg-cli-dist/4.18.1/package.json +7 -0
- package/LICENSE +21 -0
- package/README.md +157 -2
- package/agents/antigravity-proxy.ts +3 -0
- package/agents/audit.md +89 -0
- package/agents/claude-proxy +5 -0
- package/agents/claude-proxy.ts +3 -0
- package/agents/codex-proxy.ts +3 -0
- package/agents/grok-proxy.ts +3 -0
- package/agents/managed-proxy.ts +55 -0
- package/agents/opencode-proxy.ts +3 -0
- package/agents/registry.json +209 -0
- package/agents/registry.schema.json +149 -0
- package/agents/setup.md +128 -0
- package/agents/t3.json +40 -0
- package/ansible/macos/manager.yml +30 -0
- package/ansible/macos/policy.json +17 -0
- package/ansible/monitoring/README.md +154 -0
- package/ansible/monitoring/agent-darwin.yml +198 -0
- package/ansible/monitoring/agent.yml +134 -0
- package/ansible/monitoring/beszel-agent.service +42 -0
- package/ansible/monitoring/compose.yml +74 -0
- package/ansible/monitoring/hub-darwin.yml +102 -0
- package/ansible/monitoring/lock.json +11 -0
- package/ansible/net/remote-probe.sh +13 -0
- package/ansible/ubuntu/authorize-sudo.sh +51 -0
- package/ansible/ubuntu/baseline.yml +89 -0
- package/ansible/ubuntu/disk-guard.py +104 -0
- package/ansible/ubuntu/policy.json +43 -0
- package/ansible/ubuntu/recovery.yml +15 -0
- package/ansible/ubuntu/t3/policy.json +7 -0
- package/ansible/ubuntu/t3-desktop.yml +220 -0
- package/ansible/ubuntu/t3-health.sh +33 -0
- package/ansible/ubuntu/t3-policy.yml +76 -0
- package/ansible/ubuntu/t3-route.yml +28 -0
- package/ansible/ubuntu/tailscale.yml +75 -0
- package/ansible/ubuntu/tasks/credentials.yml +47 -0
- package/ansible/ubuntu/tasks/docker.yml +31 -0
- package/ansible/ubuntu/tasks/packages.yml +56 -0
- package/ansible/ubuntu/tasks/power.yml +51 -0
- package/ansible/ubuntu/tasks/recovery.yml +39 -0
- package/ansible/ubuntu/tasks/resources.yml +252 -0
- package/ansible/ubuntu/tasks/services.yml +31 -0
- package/ansible/ubuntu/tasks/ssh.yml +71 -0
- package/ansible/ubuntu/tasks/user.yml +120 -0
- package/bin/devfleet.mjs +36 -0
- package/bootstrap/bootstrap.ps1 +50 -0
- package/bootstrap/bootstrap.sh +73 -0
- package/bootstrap/devfleet +7 -0
- package/bootstrap/docker-desktop.sh +33 -0
- package/bootstrap/doctor.ts +189 -0
- package/bootstrap/fleet-manager-run.sh +76 -0
- package/bootstrap/fleet-remote-bootstrap.sh +185 -0
- package/bootstrap/global-config.ts +113 -0
- package/bootstrap/install-launcher.sh +7 -0
- package/bootstrap/native-aws.ts +86 -0
- package/bootstrap/native-t3.ts +154 -0
- package/bootstrap/npm.ts +350 -0
- package/bootstrap/setup-status.ts +51 -0
- package/bootstrap/setup.ts +88 -0
- package/bootstrap/shell-path.ts +105 -0
- package/bootstrap/verify-t3-archive.py +49 -0
- package/bootstrap/worker-auth.ts +65 -0
- package/bootstrap/worker-github.ts +47 -0
- package/bootstrap/worker-tools.ts +24 -0
- package/cliproxy/AGENTS.md +11 -0
- package/cliproxy/README.md +269 -0
- package/cliproxy/clients/bootstrap.py +143 -0
- package/cliproxy/clients/launcher.py +57 -0
- package/cliproxy/compose.yaml +90 -0
- package/cliproxy/config.template.yaml +70 -0
- package/cliproxy/docs/cloud-adoption.md +16 -0
- package/cliproxy/docs/deployment.png +0 -0
- package/cliproxy/docs/deployment.svg +109 -0
- package/cliproxy/docs/health-workflow.example.yml +185 -0
- package/cliproxy/docs/migration.md +131 -0
- package/cliproxy/docs/model-health-report.schema.json +364 -0
- package/cliproxy/docs/model-health.md +393 -0
- package/cliproxy/image.lock.json +5 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-backup-check.plist +38 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-backup.plist +48 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-fleet.plist +32 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-gc.plist +38 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-monitor.plist +29 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-vault-renew.plist +31 -0
- package/cliproxy/models.json +1618 -0
- package/cliproxy/requirements.lock +78 -0
- package/cliproxy/scripts/accounts.py +38 -0
- package/cliproxy/scripts/audit.py +123 -0
- package/cliproxy/scripts/backup +234 -0
- package/cliproxy/scripts/check.py +34 -0
- package/cliproxy/scripts/checkpoint.py +226 -0
- package/cliproxy/scripts/cli.py +64 -0
- package/cliproxy/scripts/cliproxy_host.py +257 -0
- package/cliproxy/scripts/cloud_state.py +150 -0
- package/cliproxy/scripts/container-health +6 -0
- package/cliproxy/scripts/docker +24 -0
- package/cliproxy/scripts/external-health.py +79 -0
- package/cliproxy/scripts/fleet_config.py +43 -0
- package/cliproxy/scripts/fleet_sync.py +274 -0
- package/cliproxy/scripts/initialize +84 -0
- package/cliproxy/scripts/install-dependencies +48 -0
- package/cliproxy/scripts/install.py +406 -0
- package/cliproxy/scripts/model_health.py +16 -0
- package/cliproxy/scripts/modelhealth/__init__.py +5 -0
- package/cliproxy/scripts/modelhealth/checks.py +429 -0
- package/cliproxy/scripts/modelhealth/cli.py +117 -0
- package/cliproxy/scripts/modelhealth/config.py +186 -0
- package/cliproxy/scripts/modelhealth/emulator.py +536 -0
- package/cliproxy/scripts/modelhealth/expect.py +88 -0
- package/cliproxy/scripts/modelhealth/findings.py +183 -0
- package/cliproxy/scripts/modelhealth/protocol.py +330 -0
- package/cliproxy/scripts/modelhealth/redact.py +28 -0
- package/cliproxy/scripts/modelhealth/report.py +150 -0
- package/cliproxy/scripts/modelhealth/runner.py +390 -0
- package/cliproxy/scripts/modelhealth/scenario.py +131 -0
- package/cliproxy/scripts/modelhealth/schema.py +63 -0
- package/cliproxy/scripts/modelhealth/simulate.py +111 -0
- package/cliproxy/scripts/modelhealth/transport.py +213 -0
- package/cliproxy/scripts/monitor +68 -0
- package/cliproxy/scripts/ops +527 -0
- package/cliproxy/scripts/public-endpoint +127 -0
- package/cliproxy/scripts/recover_node.py +177 -0
- package/cliproxy/scripts/restore-verify +60 -0
- package/cliproxy/scripts/retention.py +144 -0
- package/cliproxy/scripts/service-start +7 -0
- package/cliproxy/scripts/validate-config +56 -0
- package/cliproxy/scripts/vault-access.py +57 -0
- package/cliproxy/scripts/vault-backup-login +55 -0
- package/cliproxy/scripts/vault-recovery +56 -0
- package/cliproxy/scripts/vault-renew +30 -0
- package/cliproxy/systemd/cliproxy-backup-check.service +10 -0
- package/cliproxy/systemd/cliproxy-backup-check.timer +8 -0
- package/cliproxy/systemd/cliproxy-backup.service +13 -0
- package/cliproxy/systemd/cliproxy-backup.timer +8 -0
- package/cliproxy/systemd/cliproxy-fleet.service +17 -0
- package/cliproxy/systemd/cliproxy-gc.service +13 -0
- package/cliproxy/systemd/cliproxy-gc.timer +8 -0
- package/cliproxy/systemd/cliproxy-monitor.service +8 -0
- package/cliproxy/systemd/cliproxy-monitor.timer +7 -0
- package/cliproxy/systemd/cliproxy-vault-renew.service +8 -0
- package/cliproxy/systemd/cliproxy-vault-renew.timer +7 -0
- package/cliproxy/vendor/LICENSE +22 -0
- package/cliproxy/vendor/config.upstream.yaml +1349 -0
- package/examples/fleet.json +95 -0
- package/examples/roster.json +13 -0
- package/mise.lock +1492 -0
- package/mise.toml +99 -0
- package/package.json +65 -4
- package/schema/fleet.schema.json +364 -0
- package/schema/roster.schema.json +77 -0
- package/src/agents/account-relay.ts +111 -0
- package/src/agents/accounts.ts +85 -0
- package/src/agents/audit.ts +77 -0
- package/src/agents/cli.ts +13 -0
- package/src/agents/command.ts +204 -0
- package/src/agents/converge.ts +123 -0
- package/src/agents/doctor.ts +107 -0
- package/src/agents/errors.ts +2 -0
- package/src/agents/files.ts +73 -0
- package/src/agents/fleet-verify.ts +156 -0
- package/src/agents/launch.ts +290 -0
- package/src/agents/native-verify.ts +226 -0
- package/src/agents/provider-errors.ts +50 -0
- package/src/agents/registry.ts +55 -0
- package/src/agents/render.ts +110 -0
- package/src/agents/round-trip.ts +192 -0
- package/src/agents/secrets.ts +13 -0
- package/src/agents/toolchain.ts +34 -0
- package/src/agents/verify-cache.ts +103 -0
- package/src/agents/verify.ts +127 -0
- package/src/auth-checks.ts +163 -0
- package/src/cli/agent-guide.ts +95 -0
- package/src/cli/app.ts +115 -0
- package/src/cli/cli.ts +21 -0
- package/src/cli/command-index.ts +50 -0
- package/src/cli/contracts.ts +25 -0
- package/src/cli/fleet-reference.ts +17 -0
- package/src/cli/fleet-sync-checkout.ts +91 -0
- package/src/cli/fleet-sync-enrollment.ts +144 -0
- package/src/cli/fleet-sync-forward.ts +134 -0
- package/src/cli/fleet-sync-manager.ts +193 -0
- package/src/cli/fleet-sync-monitoring.ts +185 -0
- package/src/cli/fleet-sync-output.ts +314 -0
- package/src/cli/fleet-sync-privilege.ts +27 -0
- package/src/cli/fleet-sync-progress.ts +109 -0
- package/src/cli/fleet-sync-remote.ts +236 -0
- package/src/cli/fleet-sync-report.ts +26 -0
- package/src/cli/fleet-sync-schedule.ts +138 -0
- package/src/cli/fleet-sync-vault.ts +166 -0
- package/src/cli/fleet-sync.ts +309 -0
- package/src/cli/fleet.ts +163 -0
- package/src/cli/managed-health.ts +219 -0
- package/src/cli/node-deployment.ts +34 -0
- package/src/cli/node-sync.ts +114 -0
- package/src/cli/node-t3.ts +31 -0
- package/src/cli/options.ts +141 -0
- package/src/cli/probe-source.ts +7 -0
- package/src/cli/program.ts +169 -0
- package/src/cli/register-fleet.ts +246 -0
- package/src/cli/registry.ts +158 -0
- package/src/cli/repair-apply.ts +67 -0
- package/src/cli/repair-guard.ts +11 -0
- package/src/cli/repair-inspect.ts +150 -0
- package/src/cli/repair-script.ts +76 -0
- package/src/cli/repair.ts +209 -0
- package/src/cli/roster.ts +89 -0
- package/src/cli/search.ts +35 -0
- package/src/cli/settings.ts +64 -0
- package/src/cli/source-operations.ts +78 -0
- package/src/cli/t3/command.ts +90 -0
- package/src/cli/t3/register.ts +55 -0
- package/src/cli/tailnet.ts +127 -0
- package/src/cli/ui-actions.ts +133 -0
- package/src/cli/ui-controller.ts +113 -0
- package/src/cli/ui-data.ts +106 -0
- package/src/cli/ui-execute.ts +163 -0
- package/src/cli/ui-repairs.ts +34 -0
- package/src/cli/ui-reports.ts +211 -0
- package/src/cli/ui-targets.ts +100 -0
- package/src/cli/ui-terminal.ts +109 -0
- package/src/cli/ui-types.ts +49 -0
- package/src/cli/ui-wizard.ts +101 -0
- package/src/cli/ui.ts +9 -0
- package/src/cli/worker-health-output.ts +37 -0
- package/src/config.ts +186 -0
- package/src/configure.ts +255 -0
- package/src/definition.ts +260 -0
- package/src/diagnostics.ts +92 -0
- package/src/doctor-check.ts +10 -0
- package/src/errors.ts +1 -0
- package/src/fingerprint.ts +120 -0
- package/src/fleet-config.ts +88 -0
- package/src/index.ts +6 -0
- package/src/input-hashes.ts +73 -0
- package/src/machine/local-source.ts +52 -0
- package/src/machine/lock-error.ts +2 -0
- package/src/machine/platform.ts +44 -0
- package/src/machine/source.ts +68 -0
- package/src/machine/state.ts +185 -0
- package/src/machine-health.ts +95 -0
- package/src/managed-source.ts +47 -0
- package/src/manager-failure.ts +48 -0
- package/src/manager-sync.ts +400 -0
- package/src/manager.ts +62 -0
- package/src/monitoring/apply.ts +171 -0
- package/src/monitoring/beszel.ts +191 -0
- package/src/monitoring/enroll.ts +110 -0
- package/src/monitoring/hub-access.ts +113 -0
- package/src/monitoring/hub-viewer.ts +142 -0
- package/src/monitoring/hub.ts +93 -0
- package/src/monitoring/manager-agent.ts +73 -0
- package/src/monitoring/manager-hub.ts +232 -0
- package/src/monitoring/remote.ts +65 -0
- package/src/network-definition.ts +83 -0
- package/src/node-converge-linux.ts +372 -0
- package/src/node-converge-shared.ts +83 -0
- package/src/node-converge.ts +40 -0
- package/src/onboard.ts +35 -0
- package/src/platform/ansible-receipt.ts +128 -0
- package/src/platform/ansible.ts +62 -0
- package/src/platform/darwin.ts +203 -0
- package/src/platform/detect.ts +11 -0
- package/src/platform/fallback.ts +110 -0
- package/src/platform/index.ts +38 -0
- package/src/platform/launchd.ts +98 -0
- package/src/platform/linux.ts +139 -0
- package/src/platform/ps.ts +45 -0
- package/src/platform/resource-verify.ts +128 -0
- package/src/platform/systemd-user.ts +95 -0
- package/src/platform/t3-policy.ts +137 -0
- package/src/platform/t3-route.ts +68 -0
- package/src/platform/t3-service.ts +75 -0
- package/src/platform/types.ts +123 -0
- package/src/platform/ubuntu-audit.ts +63 -0
- package/src/platform/ubuntu-verify.ts +105 -0
- package/src/platform/windows.ts +148 -0
- package/src/power-recovery.ts +55 -0
- package/src/probe.ts +51 -0
- package/src/protocol.ts +119 -0
- package/src/proxy-converge.ts +85 -0
- package/src/remote-bootstrap.ts +212 -0
- package/src/remote-entry.ts +89 -0
- package/src/remote-lock.ts +12 -0
- package/src/repair-catalog.ts +206 -0
- package/src/repair-plan.ts +78 -0
- package/src/repair-runner.ts +84 -0
- package/src/report.ts +71 -0
- package/src/runner.ts +104 -0
- package/src/secrets.ts +169 -0
- package/src/service-auth.ts +115 -0
- package/src/ssh.ts +135 -0
- package/src/sync.ts +104 -0
- package/src/t3/accounts.ts +81 -0
- package/src/t3/desired.ts +165 -0
- package/src/t3/files.ts +81 -0
- package/src/t3/names-check.ts +53 -0
- package/src/t3/names.ts +155 -0
- package/src/t3/plan.ts +82 -0
- package/src/t3/providers.ts +74 -0
- package/src/t3/reconcile.ts +123 -0
- package/src/t3-endpoint.ts +48 -0
- package/src/t3-linked-check.ts +101 -0
- package/src/tailnet-health.ts +231 -0
- package/src/tailnet-matching.ts +37 -0
- package/src/tailscale.ts +141 -0
- package/src/test-fixtures.ts +36 -0
- package/src/toolchain-checks.ts +83 -0
- package/src/topology.ts +24 -0
- package/src/transport.ts +122 -0
- package/src/types.ts +95 -0
- package/src/vault-config.ts +38 -0
- package/src/worker-access-checks.ts +115 -0
- package/src/worker-capacity.ts +34 -0
- package/src/worker-host-checks.ts +176 -0
- package/src/worker-policy.ts +64 -0
- package/src/worker-readiness.ts +64 -0
- package/src/workstation-checks.ts +29 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# Model validation and health checks
|
|
2
|
+
|
|
3
|
+
This is the declarative validation layer for the hosted OpenAI-compatible endpoint
|
|
4
|
+
`https://cli-proxy.example.com/v1`. It extends the existing external health workflow; it does
|
|
5
|
+
not replace the provenance, backup-freshness or recovery checks.
|
|
6
|
+
|
|
7
|
+
Models are tested under the ids the proxy serves in `/v1/models` (`claude-opus-5-5`, `claude-sonnet-5-5`, `gpt-6-astra`, `gpt-6.1-sol`), the conventional setup with no alias layer. Everything model-specific lives in [`models.json`](../models.json). The code in
|
|
8
|
+
`scripts/modelhealth/` is generic: adding a model, capability, check or fault scenario is a
|
|
9
|
+
configuration change.
|
|
10
|
+
|
|
11
|
+
## What counts as evidence
|
|
12
|
+
|
|
13
|
+
Every result is labelled, and the report never blends the classes:
|
|
14
|
+
|
|
15
|
+
| Evidence | Meaning |
|
|
16
|
+
| ---------------------- | ------------------------------------------------------------------------------------------- |
|
|
17
|
+
| `live` | A real request to the configured endpoint passed or failed protocol and invariant checks. |
|
|
18
|
+
| `simulated` | A scenario ran against the local emulator. It proves the harness detects the behavior. |
|
|
19
|
+
| `untested` | Nothing exercised it. It is never reported as healthy, whatever the model status says. |
|
|
20
|
+
| `unsupported` | Declared unsupported in configuration with a reason. It is not requested and not "broken". |
|
|
21
|
+
| `observed_unsupported` | Declared `optional`, and the request failed cleanly (rejected, wrong shape). Informational. |
|
|
22
|
+
|
|
23
|
+
Account failover, quota exhaustion and all-accounts-unavailable behavior cannot be provoked against
|
|
24
|
+
the hosted proxy without burning real subscription quota. Those are `simulated` only, and their
|
|
25
|
+
live status stays `untested`.
|
|
26
|
+
|
|
27
|
+
**Cursor.** The Cursor suite is protocol-level compatibility: public OpenAI Chat Completions and
|
|
28
|
+
Responses request shapes, streaming tool calls, tool round trips, a scripted multi-step coding-agent
|
|
29
|
+
workflow, cancellation and recovery, usage and finish reasons. It does not reproduce Cursor's
|
|
30
|
+
private behavior, and no run of this suite proves the Cursor application works. Every report states
|
|
31
|
+
`Verified with the actual Cursor application: no`. Verifying the application needs a human running
|
|
32
|
+
Cursor against the endpoint with the same model ids and recording the result separately.
|
|
33
|
+
|
|
34
|
+
## Architecture
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
models.json ──► config.py (validate, resolve capability states)
|
|
38
|
+
│
|
|
39
|
+
levels ▼
|
|
40
|
+
liveness ─► readiness ─► e2e ── per model, in parallel, isolated ──► derive status ─► JSON + Markdown
|
|
41
|
+
(no key) (key, no │ checks.py engines ◄── scenario.py (turn → chat | responses body)
|
|
42
|
+
inference) │ transport.py (HTTP/SSE, no redirects, no hidden retry)
|
|
43
|
+
│ protocol.py (wire contracts) + expect.py (declared invariants)
|
|
44
|
+
▼
|
|
45
|
+
emulator.py + simulate.py (routing, rate limit, timeout, truncation: `simulated`)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- **Protocol-neutral turns.** A check describes one conversation turn (`system`, `messages`,
|
|
49
|
+
`tools`, `tool_choice`, `json_schema`, `stream`, …). `scenario.py` renders it as a Chat
|
|
50
|
+
Completions body and as a Responses body, so one declaration yields `chat.<id>` and
|
|
51
|
+
`responses.<id>` cases.
|
|
52
|
+
- **Wire contract before semantics.** `protocol.py` normalizes a response and records violations
|
|
53
|
+
(object type, ids, usage arithmetic, finish reasons, tool-call ids and JSON arguments, SSE
|
|
54
|
+
framing, `[DONE]`, terminal Responses event, sequence numbers, streamed vs final consistency).
|
|
55
|
+
`expect.py` then checks the declared invariants. Exact natural-language output is never asserted;
|
|
56
|
+
text checks use random per-run tokens (`{codeword}`, `{marker}`, `{nonce}`) and tool checks use
|
|
57
|
+
forced tool choice with JSON-Schema-validated arguments.
|
|
58
|
+
- **Independence.** Each model gets its own context, request budget share and consecutive-failure
|
|
59
|
+
counter. An exception in one check becomes a `harness` failure for that check only.
|
|
60
|
+
|
|
61
|
+
## Levels and profiles
|
|
62
|
+
|
|
63
|
+
| Profile | Levels | Inference | Intended use |
|
|
64
|
+
| ----------- | ------------------- | ------------------ | ---------------------------------------------------------------------------------------------- |
|
|
65
|
+
| `liveness` | liveness | none | "Is it reachable and does it reject anonymous callers?" No credentials. |
|
|
66
|
+
| `readiness` | liveness, readiness | none | Key works, `/v1/models` valid, **every configured model served**. |
|
|
67
|
+
| `light` | + cheapest e2e | 2 requests/model | Hourly. Chat non-stream + Responses stream. |
|
|
68
|
+
| `nightly` | + all `full` checks | ~53 requests/model | Comprehensive protocol, tools, agent workflow, errors, concurrency; also runs the simulations. |
|
|
69
|
+
| `manual` | + `manual` checks | + wrong-key probe | Full diagnostics, plus the fault-injection scenarios. |
|
|
70
|
+
|
|
71
|
+
Liveness checks that `GET /v1/models` without a key returns 401 (a 200 is a failure) and that the
|
|
72
|
+
dashboard serves. Readiness lists discovered models and reports any not in configuration
|
|
73
|
+
(`discovered_unconfigured`). A configured model id missing from `/v1/models` makes that model
|
|
74
|
+
`unhealthy` with category `model_missing` and no inference is sent to it. It is never skipped
|
|
75
|
+
silently.
|
|
76
|
+
|
|
77
|
+
The wrong-key probe is `manual` only. Upstream counts failed _management_ logins toward an IP ban,
|
|
78
|
+
and scheduled checks must not generate failed logins; the harness never sends a management key at
|
|
79
|
+
all.
|
|
80
|
+
|
|
81
|
+
## Commands
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Frequent, cheap: liveness + readiness + 2 requests per model
|
|
85
|
+
devfleet cliproxy model-health # default profile: light
|
|
86
|
+
devfleet cliproxy model-health --profile readiness # no inference
|
|
87
|
+
devfleet cliproxy model-health --profile liveness # no credentials
|
|
88
|
+
|
|
89
|
+
# Complete suite (default profile: nightly)
|
|
90
|
+
devfleet cliproxy model-suite
|
|
91
|
+
devfleet cliproxy model-suite --suite cursor # Cursor-style agent checks only
|
|
92
|
+
devfleet cliproxy model-suite --profile manual --model gpt-6.1-sol --output ./report
|
|
93
|
+
|
|
94
|
+
# Offline: the same declarative suite against the local emulator. No key, no spend, no network.
|
|
95
|
+
devfleet cliproxy model-suite --target mock --profile manual
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Useful flags: `--model MODEL_ID` (repeatable), `--check CAPABILITY_GLOB` (repeatable), `--force-probe`, `--suite core|cursor|all`, `--json`, `--output DIR`
|
|
99
|
+
(writes `model-health.json`, `model-health.md` and `agent-brief.md`), `--state FILE` (last-success memory),
|
|
100
|
+
`--max-requests N`, `--concurrency N`, `--timeout-scale F`, `--seed N` (reproducible tokens),
|
|
101
|
+
`--fail-on unhealthy|degraded`, `--allow-unknown`.
|
|
102
|
+
|
|
103
|
+
Exit codes: `0` ok, `1` unhealthy (or degraded with `--fail-on degraded`), `2` unknown (for example
|
|
104
|
+
no credentials; a result that was not obtained is never a pass), `3` bad configuration or arguments.
|
|
105
|
+
|
|
106
|
+
The client key is read, in order, from `CLIPROXY_API_KEY`, an existing `VAULT_TOKEN`
|
|
107
|
+
(`secret/personal/prd:CLIPROXY_FLEET_CLIENT_API_KEY`, the same short-lived GitHub OIDC login the
|
|
108
|
+
workflow already uses), then the installed host's `state/secrets/client-key`. It is held in memory,
|
|
109
|
+
sent only as a bearer header, registered with the redactor, and never printed or written.
|
|
110
|
+
|
|
111
|
+
## Status model
|
|
112
|
+
|
|
113
|
+
Per model: `healthy`, `degraded`, `unhealthy`, `unknown`.
|
|
114
|
+
|
|
115
|
+
- `unknown`: inference was not exercised at this scope, readiness did not pass, or no check
|
|
116
|
+
completed. Readiness-only profiles therefore report models as `unknown`, not `healthy`.
|
|
117
|
+
- `unhealthy`: model id not served; a `critical` required capability fails; or at least
|
|
118
|
+
`health.unhealthy_if_failed_ratio` of the exercised required capabilities fail.
|
|
119
|
+
- `degraded`: a non-critical required capability fails, a required capability's optional sibling
|
|
120
|
+
hit an infrastructure failure, latency exceeds `health.latency_ms`, or one model id resolved to
|
|
121
|
+
several response model ids (`health.model_consistency`).
|
|
122
|
+
- `healthy`: everything that was exercised passed. **Healthy applies to the exercised capabilities
|
|
123
|
+
only**; read `coverage` and the `untested` rows. A `light` run exercises 2 of 38.
|
|
124
|
+
|
|
125
|
+
Run-level status is the worst of the levels and models. Simulation failures degrade it.
|
|
126
|
+
|
|
127
|
+
Safeguards against runaway cost: an exhausted budget leaves the remaining checks `untested` with
|
|
128
|
+
reason `budget`; four consecutive failures, or any HTTP 429, stop further requests to that model
|
|
129
|
+
(`aborted`); inference requests are never retried (`retry.inference` must be 0 and the validator
|
|
130
|
+
rejects anything else). Only the read-only model listing is retried once, on transport errors.
|
|
131
|
+
|
|
132
|
+
## Configuration reference (`models.json`)
|
|
133
|
+
|
|
134
|
+
| Section | Purpose |
|
|
135
|
+
| --------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
136
|
+
| `endpoint` | Base URL (HTTPS), key environment variable, Vault field. |
|
|
137
|
+
| `runs` | Profiles: levels, highest check tier, request/token budget, concurrency, `simulations`. |
|
|
138
|
+
| `timeouts`, `retry` | Per-request, stream idle/deadline, liveness; retry policy. |
|
|
139
|
+
| `health` | Abort threshold, unhealthy ratio, latency warnings, model-id consistency. |
|
|
140
|
+
| `protocols` | Path and token-limit field for `chat` and `responses`. |
|
|
141
|
+
| `capability_profiles` | Default state, `optional` and `unsupported` capability globs, shared request extras. |
|
|
142
|
+
| `models` | Model id, provider, profile, per-model capability overrides and request extras. |
|
|
143
|
+
| `tools` | Function definitions (JSON Schema) shared by checks. |
|
|
144
|
+
| `checks` | Declarative test cases (below). |
|
|
145
|
+
| `simulated_capabilities`, `simulations` | Routing, rate-limit, timeout and truncation scenarios. |
|
|
146
|
+
| `cursor` | Compatibility statement shown in every report. |
|
|
147
|
+
| `diagnostics` | Actionable advice per failure category. |
|
|
148
|
+
|
|
149
|
+
Capability ids are `<protocol>.<check id>`, for example `responses.tools_stream`. States are
|
|
150
|
+
`required`, `optional` (failure by assertion, protocol or rejection becomes
|
|
151
|
+
`observed_unsupported`; infrastructure failures still count) and `unsupported` (needs a reason).
|
|
152
|
+
Globs such as `*.tools*` are matched with `fnmatch` and must match at least one capability, so a
|
|
153
|
+
typo is a configuration error.
|
|
154
|
+
|
|
155
|
+
Check kinds (the only code paths): `request`, `roundtrip` (tool call, result, answer), `agent`
|
|
156
|
+
(scripted read, edit, test workflow with a virtual file system), `cancel_recover`, `concurrent`,
|
|
157
|
+
`error_probe`. Expectations: `finish_reason`, `content` (`non_empty`, `contains`), `usage`,
|
|
158
|
+
`stream` (`min_events`, `max_gap_s`), `json` (schema), `tool_calls` (`min`, `max`, `names`,
|
|
159
|
+
`unique_ids`, `arguments_schema: from_tools`, `arguments`, `values`), and for probes `status` and
|
|
160
|
+
`error_envelope`. Tiers: `light` < `full` < `manual`. Severities: `critical`, `major`, `minor`.
|
|
161
|
+
|
|
162
|
+
### Add a model
|
|
163
|
+
|
|
164
|
+
Append to `models` and nothing else:
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"id": "new-vendor-model",
|
|
169
|
+
"provider": "anthropic",
|
|
170
|
+
"profile": "frontier-agent",
|
|
171
|
+
"capabilities": {
|
|
172
|
+
"*.json_schema": {
|
|
173
|
+
"state": "unsupported",
|
|
174
|
+
"reason": "No structured output on this route."
|
|
175
|
+
},
|
|
176
|
+
"responses.parallel_tools": "optional"
|
|
177
|
+
},
|
|
178
|
+
"extra": { "chat": { "reasoning_effort": "low" } }
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Run `python3 -B cliproxy/scripts/check.py` (it validates `models.json`), then
|
|
183
|
+
`devfleet cliproxy model-suite --target mock` and finally a live `--model` run. Unit tests
|
|
184
|
+
(`tests/test_model_config.py`) demonstrate that a new model is picked up with no code changes.
|
|
185
|
+
|
|
186
|
+
### Add a capability or check
|
|
187
|
+
|
|
188
|
+
Append to `checks`. Reuse a kind, write the turn and the expectation, choose `severity`, `tier` and
|
|
189
|
+
`suites`. List the protocols it applies to; the capability ids appear automatically in every
|
|
190
|
+
model's report, defaulting to the profile's state. If no existing kind can express it, add a kind
|
|
191
|
+
to `checks.RUNNERS`; that is the only case that needs code.
|
|
192
|
+
|
|
193
|
+
### Add a fault scenario
|
|
194
|
+
|
|
195
|
+
Append to `simulations` (accounts with `quota` or `fail_next`, then `request`, `fault`,
|
|
196
|
+
`account`, `advance` steps with `expect` keys such as `served_by_all`, `served_set`, `category`,
|
|
197
|
+
`retry_after`, `no_retry`). The emulator's virtual clock (`advance`) makes cooldown recovery
|
|
198
|
+
instantaneous and deterministic.
|
|
199
|
+
|
|
200
|
+
## Multi-account routing: fill first
|
|
201
|
+
|
|
202
|
+
The proxy is configured to multiplex across accounts with a **fill-first** pattern: one account
|
|
203
|
+
takes all traffic until its quota is exhausted (a 429 puts it into cooldown), then the next
|
|
204
|
+
account serves, and so on. This is `routing.strategy: fill-first` in
|
|
205
|
+
[`config.template.yaml`](../config.template.yaml), together with `session-affinity: true` (a
|
|
206
|
+
session stays on its account while that account is available and rebinds on failover),
|
|
207
|
+
`cooldown.disable-cooling: false` (cooldown is what moves the fill to the next account) and
|
|
208
|
+
`retry.max-retry-credentials: 0` (every eligible account may be tried, so several exhausted
|
|
209
|
+
accounts still reach the next usable one). `models.json` mirrors the policy under `routing`, and a
|
|
210
|
+
test fails if the two disagree.
|
|
211
|
+
|
|
212
|
+
What is enforced where:
|
|
213
|
+
|
|
214
|
+
- **New or recovered deployments** start from the template, so they fill first.
|
|
215
|
+
- **`cliproxy apply FILE`** passes `--require-fill-first` to `validate-config`; a candidate config with
|
|
216
|
+
another strategy is refused. Starting an existing config is not blocked, so an older deployment
|
|
217
|
+
still comes up after an install.
|
|
218
|
+
- **The five-minute host monitor** reports `Live routing strategy is not fill-first` when the
|
|
219
|
+
running `state/runtime/config.yaml` differs from the policy. This is the signal that the live
|
|
220
|
+
config still needs the change below.
|
|
221
|
+
- **The emulator** implements the same policy (ordered fill, quota and transient-error cooldowns of
|
|
222
|
+
30s and 60s, affinity binding that outranks order, rebinding on failover) and the scenarios
|
|
223
|
+
`fill_first_*`, `transient_failure_cools_the_account_then_it_rejoins` and
|
|
224
|
+
`session_binding_survives_recovery_and_rebinds_on_failover` assert it. The same scenarios fail
|
|
225
|
+
when the emulator is switched to round robin, so they cannot pass vacuously.
|
|
226
|
+
|
|
227
|
+
**Applying it to the running proxy is an operator step.** The repository cannot change the live
|
|
228
|
+
config, and the strategy is not observable through the API, so the health report labels the policy
|
|
229
|
+
`declared` and never `live_verified`. On the proxy host:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
cp /opt/cliproxy-fleet/state/runtime/config.yaml /protected/candidate.yaml
|
|
233
|
+
# edit routing: strategy -> fill-first, retry.max-retry-credentials -> 0; change nothing else
|
|
234
|
+
devfleet cliproxy apply /protected/candidate.yaml # validate, isolated staging, restart, health wait
|
|
235
|
+
devfleet cliproxy status # monitor-failed clears on the next 5-minute run
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Not established by this repository: which account counts as "first". Upstream chooses the order
|
|
239
|
+
among OAuth credentials; the vendored configuration documents `priority` (larger first) only for
|
|
240
|
+
API-key entries. Confirm the fill order on the host (for example by watching which account's quota
|
|
241
|
+
moves in the dashboard) before relying on a particular account being drained first.
|
|
242
|
+
|
|
243
|
+
## Running in T3 Code and other agent sandboxes
|
|
244
|
+
|
|
245
|
+
The offline suite is hermetic: it uses only loopback sockets on ephemeral ports, standard-library
|
|
246
|
+
Python (3.9 through 3.15, so both the system and the mise-pinned interpreter work), temporary
|
|
247
|
+
directories it removes, and no network, credentials, Docker, Restic or PyYAML. Tests scrub ambient
|
|
248
|
+
`CLIPROXY_API_KEY`, `VAULT_TOKEN`, `CLIPROXY_ROOT` and proxy variables, and a test proves a
|
|
249
|
+
planted key is never used or printed. The suite passes under `python -X dev -W error` (no leaked
|
|
250
|
+
sockets), with a hostile environment, and 8-way parallel with CPU hogs running.
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
# T3 project action (runs the shared bootstrap first, then the personal CLI)
|
|
254
|
+
bash bootstrap/project-action.sh infra-cliproxy model-suite --target mock --profile manual
|
|
255
|
+
bash bootstrap/project-action.sh infra-cliproxy model-health # live, needs a key
|
|
256
|
+
|
|
257
|
+
# Unit tests only, through the pinned toolchain
|
|
258
|
+
mise exec -- bun run --filter @pkgs/cliproxy-fleet test:models
|
|
259
|
+
mise exec -- bun run --filter @pkgs/cliproxy-fleet lint
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Suggested T3 script labels: `Infra: Cliproxy model health` (`infra-cliproxy model-health`) and
|
|
263
|
+
`Infra: Cliproxy model suite` (`infra-cliproxy model-suite`). The full package `test` still needs
|
|
264
|
+
Restic and PyYAML for the older backup and recovery tests; `test:models` does not.
|
|
265
|
+
|
|
266
|
+
## Emulator and contract tests
|
|
267
|
+
|
|
268
|
+
`scripts/modelhealth/emulator.py` is a deterministic implementation of the public wire protocols
|
|
269
|
+
plus the proxy's documented routing policy from `config.template.yaml`: round robin, session
|
|
270
|
+
affinity, cooldown after quota exhaustion, bounded credential retries. It supports injected faults
|
|
271
|
+
(status codes, stalls, truncation, malformed SSE, missing ids or usage, cross-request token
|
|
272
|
+
contamination). It is a test double, not a model of any provider's behavior.
|
|
273
|
+
|
|
274
|
+
Pull requests run these as part of `bun run --filter @pkgs/cliproxy-fleet test` (offline, a few
|
|
275
|
+
seconds, no spend): protocol validators against valid fixtures and one mutation per defect, SSE
|
|
276
|
+
framing edge cases against a raw socket server, property-style tests (randomized tool-argument
|
|
277
|
+
fragmentation, schema validation), fill-first routing, the full suite against the emulator, per-model isolation,
|
|
278
|
+
budgets, fault detection, last-success persistence, and secret hygiene.
|
|
279
|
+
|
|
280
|
+
## Scheduling and cost
|
|
281
|
+
|
|
282
|
+
[`cliproxy-health.yml`](../../../.github/workflows/cliproxy-health.yml) has five entry points:
|
|
283
|
+
|
|
284
|
+
| Trigger | Profile | Inference | Notes |
|
|
285
|
+
| ---------------- | ----------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
286
|
+
| Every 15 minutes | `readiness` | none | Key, `/v1/models`, every configured model served, plus cloud checkpoint freshness. Free. |
|
|
287
|
+
| Hourly (`:17`) | `light` | 2 requests per model (about 8/run) | About 190 requests and well under 5,000 output tokens a day across four models. |
|
|
288
|
+
| 03:41 UTC | `nightly` | about 53 requests per model | Capped at 240 requests and 24,000 output tokens per run. |
|
|
289
|
+
| Pull request | (offline) | none | `contract` job: `models.json` lint, the offline tests and the whole suite against the emulator. No credentials. |
|
|
290
|
+
| Manual dispatch | any | your choice | `model`, `check`, `max_requests` and `force_probe` inputs. |
|
|
291
|
+
|
|
292
|
+
Controls that keep usage bounded, all in `models.json`:
|
|
293
|
+
|
|
294
|
+
- Per-profile caps on total requests, requests per model, output tokens and concurrency. Exhaustion leaves
|
|
295
|
+
the remaining checks `untested` (reason `budget`); it never fails silently or spends more.
|
|
296
|
+
- Small fixtures: every check caps output at 400 tokens or fewer; the long-stream and cancellation
|
|
297
|
+
checks ask for 300 and 200.
|
|
298
|
+
- No inference retries, ever. Four consecutive failures stop a model.
|
|
299
|
+
- **Rate-limit pause.** A 429 stops that model immediately and records the time in the state file. For
|
|
300
|
+
`health.rate_limit_backoff_s` (30 minutes) later runs send that model nothing: its status stays
|
|
301
|
+
`unhealthy` (still excluded from the overall verdict), the finding is `paused`, and the reason says when probing resumes. The first probe after
|
|
302
|
+
the pause that succeeds clears it. `--force-probe` overrides. Quota exhaustion therefore costs one
|
|
303
|
+
rejected request per half hour, not a request per run.
|
|
304
|
+
- A 429 is rejected before inference and does not consume provider usage; successful requests are tiny.
|
|
305
|
+
- Last-success and pause state persist between runs through the Actions cache, shared by all profiles.
|
|
306
|
+
|
|
307
|
+
Each live run uploads `model-health.json`, `model-health.md` and `agent-brief.md` as an artifact
|
|
308
|
+
(30 days) and writes the brief and the report to the job summary.
|
|
309
|
+
|
|
310
|
+
## Findings, the agent brief and the tracking issue
|
|
311
|
+
|
|
312
|
+
Every failure becomes a **finding** in `model-health.json` (`findings[]`, validated by
|
|
313
|
+
[`model-health-report.schema.json`](model-health-report.schema.json)) and in `agent-brief.md`:
|
|
314
|
+
|
|
315
|
+
- `id`: stable (`<model>/<capability>/<category>`), so a fix can be confirmed by its absence.
|
|
316
|
+
- `resolver` / `agent_fixable`: `operator` for quota, credentials, the proxy host or proxy configuration,
|
|
317
|
+
which no edit to this repository can fix; `agent` for protocol or assertion mismatches, harness defects
|
|
318
|
+
and budgets. Operator findings are listed first.
|
|
319
|
+
- `evidence`: the failure details plus one **trace** per request: method, path, HTTP status, timings,
|
|
320
|
+
Cloudflare `cf-ray` and `x-request-id`, `retry-after`, resolved model id, finish reason, event count,
|
|
321
|
+
tool-call names, usage, and the protocol violations found. Traces contain structure and numbers only:
|
|
322
|
+
never prompt text, completions or keys, and error messages are redacted and truncated.
|
|
323
|
+
- `reproduce`: the exact cheap command, for example
|
|
324
|
+
`devfleet cliproxy model-suite --profile nightly --model gpt-6.1-sol --check chat.tools --seed 4` (one
|
|
325
|
+
check, one or two requests). `--check` takes capability globs.
|
|
326
|
+
- `fix_hints`: where to edit (`models.json` declaration, check fixture, validator, or the operator
|
|
327
|
+
action), and what not to do (delete a check, loosen an assertion, call an untested capability healthy).
|
|
328
|
+
|
|
329
|
+
On scheduled and full manual runs the workflow also keeps one issue per scope,
|
|
330
|
+
`[ops] CLI proxy model health (live)` and `(nightly)`: opened with the brief when the run is unhealthy or
|
|
331
|
+
degraded, updated (with a comment) only when the set of findings changes (`summary.findings.fingerprint`),
|
|
332
|
+
and closed when a full run is healthy. Partial runs (`model` or `check` set) never touch it. The issue body
|
|
333
|
+
is the redacted brief, which includes provider error text such as `usage_limit_reached` and request ids;
|
|
334
|
+
keep that in mind if the repository is public.
|
|
335
|
+
|
|
336
|
+
### Agent runbook
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
gh workflow run "CLI proxy health" -f profile=readiness # free
|
|
340
|
+
gh workflow run "CLI proxy health" -f profile=nightly -f model=claude-opus-5-5 # one model
|
|
341
|
+
gh run list --workflow "CLI proxy health" --limit 5
|
|
342
|
+
gh run download <run-id> -n model-health-nightly-<run-id> # agent-brief.md, model-health.json
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
The same flow is the `/model-health` agent command (`.agents/commands/model-health.md`): read the brief,
|
|
346
|
+
stop on operator findings, reproduce an agent finding with its command, fix the declaration, check or
|
|
347
|
+
validator, add an offline test, run `test:models`, and verify with a live run of the reproduce command.
|
|
348
|
+
|
|
349
|
+
## Report
|
|
350
|
+
|
|
351
|
+
`model-health.json` (`schema: cliproxy-model-health/1`) contains `levels`, `models[]` (status,
|
|
352
|
+
reasons, `coverage`, `capabilities` with declared state and observed result, `checks[]` with
|
|
353
|
+
category, endpoint, severity, details and observations, `metrics`, `last_success`),
|
|
354
|
+
`simulations`, `budget`, `cursor` and `summary.diagnostics`. Metrics per model: availability, check
|
|
355
|
+
success rate, TTFT p50/max, latency p50/p95, streaming completion rate, tool-call success rate,
|
|
356
|
+
error categories, upstream failures and the resolved model ids. Routing outcomes are reported only
|
|
357
|
+
for simulations.
|
|
358
|
+
|
|
359
|
+
Failure categories: `credentials`, `auth`, `not_found`, `rate_limit`, `timeout`, `transport`,
|
|
360
|
+
`upstream`, `protocol`, `assertion`, `request_rejected`, `budget`, `aborted`, `model_missing`,
|
|
361
|
+
`harness`. Diagnostics never contain keys, tokens, request bodies or prompt text; messages from the
|
|
362
|
+
endpoint are redacted and truncated to a few hundred characters.
|
|
363
|
+
|
|
364
|
+
## Investigating a failure
|
|
365
|
+
|
|
366
|
+
1. Open the run summary. Read **Levels** first: a liveness or readiness failure explains every
|
|
367
|
+
model failure below it.
|
|
368
|
+
2. `transport`/`timeout` at liveness: host, tunnel or DNS. Use `devfleet cliproxy status` on the
|
|
369
|
+
workstation. `auth` at readiness: the client key and `access.api-keys` disagree.
|
|
370
|
+
3. `model_missing`: the model id is not in `/v1/models`. Compare `devfleet cliproxy models` with
|
|
371
|
+
`models.json`; the provider account behind it may be unauthenticated or the model retired.
|
|
372
|
+
4. A model `unhealthy` with `upstream`: provider account or upstream outage. Check the dashboard and
|
|
373
|
+
`devfleet cliproxy logs`. A model with `rate_limit` (quota exhausted, every credential cooling down)
|
|
374
|
+
is listed in `summary.rate_limited` and as an operator finding, but never fails the run or turns
|
|
375
|
+
`summary.status` red: the proxy answered, and the limit clears on its own. The harness already
|
|
376
|
+
stopped requesting after the first 429.
|
|
377
|
+
5. `protocol` or `assertion`: reproduce one case with
|
|
378
|
+
`model-suite --profile nightly --model MODEL_ID --seed N` (the seed is in the report). `protocol`
|
|
379
|
+
after a CLIProxyAPI upgrade usually means the translation changed; compare the check's details
|
|
380
|
+
with the validator in `protocol.py`.
|
|
381
|
+
6. If the capability is genuinely unavailable on that route, change its state to `optional` or
|
|
382
|
+
`unsupported` with a reason, in a reviewed commit. Do not delete checks to make a report green.
|
|
383
|
+
7. `harness`: a defect in the checks, not the endpoint. Run the unit tests.
|
|
384
|
+
|
|
385
|
+
## What was and was not verified
|
|
386
|
+
|
|
387
|
+
The emulator and unit tests prove the harness's assertions, classification, budgets and reports.
|
|
388
|
+
They do not prove the hosted endpoint is healthy. Live health is established only by a report whose
|
|
389
|
+
target is `live` with `evidence: live` checks; until a scheduled or manual run has completed with a
|
|
390
|
+
valid client key, no model has a live validation on record. The first live run may legitimately
|
|
391
|
+
surface capability declarations in `models.json` that need adjusting (for example parallel tool
|
|
392
|
+
calls or structured output on a given route); such results are the signal the configuration
|
|
393
|
+
exists to capture.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"eceasy/cli-proxy-api": "eceasy/cli-proxy-api@sha256:afe1135e8d8752867b73d717c1ca8ed27c44bfe8c6e1a2bebf228dba98889eac",
|
|
3
|
+
"tailscale/tailscale": "tailscale/tailscale@sha256:ed6480b33c6eb67c9cbd203ed42b9fb57e361986725b6856def71b7a3d9e276c",
|
|
4
|
+
"cloudflare/cloudflared": "cloudflare/cloudflared@sha256:072c067d25ccbe61d46e18f0d0723255f2bb5304f7317caa95b27031520ff92c"
|
|
5
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string>dev.devfleet.cliproxy-backup-check</string>
|
|
7
|
+
<key>ProgramArguments</key>
|
|
8
|
+
<array>
|
|
9
|
+
<string>/bin/sh</string>
|
|
10
|
+
<string>-c</string>
|
|
11
|
+
<string>PATH="$HOME/Library/Application Support/cliproxy-fleet/tools/bin:$PATH" exec "$HOME/Library/Application Support/cliproxy-fleet/scripts/backup" check</string>
|
|
12
|
+
</array>
|
|
13
|
+
<key>EnvironmentVariables</key>
|
|
14
|
+
<dict>
|
|
15
|
+
<key>PATH</key>
|
|
16
|
+
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin</string>
|
|
17
|
+
<key>PYTHONDONTWRITEBYTECODE</key>
|
|
18
|
+
<string>1</string>
|
|
19
|
+
</dict>
|
|
20
|
+
<key>Umask</key>
|
|
21
|
+
<integer>63</integer>
|
|
22
|
+
<key>ProcessType</key>
|
|
23
|
+
<string>Background</string>
|
|
24
|
+
<key>Nice</key>
|
|
25
|
+
<integer>10</integer>
|
|
26
|
+
<key>StartCalendarInterval</key>
|
|
27
|
+
<dict>
|
|
28
|
+
<key>Weekday</key>
|
|
29
|
+
<integer>0</integer>
|
|
30
|
+
<key>Hour</key>
|
|
31
|
+
<integer>5</integer>
|
|
32
|
+
<key>Minute</key>
|
|
33
|
+
<integer>0</integer>
|
|
34
|
+
</dict>
|
|
35
|
+
<key>LowPriorityIO</key>
|
|
36
|
+
<true/>
|
|
37
|
+
</dict>
|
|
38
|
+
</plist>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string>dev.devfleet.cliproxy-backup</string>
|
|
7
|
+
<key>ProgramArguments</key>
|
|
8
|
+
<array>
|
|
9
|
+
<string>/bin/sh</string>
|
|
10
|
+
<string>-c</string>
|
|
11
|
+
<string>PATH="$HOME/Library/Application Support/cliproxy-fleet/tools/bin:$PATH" exec "$HOME/Library/Application Support/cliproxy-fleet/scripts/backup" backup</string>
|
|
12
|
+
</array>
|
|
13
|
+
<key>EnvironmentVariables</key>
|
|
14
|
+
<dict>
|
|
15
|
+
<key>PATH</key>
|
|
16
|
+
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin</string>
|
|
17
|
+
<key>PYTHONDONTWRITEBYTECODE</key>
|
|
18
|
+
<string>1</string>
|
|
19
|
+
</dict>
|
|
20
|
+
<key>Umask</key>
|
|
21
|
+
<integer>63</integer>
|
|
22
|
+
<key>ProcessType</key>
|
|
23
|
+
<string>Background</string>
|
|
24
|
+
<key>Nice</key>
|
|
25
|
+
<integer>10</integer>
|
|
26
|
+
<key>StartCalendarInterval</key>
|
|
27
|
+
<array>
|
|
28
|
+
<dict>
|
|
29
|
+
<key>Minute</key>
|
|
30
|
+
<integer>0</integer>
|
|
31
|
+
</dict>
|
|
32
|
+
<dict>
|
|
33
|
+
<key>Minute</key>
|
|
34
|
+
<integer>15</integer>
|
|
35
|
+
</dict>
|
|
36
|
+
<dict>
|
|
37
|
+
<key>Minute</key>
|
|
38
|
+
<integer>30</integer>
|
|
39
|
+
</dict>
|
|
40
|
+
<dict>
|
|
41
|
+
<key>Minute</key>
|
|
42
|
+
<integer>45</integer>
|
|
43
|
+
</dict>
|
|
44
|
+
</array>
|
|
45
|
+
<key>LowPriorityIO</key>
|
|
46
|
+
<true/>
|
|
47
|
+
</dict>
|
|
48
|
+
</plist>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string>dev.devfleet.cliproxy-fleet</string>
|
|
7
|
+
<key>ProgramArguments</key>
|
|
8
|
+
<array>
|
|
9
|
+
<string>/bin/sh</string>
|
|
10
|
+
<string>-c</string>
|
|
11
|
+
<string>PATH="$HOME/Library/Application Support/cliproxy-fleet/tools/bin:$PATH" exec "$HOME/Library/Application Support/cliproxy-fleet/scripts/service-start"</string>
|
|
12
|
+
</array>
|
|
13
|
+
<key>EnvironmentVariables</key>
|
|
14
|
+
<dict>
|
|
15
|
+
<key>PATH</key>
|
|
16
|
+
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin</string>
|
|
17
|
+
<key>PYTHONDONTWRITEBYTECODE</key>
|
|
18
|
+
<string>1</string>
|
|
19
|
+
</dict>
|
|
20
|
+
<key>Umask</key>
|
|
21
|
+
<integer>63</integer>
|
|
22
|
+
<key>RunAtLoad</key>
|
|
23
|
+
<true/>
|
|
24
|
+
<key>KeepAlive</key>
|
|
25
|
+
<dict>
|
|
26
|
+
<key>SuccessfulExit</key>
|
|
27
|
+
<false/>
|
|
28
|
+
</dict>
|
|
29
|
+
<key>ThrottleInterval</key>
|
|
30
|
+
<integer>60</integer>
|
|
31
|
+
</dict>
|
|
32
|
+
</plist>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string>dev.devfleet.cliproxy-gc</string>
|
|
7
|
+
<key>ProgramArguments</key>
|
|
8
|
+
<array>
|
|
9
|
+
<string>/bin/sh</string>
|
|
10
|
+
<string>-c</string>
|
|
11
|
+
<string>PATH="$HOME/Library/Application Support/cliproxy-fleet/tools/bin:$PATH" exec "$HOME/Library/Application Support/cliproxy-fleet/scripts/backup" gc</string>
|
|
12
|
+
</array>
|
|
13
|
+
<key>EnvironmentVariables</key>
|
|
14
|
+
<dict>
|
|
15
|
+
<key>PATH</key>
|
|
16
|
+
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin</string>
|
|
17
|
+
<key>PYTHONDONTWRITEBYTECODE</key>
|
|
18
|
+
<string>1</string>
|
|
19
|
+
</dict>
|
|
20
|
+
<key>Umask</key>
|
|
21
|
+
<integer>63</integer>
|
|
22
|
+
<key>ProcessType</key>
|
|
23
|
+
<string>Background</string>
|
|
24
|
+
<key>Nice</key>
|
|
25
|
+
<integer>10</integer>
|
|
26
|
+
<key>StartCalendarInterval</key>
|
|
27
|
+
<dict>
|
|
28
|
+
<key>Weekday</key>
|
|
29
|
+
<integer>0</integer>
|
|
30
|
+
<key>Hour</key>
|
|
31
|
+
<integer>4</integer>
|
|
32
|
+
<key>Minute</key>
|
|
33
|
+
<integer>0</integer>
|
|
34
|
+
</dict>
|
|
35
|
+
<key>LowPriorityIO</key>
|
|
36
|
+
<true/>
|
|
37
|
+
</dict>
|
|
38
|
+
</plist>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string>dev.devfleet.cliproxy-monitor</string>
|
|
7
|
+
<key>ProgramArguments</key>
|
|
8
|
+
<array>
|
|
9
|
+
<string>/bin/sh</string>
|
|
10
|
+
<string>-c</string>
|
|
11
|
+
<string>PATH="$HOME/Library/Application Support/cliproxy-fleet/tools/bin:$PATH" exec "$HOME/Library/Application Support/cliproxy-fleet/scripts/monitor"</string>
|
|
12
|
+
</array>
|
|
13
|
+
<key>EnvironmentVariables</key>
|
|
14
|
+
<dict>
|
|
15
|
+
<key>PATH</key>
|
|
16
|
+
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin</string>
|
|
17
|
+
<key>PYTHONDONTWRITEBYTECODE</key>
|
|
18
|
+
<string>1</string>
|
|
19
|
+
</dict>
|
|
20
|
+
<key>Umask</key>
|
|
21
|
+
<integer>63</integer>
|
|
22
|
+
<key>ProcessType</key>
|
|
23
|
+
<string>Background</string>
|
|
24
|
+
<key>Nice</key>
|
|
25
|
+
<integer>10</integer>
|
|
26
|
+
<key>StartInterval</key>
|
|
27
|
+
<integer>300</integer>
|
|
28
|
+
</dict>
|
|
29
|
+
</plist>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string>dev.devfleet.cliproxy-vault-renew</string>
|
|
7
|
+
<key>ProgramArguments</key>
|
|
8
|
+
<array>
|
|
9
|
+
<string>/bin/sh</string>
|
|
10
|
+
<string>-c</string>
|
|
11
|
+
<string>PATH="$HOME/Library/Application Support/cliproxy-fleet/tools/bin:$PATH" exec "$HOME/Library/Application Support/cliproxy-fleet/scripts/vault-renew"</string>
|
|
12
|
+
</array>
|
|
13
|
+
<key>EnvironmentVariables</key>
|
|
14
|
+
<dict>
|
|
15
|
+
<key>PATH</key>
|
|
16
|
+
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Docker.app/Contents/Resources/bin</string>
|
|
17
|
+
<key>PYTHONDONTWRITEBYTECODE</key>
|
|
18
|
+
<string>1</string>
|
|
19
|
+
</dict>
|
|
20
|
+
<key>Umask</key>
|
|
21
|
+
<integer>63</integer>
|
|
22
|
+
<key>ProcessType</key>
|
|
23
|
+
<string>Background</string>
|
|
24
|
+
<key>Nice</key>
|
|
25
|
+
<integer>10</integer>
|
|
26
|
+
<key>RunAtLoad</key>
|
|
27
|
+
<true/>
|
|
28
|
+
<key>StartInterval</key>
|
|
29
|
+
<integer>900</integer>
|
|
30
|
+
</dict>
|
|
31
|
+
</plist>
|