diff --git a/cc-ci-plan/JOURNAL.md b/cc-ci-plan/JOURNAL.md index 8fab356..35c2849 100644 --- a/cc-ci-plan/JOURNAL.md +++ b/cc-ci-plan/JOURNAL.md @@ -422,3 +422,19 @@ session cc-ci-orchestrator-stale can be killed; recipe-mirrors org still private not backup-capable, no upgrade target). UNINTENTIONAL N/A (infra error, missing tool, aborted tier = unverified) blocks — the level cannot be above an unverified rung. Statuses now {pass, fail, skip, unver}; unclassifiable N/A defaults to unver. + +## 2026-06-11 ~04:50 — night-watch findings: limit system held core invariant; 2 bugs fixed +- ~01:49-01:51 all three sessions hit a MONTHLY SPEND limit ("You've hit your monthly + spend limit. /usage-credits to adjust") — no reset time exists, so "unparsable → flat + 5-min probe" was CORRECT behavior. Zero kill+reboots during the limit window (the old + system's churn bug is confirmed gone — last stall reboots were 23:26-23:50, old code). +- Bug 1: probe text contained "usage limit" → matched LIMIT_RE → self-sustaining window. + Reworded to "quota window" (must never match LIMIT_RE). +- Bug 2: probe dedupe checked the whole 40-line pane → once the submitted probe scrolled + into the conversation, all further probes were suppressed (builder/adv stuck at + nudges=1; orchestrator probes degraded to hourly, riding the wake's scroll). Dedupe now + checks only the bottom 8 lines (the input area). +- shot phase: M1 PASSed (ae10b55, 19/19 matrix) + builder landed the harness capture fix + (ce50f64) BEFORE the limit hit. Loops resume via watchdog probe after this bounce. +- lvl5 plan: operator addition — top badge (card corner/dashboard pill/SVG) shows ONLY + the level, no capping info; inline rung table keeps intentional-skip detail. diff --git a/cc-ci-plan/launch.py b/cc-ci-plan/launch.py index 4e25078..b47ed13 100644 --- a/cc-ci-plan/launch.py +++ b/cc-ci-plan/launch.py @@ -376,11 +376,14 @@ def _next_limit_until(pane, now): return now + LIMIT_PROBE_FALLBACK, False def _limit_nudge_msg(role): + # CAUTION: this text lands in the pane that limit_tick later greps. It must NEVER + # match LIMIT_RE (found 2026-06-11: "usage limit has reset" matched, making the + # window self-sustaining once the probe scrolled into the conversation). if role == "orchestrator": - return ("watchdog limit-probe: if the usage limit has reset, RESUME now — " + return ("watchdog probe: if the quota window has reset, RESUME now — " "you are the cc-ci orchestrator; re-check loop status and continue " "supervising from where you stopped.") - return ("watchdog limit-probe: if the usage limit has reset, RESUME your loop now — " + return ("watchdog probe: if the quota window has reset, RESUME your loop now — " "pull latest, re-read your phase STATUS/REVIEW files, and continue from " "where you stopped; re-arm your loop pacing.") @@ -415,10 +418,12 @@ def limit_tick(role, session, pane): if now < state.get("until", 0): return True # quietly inside the window - # Window elapsed, banner still showing → probe. Dedupe: never stack a second - # probe while our own text is still visible (typed-but-unsubmitted, or echoed). + # Window elapsed, banner still showing → probe. Dedupe: never stack a second probe + # while our own text sits typed-but-unsubmitted in the INPUT area (bottom lines only — + # checking the whole pane wedged the machine once a submitted probe scrolled into the + # conversation above, suppressing all further probes; found 2026-06-11). msg = _limit_nudge_msg(role) - if msg[:28] in pane: + if msg[:28] in "\n".join(pane.splitlines()[-8:]): return True nudges = state.get("nudges", 0) + 1 log(f"limit probe #{nudges} on {role} ({session}) — nudging to resume") diff --git a/cc-ci-plan/plan-phase-lvl5-lint-rung.md b/cc-ci-plan/plan-phase-lvl5-lint-rung.md index a7fb8a7..a381433 100644 --- a/cc-ci-plan/plan-phase-lvl5-lint-rung.md +++ b/cc-ci-plan/plan-phase-lvl5-lint-rung.md @@ -90,7 +90,12 @@ State files (phase-namespaced): `STATUS-lvl5.md`, `BACKLOG-lvl5.md`, `REVIEW-lvl new formal rule; `cap_reason`/`capped` deleted from level.py, derive_rungs/results.json schema, card (the "capped: …"/"full clean climb — top level (4)" line at card.py:~246 is replaced by the rung table alone or a neutral "level N of 5"), dashboard fields, - and docs. Unit tests rewritten to the new semantics, INCLUDING the three worked + and docs. **The top-corner level badge in particular** (the big LEVEL badge on the + card, the dashboard `_level_pill`, and `/badge/.svg`) shows ONLY the level — + number + color, zero capping/cap-reason annotation (operator-specified 2026-06-11). + The INLINE detail keeps the intentional-skip information: the per-rung table still + marks each rung ✔ / ✘ / intentional-skip / unverified, so "why isn't it higher" lives + there and only there. Unit tests rewritten to the new semantics, INCLUDING the worked examples from the mission and the old N/A-cases (single-published-version recipe, non-backup-capable recipe) now climbing past their former caps. 7. **All consumers updated coherently:** RUNGS/labels, results schema, card (color map +