constraintloop 0.4.1__tar.gz → 0.5.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.
- {constraintloop-0.4.1 → constraintloop-0.5.0}/CHANGELOG.md +31 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/CONTRIBUTING.md +2 -2
- {constraintloop-0.4.1 → constraintloop-0.5.0}/PKG-INFO +14 -5
- {constraintloop-0.4.1 → constraintloop-0.5.0}/README.md +13 -4
- constraintloop-0.5.0/docs/completion-policy.md +74 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/docs/configuration.md +29 -1
- constraintloop-0.5.0/docs/convergence-loops.md +370 -0
- constraintloop-0.5.0/docs/pre-release-review-2026-09-06.md +236 -0
- constraintloop-0.5.0/docs/release-readiness.md +75 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/docs/threat-model.md +9 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/pyproject.toml +1 -1
- {constraintloop-0.4.1 → constraintloop-0.5.0}/schema/constraintloop.schema.json +54 -0
- constraintloop-0.5.0/scripts/wheel_failure_smoke.py +173 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/__init__.py +2 -2
- constraintloop-0.5.0/src/constraintloop/_numbers.py +18 -0
- constraintloop-0.5.0/src/constraintloop/_process.py +121 -0
- constraintloop-0.5.0/src/constraintloop/challenges.py +248 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/cli.py +56 -5
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/config.py +23 -2
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/digest.py +21 -33
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/engine.py +32 -12
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/hooks.py +156 -66
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/loops.py +201 -13
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/models.py +133 -2
- constraintloop-0.5.0/src/constraintloop/redaction.py +38 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/runners.py +11 -8
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/state.py +7 -3
- constraintloop-0.5.0/tests/test_challenges.py +601 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_cli.py +15 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_cli_commands.py +1 -1
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_digest.py +22 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_failure_lab.py +2 -1
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_hooks.py +29 -3
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_loops.py +2 -2
- constraintloop-0.5.0/tests/test_process.py +99 -0
- constraintloop-0.5.0/tests/test_review_regressions.py +499 -0
- constraintloop-0.4.1/docs/convergence-loops.md +0 -219
- constraintloop-0.4.1/docs/release-readiness.md +0 -271
- constraintloop-0.4.1/scripts/wheel_failure_smoke.py +0 -47
- constraintloop-0.4.1/src/constraintloop/_process.py +0 -63
- constraintloop-0.4.1/tests/test_process.py +0 -50
- {constraintloop-0.4.1 → constraintloop-0.5.0}/.gitignore +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/GOVERNANCE.md +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/LICENSE +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/RELEASE.md +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/SECURITY.md +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/SUPPORT.md +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/docs/faq.md +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/docs/native-cli-evaluators.md +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/docs/openai-evaluation.md +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/docs/provider-privacy.md +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/docs/recipes.md +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/scripts/check_anthropic_sdk.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/scripts/check_coverage.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/scripts/check_openai_sdk.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/scripts/check_sdist_contents.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/scripts/generate_schema.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/scripts/openai_eval_canary.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/__main__.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/diagnostics.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/environment.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/eval_corpus.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/evaluators.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/hygiene.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/native_cli_evaluator.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/py.typed +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/scaffold.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/src/constraintloop/setup_hooks.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/__init__.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/failure_lab.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/fixtures/openai_eval_corpus_v1.yml +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_diagnostics.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_engine.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_environment.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_eval_corpus.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_evaluators.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_models.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_native_cli_evaluator.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_release_metadata.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_runners.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_security.py +0 -0
- {constraintloop-0.4.1 → constraintloop-0.5.0}/tests/test_state.py +0 -0
|
@@ -5,6 +5,37 @@ Versioning, with the usual initial-development flexibility for `0.y.z`.
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.5.0] - 2026-09-06
|
|
9
|
+
|
|
10
|
+
- Add optional session challenge gates for Claude Code, Codex, and Gemini CLI:
|
|
11
|
+
generate configurable domain-grounded scenarios, record immutable plans,
|
|
12
|
+
verify outcomes against fresh deterministic evidence, and repair defects
|
|
13
|
+
without launching a model evaluator.
|
|
14
|
+
- Add challenge show/submit commands, challenge/verify cycle states, Gemini
|
|
15
|
+
loop prompts, and persisted continuation budgets for all three adapters.
|
|
16
|
+
- Preserve task goals through generated continuation prompts and stop Gemini
|
|
17
|
+
sessions on exhausted budgets instead of requesting another retry.
|
|
18
|
+
- Fix all ten pre-release findings: frame content hashes unambiguously; bound
|
|
19
|
+
ordinary recursive Stop hooks and advisory continuations; fail closed on
|
|
20
|
+
malformed evidence and unexpected hook errors; reject push/CI waivers in
|
|
21
|
+
every engine entry point; report repairable dependency failures by root
|
|
22
|
+
cause; renew budgets for completed tasks; refresh pending hook evidence on
|
|
23
|
+
the shared cycle interval; reject non-finite metrics, thresholds, and
|
|
24
|
+
baselines; redact retained evidence; and deny observed agent baseline
|
|
25
|
+
weakening and direct baseline edits.
|
|
26
|
+
- Reject disabled or phase-incompatible prerequisites, keep CI loops free of
|
|
27
|
+
local overlays, bound subprocess collection to 8 MiB, and renew supervisor
|
|
28
|
+
leases during long evaluations and polling waits.
|
|
29
|
+
- Add regression matrices for adapters, phase policy, malformed numbers, digest
|
|
30
|
+
boundaries, lifecycle sequences, and installed-package challenge workflows.
|
|
31
|
+
- Cover every changed executable line, including submission rejection,
|
|
32
|
+
missing requests, unreadable files, and lost leases. Report malformed YAML
|
|
33
|
+
by location without raw source excerpts that could disclose credentials.
|
|
34
|
+
- Migration: existing evidence and waivers become stale under the new input
|
|
35
|
+
digest. Re-run checks; review incompatible prerequisite phases and invalid
|
|
36
|
+
numeric baselines. Challenge gates remain opt-in. Re-run hook setup after
|
|
37
|
+
upgrading if hooks use a pinned ephemeral executable.
|
|
38
|
+
|
|
8
39
|
## [0.4.1] - 2026-09-04
|
|
9
40
|
|
|
10
41
|
- Raise enforced statement coverage from 90% to 95% and branch coverage from
|
|
@@ -5,7 +5,7 @@ By participating, you agree to follow the
|
|
|
5
5
|
the contact method documented there.
|
|
6
6
|
|
|
7
7
|
ConstraintLoop accepts focused changes that strengthen evidence, state,
|
|
8
|
-
budgeting, locks, and stopping. It is not a general agent runtime and
|
|
8
|
+
budgeting, locks, and stopping. It is not a general agent runtime and must
|
|
9
9
|
not launch provider CLIs for repair turns or offer unbounded repair loops.
|
|
10
10
|
Opt-in native CLI evaluators are limited to isolated, tool-disabled reviews.
|
|
11
11
|
|
|
@@ -43,5 +43,5 @@ Releases are prepared through a focused release pull request and published only
|
|
|
43
43
|
through GitHub Trusted Publishing. See `RELEASE.md`. Contributors and agents
|
|
44
44
|
must not run local package upload commands or add long-lived registry tokens.
|
|
45
45
|
|
|
46
|
-
The supported
|
|
46
|
+
The supported platforms are macOS and Linux. Windows is not supported
|
|
47
47
|
until hook command generation and clean-wheel tests are implemented there.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: constraintloop
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Evidence-based completion gates for AI coding agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/mauhpr/constraintloop
|
|
6
6
|
Project-URL: Documentation, https://github.com/mauhpr/constraintloop/tree/main/docs
|
|
@@ -69,11 +69,17 @@ The central distinction is deliberate:
|
|
|
69
69
|
ConstraintLoop supports Claude Code, Codex, and Gemini CLI through their hook
|
|
70
70
|
lifecycles. CI is the final authority: it ignores local caches and human waivers.
|
|
71
71
|
|
|
72
|
-
Bounded convergence loops are
|
|
72
|
+
Bounded convergence loops are implemented. The design
|
|
73
73
|
keeps ConstraintLoop in control of evidence, budgets, and stopping while native
|
|
74
74
|
Claude or Codex loops perform at most one requested repair per transition. See
|
|
75
75
|
[docs/convergence-loops.md](docs/convergence-loops.md).
|
|
76
76
|
|
|
77
|
+
Completion loops can also require the current coding session to generate and
|
|
78
|
+
investigate N domain-grounded failure scenarios before stopping. Claude Code,
|
|
79
|
+
Codex, and Gemini CLI use their existing session context and tools; this
|
|
80
|
+
challenge gate requires no separate model evaluator. See
|
|
81
|
+
[session challenge gates](docs/convergence-loops.md#session-challenge-gates).
|
|
82
|
+
|
|
77
83
|
## At a glance
|
|
78
84
|
|
|
79
85
|
| Question | ConstraintLoop answer |
|
|
@@ -351,8 +357,11 @@ reactivate ConstraintLoop; setup clears the tombstone.
|
|
|
351
357
|
- `constraintloop cycle NAME --json` — execute one journaled loop transition.
|
|
352
358
|
- `constraintloop supervise NAME` — poll pending evidence under a recoverable
|
|
353
359
|
single-writer lease and exit whenever repair or termination is required.
|
|
354
|
-
- `constraintloop loop-prompt NAME --adapter claude|codex` — print the bounded
|
|
355
|
-
native-agent repair protocol without launching an agent.
|
|
360
|
+
- `constraintloop loop-prompt NAME --adapter claude|codex|gemini` — print the bounded
|
|
361
|
+
native-agent repair and challenge protocol without launching an agent.
|
|
362
|
+
- `constraintloop challenge show NAME` — inspect saved scenarios and the submission schema.
|
|
363
|
+
- `constraintloop challenge submit NAME --file PATH` — record session-authored
|
|
364
|
+
discovery or verification for the current request and input snapshot.
|
|
356
365
|
- `constraintloop status` — inspect evidence without executing commands.
|
|
357
366
|
- `constraintloop explain --phase change|stop|push|ci` — show why each constraint
|
|
358
367
|
runs or is skipped, including matched and changed watch paths, cache state,
|
|
@@ -375,7 +384,7 @@ reactivate ConstraintLoop; setup clears the tombstone.
|
|
|
375
384
|
- `constraintloop author` — write a review-only QA/test-authoring proposal.
|
|
376
385
|
|
|
377
386
|
`enhance` and `author` intentionally do not install dependencies or modify the
|
|
378
|
-
active contract
|
|
387
|
+
active contract. Their proposal files make the future self-improvement
|
|
379
388
|
path auditable.
|
|
380
389
|
|
|
381
390
|
## Documentation
|
|
@@ -26,11 +26,17 @@ The central distinction is deliberate:
|
|
|
26
26
|
ConstraintLoop supports Claude Code, Codex, and Gemini CLI through their hook
|
|
27
27
|
lifecycles. CI is the final authority: it ignores local caches and human waivers.
|
|
28
28
|
|
|
29
|
-
Bounded convergence loops are
|
|
29
|
+
Bounded convergence loops are implemented. The design
|
|
30
30
|
keeps ConstraintLoop in control of evidence, budgets, and stopping while native
|
|
31
31
|
Claude or Codex loops perform at most one requested repair per transition. See
|
|
32
32
|
[docs/convergence-loops.md](docs/convergence-loops.md).
|
|
33
33
|
|
|
34
|
+
Completion loops can also require the current coding session to generate and
|
|
35
|
+
investigate N domain-grounded failure scenarios before stopping. Claude Code,
|
|
36
|
+
Codex, and Gemini CLI use their existing session context and tools; this
|
|
37
|
+
challenge gate requires no separate model evaluator. See
|
|
38
|
+
[session challenge gates](docs/convergence-loops.md#session-challenge-gates).
|
|
39
|
+
|
|
34
40
|
## At a glance
|
|
35
41
|
|
|
36
42
|
| Question | ConstraintLoop answer |
|
|
@@ -308,8 +314,11 @@ reactivate ConstraintLoop; setup clears the tombstone.
|
|
|
308
314
|
- `constraintloop cycle NAME --json` — execute one journaled loop transition.
|
|
309
315
|
- `constraintloop supervise NAME` — poll pending evidence under a recoverable
|
|
310
316
|
single-writer lease and exit whenever repair or termination is required.
|
|
311
|
-
- `constraintloop loop-prompt NAME --adapter claude|codex` — print the bounded
|
|
312
|
-
native-agent repair protocol without launching an agent.
|
|
317
|
+
- `constraintloop loop-prompt NAME --adapter claude|codex|gemini` — print the bounded
|
|
318
|
+
native-agent repair and challenge protocol without launching an agent.
|
|
319
|
+
- `constraintloop challenge show NAME` — inspect saved scenarios and the submission schema.
|
|
320
|
+
- `constraintloop challenge submit NAME --file PATH` — record session-authored
|
|
321
|
+
discovery or verification for the current request and input snapshot.
|
|
313
322
|
- `constraintloop status` — inspect evidence without executing commands.
|
|
314
323
|
- `constraintloop explain --phase change|stop|push|ci` — show why each constraint
|
|
315
324
|
runs or is skipped, including matched and changed watch paths, cache state,
|
|
@@ -332,7 +341,7 @@ reactivate ConstraintLoop; setup clears the tombstone.
|
|
|
332
341
|
- `constraintloop author` — write a review-only QA/test-authoring proposal.
|
|
333
342
|
|
|
334
343
|
`enhance` and `author` intentionally do not install dependencies or modify the
|
|
335
|
-
active contract
|
|
344
|
+
active contract. Their proposal files make the future self-improvement
|
|
336
345
|
path auditable.
|
|
337
346
|
|
|
338
347
|
## Documentation
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Completion policy and v0.5 migration
|
|
2
|
+
|
|
3
|
+
## Entry points
|
|
4
|
+
|
|
5
|
+
| Entry point | Local overlays | Local waivers | Pending refresh | Task completion |
|
|
6
|
+
| --- | --- | --- | --- | --- |
|
|
7
|
+
| `run --phase change/stop` | Strengthening only | Deterministic gates only | Use `--no-cache` for a fresh observation | Constraint report only |
|
|
8
|
+
| `run --phase push` | Strengthening only | Never | Use `--no-cache` | Constraint report only |
|
|
9
|
+
| `ci` / `run --phase ci` | Never | Never | Always uncached | Independent CI evidence |
|
|
10
|
+
| `cycle` / `supervise` | Except CI phase | Except push/CI | Refresh after loop interval | Persisted bounded transition; includes configured challenge work |
|
|
11
|
+
| Stop / AfterAgent hooks | Strengthening only | Deterministic gates only | Shared cycle interval, or refresh each event without a loop | Required evidence, configured challenges, and advisory dispositions |
|
|
12
|
+
|
|
13
|
+
The engine enforces waiver and CI-cache policy regardless of caller defaults.
|
|
14
|
+
`run` does not finish a session challenge gate. Use `cycle` and the native Stop
|
|
15
|
+
hook for completion. CI verifies committed deterministic/rubric constraints;
|
|
16
|
+
it does not trust a local challenge journal or start an interactive session.
|
|
17
|
+
|
|
18
|
+
Failed prerequisites produce blocked dependents with `blocked_by` IDs, not
|
|
19
|
+
spurious evaluation errors. A cycle's `blocking_constraints` names the root
|
|
20
|
+
causes, including advisory prerequisites needed by required gates. Missing
|
|
21
|
+
tools, parser failures, and uncertain evaluations remain blocking errors.
|
|
22
|
+
|
|
23
|
+
## Task lifecycle
|
|
24
|
+
|
|
25
|
+
After a loop passes, a changed watched input or task goal starts a new run with
|
|
26
|
+
a fresh budget. Restarting an unfinished run, changing its code, or changing
|
|
27
|
+
its goal does not reset its limits. Unchanged completed evidence stays passed
|
|
28
|
+
even after the old time budget elapses. One project loop has one journal;
|
|
29
|
+
use separate worktrees for independent concurrent tasks.
|
|
30
|
+
|
|
31
|
+
Recursive Stop hooks are completion boundaries too. Ordinary loops use their
|
|
32
|
+
repair and duration budgets. Challenge loops also bound session continuations.
|
|
33
|
+
Without a loop, `max_auto_retries` bounds repair and advisory-disposition
|
|
34
|
+
continuations across changing evidence until completion succeeds. Exhaustion
|
|
35
|
+
returns `continue: false`, including Gemini, rather than silently allowing
|
|
36
|
+
completion or asking the agent to retry indefinitely.
|
|
37
|
+
|
|
38
|
+
`supervise` renews its lease during checks and waits, and checks ownership
|
|
39
|
+
before yielding a transition. It does not launch an agent or perform repairs.
|
|
40
|
+
|
|
41
|
+
## Evidence and redaction
|
|
42
|
+
|
|
43
|
+
The input-digest format is versioned and length-framed: filename/content
|
|
44
|
+
boundaries, unreadable files, and missing baselines cannot alias ordinary
|
|
45
|
+
content. Upgrading invalidates old evidence and snapshot-bound waivers.
|
|
46
|
+
|
|
47
|
+
Known sensitive environment values of at least eight characters are scrubbed,
|
|
48
|
+
as are credential assignments such as `password=...`, `api_key=...`, and
|
|
49
|
+
`access_token=...`. Structured sensitive keys are scrubbed recursively.
|
|
50
|
+
Scrubbing applies to evidence messages, findings, structured artifact fields,
|
|
51
|
+
retained command output, cached reads, and native-hook feedback. Command output
|
|
52
|
+
is scrubbed before tail truncation so truncation cannot sever the credential
|
|
53
|
+
label from its value.
|
|
54
|
+
|
|
55
|
+
This is best-effort redaction, not a data-loss-prevention boundary. Unknown,
|
|
56
|
+
encoded, split, or unlabeled secrets may escape detection. Raw command output
|
|
57
|
+
exists transiently in memory for parsing, bounded to 8 MiB per subprocess.
|
|
58
|
+
Pre-existing files from older releases are not retroactively erased. Avoid
|
|
59
|
+
printing credentials and restrict access to local state. Repository artifacts
|
|
60
|
+
and challenge submissions remain author-controlled data; do not put secrets
|
|
61
|
+
in them. No new remote model API is used by the session challenge gate.
|
|
62
|
+
|
|
63
|
+
## Upgrade checklist
|
|
64
|
+
|
|
65
|
+
1. Upgrade ConstraintLoop to 0.5.0 and re-run `constraintloop setup --adapter all`
|
|
66
|
+
in projects whose hooks pin an ephemeral package version.
|
|
67
|
+
2. Re-run checks to replace stale cached evidence. Revisit any intentional
|
|
68
|
+
local waiver against the new exact evidence; CI and push cannot use it.
|
|
69
|
+
3. Ensure prerequisites are enabled in every dependent phase. Correct invalid
|
|
70
|
+
numeric baselines; finite numeric strings are still accepted.
|
|
71
|
+
4. Keep noisy tool output below 8 MiB or write detailed reports to artifacts
|
|
72
|
+
and emit a compact command summary.
|
|
73
|
+
5. Enable `loops.NAME.challenge` explicitly where domain-driven self-review is
|
|
74
|
+
desired. Omitted challenge configuration preserves ordinary gating.
|
|
@@ -41,6 +41,10 @@ Every constraint supports `description`, `enforcement` (`required` or
|
|
|
41
41
|
`advisory`), `phases` (`change`, `stop`, `push`, `ci`), `watch` globs, dependency IDs
|
|
42
42
|
in `needs`, `timeout_seconds`, and `enabled`. Dependencies must exist and the
|
|
43
43
|
graph must be acyclic.
|
|
44
|
+
Every enabled dependent must have its prerequisites enabled in all of its
|
|
45
|
+
phases. A failed prerequisite blocks its dependents without running them;
|
|
46
|
+
cycles report the root cause for repair, even if that prerequisite is advisory.
|
|
47
|
+
Genuine evaluation errors still require human inspection.
|
|
44
48
|
Identifiers may contain letters, numbers, dots, underscores, and hyphens.
|
|
45
49
|
`watch` and `include` values must be nonempty project-relative POSIX globs.
|
|
46
50
|
|
|
@@ -75,11 +79,18 @@ retries require an explicit `total_timeout_seconds` greater than the per-attempt
|
|
|
75
79
|
timeout. This keeps the total bound visible while leaving enough budget for a
|
|
76
80
|
second attempt. Command and command-evaluator processes run from the selected
|
|
77
81
|
project root by default, and ConstraintLoop prepends that root to `PYTHONPATH`.
|
|
82
|
+
Collection of combined stdout/stderr has a separate hard 8 MiB limit per
|
|
83
|
+
process. Exceeding it terminates the process group and produces an error;
|
|
84
|
+
truncated output is never treated as a complete metric or evaluator response.
|
|
85
|
+
`evidence_output_limit` controls the smaller, redacted tail retained afterward.
|
|
78
86
|
|
|
79
87
|
Metric constraints add `parser` and `threshold`. A parser has type `json` or
|
|
80
88
|
`regex`, reads `stdout`, `stderr`, or a project-contained `file`, and selects a
|
|
81
89
|
dotted JSON `path` or regex `pattern` and `group`. Threshold operators are
|
|
82
90
|
`gt`, `gte`, `lt`, `lte`, and `eq`.
|
|
91
|
+
Measurements, thresholds, and baselines must be finite numbers. Finite numeric
|
|
92
|
+
strings remain supported; booleans, nulls, containers, NaN, and infinities are
|
|
93
|
+
rejected. `--allow-regression` never overrides numeric validation.
|
|
83
94
|
|
|
84
95
|
Ratchet constraints use `kind: ratchet` with the same command and parser fields
|
|
85
96
|
as a metric. Their default `mode: must_not_increase` compares the current value
|
|
@@ -94,7 +105,11 @@ constraintloop baseline update --all
|
|
|
94
105
|
Updates that would weaken an existing baseline are rejected. Use
|
|
95
106
|
`--allow-regression` only for a reviewed, intentional reset, then commit the
|
|
96
107
|
baseline artifact with the contract. `baseline_file` can select another
|
|
97
|
-
project-relative JSON file.
|
|
108
|
+
project-relative JSON file. Observed agent commands using `--allow-regression`
|
|
109
|
+
and direct edits to baseline files are denied by pre-tool hooks; ask the human
|
|
110
|
+
to perform intentional policy changes outside the hooked session. Strengthening
|
|
111
|
+
through the ordinary baseline-update command remains allowed. Each baseline
|
|
112
|
+
entry records both the numeric value
|
|
98
113
|
and the SHA-256 digest of the parsed evidence source, replacing the separate
|
|
99
114
|
count-and-hash bookkeeping commonly used for migration inventories.
|
|
100
115
|
|
|
@@ -142,3 +157,16 @@ Hook responses use `hook_output_limit` to retain failing test names and the firs
|
|
|
142
157
|
useful traceback line without injecting the complete test log. The unabridged
|
|
143
158
|
retained tail remains available with `constraintloop debug CONSTRAINT`.
|
|
144
159
|
See `docs/convergence-loops.md` for the cycle protocol and stable exit codes.
|
|
160
|
+
|
|
161
|
+
Stop-phase loops optionally accept `challenge` for discovery and verification
|
|
162
|
+
performed in the active Claude Code, Codex, or Gemini CLI session. Defaults are
|
|
163
|
+
`count: 10` (1–100), `max_rounds: 2` (1–10), `max_continuations: 8` (1–100),
|
|
164
|
+
`watch: ["**/*"]`, and `domain_context: []`. Context and watch entries are
|
|
165
|
+
project-relative globs. The existing loop duration and repair budgets also
|
|
166
|
+
apply; challenge work uses no model evaluator configuration. Omit `challenge`
|
|
167
|
+
to retain the ordinary completion behavior. See
|
|
168
|
+
[session challenge gates](convergence-loops.md#session-challenge-gates) for
|
|
169
|
+
submission examples, evidence requirements, and adapter behavior.
|
|
170
|
+
|
|
171
|
+
See [completion policy](completion-policy.md) for the cross-entry-point matrix,
|
|
172
|
+
task lifecycle, redaction policy, and upgrade notes.
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# Bounded convergence loops
|
|
2
|
+
|
|
3
|
+
Bounded convergence loops are part of the ConstraintLoop v0.1 release scope.
|
|
4
|
+
They connect completion evidence to repeated agent work and delayed external
|
|
5
|
+
state without turning ConstraintLoop into another general-purpose agent
|
|
6
|
+
runtime.
|
|
7
|
+
|
|
8
|
+
## Product boundary
|
|
9
|
+
|
|
10
|
+
ConstraintLoop owns the state machine, evidence, budgets, locking, and stop
|
|
11
|
+
decision. Claude Code, Codex, or Gemini CLI may perform a repair after
|
|
12
|
+
ConstraintLoop requests one. A native scheduler may wake the workflow.
|
|
13
|
+
|
|
14
|
+
Neither the agent nor the scheduler decides that work is complete. Only a fresh
|
|
15
|
+
contract evaluation can do that.
|
|
16
|
+
|
|
17
|
+
The first release will not launch provider CLIs for repair turns, manage
|
|
18
|
+
provider credentials, or implement a general autonomous task queue. An
|
|
19
|
+
explicitly configured command evaluator may invoke one isolated, read-only
|
|
20
|
+
Codex or Claude Code review and return the existing evaluator protocol. The
|
|
21
|
+
loop engine itself remains provider-neutral.
|
|
22
|
+
|
|
23
|
+
## Loop types
|
|
24
|
+
|
|
25
|
+
### Completion
|
|
26
|
+
|
|
27
|
+
Runs during an active coding session. A failed required gate produces one
|
|
28
|
+
focused repair instruction. Passing evidence stops the loop once any configured
|
|
29
|
+
session challenge gate is also satisfied.
|
|
30
|
+
|
|
31
|
+
### Monitor
|
|
32
|
+
|
|
33
|
+
Polls delayed deterministic evidence such as CI, deployments, integration
|
|
34
|
+
environments, or review state. Unchanged pending evidence waits without calling
|
|
35
|
+
a model.
|
|
36
|
+
|
|
37
|
+
### Maintenance
|
|
38
|
+
|
|
39
|
+
Starts an independent contract run on a recurring schedule, usually through
|
|
40
|
+
Claude/Codex scheduled tasks or CI. Examples include mutation testing,
|
|
41
|
+
dependency audits, and coverage regression checks.
|
|
42
|
+
|
|
43
|
+
## Contract shape
|
|
44
|
+
|
|
45
|
+
The v0.1 schema is:
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
loops:
|
|
49
|
+
completion:
|
|
50
|
+
phase: stop
|
|
51
|
+
interval_seconds: 10
|
|
52
|
+
max_repair_attempts: 3
|
|
53
|
+
max_unchanged_repairs: 2
|
|
54
|
+
max_duration_seconds: 1200
|
|
55
|
+
on_pass: stop
|
|
56
|
+
on_failure: repair
|
|
57
|
+
on_pending: wait
|
|
58
|
+
on_budget_exhausted: human_required
|
|
59
|
+
|
|
60
|
+
ci_watch:
|
|
61
|
+
phase: ci
|
|
62
|
+
interval_seconds: 120
|
|
63
|
+
max_repair_attempts: 2
|
|
64
|
+
max_unchanged_repairs: 1
|
|
65
|
+
max_duration_seconds: 2700
|
|
66
|
+
on_pass: stop
|
|
67
|
+
on_failure: repair
|
|
68
|
+
on_pending: wait
|
|
69
|
+
on_budget_exhausted: human_required
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
All fields are explicit and schema-validated. There is no unbounded mode.
|
|
73
|
+
|
|
74
|
+
Commands that monitor asynchronous state can declare pending exit codes. The
|
|
75
|
+
default convention reserves exit code `75` for a temporary pending result:
|
|
76
|
+
|
|
77
|
+
```yaml
|
|
78
|
+
constraints:
|
|
79
|
+
deployment:
|
|
80
|
+
kind: command
|
|
81
|
+
command: [scripts/deployment-status]
|
|
82
|
+
success_codes: [0]
|
|
83
|
+
pending_codes: [75]
|
|
84
|
+
phases: [stop, ci]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Pending is neither pass nor failure. It never authorizes completion and never
|
|
88
|
+
consumes a repair attempt.
|
|
89
|
+
|
|
90
|
+
## Cycle protocol
|
|
91
|
+
|
|
92
|
+
`constraintloop cycle NAME --json` executes exactly one transition. It does not
|
|
93
|
+
sleep and does not launch an agent.
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"schema_version": 1,
|
|
98
|
+
"loop": "ci_watch",
|
|
99
|
+
"state": "repair",
|
|
100
|
+
"snapshot": "sha256:...",
|
|
101
|
+
"observation": 4,
|
|
102
|
+
"repair_attempt": 1,
|
|
103
|
+
"next_action": "Repair the failing required constraints, then run one cycle.",
|
|
104
|
+
"wake_after_seconds": 0,
|
|
105
|
+
"blocking_constraints": ["integration_tests"]
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
States are:
|
|
110
|
+
|
|
111
|
+
- `passed`: fresh required evidence passes; stop.
|
|
112
|
+
- `repair`: new repairable failure; allow one focused agent turn.
|
|
113
|
+
- `waiting`: evidence is pending or unchanged without an attempted repair.
|
|
114
|
+
- `human_required`: unchanged repairs or policy require a human decision.
|
|
115
|
+
- `budget_exhausted`: attempts or elapsed time reached a hard limit.
|
|
116
|
+
- `error`: ConstraintLoop could not evaluate the contract reliably.
|
|
117
|
+
- `challenge`: the current coding session must generate domain-grounded scenarios.
|
|
118
|
+
- `verify`: the current coding session must investigate recorded scenarios and
|
|
119
|
+
submit evidence for unresolved or stale outcomes.
|
|
120
|
+
|
|
121
|
+
Exit codes will remain stable for automation:
|
|
122
|
+
|
|
123
|
+
| Code | State |
|
|
124
|
+
| ---: | --- |
|
|
125
|
+
| 0 | passed |
|
|
126
|
+
| 10 | repair |
|
|
127
|
+
| 11 | waiting |
|
|
128
|
+
| 12 | human required |
|
|
129
|
+
| 13 | budget exhausted |
|
|
130
|
+
| 14 | engine error |
|
|
131
|
+
| 15 | challenge discovery |
|
|
132
|
+
| 16 | challenge verification |
|
|
133
|
+
|
|
134
|
+
## Supervisor
|
|
135
|
+
|
|
136
|
+
`constraintloop supervise NAME` repeatedly calls the same state machine while
|
|
137
|
+
holding a project lease. It polls deterministic constraints locally and emits
|
|
138
|
+
JSON Lines when state changes.
|
|
139
|
+
|
|
140
|
+
The supervisor does not launch coding agents. On `repair`, `challenge`, or
|
|
141
|
+
`verify`, it exits with code 10, 15, or 16 so the native session or another
|
|
142
|
+
explicit controller can perform the requested work. Optional native rubric evaluators are
|
|
143
|
+
single-shot, tool-disabled reviews and cannot perform a repair transition.
|
|
144
|
+
|
|
145
|
+
The supervisor:
|
|
146
|
+
|
|
147
|
+
- use a single-writer lease under `.constraintloop/state/loops/`;
|
|
148
|
+
- recover leases after a bounded TTL;
|
|
149
|
+
- handle cancellation signals;
|
|
150
|
+
- never count polling observations as repair attempts;
|
|
151
|
+
- avoid rerunning unchanged expensive evidence before its configured interval;
|
|
152
|
+
- journal transitions atomically;
|
|
153
|
+
- redact secrets and cap retained output;
|
|
154
|
+
- stop at every attempt and duration budget.
|
|
155
|
+
|
|
156
|
+
## Native integration
|
|
157
|
+
|
|
158
|
+
`constraintloop loop-prompt NAME --adapter claude|codex|gemini` prints a durable
|
|
159
|
+
prompt that tells the native agent to:
|
|
160
|
+
|
|
161
|
+
1. run one cycle;
|
|
162
|
+
2. follow only the returned `next_action`;
|
|
163
|
+
3. make at most one repair per `repair` transition;
|
|
164
|
+
4. make no edits while `waiting`;
|
|
165
|
+
5. stop on `passed`, `human_required`, `budget_exhausted`, or `error`;
|
|
166
|
+
6. never edit the contract or create a waiver.
|
|
167
|
+
7. perform `challenge` and `verify` work in the current session, read the saved
|
|
168
|
+
request with `challenge show`, and submit evidence with `challenge submit`.
|
|
169
|
+
|
|
170
|
+
The generated prompt can be copied into a Claude Code, Codex, or Gemini CLI session. It
|
|
171
|
+
is provider-neutral except for adapter-specific command framing. ConstraintLoop
|
|
172
|
+
does not create account-level scheduled tasks or launch either provider CLI.
|
|
173
|
+
|
|
174
|
+
## Session challenge gates
|
|
175
|
+
|
|
176
|
+
An optional `challenge` block on a Stop-phase loop requires the current coding
|
|
177
|
+
session to explore failure scenarios before completion. The session supplies
|
|
178
|
+
its existing context, reasoning, and tools. ConstraintLoop does not call an
|
|
179
|
+
evaluator or launch another agent for this gate. Separately configured rubric
|
|
180
|
+
constraints still run normally.
|
|
181
|
+
|
|
182
|
+
```yaml
|
|
183
|
+
loops:
|
|
184
|
+
completion:
|
|
185
|
+
phase: stop
|
|
186
|
+
interval_seconds: 10
|
|
187
|
+
max_repair_attempts: 3
|
|
188
|
+
max_unchanged_repairs: 2
|
|
189
|
+
max_duration_seconds: 1200
|
|
190
|
+
challenge:
|
|
191
|
+
count: 10
|
|
192
|
+
max_rounds: 2
|
|
193
|
+
max_continuations: 8
|
|
194
|
+
watch: ["src/**/*.py", "tests/**/*.py", "docs/**/*.md", README.md]
|
|
195
|
+
domain_context: [README.md, "docs/**/*.md"]
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Install the existing hooks with `constraintloop setup --adapter all`, or use
|
|
199
|
+
`loop-prompt` for a specific adapter. The same state machine serves every agent:
|
|
200
|
+
|
|
201
|
+
| Agent | Completion event | Continue current session | Budget exhausted |
|
|
202
|
+
| --- | --- | --- | --- |
|
|
203
|
+
| Claude Code | `Stop` | `decision: block` with reason | `continue: false` |
|
|
204
|
+
| Codex | `Stop` | `decision: block` with reason | `continue: false` |
|
|
205
|
+
| Gemini CLI | `AfterAgent` | `decision: deny` with reason | `continue: false` |
|
|
206
|
+
|
|
207
|
+
These responses follow the official [Claude Code hooks](https://code.claude.com/docs/en/hooks#stop),
|
|
208
|
+
[Codex hooks](https://learn.chatgpt.com/docs/hooks#stop), and
|
|
209
|
+
[Gemini CLI hooks](https://geminicli.com/docs/hooks/reference/#afteragent) protocols.
|
|
210
|
+
Challenge-enabled loops recheck recursive completion events against their
|
|
211
|
+
persisted budgets. Other loops retain the legacy recursive-hook guard.
|
|
212
|
+
Generated continuation feedback does not replace the saved user goal.
|
|
213
|
+
|
|
214
|
+
Run `constraintloop cycle completion --json`. After required checks pass, the
|
|
215
|
+
cycle returns `challenge`. `constraintloop challenge show completion` returns
|
|
216
|
+
the goal, context paths, current request ID and input snapshot, saved scenarios,
|
|
217
|
+
and the exact JSON submission schema. The session reads the relevant domain
|
|
218
|
+
sources and produces a discovery submission:
|
|
219
|
+
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"kind": "discovery",
|
|
223
|
+
"request_id": "COPY_FROM_CHALLENGE_SHOW",
|
|
224
|
+
"input_snapshot": "COPY_FROM_CHALLENGE_SHOW",
|
|
225
|
+
"domain_summary": "Pending evidence must never authorize completion.",
|
|
226
|
+
"domain_sources": ["docs/convergence-loops.md"],
|
|
227
|
+
"challenges": [
|
|
228
|
+
{
|
|
229
|
+
"id": "r1-c1",
|
|
230
|
+
"perspective": "recovery",
|
|
231
|
+
"assumption": "Pending state survives process restarts.",
|
|
232
|
+
"scenario": "Restart the supervisor while its evidence is pending.",
|
|
233
|
+
"expected_behavior": "The restarted supervisor waits and does not pass.",
|
|
234
|
+
"verification_plan": "Run the restart regression in the tests gate.",
|
|
235
|
+
"source_refs": ["docs/convergence-loops.md"]
|
|
236
|
+
}
|
|
237
|
+
]
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
The example contains one scenario; submit exactly `count` scenarios per round.
|
|
242
|
+
At least three distinct perspective labels are required, or `count` when it is
|
|
243
|
+
smaller. IDs and normalized scenario text must be unique across every round.
|
|
244
|
+
Source references must name existing files covered by challenge `watch` or
|
|
245
|
+
`domain_context`; references are project-relative paths, without line suffixes.
|
|
246
|
+
The prompt requests distinct failure mechanisms and rejects invented domain
|
|
247
|
+
requirements. Structural checks cannot establish semantic diversity or creativity.
|
|
248
|
+
|
|
249
|
+
Save the submission under the gitignored `.constraintloop/state/` directory, then run:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
constraintloop challenge submit completion --file .constraintloop/state/discovery.json
|
|
253
|
+
constraintloop cycle completion --json
|
|
254
|
+
constraintloop challenge show completion
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The cycle now returns `verify`. The session investigates the scenarios using
|
|
258
|
+
existing tests, new regression tests, and other domain-appropriate evidence.
|
|
259
|
+
Submit a verification document using the current request ID and input snapshot:
|
|
260
|
+
|
|
261
|
+
```json
|
|
262
|
+
{
|
|
263
|
+
"kind": "verification",
|
|
264
|
+
"request_id": "COPY_FROM_CHALLENGE_SHOW",
|
|
265
|
+
"input_snapshot": "COPY_FROM_CHALLENGE_SHOW",
|
|
266
|
+
"resolutions": [
|
|
267
|
+
{
|
|
268
|
+
"challenge_id": "r1-c1",
|
|
269
|
+
"outcome": "verified",
|
|
270
|
+
"evidence": "The restart regression asserts that pending state remains blocking.",
|
|
271
|
+
"constraint_ids": ["tests"],
|
|
272
|
+
"source_refs": ["tests/test_loops.py"]
|
|
273
|
+
}
|
|
274
|
+
]
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Verification can be submitted in batches. `verified` requires at least one
|
|
279
|
+
enabled deterministic Stop constraint ID; the cycle checks that every cited
|
|
280
|
+
gate passes. A waiver, skipped result, rubric verdict, or the session's claim
|
|
281
|
+
alone does not satisfy this check. `defect` requests a focused repair;
|
|
282
|
+
`unresolved` continues verification; `rejected` requires a written explanation
|
|
283
|
+
and watched source references. Rejections are recorded self-review judgments,
|
|
284
|
+
not independently proven dispositions. The session must explain why the cited
|
|
285
|
+
checks or source evidence actually address the scenario.
|
|
286
|
+
|
|
287
|
+
Accepted discovery plans cannot be replaced through the submission protocol.
|
|
288
|
+
Every accepted submission rotates the request token to reject stale replays.
|
|
289
|
+
Changes to the goal, contract, constraint inputs, or watched domain/source files
|
|
290
|
+
invalidate prior verification. After edits, run one cycle to refresh the
|
|
291
|
+
snapshot before submitting evidence. A source change during evaluation prevents
|
|
292
|
+
completion until a fresh evaluation. Keep generated reports outside the watched
|
|
293
|
+
set; `.constraintloop/` is excluded automatically.
|
|
294
|
+
|
|
295
|
+
After repairs or input changes, resolving the current scenarios starts a fresh
|
|
296
|
+
discovery round if `max_rounds` allows it. Earlier scenarios remain recorded.
|
|
297
|
+
The round cap limits further exploration; it never excuses unresolved scenarios.
|
|
298
|
+
An unchanged successful round can pass immediately. A new goal or changed inputs
|
|
299
|
+
after completion starts a new challenge run.
|
|
300
|
+
|
|
301
|
+
Discovery and verification do not consume repair attempts. Each hook-requested
|
|
302
|
+
continuation for challenge, verification, or repair consumes the separate
|
|
303
|
+
`max_continuations` budget. Reading requests, submitting results, and polling
|
|
304
|
+
cycles do not consume that budget. The time budget bounds the entire loop;
|
|
305
|
+
repair and unchanged-repair budgets still apply. Journals and budgets survive
|
|
306
|
+
session restarts, and startup/compaction hooks point back to the saved work.
|
|
307
|
+
Native runtimes may impose their own continuation caps; the generated loop
|
|
308
|
+
prompt lets the session perform several steps before another completion event.
|
|
309
|
+
|
|
310
|
+
This gate applies to completion loops and their hooks. `constraintloop run`
|
|
311
|
+
evaluates ordinary constraints; use `cycle` to evaluate the full completion
|
|
312
|
+
decision. Challenge configuration on a non-Stop loop is rejected. CI continues
|
|
313
|
+
to execute committed constraints without trusting local challenge judgments.
|
|
314
|
+
This is evidence-backed self-review, with the author's potential blind spots;
|
|
315
|
+
it does not provide independent model review or exhaustive correctness proof.
|
|
316
|
+
|
|
317
|
+
## Snapshot and accounting rules
|
|
318
|
+
|
|
319
|
+
The snapshot includes the contract digest plus each applicable constraint ID,
|
|
320
|
+
input digest, verdict, and normalized findings. A repair attempt is consumed
|
|
321
|
+
only when:
|
|
322
|
+
|
|
323
|
+
1. the prior transition returned `repair`; and
|
|
324
|
+
2. a later cycle observes the result of that agent turn.
|
|
325
|
+
|
|
326
|
+
Repeated polling of the same pending snapshot increments observations but not
|
|
327
|
+
repair attempts. A changed source or external-evidence snapshot resets the
|
|
328
|
+
unchanged-repair counter, but not the total duration budget.
|
|
329
|
+
|
|
330
|
+
Required non-deterministic rubrics retain their existing quorum rules. Repeating
|
|
331
|
+
a rubric until it happens to pass is forbidden; all configured runs belong to
|
|
332
|
+
one evaluation and one snapshot.
|
|
333
|
+
|
|
334
|
+
Advisory feedback is actionable but does not require a passing verdict. A Stop
|
|
335
|
+
transition remains blocked until the agent either changes the evidence and a
|
|
336
|
+
fresh review passes, or records an explicit explanation with `constraintloop
|
|
337
|
+
acknowledge`. The explanation is bound to the exact input, verdict, rationale,
|
|
338
|
+
and findings; changed feedback requires a new disposition. Acknowledgment never
|
|
339
|
+
changes the verdict and is not a waiver.
|
|
340
|
+
|
|
341
|
+
## First-release acceptance criteria
|
|
342
|
+
|
|
343
|
+
- The schema rejects unknown loop fields, missing referenced phases, zero
|
|
344
|
+
budgets, and unbounded configurations.
|
|
345
|
+
- `cycle` produces stable structured output and exit codes for every state.
|
|
346
|
+
- Pending evidence cannot pass the contract or consume repairs.
|
|
347
|
+
- Identical polling does not invoke an evaluator or consume repair attempts.
|
|
348
|
+
- Changed evidence invalidates the prior transition.
|
|
349
|
+
- Attempt and time budgets survive process restarts.
|
|
350
|
+
- A second supervisor cannot acquire an active project lease.
|
|
351
|
+
- A stale lease is safely recoverable.
|
|
352
|
+
- SIGINT/SIGTERM release the lease and preserve the journal.
|
|
353
|
+
- Claude and Codex prompt fixtures follow the same provider-neutral protocol.
|
|
354
|
+
- Stop hooks and cycles share one attempt ledger rather than double-counting.
|
|
355
|
+
- CI continues to ignore local waivers and cached evidence.
|
|
356
|
+
- The ConstraintLoop repository dogfoods a bounded completion-loop
|
|
357
|
+
configuration before v0.1 is tagged.
|
|
358
|
+
|
|
359
|
+
## Implementation sequence
|
|
360
|
+
|
|
361
|
+
1. Add `PENDING`, `pending_codes`, and strict loop models.
|
|
362
|
+
2. Extract the current Stop retry accounting into a shared loop state machine.
|
|
363
|
+
3. Implement atomic journals, leases, snapshots, and budget accounting.
|
|
364
|
+
4. Add `cycle` with stable JSON and exit codes.
|
|
365
|
+
5. Add the deterministic `supervise` process.
|
|
366
|
+
6. Generate Claude and Codex native prompts.
|
|
367
|
+
7. Connect Stop hooks to the same completion loop.
|
|
368
|
+
8. Add integration tests for restart, locking, pending, cancellation, and
|
|
369
|
+
unchanged evidence.
|
|
370
|
+
9. Enable and exercise the completion loop in this repository.
|