agent-reliability-ci 0.8.0__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 (41) hide show
  1. agent_reliability_ci-0.8.0/.gitignore +12 -0
  2. agent_reliability_ci-0.8.0/CHANGELOG.md +375 -0
  3. agent_reliability_ci-0.8.0/LICENSE +201 -0
  4. agent_reliability_ci-0.8.0/NOTICE +9 -0
  5. agent_reliability_ci-0.8.0/PKG-INFO +506 -0
  6. agent_reliability_ci-0.8.0/README.md +478 -0
  7. agent_reliability_ci-0.8.0/pyproject.toml +83 -0
  8. agent_reliability_ci-0.8.0/src/arci/__init__.py +3 -0
  9. agent_reliability_ci-0.8.0/src/arci/__main__.py +3 -0
  10. agent_reliability_ci-0.8.0/src/arci/cli.py +869 -0
  11. agent_reliability_ci-0.8.0/src/arci/contracts.py +103 -0
  12. agent_reliability_ci-0.8.0/src/arci/demo/__init__.py +7 -0
  13. agent_reliability_ci-0.8.0/src/arci/demo/agents.py +131 -0
  14. agent_reliability_ci-0.8.0/src/arci/demo/experiment.py +76 -0
  15. agent_reliability_ci-0.8.0/src/arci/demo/run.py +340 -0
  16. agent_reliability_ci-0.8.0/src/arci/demo/world.py +125 -0
  17. agent_reliability_ci-0.8.0/src/arci/descriptor.py +1031 -0
  18. agent_reliability_ci-0.8.0/src/arci/diff.py +174 -0
  19. agent_reliability_ci-0.8.0/src/arci/fingerprint.py +35 -0
  20. agent_reliability_ci-0.8.0/src/arci/gate.py +414 -0
  21. agent_reliability_ci-0.8.0/src/arci/grade.py +75 -0
  22. agent_reliability_ci-0.8.0/src/arci/hashing.py +29 -0
  23. agent_reliability_ci-0.8.0/src/arci/init.py +677 -0
  24. agent_reliability_ci-0.8.0/src/arci/interfaces.py +181 -0
  25. agent_reliability_ci-0.8.0/src/arci/mcp_boundary.py +2120 -0
  26. agent_reliability_ci-0.8.0/src/arci/mcp_shim.py +74 -0
  27. agent_reliability_ci-0.8.0/src/arci/mcp_toolset_server.py +269 -0
  28. agent_reliability_ci-0.8.0/src/arci/minimize.py +148 -0
  29. agent_reliability_ci-0.8.0/src/arci/perturb.py +219 -0
  30. agent_reliability_ci-0.8.0/src/arci/planning.py +515 -0
  31. agent_reliability_ci-0.8.0/src/arci/py.typed +0 -0
  32. agent_reliability_ci-0.8.0/src/arci/reliability.py +113 -0
  33. agent_reliability_ci-0.8.0/src/arci/replay.py +129 -0
  34. agent_reliability_ci-0.8.0/src/arci/report.py +377 -0
  35. agent_reliability_ci-0.8.0/src/arci/runner.py +1594 -0
  36. agent_reliability_ci-0.8.0/src/arci/schedule.py +62 -0
  37. agent_reliability_ci-0.8.0/src/arci/schema.py +641 -0
  38. agent_reliability_ci-0.8.0/src/arci/stats.py +167 -0
  39. agent_reliability_ci-0.8.0/src/arci/storage.py +40 -0
  40. agent_reliability_ci-0.8.0/src/arci/toolbox.py +338 -0
  41. agent_reliability_ci-0.8.0/src/arci/worker.py +222 -0
@@ -0,0 +1,12 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ dist/
7
+ build/
8
+ *.egg-info/
9
+ .DS_Store
10
+ runs/
11
+ .env
12
+ node_modules/
@@ -0,0 +1,375 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ (nothing yet)
6
+
7
+ ## v0.8.0 (2026-10-13)
8
+
9
+ The onboarding release: install from PyPI, run the recorded retry story with one `uvx` command, scaffold
10
+ a first experiment from four references, and read the whole point on one screen. No change to the
11
+ decision rule, its calibration, the schema (`arci/0.5`) or any recorded result.
12
+
13
+ - **Added:** the PyPI package `agent-reliability-ci` and `.github/workflows/release.yml`: a version
14
+ tag builds the wheel and sdist once, smoke-tests that wheel on Ubuntu and macOS (Python 3.11 and
15
+ 3.14) from an empty directory, and publishes the same files through PyPI trusted publishing with
16
+ attestations. The guard refuses a tag that is not `v` + the package version. `docs/RELEASING.md`
17
+ has the steps; `docs/design/0005-v0.8.0-packaging-and-version-bump.md` records the frozen-file
18
+ changes (version, project URLs, classifiers, keywords, an sdist restricted by `only-include` to
19
+ the package, README, LICENSE, NOTICE, CHANGELOG and pyproject, plus hatchling's own `PKG-INFO`
20
+ and `.gitignore`).
21
+ - **Added:** `arci demo` (and `python -m arci`): the six-step retry story from an installed wheel with
22
+ no checkout, through the real `run`, `diff`, `minimize` and `replay`. The seeded world and agents
23
+ now live in `arci.demo` (`examples/retry_agent/{world,agents}.py` re-export them); the demo's
24
+ manifests use `arci.demo` references and an `arci-demo-` experiment id, so their seals differ from
25
+ the recorded run while the seeds, counts (192/200 vs 132/200) and verdicts are the same, and the
26
+ demo says whether its counts matched. Run stores go to a temporary directory unless `--keep DIR`.
27
+ - **Added:** the `arci.yaml` descriptor (`src/arci/descriptor.py`, `docs/DESCRIPTOR.md`,
28
+ `docs/design/0007-descriptor.md`): a thin, `extra="forbid"` front-end whose keys are the `Manifest`'s
29
+ fields with the same defaults, compiled and sealed with `Manifest.create` exactly as the Python
30
+ builders do. `arci run` accepts a `.yaml`/`.yml` descriptor or a sealed `.json` manifest, and its
31
+ `--out` now defaults to `runs`. `arci schema` prints the JSON Schema generated from the model;
32
+ the bytes are committed at `docs/schema/arci.schema.json` and tested for staleness. Pydantic is
33
+ authoritative; the YAML loader resolves only `true`/`false` as booleans and decimal, `0x`, `0o`,
34
+ `0b` as integers, so `yes` and `on` stay strings and `010` is ten, not octal eight; explicit
35
+ `!!int`, `!!float` and `!!null` tags accept only those same forms, and alias expansion is capped.
36
+ - **Added:** `arci init EXPERIMENT_ID --baseline --candidate --toolset --oracle [...]`
37
+ (`docs/design/0008-arci-init.md`): validates the four references in a child process with the
38
+ runner's import rule (the toolset factory is called once; agents and the oracle are only imported),
39
+ checks every `--fault` tool against the toolset's tools, and writes a smoke-design descriptor
40
+ (`n_per_arm` 8, the smallest N at which a total collapse can still BLOCK under the default rule;
41
+ two perfect arms cannot PASS below N=42). One line on stderr and exit 3 on the first problem. The
42
+ file is published atomically (a hard link, or a rename with `--force`); without `--force` an
43
+ existing file is never replaced.
44
+ - **Added:** a smoke-design notice on stderr from `arci run` when a gating condition has fewer than
45
+ 100 trials per arm, pointing at `arci plan`. stdout, reports, decisions and stores are unchanged.
46
+ - **Changed:** the runner appends the current directory to the import path of every child it starts
47
+ (worker, grader, boundary, command agent, MCP server;
48
+ `docs/design/0006-cwd-on-the-child-import-path.md`), so references into the project directory
49
+ resolve under the `arci` console script as they already did under `python -m arci.cli`. Appended,
50
+ never prepended; an MCP server whose `env` sets `PYTHONPATH` keeps that configured value, as
51
+ before; records are unaffected.
52
+ - **Added:** CI jobs that build the wheel and run `arci demo` from an empty directory on Ubuntu and
53
+ macOS, a Windows job that only installs the wheel and runs `arci --help` (execution stays
54
+ unsupported on Windows), and an Action fixture (`examples/action_fixture/`) that runs the composite
55
+ Action on the demo's A-vs-B manifest and asserts `BLOCK`. CI also runs on `sprint/**` branches.
56
+ - **Added:** `docs/measurement/`: the time-to-first-verdict and cold-read protocol, a receipt
57
+ template and a receipts directory; maintainer measurements are labelled and never counted as
58
+ cold readers.
59
+ - **Documentation:** the README opens with the question, one sentence, the two commands, the pipeline
60
+ line, what PASS means, what a small run means and the boundary (`docs/design/0009-readme-first-screen.md`);
61
+ the recorded result, the figure and the badges moved below the fold; "What it does not do" gains two
62
+ items (reference validation imports your code; a fault naming a tool the agent never calls silently
63
+ never fires). Links from the old first screen are absolute so the PyPI page renders them.
64
+ - **Documentation:** two recipes, each a runnable tree under `examples/recipes/` with a narrative in
65
+ `docs/recipes/` and a test that runs it at smoke N from a copied directory without `PYTHONPATH`:
66
+ `python_agent` (a blank project with `app/v1.py`, `app/v2.py` and `tests/world.py`; `arci init`,
67
+ the smoke run, `arci plan`, the confirmatory run, then `diff`, `minimize` and `replay`, with the
68
+ recorded output) and `mcp_agent` (a stdlib newline-JSON-RPC client against
69
+ `arci.mcp_toolset_server`, a hand-written command-arm descriptor and an Inspector preflight). The
70
+ Inspector step is recorded as blocked on 2026-10-13: Inspector 2.10.1 (TypeScript SDK 1.29.0)
71
+ rejects the bridge's protocol revision `2026-07-28` at `initialize`; the recipe keeps the verbatim
72
+ result and the ARCI steps run without it.
73
+ - Everything that was already on `main` and unreleased is in this version:
74
+ - **Documentation:** the README presents the recorded retry result once (200 trials per arm,
75
+ 192/200 vs 132/200, BLOCK) with its boundary, links to the evidence, and the offline demo with
76
+ lines from the committed demo log (in this release these sections sit below the new first
77
+ screen); a "Where it has been run" summary links every campaign's records, including the
78
+ guardrail run and the invalid and inconclusive attempts. The hero PNG is replaced by
79
+ generated light and dark SVGs (`docs/assets/hero-*.svg`) and the how-it-works exposition by a
80
+ generated pipeline figure (`docs/assets/where-*.svg`), both written by
81
+ `docs/assets/src/make_figures.py` (stdlib only), whose `--check` mode runs in CI and in
82
+ `tests/unit/docs/test_figures.py`.
83
+ - **Added:** the technical report package `docs/reports/ci-gate-2026-10-06/` (report, plan of
84
+ record, enumerated operating-characteristics metrics for both interval methods, the Linux
85
+ container re-derivation log for all 18 archived decisions, the offline replay probe log for
86
+ both committed failure bundles, and the two-stage Docker reproduction recipe) and
87
+ `CITATION.cff`.
88
+ - **Fixed:** platform-dependent rounding in 95% Wilson intervals by pinning the inverse-normal
89
+ value used by the existing Linux-produced records (CPython's C accelerator on arm64 macOS
90
+ differs by one ulp from the pure-Python fallback). Restores reproducible decision seals for
91
+ the archived Clopper-Pearson stores without changing any verdict. Regression tests re-derive
92
+ every committed `docs/results/jev` decision byte for byte.
93
+ - **Fixed:** platform-dependent Clopper-Pearson bounds by comparing binomial tails with exact
94
+ integer arithmetic, including zero-success and all-success bounds. The existing 60-step
95
+ bisection, statistical method, confidence allocation, and gate rules are unchanged. Re-derived
96
+ six archived Jev decisions and five guardrail decisions from unchanged sealed manifests and
97
+ trials. Only CP bounds, their derived difference bounds, and decision seals changed; verdicts,
98
+ exit codes, counts, stopping histories, and rendered Markdown/JUnit reports are unchanged.
99
+ Byte-for-byte regeneration is checked on macOS and Ubuntu.
100
+ - **Added:** `arci plan` enumerates PASS, BLOCK and INCONCLUSIVE probabilities under the
101
+ existing Clopper-Pearson gate for independent binomial arms, one gating condition, one
102
+ fixed-sample look and N <= 400 per arm, reporting assumptions and the smallest tested N meeting
103
+ a target or "target not reached"; probabilities are enumerated with exact integer arithmetic
104
+ and converted to floating point once, so the output is identical on every platform.
105
+ - **Added:** opt-in Markdown `arci report --pass-k` estimates using C(successes,k)/C(n,k)
106
+ separately per arm and condition, with explicit IID assumptions and unavailability for n < k,
107
+ ERROR verdicts and multi-look designs; default report output, gate decisions and stored records
108
+ are unchanged.
109
+ - **Guardrail experiment:** published the pre-registered live run of
110
+ `examples/guardrail_agent/` (2026-10-05, `run.sh` unchanged): the sealed stores of all six
111
+ runs, the preflight receipt, per-run gate reports, and the N=200 failure diffed, minimised
112
+ and replayed (REPRODUCED), in `docs/results/guardrail/`. The write-up and `metrics.json` are
113
+ generated from the committed evidence by `docs/results/guardrail/summarize.py`
114
+ (`--check` fails if they are stale), including the N=50 `decision_unavailable` run that came
115
+ out INCONCLUSIVE rather than the pre-registered BLOCK. Added
116
+ `tests/unit/examples/test_guardrail_results.py`, an offline test that re-derives every
117
+ committed guardrail decision byte for byte with `arci gate`.
118
+ - **Documentation:** the offline demo section was renamed "Try the offline demo" (this release's
119
+ README now points it at `arci demo`); the availability note that separated `main` from the
120
+ `v0.7.0` Action is replaced by this release's Availability line; unsupported comparison and
121
+ reviewer-count wording removed; the calibration roadmap item now extends the published
122
+ intent-routing audit. `CITATION.cff` pins the report URL to the `evidence-2026-10-06` tag (its
123
+ version and date are now 0.8.0 and 2026-10-13). Added `SECURITY.md` (private reporting through
124
+ GitHub security advisories, the trusted-code assumption, no private stores or credentials in
125
+ reports).
126
+
127
+ ## v0.7.0 (2026-10-05)
128
+
129
+ - **Calibration audit of the decision model (2026-10-03):** `bench/jev_calibration/` is a
130
+ pre-registered audit of `jev-1.13.0` on CLINC150 (4,500 in-scope + 1,000 out-of-scope) and
131
+ Banking77 (3,080), three passes each plus a bundling check, 26,140 requests, about USD 4.6
132
+ at list price. `PROTOCOL.md` (hash posted on PR #2 before the first request) fixes the
133
+ questions, passes, measures and seven expectations; `run.py` seals every answer in a
134
+ hash-chained store; `metrics.py` (exact binomial intervals, ECE/MCE/Brier/log loss,
135
+ tie-aware AUROC and average precision, bootstrap, agreement) is unit tested; `analyze.py`
136
+ verifies the chains and writes `metrics.json`, `report.md`, reliability diagrams and a
137
+ self-verifying compact store from which every number re-derives. All seven expectations
138
+ met: zero-shot accuracy 0.921 [0.912, 0.928] on CLINC150 (a supervised TF-IDF+LR trained on
139
+ 15,000 examples: 0.925) with ECE 0.024; 0.801 on Banking77 with ECE 0.084 and mid-range
140
+ over-confidence; 0.970 accuracy at confidence >= 0.9 on 83% coverage; out-of-scope AUROC
141
+ 0.977 (yes/no question) against 0.911 from 1 - p_max; 99.4% repeat agreement; p50 322 ms.
142
+ Write-up: `docs/results/jev-calibration/README.md`.
143
+ - **Added:** `examples/jev_triage_agent/experiment.py` builds live manifests
144
+ (`live_manifest`, `decisions.upstream = "http"`, pinned model, paced trial starts, prior
145
+ runs) and writes them from the command line
146
+ (`python -m examples.jev_triage_agent.experiment --out manifest.json`), so the day-one
147
+ sequence in `docs/design/0004-day-one.md` runs from files. `examples/jev_triage_agent/day_one.sh`
148
+ drives it end to end: preflight, the clean pair, the N=50 trio, the Node agent through the
149
+ official SDK, the pre-registered N=200 run, and a minimised, replayed failure, with a gate
150
+ report per run and a refusal to finish if the key appears in any output. Results:
151
+ `docs/results/jev/`.
152
+ - **Run against Jev (2026-10-03):** the pre-registered day one ran end to end against
153
+ `https://api.typesafe.ai` with `jev-1.13.0` pinned. A vs B under `decision_low_confidence` at
154
+ N=200: 200/200 vs 0/200, bounds [-1.000, -0.957], BLOCK; A vs A and A vs C PASS at N=50; the
155
+ Node agent through the unchanged official SDK BLOCK; the minimised failure replays REPRODUCED;
156
+ an exploratory clean run at N=50 routed all 100 decisions correctly at confidence 1.0. 902
157
+ recorded decisions, about USD 0.018 at list price. Sealed stores, the preflight receipt, the
158
+ invalid first attempt and one write-up per run: `docs/results/jev/`; every `decision.json`
159
+ re-derives from its committed `trials.jsonl`. Findings: `docs/DECISIONS.md`, "What day one
160
+ found".
161
+ - **Added:** `arci preflight --allow-unlisted-model`. The account's `GET /v1/models` lists only
162
+ the aliases `jev-latest` and `jev-preview`, so the pre-registered preflight exits 2 on a pinned
163
+ versioned id. With the flag, preflight prints the listed names, sends the smoke request, and
164
+ exits 0 only if the validated response reports exactly the pinned id (3 otherwise). Without the
165
+ flag nothing changes except a hint after the exit-2 message. Tests:
166
+ `tests/unit/cli/test_preflight_unlisted_model.py`.
167
+ - **Added:** `ARCI_HTTPS_PROXY=http://host:port` makes the decision upstream sender tunnel through
168
+ an HTTP CONNECT proxy, for environments whose only egress is such a proxy; unset, the direct
169
+ connection is unchanged, and a malformed value is a transport error. Tests:
170
+ `tests/unit/decisions/test_upstream_proxy.py`.
171
+ - **Fixed:** the three preflight smoke questions carry `instructions`; the vendor rejects a
172
+ question with neither `instructions` nor `criteria` (400), so the pre-registered smoke request
173
+ could not be accepted as written.
174
+ - **Fixed:** `examples/jev_triage_agent/day_one.sh` puts the repository root on `PYTHONPATH`
175
+ (the manifests name `examples.jev_triage_agent.*` modules, invisible to the `arci` console
176
+ script), insists on running from the repository root, and stops with exit 4 unless both arms of
177
+ the N=1 clean pair PASS, so a harness fault that breaks both arms equally cannot be mistaken
178
+ for a measurement.
179
+ - **Fixed:** two reader threads, the grader's response reader and the MCP boundary's frame
180
+ reader, could end a read on a "not ready" poll verdict computed before the child wrote and
181
+ before the parent asked them to stop. On a loaded machine the thread was descheduled across
182
+ the child's exit, the stale verdict dropped the whole response, and the trial ended `ERROR`
183
+ (`grader returned invalid output`, or `boundary exited before returning` for command agents)
184
+ at about 1 trial in 400 with 8 workers on 4 cores, which is enough to turn a 200-per-arm
185
+ experiment into an `ERROR` verdict on a busy CI runner. The worker reader already followed
186
+ the correct rule; both readers now snapshot the stop flag before polling, and only a poll
187
+ made after the stop was observed may end the read. Regression tests:
188
+ `tests/unit/runner/test_reader_stop_race.py`.
189
+
190
+ ## v0.6.0 (2026-09-22)
191
+
192
+ Day-one Jev readiness. The upstream behavior below is derived from vendor and official SDK
193
+ documentation and tested against shaped fixtures; it was not run against Jev because no key was
194
+ available.
195
+
196
+ - **A1:** HTTP decision upstreams accept a path-prefixed base URL, including the Vercel AI Gateway
197
+ TypeSafe route and its `typesafe-ai/jev` model id.
198
+ - **A2:** Response validation accepts the tested SDK response shapes: unknown metadata is tolerated and rounded
199
+ probability sums are accepted within `1e-3`, while required keys and pinned-model checks remain.
200
+ - **A3:** Harness-owned request headers, allowlisted response headers, deterministic transport
201
+ diagnostics, and one recorded bounded wait on an upstream 429/529 make gateway attempts auditable.
202
+ - **B4:** `arci preflight MANIFEST` checks credentials, model discovery and one tiny smoke decision,
203
+ then emits a credential-free receipt with exit 0/2/3 semantics.
204
+ - **B5:** HTTP experiments pace trial starts through a shared parent token bucket; users divide the
205
+ provider rate by the maximum decisions per trial.
206
+ - **B6:** Markdown reports count completed decision recordings and their available token usage,
207
+ and show estimated input cost at the list price read on 2026-09-22 (fixtures and replays are
208
+ free; this is an estimate, not billed spend). Incomplete admissions are excluded; before-injected
209
+ results contribute zero tokens.
210
+ - **B7:** The Jev guide now covers the three-command day-one workflow, provider limits, privacy,
211
+ sampled answers and live-run minimality; `docs/results/TEMPLATE-jev.md` standardises write-ups.
212
+ - **C8:** The triage example gains a Node 20+ ES-module agent using `@typesafe-ai/sdk` 0.6.0 through
213
+ environment-only `new TypeSafeClient()`, plus CI coverage on Python 3.14 / Node 22.
214
+ - **C9:** Decision records retain an independent raw upstream snapshot before perturbation; live
215
+ HTTP upstreams, removal trials ending in ERROR, and replay INVALID results report `reduced`, never
216
+ `1-minimal`.
217
+ - **D10:** The offline triage fixture can inject seeded synthetic miscalibration for testing
218
+ confidence gates; it is explicitly not evidence about Jev's calibration.
219
+
220
+ ## v0.5.0 (2026-09-22)
221
+
222
+ Command agents can now test the decision logic around TypeSafe's Jev/System One API.
223
+
224
+ - `Manifest.decisions: DecisionSpec` adds a harness-owned loopback `POST /v1/systemone` boundary.
225
+ Agents are redirected through `TYPESAFE_BASE_URL` and a per-trial token; the real upstream key
226
+ stays in the harness (the MCP server child does not inherit it, diagnostics are scrubbed). The
227
+ Python `typesafe-sdk` is exercised unchanged by the acceptance tests; the JavaScript SDK reads the
228
+ same variables but is untested here.
229
+ - Admitted decisions use the existing `ToolCall`, `ToolResult` and `RecordedCall` records under
230
+ `decision:systemone`, so budgets, events, diff, minimisation, bundles and exact replay apply.
231
+ - `decision_low_confidence` mixes choice probabilities toward uniform without changing the winner;
232
+ `decision_unavailable` returns an injected 529 from a selected occurrence onward.
233
+ - The boundary now lives until the command agent exits when decisions are configured, including
234
+ decisions made after the MCP session closes. Decision/MCP overlap and concurrent decisions are
235
+ rejected as harness faults.
236
+ - Schema `arci/0.5` adds decision configuration to sealed manifests and trial specs. Records sealed
237
+ by earlier schema versions are not readable; as with every field addition, experiments must be
238
+ re-run.
239
+ - The official `typesafe-sdk` is a development-only dependency used by an acceptance test against
240
+ the boundary. Runtime code and `examples/jev_triage_agent` do not import it.
241
+ - `examples/jev_triage_agent` is a six-step offline triage demo: a confidence-gating regression is
242
+ blocked, reduced, replayed, and repaired. `docs/DECISIONS.md` documents fixture and real-Jev use.
243
+
244
+ ## v0.4.0 (2026-09-22)
245
+
246
+ One thing: pre-registered looks, so an experiment can stop early without losing error control.
247
+
248
+ - `Manifest.looks = (N_1, ..., N_L)`: cumulative pairs per condition, last equal to `n_per_arm`.
249
+ Equal Bonferroni spending, `alpha / L` per look, with either interval method. The run stops at
250
+ the first look that is PASS or BLOCK; the final look is INCONCLUSIVE otherwise. No `looks` is
251
+ the fixed design, unchanged.
252
+ - The gate replays every look and treats the first decisive one as a mandatory stop: a store that
253
+ continued past it, stopped without a decision, or is not a whole-pair prefix at a declared look
254
+ is ERROR. The plan is bound into every trial's identity; the look history is sealed into the
255
+ decision.
256
+ - `bench/selfcheck.py --looks 50,100,200`: exact enumeration over sequential paths (a
257
+ (x_A, x_B) state table, at most (N+1)^2 states), with the same false-PASS / false-BLOCK <= alpha
258
+ sweep. Measured, K=1: a 0.95 -> 0.65 regression costs 302 expected trials with Clopper-Pearson
259
+ (P(BLOCK) .985 -> .943) and 159 with Newcombe, against 400 for the fixed design; two equal 0.95
260
+ agents cost 350 and 239. The Markdown report shows the look history and the stopping look.
261
+
262
+ ## v0.3.0 (2026-09-22)
263
+
264
+ One thing: a tighter interval for the margin, opt-in.
265
+
266
+ - `Manifest.interval_method`: `clopper_pearson` (default, unchanged) or `newcombe` (Newcombe's
267
+ hybrid score interval, method 10, no continuity correction, Wilson per arm at `1 - alpha/K`).
268
+ Frozen with the manifest; printed in every decision and report.
269
+ - Calibration by exact enumeration in `bench/selfcheck.py --method newcombe`: a sweep of the
270
+ boundary and the no-change line for p in [0.5, 0.99], N in {20, 50, 100, 200, 400}. Worst
271
+ directional error 0.031 (alpha 0.05). The bench exits non-zero if any sweep fails. Head-to-head
272
+ table in `docs/STATISTICS.md`.
273
+ - Why: the clean v0.2 confirmatory run (376/400 vs 308/400) was INCONCLUSIVE by 0.008 under the
274
+ default rule; Clopper-Pearson with Bonferroni was spending about a tenth of its allowed alpha.
275
+ Re-analysed under `newcombe` it blocks. Its sealed verdict stays INCONCLUSIVE.
276
+
277
+ ## v0.2.0 (2026-09-21)
278
+
279
+ Command agents: test any program that speaks MCP over stdio, not only Python functions.
280
+
281
+ ### Added
282
+
283
+ - **The out-of-process boundary.** A trial can be any subprocess (`CommandSpec`). Its tools are ONE
284
+ stdio MCP server owned by the harness (`McpServerSpec`). The agent's process tree holds only a
285
+ byte-relay shim (`arci.mcp_shim`); the recorder, fault injection, budgets and fault latches live in
286
+ a harness-owned boundary process (`arci.mcp_boundary`). Same frame protocol, latch precedence,
287
+ deadlines, process-group cleanup and sealed envelopes as v0.1.
288
+ - Supported MCP subset (revision 2026-07-28): `initialize`, `notifications/initialized`, `ping`,
289
+ `tools/list`, serial `tools/call` with `resultType: "complete"`. Task results, sampling,
290
+ elicitation and concurrent calls are a harness ERROR, never a silent pass-through.
291
+ - Replay for command agents: the recording includes `initialize` and `tools/list`, the server is
292
+ never started, JSON-RPC ids are normalised, consumption must be exact.
293
+ - `arci.mcp_toolset_server`: serve any v0.1 python toolset as an MCP server, with a trusted
294
+ `snapshot` for grading.
295
+ - `examples/ollama_mcp_agent`: a real tool-calling agent on a local model, with a one-sentence
296
+ prompt regression between its arms. `docs/REAL_AGENTS.md`, `docs/design/0002-...md`.
297
+ - Schema `arci/0.2`: `ArmSpec.command`, `Manifest.mcp_server`, `McpServerSpec.snapshot`. An
298
+ experiment is all python agents or all command agents. v0.1 run stores must be re-run.
299
+
300
+ - `CommandSpec.infra_exit_codes` (default 75, EX_TEMPFAIL): an agent can say "my infrastructure
301
+ failed, not me". The trial is ERROR and invalidates the experiment instead of counting against the
302
+ agent. Added after a local model server died mid-experiment and 435 trials "crashed".
303
+
304
+ ### Evidence (docs/results)
305
+
306
+ A real local-LLM agent, two arms differing by one sentence of the system prompt, one injected tool
307
+ timeout. Four runs are reported, including two invalid ones that each exposed a defect (a bridge
308
+ that advertised no tool parameters; a dead model server plus a harness shutdown race). The clean
309
+ confirmatory run: 376/400 (94.0%) versus 308/400 (77.0%), bounds [-0.2445, -0.0921], verdict
310
+ INCONCLUSIVE by 0.008 under the pre-registered rule. Reported as is.
311
+
312
+ ### Fixed during review
313
+
314
+ Eleven findings from an adversarial review of the boundary (false REPRODUCED at a deadline kill,
315
+ boundary crashes blamed on the agent, client mistakes invalidating experiments, malformed server
316
+ results accepted, id reuse, pipe deadlocks, recordings over 1 MiB, path leaks), a shim deadlock, and
317
+ a shutdown race that turned about 5% of trials into false ERRORs on a loaded machine.
318
+
319
+ ### Trust model
320
+
321
+ For command agents the record can no longer be corrupted by accident from inside the agent's
322
+ process. This is isolation from accident, not a sandbox: the agent still holds the socket it was
323
+ given, and whatever it does outside MCP is invisible.
324
+
325
+ ### Known limits
326
+
327
+ - One MCP server per trial, stdio only. No HTTP transport yet.
328
+ - Tool replay is not agent replay: a live model rarely repeats its calls, so replaying its bundle is
329
+ usually INVALID. Deterministic replay is demonstrated only with scripted clients.
330
+ - The Claude Code recipe in `docs/REAL_AGENTS.md` is an untested sketch; no paid-agent trials were
331
+ run for this release. The local-model results are exploratory (one machine, one small model).
332
+ - POSIX only (unix sockets, process groups).
333
+
334
+ ## v0.1.0 (2026-09-21)
335
+
336
+ First release. One claim: a measured regression becomes an executable, reduced failure case.
337
+
338
+ ### What is in it
339
+
340
+ - Frozen, sealed experiments (`Manifest`), a deterministic paired schedule, one fresh process per
341
+ trial with a separate grader process, a single parent writer for `events.jsonl` and `trials.jsonl`.
342
+ - The tool boundary (`ToolBox`): budgets, seeded fault injection (`tool_timeout`, `tool_error_once`,
343
+ `empty_result`, or your own `"module:function"`), record and replay.
344
+ - The gate: exact Clopper-Pearson at tail `alpha / (4K)`, Bonferroni bounds on the difference,
345
+ verdicts PASS / BLOCK / INCONCLUSIVE / ERROR with exit codes 0 / 1 / 2 / 3. It never raises.
346
+ - `bench/selfcheck.py`: the gate's own operating characteristics by exact enumeration.
347
+ - Boundary-aligned trace divergence, ddmin fault minimisation with an honest 1-minimal claim,
348
+ portable replay bundles with hash-verified embedded code.
349
+ - CLI (`arci run | gate | report | bundle | replay | diff | minimize`), Markdown and JUnit reports,
350
+ a composite GitHub Action.
351
+ - `examples/retry_agent`: agents A, B (A minus one retry) and C (the repair), with a six-step demo.
352
+
353
+ ### How it was checked
354
+
355
+ 229 tests, basedpyright strict, CI on Python 3.11 and 3.14. The acceptance suite was written before
356
+ the implementation and is hash-pinned (`FROZEN.sha256`). An adversarial reviewer attacked the design and
357
+ the code in four rounds, with reproductions: about 45 findings. They were fixed, or, where out of
358
+ scope (a hostile in-process agent, detached descendants), documented as non-goals. The behavioural
359
+ fixes have frozen regression tests (`tests/acceptance/test_hardening*.py` and the gate, replay and
360
+ schema suites); documentation corrections and the protocol queue bound do not. Every published
361
+ calibration number was recomputed independently by the reviewer and matched.
362
+
363
+ ### Known limits and residual risks
364
+
365
+ - Trust model: the agent is assumed buggy, not hostile. It shares a process with the tool boundary,
366
+ so a deliberately hostile agent can forge its result. See `docs/TRUST_MODEL.md`.
367
+ - Only the tool boundary is observed. Direct file, network or subprocess use by the agent is
368
+ invisible. Descendants that start their own session survive cleanup.
369
+ - The gate is conservative by design: mid-range success rates need large N to reach PASS, and
370
+ N=20 decides almost nothing. `prior_runs` is author-supplied; no cross-run error budget is enforced.
371
+ - Supported statistics range: `alpha` in [1e-6, 0.5] with `alpha >= K x 1e-6`, `n_per_arm <= 10000`.
372
+ - Bundles embed only the files you include; the minimiser's output embeds none.
373
+ - The final reviewer re-check ran on Python 3.13 in a read-only sandbox, so writing bundle payloads
374
+ to disk was exercised by the test suite and CI (3.11, 3.14) but not by that review.
375
+ - POSIX only (process groups, `ps` in tests). Windows is untested.
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2026 Ajay Surya Senthilrajan
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
@@ -0,0 +1,9 @@
1
+ agent-reliability-ci
2
+ Copyright 2026 Ajay Surya Senthilrajan
3
+
4
+ This product includes software adapted from evalopt-graph
5
+ (https://github.com/ajaysurya1221/evalopt-graph), Copyright (c) 2026
6
+ Ajay Surya Senthilrajan, MIT License: the canonical JSON hashing helpers in
7
+ src/arci/hashing.py (from src/evalopt_graph/attestation.py) and the
8
+ self-sealing decision pattern in src/arci/schema.py (from
9
+ src/evalopt_graph/kernel.py).