Skip to content

Fix quota-aware resumes and preserve partial-work provenance - #392

Merged
datacas merged 4 commits into
mainfrom
task-389
Nov 3, 2026
Merged

datacas merged 4 commits into
mainfrom
task-389

Conversation

@datacas

@datacas datacas commented Nov 2, 2026

Copy link
Copy Markdown
Owner

Closes #389.

Resumed production stages now honor recorded quota exhaustion and explain the fallback selection. Complete reset dates, ordinal days, offsets and local DST rules are retained; ambiguous dated resets require an explicit operator retry, while missing reset information keeps the minimum 30-minute window.

Dirty PR resumes require an exact ownership checkpoint bound to the work item, stage, PR, HEAD, executors and complete staged/unstaged/untracked fingerprint. Checkpoints survive quota expiry, allowing the original executor to resume after expiry. A matching fallback receives the existing changes intact and instructions to inspect them. Unrelated or altered edits are refused. Legacy worktrees have a scoped, confirmed, single-use operator attestation; new unattested work cannot use it. The PR-head guard, .code-cycle.yml, sandbox code and permission policies are unchanged.

Diagnosis

Classification: shared_cause; decision: implement_root_fix. Quota eligibility was loaded only for implementation continuations, reset parsing retained only a clock, and no durable ownership checkpoint distinguished an exhausted executor's work from unrelated edits. Two regression tests reproduced primary redispatch and the dropped ordinal date before editing; both failed initially. The root fix separates quota availability from durable worktree ownership rather than introducing WIP commits or relaxing the HEAD guard.

The related-work search covered the issue's links and open/recently closed quota/fallback items, including #338, #330 / PR #384, #285, #262, #173 and #281. This change provides recovery support for #384 without editing that worktree or asserting that its findings are resolved.

Work units

Unit Behavior Files Tests Verification Rollback
WU-1 Quota-aware resumes, durable provenance and operator recovery Runtime recorder/dispatch, quota state, telemetry schema 26, manifests, tests and owning docs test_quota_resume, existing cycle/outcome/schema/installation suites 23 focused acceptance tests and the full configured suite pass independent: revert the combined implementation; additive audit tables remain unused

Routing, operator CLI and stored schema behavior are documented in docs/routing.md, docs/telemetry.md and docs/instrumentation.md. README links the new operator entry point.

Verification (agent-reported)

Checks were frozen before execution, using tests version 2 and stable criterion links:

Check ID Command Result Criteria
quota-regressions python3 -m unittest discover -s tests -p test_quota_resume.py pass, 23 tests, exit 0 AC-1, AC-2, AC-3, AC-4, AC-5
configured-test python3 -m unittest discover -s tests pass, 2,158 tests, one skip, exit 0 required configured command
package-validation python3 scripts/validate-package.py pass, exit 0 package/runtime integration
configuration-invariant git diff --exit-code 06277226a18f5fd7d427e700a896ca97deafec62 -- .code-cycle.yml scripts/sandbox.py scripts/native_sandbox.py pass, exit 0 AC-6

An additional diff check confirms scripts/executors.py, native prerequisites, stage permission policy and .claude/.codex are unchanged. The installed CLI process tests passed (18 tests), stage dispatch passed (49), cycle tests passed (66), and outcome tests passed (55). Disposable Git fixtures set their own commit identity and exercise staged binary content, unstaged edits, untracked files, expiry, repeated exhaustion, mismatches, operator recovery and the actual CLI parser.

basedpyright --level error scripts/quota_state.py passes with zero errors. Broader static analysis has reservations: shared-module analysis was interrupted without diagnostics after a prolonged run; the new unittest file reports seven fixture initialization/import convention diagnostics. No type-check configuration was changed. No live provider quota was spent, and the historical PR #384 worktree was not modified. The one full-suite skip is retained as a skip, not a pass.

Security

cc-security-review ran; security_audit_ran=true. No confirmed vulnerabilities found in the scoped audit. Reviewed SQL parameter binding, argv subprocess calls, operator identity, exact fingerprint/scope validation, atomic single-use attestation claims, journal redaction and unchanged isolation controls. Local telemetry and the authenticated operator remain trusted boundaries; ownership evidence does not verify file correctness.

Implementation run: schema:2; profile:deep_coder; requested:openai/gpt-6.1-sol; effort:medium; resolved:?. CI policy is parallel; pushed-head checks are read once and remain the cycle gate's responsibility.

@datacas

datacas commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

Implementation completed for #389 at 4028252bd648ecc03424de2709236ad7a878df6f. The publication helper uploaded this commit, and gh pr view confirmed PR #392 has exactly that head.

The final configured suite passed: 2,158 tests, one skip, exit 0. The current focused acceptance suite passed all 23 tests; package validation and unchanged configuration/sandbox checks passed. Verification is agent-reported, tests version 2, with AC-1–AC-6 covered by the frozen checks listed in the PR description. Broader static-analysis limitations are disclosed there.

cc-security-review ran (security_audit_ran=true); no confirmed vulnerabilities were found in the scoped pass. Implementation run: schema:2; profile:deep_coder; requested:openai/gpt-6.1-sol; effort:medium; resolved:?.

Checks of this exact pushed head were read once under the parallel policy: 0 passed, 0 failed, 5 pending — Skills, manifests, and Bash installer; Windows test shard (windows-1); Windows test shard (windows-2); Windows test shard (windows-3); Windows test shard (windows-4). The cycle CI gate owns the wait.


Closes #389.

Resumed production stages now honor recorded quota exhaustion and explain the fallback selection. Complete reset dates, ordinal days, offsets and local DST rules are retained; ambiguous dated resets require an explicit operator retry, while missing reset information keeps the minimum 30-minute window.

Dirty PR resumes require an exact ownership checkpoint bound to the work item, stage, PR, HEAD, executors and complete staged/unstaged/untracked fingerprint. Checkpoints survive quota expiry, allowing the original executor to resume after expiry. A matching fallback receives the existing changes intact and instructions to inspect them. Unrelated or altered edits are refused. Legacy worktrees have a scoped, confirmed, single-use operator attestation; new unattested work cannot use it. The PR-head guard, .code-cycle.yml, sandbox code and permission policies are unchanged.

Diagnosis

Classification: shared_cause; decision: implement_root_fix. Quota eligibility was loaded only for implementation continuations, reset parsing retained only a clock, and no durable ownership checkpoint distinguished an exhausted executor's work from unrelated edits. Two regression tests reproduced primary redispatch and the dropped ordinal date before editing; both failed initially. The root fix separates quota availability from durable worktree ownership rather than introducing WIP commits or relaxing the HEAD guard.

The related-work search covered the issue's links and open/recently closed quota/fallback items, including #338, #330 / PR #384, #285, #262, #173 and #281. This change provides recovery support for #384 without editing that worktree or asserting that its findings are resolved.

Work units

Unit Behavior Files Tests Verification Rollback
WU-1 Quota-aware resumes, durable provenance and operator recovery Runtime recorder/dispatch, quota state, telemetry schema 26, manifests, tests and owning docs test_quota_resume, existing cycle/outcome/schema/installation suites 23 focused acceptance tests and the full configured suite pass independent: revert the combined implementation; additive audit tables remain unused

Routing, operator CLI and stored schema behavior are documented in docs/routing.md, docs/telemetry.md and docs/instrumentation.md. README links the new operator entry point.

Verification (agent-reported)

Checks were frozen before execution, using tests version 2 and stable criterion links:

Check ID Command Result Criteria
quota-regressions python3 -m unittest discover -s tests -p test_quota_resume.py pass, 23 tests, exit 0 AC-1, AC-2, AC-3, AC-4, AC-5
configured-test python3 -m unittest discover -s tests pass, 2,158 tests, one skip, exit 0 required configured command
package-validation python3 scripts/validate-package.py pass, exit 0 package/runtime integration
configuration-invariant git diff --exit-code 06277226a18f5fd7d427e700a896ca97deafec62 -- .code-cycle.yml scripts/sandbox.py scripts/native_sandbox.py pass, exit 0 AC-6

An additional diff check confirms scripts/executors.py, native prerequisites, stage permission policy and .claude/.codex are unchanged. The installed CLI process tests passed (18 tests), stage dispatch passed (49), cycle tests passed (66), and outcome tests passed (55). Disposable Git fixtures set their own commit identity and exercise staged binary content, unstaged edits, untracked files, expiry, repeated exhaustion, mismatches, operator recovery and the actual CLI parser.

basedpyright --level error scripts/quota_state.py passes with zero errors. Broader static analysis has reservations: shared-module analysis was interrupted without diagnostics after a prolonged run; the new unittest file reports seven fixture initialization/import convention diagnostics. No type-check configuration was changed. No live provider quota was spent, and the historical PR #384 worktree was not modified. The one full-suite skip is retained as a skip, not a pass.

Security

cc-security-review ran; security_audit_ran=true. No confirmed vulnerabilities found in the scoped audit. Reviewed SQL parameter binding, argv subprocess calls, operator identity, exact fingerprint/scope validation, atomic single-use attestation claims, journal redaction and unchanged isolation controls. Local telemetry and the authenticated operator remain trusted boundaries; ownership evidence does not verify file correctness.

Implementation run: schema:2; profile:deep_coder; requested:openai/gpt-6.1-sol; effort:medium; resolved:?. CI policy is parallel; pushed-head checks are read once and remain the cycle gate's responsibility.

@datacas

datacas commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

[CCR-20261102-001] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

Initial review — PR #392 (closes #389)

Verdict: CHANGES_REQUESTED at 4028252bd648ecc03424de2709236ad7a878df6f.

Summary and scope

Reviewed the complete accumulated diff origin/main...4028252 (merge base 06277226a18f5fd7d427e700a896ca97deafec62, 1,182 lines, 14 files): scripts/cycle.py, scripts/cycle_dispatch.py, new scripts/quota_state.py, scripts/telemetry.py (schema 26), manifests, docs/routing.md, docs/telemetry.md, docs/instrumentation.md, README.md, and tests (test_quota_resume.py plus adjusted test_cycle, test_cycle_outcomes, test_work_item_outcomes).

The routing change (every production route honours active quota rows, including --from), the durable handoff ledger, the provenance gate for dirty --from resumes, operator retry/attest, the stop-message fix and the redaction of provider prose are sound and well tested. Two defects in the new reset parser break AC-2 ("the stored reset equals the message's date, time and timezone … never produces an earlier reset"), one of them a platform regression.

Findings

[REV-001] · high · open · - · blocks:yes — Windows: every clock-only reset becomes reset_time_ambiguous (indefinite unavailability)

scripts/quota_state.py:39 (local_zone), used at :73 and refused at :95-96.

local_zone() only resolves the zone from TZ or /etc/localtime. On Windows neither normally exists (GitHub's Windows runners do not set TZ), so it returns None and quota_reset raises "local zone unavailable" for every message without an explicit zone. A common message such as quota exhausted; reset at 9:46 PM (or Claude's resets 2:50pm) is therefore stored with expires_at=''/reset_time_ambiguous, and the executor stays unavailable until an operator runs quota_state.py retry. The base code used current.astimezone(), which works on every platform, so this is a regression for a supported platform rather than a deliberate ambiguity.

Evidence (code trace; ad-hoc execution is outside this stage's command table): tests/test_telemetry.py:194-197 records "quota exhausted; reset at 9:46 PM" and asserts a truthy expiry. On Windows that assertion fails by the trace above. test_telemetry belongs to the windows-2 shard, which is the shard reported failed on this head. The shard log is not readable from this stage, so the trace is consistent with that failure but not proven to be its cause. tests/test_cycle.py:903 (windows-4, still pending) expects quota exhaustion recorded until for the same message and would fail the same way.

Suggested fix: when no IANA zone can be resolved, interpret the naive local wall time with the platform's own rules. For example, datetime(y, m, d, h, mi, s).astimezone() applies the OS's DST rules for that date on Windows as well. Add a test that patches the zone lookup to the no-/etc/localtime path and asserts a non-ambiguous expiry for a clock-only reset.

[REV-002] · medium · open · - · blocks:yes — Unrecognised reset text falls through to a permissive path and produces an earlier reset

scripts/quota_state.py:74 (zone suffix), :112-116 (clock-only path), :62-65 (no-clock path).

The parser refuses some unknown text, but other forms fall through silently to the clock-only path or to the 30-minute path instead of to reset_time_ambiguous:

  • Parenthesised explicit zone. For reset at 3:30pm (America/Los_Angeles), the suffix becomes (America/Los_Angeles after .strip(" .),"). Neither the offset regex nor [A-Za-z_/]+ matches a leading (, so the explicit zone is ignored and the local zone is used. With TZ=Europe/Madrid that stores 14:30 UTC instead of 23:30 UTC, which is 9 hours early. (CST) in parentheses is likewise treated as local, while bare CST is correctly refused.
  • Weekday. resets Tuesday 3:20 PM has no digit or month in its prefix, so it takes the next-occurrence path and can be days early.
  • Relative duration. Try again in 4 hours 23 minutes has no clock and none of reset|resets|resetting|until, so it gets the 30-minute window. Design decision 3 of Route around recorded quota exhaustion and hand partial work to the fallback on resume #389 says 30 minutes "is only a minimum safety bound, not a substitute for a later provider-stated reset".

Evidence: a deterministic code trace of the regexes. None of these forms is covered by ResetTests. Suggested fix: make the fall-through conservative. Parse or refuse a parenthesised zone, treat weekday names as unresolved dates, and parse in N days/hours/minutes (or classify it as ambiguous). Add these strings to test_ambiguity_never_becomes_an_earlier_clock_only_reset or to a parse test.

[REV-003] · low · open · - · blocks:no — docs/routing.md still says later stages keep the original executor availability

docs/routing.md:114. The unchanged "One reroute per stage" bullet ends with "The fallback applies only to this stage; later stages keep the original executor availability." After this change a quota failure adds the target to exhausted_until (scripts/cycle.py:952), so later stages of the same cycle skip it. tests/test_cycle.py:741 now expects one primary dispatch for quota, and test_cycle_outcomes expects two fallback stages. The new "Quota across resumes" bullet implies the new behaviour, but the older sentence now contradicts it for quota. Qualify the sentence, for example "except a recorded quota exhaustion, which later stages honour". Under AGENTS.md, the owning page should describe the visible behaviour.

Security triage and audit

  • Deterministic rule: .code-cycle.yml declares no security_review.always_when, so the defaults and the mandatory minimum apply. No changed path matches the mandatory minimum (no CI, secrets or agent-configuration files changed).
  • Reviewer judgement and runtime plan: the change touches durable telemetry (schema 26), operator identity (gh api user), subprocess calls, journal redaction of provider prose, and text injected into an executor task. The plan also sets security_required=true.
  • cc-security-review ran on 4028252: no confirmed vulnerabilities. Reviewed: all new SQL is parameter-bound (the only f-string table name is in tests); gh api user --jq .login uses argv with no shell, and its output is validated against [A-Za-z0-9-]{1,100}; operator inputs are validated (_identifier, _change_request_identifier, _checked("model_requested"), choices= for executors and stages); provider detail is redacted in the stop report (redact() in cycle.py:1007) and in the journal (cycle_journal.py:270); quota_history and quota_handoffs hold no prose or file contents; values appended to the executor task are runtime- or choice-constrained tokens and hex digests; the single-use attestation is enforced by a partial unique index plus an atomic UPDATE … WHERE claimed_at IS NULL.
  • Informational, not a finding: legacy-attestation eligibility (quota_state.py:274-281) is keyed on repository, executor and model, not on the task. The operator's explicit fingerprint confirmation remains the control. Local telemetry and the authenticated operator stay trusted boundaries, as the PR states.

Verification (tests.version=2, checks frozen before running)

Check ID Command Result Criteria
configured-test python3 -m unittest discover -s tests exit 0; Ran 2158 tests in 246.305s — OK (skipped=1) on Linux AC-1, AC-3, AC-4, AC-5 (through test_quota_resume)
package-validation python3 scripts/validate-package.py exit 0; VALID: 16 skills (7 cycle, 9 supporting), shared sections in sync, cross-agent manifests aligned package integration
unittest-default python3 -m unittest exit 0; Ran 0 tests (no discovery from the repository root; proves nothing) —
configuration-invariant git diff --stat 0627722..4028252 .code-cycle.yml, scripts/sandbox.py, scripts/native_sandbox.py and scripts/executors.py are absent from the 14 changed files AC-6

Acceptance criteria:

  • AC-1: met. test_from_resume_skips_recorded_primary passes, and the decision reasons name the substitution.
  • AC-2: open. The Linux tests pass, but see REV-001 (Windows) and REV-002 (earlier resets for parenthesised zones, weekdays and relative durations).
  • AC-3: met. The stop advice --from resolve --pr 384 is accepted by run_cycle.py --dry-run (test_stop_advice_is_accepted_at_the_real_cli_boundary).
  • AC-4: met. GitHandoffTests cover byte-exact staged, unstaged and untracked content, an unchanged HEAD, the record of both executors and the fingerprint, and refusal of altered or unrelated diffs.
  • AC-5: met. test_ordinary_dirty_executor_change_is_refused passes.
  • AC-6: met (diff stat above).

Unverified

  • REV-001 and REV-002 are established by code trace only. This stage's command table denies ad-hoc python3 -c and helper scripts, so no reproduction was executed. REV-001 matches the failing Windows shard, whose log (gh run view --log-failed) is also outside the command table.
  • No live provider quota messages were exercised.

CI (parallel policy; read once at 4028252, not awaited)

Check State
Skills, manifests, and Bash installer pass
Windows test shard (windows-1) pending
Windows test shard (windows-2) fail (7m53s)
Windows test shard (windows-3) pass
Windows test shard (windows-4) pending

The cycle's CI gate owns these states. Not every required check has passed.

Residual risk

  • quota_reset is a hand-written grammar over free provider text. Formats not listed here may still fall through. The conservative-fall-through fix in REV-002 is what bounds this risk.
  • When a quota failure happens and a PR is known, snapshot() now runs one extra time (cycle.py:958), even for read-only stages where before is None. This costs extra gh calls but does not change correctness.

@datacas

datacas commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

[CCR-20261102-001] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCT-20261102-001] · deep_coder · openai/gpt-6.1-sol→? · high · triaged:4028252bd648ecc03424de2709236ad7a878df6f · schema:2

Triage is frozen before source edits at the reviewed PR head. All three findings are valid; no earlier resolver dispositions exist. The complete supplied 1,182-line accumulated diff and provider-authenticated review were inspected. No review threads exist.

[REV-001] · high · open · valid · blocks:yes — Restore platform-local reset conversion

Confirmed: missing TZ and /etc/localtime make ordinary Windows clock resets ambiguous. Use OS date-specific conversion, with regression coverage for the missing-IANA path.

[REV-002] · medium · open · valid · blocks:yes — Reject unresolved reset formats conservatively

Confirmed: parenthesized zones, weekdays and relative durations can silently become earlier resets. Add parsing/refusal and regressions before recording resolution.

[REV-003] · low · open · valid · blocks:no — Correct later-stage availability documentation

Confirmed: the owning routing page incorrectly says later stages retain availability after recorded quota exhaustion.

Verification obligations are frozen before execution (agent-reported results will follow). All checks retain executor codex, profile deep_coder, context project, and required=true:

ID Command Criteria Level Provenance Reason
configured-test python3 -m unittest discover -s tests — test project configured test command
quota-regressions python3 -m unittest discover -s tests -p test_quota_resume.py AC-1, AC-2, AC-3, AC-4, AC-5 boundary acceptance quota routing, CLI and real Git handoff regressions
package-validation python3 scripts/validate-package.py — static project package validation
configuration-invariant git diff --exit-code 06277226a18f5fd7d427e700a896ca97deafec62 -- .code-cycle.yml scripts/sandbox.py scripts/native_sandbox.py AC-6 static acceptance routing configuration and sandbox settings remain unchanged

Post-change delegated code review and cc-security-review are required. CI policy is parallel.

@datacas

datacas commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

[CCR-20261102-001] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCT-20261102-001] · deep_coder · openai/gpt-6.1-sol→? · high · triaged:4028252bd648ecc03424de2709236ad7a878df6f · schema:2

Resolution: RESOLVED. All three dispositions were frozen as valid before edits and remain unchanged. Fix commit: bf7672096b0296c4cc56a6a89ed598fc9ff85e4d. Publication preflight passed inside this stage; the publication helper pushed the commit successfully, and a subsequent gh pr view confirmed this exact PR head. No findings remain open.

[REV-001] · high · resolved · valid · blocks:yes — Restore platform-local reset conversion

When IANA lookup is unavailable (including Windows without TZ or /etc/localtime), local reset wall times stay naive until the OS converts them using rules for the candidate date. The parser no longer rejects an ordinary clock reset or substitutes today's fixed offset for a future date. Regression tests exercise both reported clock forms and a dated reset across seasonal offsets. These assertions failed before the fix and now pass.

[REV-002] · medium · resolved · valid · blocks:yes — Reject unresolved reset formats conservatively

Timezone suffixes must match completely. Parenthesized UTC offsets and IANA zones are interpreted explicitly; ambiguous abbreviations, malformed parentheses and trailing unknown text are refused. Weekday-only dates and relative-duration messages remain reset_time_ambiguous, with no fabricated earlier expiry. Tests cover the review's Los Angeles, CST, Tuesday and four-hour examples, plus malformed suffixes and compact/spelled-out durations. Existing journal tests preserve the redacted provider text outside structured quota telemetry. Before the fix, the focused suite reproduced 16 failing assertions; its final run passed all 25 tests.

[REV-003] · low · resolved · valid · blocks:no — Correct later-stage availability documentation

docs/routing.md now states that later stages honour recorded quota exhaustion and documents OS local-time conversion, parenthesized zones and conservative handling of unresolved resets. This is the owning page required by AGENTS.md; no README change is needed.

Verification is agent-reported, tests version 2. The four required checks were frozen before execution with their runtime identities unchanged:

Check Result Criteria
configured-test exit 0; 2,160 tests in 335.320s; OK (skipped=1) project suite
quota-regressions exit 0; 25 tests in 19.272s; OK AC-1, AC-2, AC-3, AC-4, AC-5
package-validation exit 0; VALID: 16 skills, shared sections in sync, manifests aligned package integration
configuration-invariant exit 0; empty diff for configuration and both sandbox files AC-6

The focused check includes actual disposable Git repositories, byte-exact dirty handoffs with unchanged HEAD, altered/unrelated diff refusals, ordinary dirty executor-change refusal, and real CLI invocation. AC-1 through AC-6 each have a required check; none is left uncovered.

Agent-reported frozen check results (tests.version=2)
{
  "version": 2,
  "ran": true,
  "passed": true,
  "conclusion": "verified_with_reservations",
  "boundary": "required",
  "checks": [
    {
      "id": "configured-test",
      "command": "python3 -m unittest discover -s tests",
      "executor": "codex",
      "profile": "deep_coder",
      "context": "project",
      "required": true,
      "criteria": [],
      "level": "test",
      "provenance": "project",
      "reason": "configured test command",
      "head_sha": "bf7672096b0296c4cc56a6a89ed598fc9ff85e4d",
      "result": "pass",
      "evidence": [
        {
          "exit_code": 0,
          "executed": 2160,
          "skipped": 1
        }
      ],
      "cause": null,
      "attempts": [
        {
          "exit_code": 0,
          "executed": 2160,
          "skipped": 1
        }
      ]
    },
    {
      "id": "quota-regressions",
      "command": "python3 -m unittest discover -s tests -p test_quota_resume.py",
      "executor": "codex",
      "profile": "deep_coder",
      "context": "project",
      "required": true,
      "criteria": [
        "AC-1",
        "AC-2",
        "AC-3",
        "AC-4",
        "AC-5"
      ],
      "level": "boundary",
      "provenance": "acceptance",
      "reason": "quota routing, CLI and real Git handoff regressions",
      "head_sha": "bf7672096b0296c4cc56a6a89ed598fc9ff85e4d",
      "result": "pass",
      "evidence": [
        {
          "exit_code": 0,
          "executed": 25
        }
      ],
      "cause": null,
      "attempts": [
        {
          "phase": "before_fix",
          "head_sha": "4028252bd648ecc03424de2709236ad7a878df6f",
          "exit_code": 1,
          "executed": 25,
          "failures": 16
        },
        {
          "phase": "after_fix",
          "exit_code": 0,
          "executed": 25
        },
        {
          "phase": "final_tree",
          "exit_code": 0,
          "executed": 25
        }
      ]
    },
    {
      "id": "package-validation",
      "command": "python3 scripts/validate-package.py",
      "executor": "codex",
      "profile": "deep_coder",
      "context": "project",
      "required": true,
      "criteria": [],
      "level": "static",
      "provenance": "project",
      "reason": "package validation",
      "head_sha": "bf7672096b0296c4cc56a6a89ed598fc9ff85e4d",
      "result": "pass",
      "evidence": [
        {
          "exit_code": 0,
          "executed": null
        }
      ],
      "cause": null,
      "attempts": [
        {
          "exit_code": 0,
          "executed": null
        }
      ]
    },
    {
      "id": "configuration-invariant",
      "command": "git diff --exit-code 06277226a18f5fd7d427e700a896ca97deafec62 -- .code-cycle.yml scripts/sandbox.py scripts/native_sandbox.py",
      "executor": "codex",
      "profile": "deep_coder",
      "context": "project",
      "required": true,
      "criteria": [
        "AC-6"
      ],
      "level": "static",
      "provenance": "acceptance",
      "reason": "routing configuration and sandbox settings remain unchanged",
      "head_sha": "bf7672096b0296c4cc56a6a89ed598fc9ff85e4d",
      "result": "pass",
      "evidence": [
        {
          "exit_code": 0,
          "executed": null
        }
      ],
      "cause": null,
      "attempts": [
        {
          "exit_code": 0,
          "executed": null
        }
      ]
    }
  ]
}

The mandatory delegated cc-code-review reviewed the complete three-file fix delta from trusted review base 4028252bd648ecc03424de2709236ad7a878df6f, including uncommitted fixes. That base is an ancestor of the final head (verified again after committing); no accumulated-diff fallback was needed. No P0–P3 findings were reported. The reviewer independently ran the 25-test focused suite successfully.

cc-security-review ran; security_audit_ran=true. No confirmed vulnerabilities were found in this scoped pass. Reviewed provider-text validation, full suffix matching, IANA traversal rejection, OS conversion, conservative unknown-expiry handling, downstream parameter-bound persistence and unchanged isolation boundaries. The runtime plan requires this audit regardless of path-trigger triage.

Supplemental static analysis: basedpyright scripts/quota_state.py tests/test_quota_resume.py exited 1 with seven errors and 498 warnings. The seven errors concern the unchanged test import and setUp fixture initialization; none is in the parser. No type-check settings were changed. This is not a clean type-check claim. git diff --check passed.

Residual limitations: local execution was Linux; the missing-IANA platform path was exercised, but native Windows execution and live provider quota messages were not. The parser still supports a bounded provider-text grammar. Tests use disposable Git identities rather than the user's global identity. The suite's one skip remains a skip. Dependency preparation was already successful; no dependency or lifecycle installation was run here.

CI policy is parallel. The exact pushed head was read once; 0 passed, 0 failed, 5 pending:

Check Observed state
Skills, manifests, and Bash installer pending (in progress)
Windows test shard (windows-1) pending (in progress)
Windows test shard (windows-2) pending (in progress)
Windows test shard (windows-3) pending (in progress)
Windows test shard (windows-4) pending (in progress)

The cycle's CI gate owns the wait; this resolution does not declare approval.

@datacas

datacas commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

[CCR-20261102-001] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCT-20261102-001] · deep_coder · openai/gpt-6.1-sol→? · high · triaged:4028252bd648ecc03424de2709236ad7a878df6f · schema:2

[CCR-20261102-002] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

Re-review — PR #392 (closes #389)

Verdict: REVIEW_PASSED_AWAITING_CI at bf7672096b0296c4cc56a6a89ed598fc9ff85e4d. The review of this head is complete and no open finding blocks approval. This is not an approval: not every required check has passed (see CI). The cycle's CI gate decides.

What changed since the previous review (4028252 → bf76720)

Only 3 files changed (git diff --stat 4028252..bf76720): scripts/quota_state.py (+25/−20), tests/test_quota_resume.py (+39/−3) and docs/routing.md (+2/−2). The other 11 files of the accumulated diff are byte-identical to the version reviewed in CCR-20261102-001. The supplied accumulated diff (origin/main...bf76720, merge base 06277226) has 1,225 lines, as stated. Its SHA-256 could not be recomputed because sha256sum is not in this stage's command table.

Parser changes reviewed:

  • local_zone() returning None no longer fails. current.astimezone(None).replace(tzinfo=None) keeps a naive local wall time, and the final astimezone(timezone.utc) applies the OS's rules for the candidate date, including fold. A non-IANA TZ such as a POSIX string now also falls through to OS conversion instead of being refused.
  • Zone suffixes use re.fullmatch. One balanced pair of parentheses is unwrapped, an IANA name must contain /, and a ZoneInfo lookup failure (KeyError, ValueError for traversal or non-normalised keys, OSError for directories) becomes reset_time_ambiguous.
  • A weekday, today, tomorrow or next in the prefix is an unresolved date. With no clock, in|after <digit> and try|retry again in|after are ambiguous and no longer get the 30-minute window.
  • Next-day rollover is now decided on the UTC instant after the fold choice (reset <= current), and only for clock-only messages. The day is added in wall time, so the DST rules of the following day apply.

Previous findings

[REV-001] · high · resolved · valid · blocks:yes — Windows: every clock-only reset becomes reset_time_ambiguous (indefinite unavailability)

scripts/quota_state.py:39-50, :97-99, :119-124. Corrected and verified by execution. test_platform_local_clock_without_iana_zone forces the no-TZ / no-/etc/localtime path (TZ="", Path.open raises FileNotFoundError). It asserts a concrete expiry for both forms in the original finding, reset at 9:46 PM and resets 2:50pm. test_platform_local_dated_reset_uses_rules_for_that_date checks that a November date evaluated in July uses November's rules. Both pass locally (Linux) in quota-regressions and configured-test. As complementary evidence (not counted as a local test), the original native-Windows reproduction, tests/test_telemetry.py in shard windows-2, now passes on this head after failing on 4028252.

[REV-002] · medium · resolved · valid · blocks:yes — Unrecognised reset text falls through to a permissive path and produces an earlier reset

scripts/quota_state.py:63-65, :75-96, :114-116. Corrected and verified by execution. The three classes this review reported now behave as follows:

  • (America/Los_Angeles) resolves to 23:30 UTC, not to local time.
  • (CST), (America/Unknown), an unbalanced (UTC and UTC+01:00 extra are refused.
  • Tuesday, Tue and tomorrow are refused.
  • in 4 hours 23 minutes, in 2 days, after 45 minutes, in 4h23m and in four hours are refused.

test_parenthesized_explicit_zones covers the resolved zone; the refusals are covered by subtests of test_ambiguity_never_becomes_an_earlier_clock_only_reset. All pass. A code trace confirms that every fall-through in the new grammar now goes to reset_time_ambiguous, never to an earlier instant. Text after the clock that is not a fully matched zone is refused, and digits or month/weekday words in a dateless prefix are refused.

[REV-003] · low · resolved · valid · blocks:no — docs/routing.md still says later stages keep the original executor availability

docs/routing.md:114. Corrected. The sentence now reads "…keep the original executor availability except for recorded quota exhaustion, which they continue to honour." The "Quota across resumes" bullet also documents OS-local conversion, parenthesised zones, and the refusal of weekday-only dates and relative durations. This matches the code and keeps the owning page current, as AGENTS.md requires.

New findings

None.

Security triage and audit

  • Deterministic rule: .code-cycle.yml declares no security_review.always_when. No changed path matches the mandatory minimum (no CI, secrets or agent-configuration files).
  • The runtime plan sets security_required=true, so the audit is mandatory.
  • cc-security-review ran on bf76720: no confirmed vulnerabilities. The new trust-boundary crossing is provider text reaching ZoneInfo(suffix). Several layers contain it:
    • The suffix must fully match [A-Za-z0-9_+.-]+(/[A-Za-z0-9_+.-]+)+.
    • zoneinfo's key validation rejects absolute and non-normalised keys, including .. traversal, with ValueError.
    • A non-TZif file or a directory raises ValueError or OSError, and every one of those errors is caught into reset_time_ambiguous.
    • Nothing read from a zone file is persisted or echoed. Only the structured UTC timestamp and closed reason tokens reach telemetry.
    • No new SQL, subprocess or publication surface.
  • Informational, unchanged trust model: an executor's own output controls its reset text, so a misbehaving executor could state a past explicit date. That predates this delta, and the executor is already inside the cycle's trust boundary.

Verification (agent-reported, tests.version=2; frozen identities reused unchanged)

Check ID Command Result Criteria
configured-test python3 -m unittest discover -s tests pass — exit 0; Ran 2160 tests in 345.631s — OK (skipped=1) —
quota-regressions python3 -m unittest discover -s tests -p test_quota_resume.py pass — exit 0; Ran 25 tests in 3.204s — OK AC-1, AC-2, AC-3, AC-4, AC-5
package-validation python3 scripts/validate-package.py pass — exit 0; VALID: 16 skills (7 cycle, 9 supporting), shared sections in sync, cross-agent manifests aligned —
configuration-invariant git diff --exit-code 06277226a18f5fd7d427e700a896ca97deafec62 -- .code-cycle.yml scripts/sandbox.py scripts/native_sandbox.py pass — exit 0, empty diff AC-6

All checks ran on Linux at bf7672096b0296c4cc56a6a89ed598fc9ff85e4d.

Acceptance criteria: AC-1 met, AC-2 met (REV-001 and REV-002 resolved), AC-3 met, AC-4 met, AC-5 met, AC-6 met. Every criterion has a passing required check.

Unverified

  • Native Windows was not executed locally. CI shard windows-4 runs test_quota_resume and test_cycle among about 30 modules, and it failed on this head. Its log is not readable from this stage's command table (gh run view --log-failed is not permitted), so the failure is unattributed. The same parser and message (reset at 9:46 PM) pass natively in windows-2, which argues against REV-001 as the cause, but that is not proof.
  • No live provider quota messages were exercised.

CI (parallel policy; read once at bf76720, not awaited)

Check State
Skills, manifests, and Bash installer pass (5m11s)
Windows test shard (windows-1) pending
Windows test shard (windows-2) pass (6m55s)
Windows test shard (windows-3) pass (11m11s)
Windows test shard (windows-4) fail (9m2s)

Not every required check has passed. The cycle's CI gate owns these states and turns a failure into work for the next resolution.

Residual risk

  • quota_reset is still a hand-written grammar over free provider text. The fall-throughs are now conservative, so unknown forms make the executor unavailable until quota_state.py retry rather than producing an earlier reset. Two forms that are not ambiguous are still treated as ambiguous:

    • An hour-only clock without minutes, such as resets 3pm (Europe/Madrid). The clock regex requires :MM.
    • A digit elsewhere in a dateless prefix, such as 5-hour limit · resets 3:20pm.

    Neither breaks the "never earlier" half of AC-2. If a provider emits them, the cost is an operator retry.

  • On Windows with an IANA-style TZ set but no tzdata package, local_zone() now falls back to the C runtime, which does not understand IANA names. This is a rare configuration and does not affect the default Windows path.

@datacas

datacas commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

CI diagnosis on head bf76720 (supporting context, not authoritative proof)

Observed in CI run 41475335733, read after the run completed:

  • Job Windows test shard (windows-4): https://github.com/datacas/code-cycle-toolkit/actions/runs/41475335733/job/125379286925 ends with Ran 1124 tests and FAILED (errors=8, skipped=79) in the step "Validate shard assignments and run tests".
  • All 8 errors are PermissionError: [WinError 32] The process cannot access the file because it is being used by another process on a temporary telemetry.sqlite. They are raised from tests in test_quota_resume.GitHandoffTests, including test_altered_staged_unstaged_or_untracked_diff_is_refused, test_ambiguous_reset_keeps_redacted_message_out_of_telemetry, test_dirty_fallback_receives_exact_bytes_and_head_with_audit, test_expired_window_returns_to_original_executor_keeps_provenance and test_legacy_attestation_requires_exact_confirmation_and_is_single_use.
  • PowerShell installer fails only because it requires every Windows shard to pass. windows-1, windows-2, windows-3 and Skills, manifests, and Bash installer passed.

Reading of the evidence: a SQLite connection (or a handle derived from it) opened by these tests is still open when the temporary directory is removed, which Windows refuses and Linux does not. This is an inference from the log; it has not been reproduced locally and should be verified.

Expected fix: close connections, cursors and any related handles deterministically at their source, including when a test fails. Do not hide it with cleanup retries, sleeps or ignored PermissionError.

The GitHandoffTests helpers opened telemetry.sqlite with a bare 'with sqlite3.connect(...)', which commits but never closes. Since Python 3.11 an unclosed connection can survive until the cyclic collector runs, so on Windows (CI Python 3.15.1) TemporaryDirectory cleanup failed with WinError 32 in eight tests. Close every connection with contextlib.closing and fail, where /proc/self/fd exists, any handle still open in the fixture directory before it is removed.
@datacas

datacas commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

[CCR-20261102-001] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCT-20261102-001] · deep_coder · openai/gpt-6.1-sol→? · high · triaged:4028252bd648ecc03424de2709236ad7a878df6f · schema:2

[CCR-20261102-002] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCT-20261102-002] · deep_coder · anthropic/claude-opus-5-5→? · high · triaged:bf7672096b0296c4cc56a6a89ed598fc9ff85e4d · schema:2

Resolution round — CI failure on bf76720 (PR #392, closes #389)

Resolution: RESOLVED. Fix commit: 33e07cd65a6c0dd0fcc67029cca42e303f62bd30. It was pushed with the publication helper, and gh pr view then confirmed it as the PR head. The rereview (CCR-20261102-002) left no open finding. This round fixes the required check that failed on bf76720: Windows test shard (windows-4). A failed check is not a finding, so it has no REV-xxx.

Previous findings (dispositions frozen, unchanged)

[REV-001] · high · resolved · valid · blocks:yes — Restore platform-local reset conversion

Resolved in bf76720 and confirmed by CCR-20261102-002. This round made no change to it.

[REV-002] · medium · resolved · valid · blocks:yes — Reject unresolved reset formats conservatively

Resolved in bf76720 and confirmed by CCR-20261102-002. This round made no change to it.

[REV-003] · low · resolved · valid · blocks:no — Correct later-stage availability documentation

Resolved in bf76720 and confirmed by CCR-20261102-002. This round made no change to it.

CI failure: Windows test shard (windows-4) on bf76720

Diagnosis. I read the failed job log directly: run 41475335733, job 125379286925. The shard reported FAILED (errors=8). All eight errors are PermissionError: [WinError 32] on the fixture telemetry.sqlite, raised during TemporaryDirectory.cleanup, and all eight tests are in test_quota_resume.GitHandoffTests. Every failing test reads or writes the database through a bare with sqlite3.connect(path) as connection:; that is, rows() or a direct DELETE/UPDATE. The GitHandoffTests that passed on Windows use none of these. The sqlite3 connection context manager commits or rolls back, but it never closes the connection. On CPython 3.11 and later, a connection's statement cache keeps a reference back to it, so an unclosed connection stays open until the cyclic collector runs. Windows then refuses to delete the still-open file; Linux does not. CI runs Python 3.15.1. Every connection in scripts/ (telemetry.py, quota_state.py, cycle_journal.py) is already opened through closing(). The leak is in the test code only.

Fix (tests/test_quota_resume.py, 1 file, +36/−9).

  • New database() and execute() helpers open the connection with contextlib.closing, so it is closed even when an assertion fails. They replace all five bare connects (rows(), two DELETEs and two UPDATEs).
  • New assert_no_open_handles cleanup runs before the temporary directory is removed (cleanups run last-in, first-out). Where /proc/self/fd exists, it fails if any descriptor still points inside the fixture directory. On Windows, the directory removal itself is the check.
  • No retries, sleeps, gc.collect() or ignored PermissionError. Production code is unchanged.

Local reproduction limits. The local interpreter is Python 3.10.12 (SQLite 3.37.2). There, a bare with connection is freed by reference counting, so the original Windows leak does not reproduce on Linux even with the GC disabled. To test the guard itself, I added a temporary test that deliberately kept a connection open. The guard failed it and named …/telemetry.sqlite. I removed that probe before committing. Final confirmation of the fix is the Windows shard on 33e07cd, which this stage did not wait for.

Verification (agent-reported, tests.version=2; frozen identities reused)

Check ID Command run Result Criteria
configured-test python3 -m unittest discover -s tests pass — exit 0; Ran 2160 tests in 651.542s · OK (skipped=1) —
quota-regressions python3 -m unittest discover -s tests -p test_quota_resume.py pass — exit 0; Ran 25 tests · OK AC-1, AC-2, AC-3, AC-4, AC-5
package-validation python3 scripts/validate-package.py pass — exit 0; VALID: 16 skills (7 cycle, 9 supporting), shared sections in sync, cross-agent manifests aligned —
configuration-invariant git diff --exit-code 06277226a18f5fd7d427e700a896ca97deafec62 -- .code-cycle.yml scripts/sandbox.py scripts/native_sandbox.py pass — exit 0, empty diff AC-6

All four ran on Linux against the committed tree. git diff --check passed. Every criterion, AC-1 through AC-6, has a passing required check. The runs share no user-global state with CI: the fixtures set their own Git identity and use their own temporary directories. They do not share CI's platform or interpreter (Linux with Python 3.10 here, Windows with Python 3.15 in CI).

Post-change review and security triage

  • Delegated cc-code-review of the fix delta from the trusted rereview base bf7672096b0296c4cc56a6a89ed598fc9ff85e4d. That base was the HEAD at triage, so it is an ancestor of the new head. The review found no P0–P2 issues and raised two P3 notes:
    • It could not see a negative control for the guard. The deliberate-leak probe above provides one.
    • It suggested a docstring note against adding gc.collect() to the guard. Not applied: it would only change a comment, and the guard's docstring already says to close every connection.
  • Security: the runtime plan does not require an audit (security_required=false). The only changed path is tests/test_quota_resume.py, which matches neither the mandatory minimum nor any sensitive area, so cc-security-review did not run (security_audit_ran=false).
  • Docs: this round changes only a test; there is no visible behaviour, command, schema or configuration change, so no docs/ page needs updating.

CI (parallel policy; read once, not awaited)

When I read the checks once, no check was registered on 33e07cd65a6c0dd0fcc67029cca42e303f62bd30 yet: 0 passed, 0 failed, 0 pending. The workflows had not started, so this is not a pass. The cycle's CI gate owns the wait. This resolution does not declare approval.

Residual risk

  • The Windows-only leak cannot be reproduced on the local Python 3.10, so whether it is fixed rests on the windows-4 shard of 33e07cd.
  • From the review, outside this change: Telemetry._connect (scripts/telemetry.py) would leak its connection if PRAGMA foreign_keys raised before returning. No test reaches that path.

@datacas

datacas commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

[CCR-20261102-001] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCT-20261102-001] · deep_coder · openai/gpt-6.1-sol→? · high · triaged:4028252bd648ecc03424de2709236ad7a878df6f · schema:2

[CCR-20261102-002] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCT-20261102-002] · deep_coder · anthropic/claude-opus-5-5→? · high · triaged:bf7672096b0296c4cc56a6a89ed598fc9ff85e4d · schema:2

[CCR-20261102-003] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

Re-review — PR #392 (closes #389)

Verdict: APPROVED at 33e07cd65a6c0dd0fcc67029cca42e303f62bd30. The whole accumulated change was rereviewed at this head. All three previous findings are classified as resolved, there are no new findings, and every check on this head passed. It is ready for a manual merge; this stage does not merge.

What changed since the previous review (bf76720 → 33e07cd)

git diff --stat bf76720 33e07cd shows one file: tests/test_quota_resume.py (+36/−9). Production code, docs and configuration did not change. The supplied accumulated diff (origin/main...33e07cd, merge base 06277226) has 1,252 lines, as stated: the 1,225 lines reviewed in CCR-20261102-002 plus this +27 delta. I read all of it again in sections.

How the delta fixes the windows-4 failure on bf76720 (WinError 32 on the fixture telemetry.sqlite):

  • GitHandoffTests.database() wraps sqlite3.connect in contextlib.closing. execute() nests it with the connection's own context manager, so the statement commits and the connection then closes. They replace all five bare with sqlite3.connect(...) uses, in rows(), two DELETEs and two UPDATEs. A bare with on a connection only commits or rolls back; it never closes. rows() builds its list before the with exits, so it reads nothing from a closed connection.
  • assert_no_open_handles is registered after temp.cleanup, so it runs before it (cleanups run last-in, first-out). It fails when any /proc/self/fd entry still points inside the fixture root. Where /proc does not exist, it is a no-op, and on Windows the directory removal itself remains the check. No retries, sleeps, gc.collect() or ignored PermissionError were added.
  • The production connections in scripts/quota_state.py (Handoffs.record/match/claim/complete, main) and scripts/telemetry.py all already use closing(), as the accumulated diff shows. The leak was confined to the tests.

Native-Windows confirmation, read once from CI and not counted as a local test: Windows test shard (windows-4), which runs test_quota_resume, now passes on 33e07cd (run 41481918962).

Previous findings

[REV-001] · high · resolved · valid · blocks:yes — Restore platform-local reset conversion

scripts/quota_state.py (local_zone, the naive-wall-time path in quota_reset). Corrected and verified by execution on this head. test_platform_local_clock_without_iana_zone and test_platform_local_dated_reset_uses_rules_for_that_date pass in quota-regressions and configured-test. windows-2 and windows-4 also pass natively on 33e07cd. That CI evidence complements the local runs and is not counted as a local test.

[REV-002] · medium · resolved · valid · blocks:yes — Reject unresolved reset formats conservatively

scripts/quota_state.py (quota_reset). Corrected and verified by execution on this head. test_ambiguity_never_becomes_an_earlier_clock_only_reset (18 subtests) and test_parenthesized_explicit_zones pass. The parser code is unchanged since CCR-20261102-002, so its trace still holds: every fall-through returns reset_time_ambiguous and never an earlier instant.

[REV-003] · low · resolved · valid · blocks:no — Correct later-stage availability documentation

docs/routing.md:114 (the "One reroute per stage" bullet). Corrected. The text is unchanged since CCR-20261102-002 and still matches the code: later stages honour recorded quota exhaustion.

New findings

None. Two notes on the delta that do not block:

  • The guard ignores handles held by child processes, but every SQLite handle in these tests belongs to this process.
  • The guard runs as a cleanup, so when the test body also fails it reports a second error. That is acceptable for a test helper.

Security triage and audit

  • Deterministic rule: .code-cycle.yml declares no security_review.always_when. No changed path matches the mandatory minimum: there are no CI, secrets or agent-configuration files in the accumulated diff.
  • The runtime plan sets security_required=true, so the audit is mandatory.
  • cc-security-review ran on 33e07cd across the accumulated diff: no confirmed vulnerabilities.
    • SQL: every statement in quota_state.py, telemetry.py and cycle.py is parameterised. The only f-string table name is in the tests, with constant names.
    • Commands: gh api user runs with an argv list and no shell, and the returned login must fully match [A-Za-z0-9-]{1,100}.
    • Zone names from provider text must fully match an IANA-shaped pattern before they reach ZoneInfo. zoneinfo itself rejects traversal and non-normalised keys, and every lookup error becomes reset_time_ambiguous.
    • Operator CLI input passes _identifier / _change_request_identifier and closed choices. The model passes Telemetry._checked.
    • Provider prose is redacted before it reaches the stop report and the journal; test_ambiguous_reset_keeps_redacted_message_out_of_telemetry covers a GitHub token.
    • Operator attestations are single-use through an atomic UPDATE … WHERE claimed_at IS NULL with a rowcount check, plus a partial unique index.
    • The fix delta is test-only, with no new surface.
  • Informational, unchanged trust model: anyone who can write the local telemetry.sqlite can forge provenance rows. The executor still controls its own reset text. Both predate this PR and sit inside the cycle's trust boundary.

Verification (agent-reported, tests.version=2; frozen identities reused unchanged)

Check ID Command Result Criteria
configured-test python3 -m unittest discover -s tests pass — exit 0; Ran 2160 tests in 447.839s · OK (skipped=1) —
quota-regressions python3 -m unittest discover -s tests -p test_quota_resume.py pass — exit 0; Ran 25 tests in 4.158s · OK AC-1, AC-2, AC-3, AC-4, AC-5
package-validation python3 scripts/validate-package.py pass — exit 0; VALID: 16 skills (7 cycle, 9 supporting), shared sections in sync, cross-agent manifests aligned —
configuration-invariant git diff --exit-code 06277226a18f5fd7d427e700a896ca97deafec62 -- .code-cycle.yml scripts/sandbox.py scripts/native_sandbox.py pass — exit 0, empty diff AC-6

All four ran on Linux in this stage's disposable clone at 33e07cd65a6c0dd0fcc67029cca42e303f62bd30.

Acceptance criteria: AC-1 through AC-6 are all met, and each one has a passing required check.

Unverified

  • Native Windows was not run locally, and neither was the Python 3.11+ cyclic-collection behaviour behind the original leak (local Python 3.10). CI shard windows-4 passing on this head is the evidence for that part.
  • No live provider quota messages were exercised.

CI (parallel policy; read once at 33e07cd, not awaited)

Check State
Skills, manifests, and Bash installer pass (8m34s)
Windows test shard (windows-1) pass (9m49s)
Windows test shard (windows-2) pass (7m26s)
Windows test shard (windows-3) pass (9m44s)
Windows test shard (windows-4) pass (9m55s)
PowerShell installer pass (1m3s)

6 passed, 0 failed, 0 pending (run 41481918962; statusCheckRollup head 33e07cd65a6c0dd0fcc67029cca42e303f62bd30).

Residual risk

  • quota_reset is still a hand-written grammar over free provider text. Two forms that are not actually ambiguous are still refused: an hour-only clock such as 3pm, and a digit in a dateless prefix such as 5-hour limit · resets 3:20pm. Both refusals are conservative and cost only an operator quota_state.py retry.
  • On Windows with an IANA TZ but no tzdata, conversion falls back to the C runtime. This configuration is rare.
  • Outside this change: Telemetry._connect would leak its connection if PRAGMA foreign_keys raised before returning. No path reaches that today.

Docs: this round changed only a test, so no docs/ page needs updating. The accumulated behaviour is documented in docs/routing.md, docs/telemetry.md and docs/instrumentation.md.

Run: schema:2; profile:senior_reviewer; requested:anthropic/claude-opus-5-5; effort:high; resolved:?.

@datacas

datacas commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

Code Cycle rereview — PR #392 (work item #389)

[CCR-20261102-001] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCT-20261102-001] · deep_coder · openai/gpt-6.1-sol→? · high · triaged:4028252bd648ecc03424de2709236ad7a878df6f · schema:2

[CCR-20261102-002] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCT-20261102-002] · deep_coder · anthropic/claude-opus-5-5→? · high · triaged:bf7672096b0296c4cc56a6a89ed598fc9ff85e4d · schema:2

[CCR-20261102-003] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCR-20261103-001] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

Status: REVIEW_PASSED_AWAITING_CI for head 9b15fd92c2e12a57bf437abdca0236b1b17d64dd. The review of this head is complete and no open finding blocks approval. This is not an approval. Two required Windows shards were still pending when the checks were read, and the cycle's CI gate decides on them.

What changed since the previous review

The previous rereview (CCR-20261102-003) approved head 33e07cd65a6c0dd0fcc67029cca42e303f62bd30. The only new commit is 9b15fd9, which merges main (3f356ac) into task-389. Compared with 33e07cd, it changes one line in docs/ROADMAP_V2.md: #389 is added to the M1 milestone row, which already landed on main in #390. The accumulated diff against merge base 3f356ac is unchanged: 14 files, +902/−59, 1252 lines in the runtime evidence file, all read. I re-reviewed it in full for this head.

Accumulated review

  • scripts/quota_state.py: reset interpretation keeps complete dates, ordinal days, explicit offsets, and parenthesized IANA zones. Weekday-only dates, relative durations, invalid dates, and abbreviation zones resolve to reset_time_ambiguous, with no reset time. When no IANA zone is available, a wall time stays naive until the OS converts it. A repeated DST hour uses its later instant. The quota_handoffs ledger binds a handoff to repo, task, stage, PR, HEAD, original and destination executor, original model, and a 64-hex fingerprint. An operator attestation is single-use: it has a unique index and is claimed atomically.
  • scripts/cycle.py: every production route honours active quota records, including --from and resolve escalation. A dirty --from resume (not implement) needs a matching provenance record, and the fingerprint is checked again against the pre-dispatch snapshot before the claim. Provenance is recorded only when the exhausted process exited, started from a clean tree (or matched provenance), left HEAD unchanged, and reconciled with no remote or publication effect. The stop text names --from <stage> --pr <n> outside implement, and the quota detail is redacted.
  • scripts/telemetry.py: schema 26 adds quota_history and quota_handoffs. Records expire instead of being deleted. An empty expires_at means an ambiguous reset and stays active until an operator retry.
  • docs/routing.md, docs/telemetry.md, docs/instrumentation.md and README.md document the visible behaviour, the schema and the operator CLI, as AGENTS.md requires.

No new findings.

Previous findings

[REV-001] · high · resolved · valid · blocks:yes — Windows: every clock-only reset becomes reset_time_ambiguous (indefinite unavailability)

scripts/quota_state.py local_zone() returns None when there is no IANA zone, and naive wall times are converted by the OS. Verified by execution: test_platform_local_clock_without_iana_zone and test_platform_local_dated_reset_uses_rules_for_that_date pass on this head. The Windows CI shards passed or are pending (see the CI section).

[REV-002] · medium · resolved · valid · blocks:yes — Unrecognised reset text falls through to a permissive path and produces an earlier reset

A reset, until, or retry phrase without a clock, an unresolved date prefix, or an unknown zone suffix now returns reset_time_ambiguous. Verified by execution: test_ambiguity_never_becomes_an_earlier_clock_only_reset (18 messages) passes on this head.

[REV-003] · low · resolved · valid · blocks:no — docs/routing.md still says later stages keep the original executor availability

docs/routing.md now reads "...keep the original executor availability except for recorded quota exhaustion, which they continue to honour", which matches CycleRecorder loading active records on every production route. Verified by reading the file and by test_cycle_outcomes (2 fallback stages), which passes in the full suite.

Security triage and audit

security_required is set by the runtime plan, so cc-security-review ran on the full accumulated diff for this head. No confirmed vulnerabilities.

  • SQL: every statement uses parameters. The only f-string query (SELECT * FROM {table}) is a test helper with constant table names.
  • Commands: gh api user runs as a list with no shell, and the login is checked against [A-Za-z0-9-]{1,100}.
  • Prompt surface: the text injected into the fallback's task carries only executor names, a hex fingerprint and a closed provenance token. It contains no file contents and no provider prose.
  • Secrets and prose: quota detail goes through redact() in the stop report and when the journal is written (cycle_journal.py:270). Telemetry tables keep only closed tokens and timestamps, as test_ambiguous_reset_keeps_redacted_message_out_of_telemetry checks.
  • Zone parsing: a provider-supplied zone suffix like ../x is rejected because ZoneInfo refuses non-normalized keys, and the result is reset_time_ambiguous.
  • Informational: quota_state.py retry and attest prove the operator through the local gh identity only. Anyone who can run the CLI can already write the local SQLite file, so this adds no new privilege.

The mandatory minimum does not fire: no CI, secret, or agent/toolkit configuration path changed.

Verification (agent-reported, tests.version 2, head 9b15fd92c2e12a57bf437abdca0236b1b17d64dd)

Check Criteria Result Evidence
configured-test (codex/deep_coder, project) — pass python3 -m unittest discover -s tests: exit 0, Ran 2160 tests, OK (skipped=1)
quota-regressions (codex/deep_coder, project) AC-1…AC-5 pass python3 -m unittest discover -s tests -p test_quota_resume.py -v: exit 0, Ran 25 tests, OK; also included in the full suite
package-validation (codex/deep_coder, project) — pass python3 scripts/validate-package.py: exit 0, VALID: 16 skills (7 cycle, 9 supporting)…
configuration-invariant (codex/deep_coder, project) AC-6 pass git diff --stat 3f356ac..9b15fd9 -- .code-cycle.yml .claude .codex .agents AGENTS.md CLAUDE.md .github: exit 0, empty

Criterion coverage:

  • AC-1: test_from_resume_skips_recorded_primary, test_resolve_escalation_cannot_restore_exhausted_target.
  • AC-2: the ResetTests class.
  • AC-3: test_stop_advice_is_accepted_at_the_real_cli_boundary, which runs run_cycle.py --from resolve --pr 384 --dry-run.
  • AC-4: test_dirty_fallback_receives_exact_bytes_and_head_with_audit and test_altered_staged_unstaged_or_untracked_diff_is_refused.
  • AC-5: test_ordinary_dirty_executor_change_is_refused.
  • AC-6: the invariant diff above.

Note: python3 -m unittest tests.test_quota_resume run from the repository root fails with ModuleNotFoundError: No module named 'test_cycle'. This is the suite's existing discover -s tests layout and not a defect of this change: five other modules use the same from test_cycle import.

Unverified: none.

CI (read once, not awaited; parallel policy)

Run 41638080129, "Validate package":

  • Skills, manifests, and Bash installer: pass
  • Windows test shard (windows-2): pass
  • Windows test shard (windows-3): pass
  • Windows test shard (windows-1): pending
  • Windows test shard (windows-4): pending

Residual risk and verdict

The resume logic depends on the Git porcelain fingerprint from executors._workspace_fingerprint. The tests use a real repository, but no real Windows run of the handoff path has been observed beyond the CI shards. Two Windows shards were still pending.

Verdict: the review of this head passed with no blocking finding. The cycle's CI gate still has to confirm the required checks before approval.

@datacas

datacas commented Nov 3, 2026

Copy link
Copy Markdown
Owner Author

Rereview — PR #392 (work item #389)

[CCR-20261102-001] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCT-20261102-001] · deep_coder · openai/gpt-6.1-sol→? · high · triaged:4028252bd648ecc03424de2709236ad7a878df6f · schema:2

[CCR-20261102-002] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCT-20261102-002] · deep_coder · anthropic/claude-opus-5-5→? · high · triaged:bf7672096b0296c4cc56a6a89ed598fc9ff85e4d · schema:2

[CCR-20261102-003] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCR-20261103-001] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

[CCR-20261103-002] · senior_reviewer · anthropic/claude-opus-5-5→? · high · schema:2

Verdict: APPROVED for head 9b15fd92c2e12a57bf437abdca0236b1b17d64dd. No finding is open, all four frozen verification checks passed locally, and all six code-host checks passed for this head.

What changed since the previous review

The head has not moved since the previous rereview (CCR-20261103-001), which had reviewed 9b15fd9 and reported REVIEW_PASSED_AWAITING_CI. The cycle then stopped because the required local verification for that head was still unverified. Since the previously approved head 33e07cd, the only change is a merge of main that touches docs/ROADMAP_V2.md (one line). That line is not part of the change under review. This run reviews the whole change again at the current head and executes the frozen checks.

Accumulated review

I read the complete accumulated diff in sections: 1,252 lines, base origin/main, merge base 3f356ac. It touches scripts/cycle.py, scripts/cycle_dispatch.py, the new scripts/quota_state.py, scripts/telemetry.py (schema 26), scripts/runtime.manifest, scripts/windows-test-shards.json, README.md, docs/{routing,telemetry,instrumentation}.md, and the tests. Points checked:

  • Production routing. Every production route now loads active quota records, not only --continue. An ambiguous reset is stored with expires_at='' and is shown as operator retry required. The resolve escalation target_override cannot restore an exhausted target.
  • Handoff provenance.
    • Recording. A record is written only when the process finished with exit proof, started on a clean tree or a validated earlier handoff, left HEAD unchanged, and left the remote and publication effects unchanged (reconcile(...) == "reroute").
    • Fingerprint. _workspace_fingerprint covers HEAD, the branch, porcelain status, staged blob IDs, and a SHA-256 of each modified or untracked file.
    • Matching. A match is bound to repo, task, stage, PR, HEAD, fingerprint and destination, and to the original model when the original executor is reused. The fingerprint is checked again right before dispatch.
    • Single use. An operator attestation is claimed atomically.
  • Reset parsing (quota_state.quota_reset):
    • Ordinal days, complete dates, ISO dates, explicit offsets, parenthesized and IANA zones, and DST fold (the later instant is chosen) are handled.
    • Abbreviations, weekday-only dates, relative durations and unresolved dates become reset_time_ambiguous and never an earlier clock-only reset.
    • On a platform without IANA data, wall times are converted by the OS for the target date.
  • Stop guidance. The message names --from <role> --pr <n>, or --continue for implementation only.
  • Documentation. The visible behaviour, the CLI and the schema 26 tables are documented in docs/routing.md#operator-quota-recovery, docs/telemetry.md and docs/instrumentation.md; README.md adds the new entry point. This meets the AGENTS.md documentation rule.

No new finding.

Previous findings

[REV-001] · high · resolved · valid · blocks:yes — Windows: every clock-only reset becomes reset_time_ambiguous (indefinite unavailability)

scripts/quota_state.py. local_zone() returns None when neither TZ nor /etc/localtime is available, and naive wall times are then converted by the OS. Verified by execution: test_platform_local_clock_without_iana_zone and test_platform_local_dated_reset_uses_rules_for_that_date pass with TZ cleared and /etc/localtime patched to be missing.

[REV-002] · medium · resolved · valid · blocks:yes — Unrecognised reset text falls through to a permissive path and produces an earlier reset

scripts/quota_state.py. Text without a clock that mentions a reset or a relative duration becomes reset_time_ambiguous. A prefix that holds an unresolved date, weekday or relative day raises an error and never falls back to clock-only. Verified by execution: test_ambiguity_never_becomes_an_earlier_clock_only_reset (18 messages) passes.

[REV-003] · low · resolved · valid · blocks:no — docs/routing.md still says later stages keep the original executor availability

docs/routing.md now says later stages keep the original availability "except for recorded quota exhaustion, which they continue to honour". The runtime behaviour this sentence describes is tested in test_cycle.py (a later stage is not redispatched to the quota-exhausted primary) and in test_cycle_outcomes.py (fallback_stages == 2), and both pass in the full suite.

Security triage and audit

The runtime plan requires a security audit (security_required). No changed path matches the mandatory minimum (CI, secrets, or agent/toolkit configuration). cc-security-review ran as a delegated pass over the complete diff and found no confirmed vulnerabilities:

  • SQL. All new statements use bound parameters. The only interpolated table name is in a test helper.
  • External commands. quota_state.py runs gh api user --jq .login as an argument list without a shell, and validates the login against [A-Za-z0-9-]{1,100} before storing it. Executor arguments are restricted to choices, --model passes the telemetry identifier check, and the PR identifier is validated.
  • Secrets and provider text. The stop detail is passed through redact(), and the journal redacts detail when it writes. Telemetry tables store only closed tokens, timestamps and fingerprints. Verified by execution: test_ambiguous_reset_keeps_redacted_message_out_of_telemetry asserts that a ghp_ token never reaches the stop detail or the journal.
  • Informational. Provenance and attestation integrity relies on the local telemetry.sqlite. Anyone with write access to that file could forge a handoff. This is the same local trust boundary the rest of telemetry already has, and nothing in this change widens it.

Verification (agent-reported, tests version 2, head 9b15fd92c2e12a57bf437abdca0236b1b17d64dd)

Check Criteria Command run Result
configured-test (codex/deep_coder, project, required) — python3 -m unittest discover -s tests pass — exit 0, 2,160 tests, OK (1 skip)
quota-regressions (codex/deep_coder, project, required) AC-1–AC-5 python3 -m unittest discover -v -s tests -p test_quota_resume.py pass — exit 0, 25 tests OK
package-validation (codex/deep_coder, project, required) — python3 scripts/validate-package.py pass — exit 0, VALID: 16 skills (7 cycle, 9 supporting)…
configuration-invariant (codex/deep_coder, project, required) AC-6 git diff --exit-code --stat 3f356ac… HEAD -- .code-cycle.yml .claude .codex .agents AGENTS.md CLAUDE.md pass — exit 0, no diff
  • quota-regressions command. The runtime froze this check's command as a hash, so I ran the acceptance module directly.
  • Module-path error. A first attempt with python3 -m unittest tests.test_quota_resume … failed to import the module: it imports test_cycle as a top-level module. That was a problem with how I invoked it, not a product failure; the other three modules in that run passed 136 tests. Rerunning through discovery passed.
  • AC-6. The comparison used merge base 3f356ac, because this clone has no origin.
  • Coverage. Every acceptance criterion (AC-1–AC-6) is covered by a passing required check. Conclusion: verified.

CI (code host, head 9b15fd9)

6 passed, 0 failed, 0 pending — Skills, manifests, and Bash installer; Windows test shard (windows-1) through (windows-4); PowerShell installer. All succeeded.

Residual risk

Legacy attestation depends on the operator actually inspecting the diff before confirming its fingerprint; the tool records this as operator_attested, never as functional verification. The reset parser's coverage of real provider messages is limited to the forms the tests exercise. Anything else becomes reset_time_ambiguous, which is the safe direction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Route around recorded quota exhaustion and hand partial work to the fallback on resume

1 participant