Repository navigation
Description
目的 (Why)
Implement contract v2.0 (caty-ai/x-collector#142, child A1) in the central reusable workflow so the supporter loop is lossless under a launch burst and honest about GitHub's 50-invitations-per-24 h rate: event runs stay the fast path, the twice-daily sweep becomes the reconciler (catch-up), and invitations are queued at ≤ 45/day. Measured background and the five-seat design review: caty-ai/x-collector design packet _handoffs/x-collector-supporter-loop-scale-design-20260908/design-v1.3.md (mirror the relevant sections into supporter-loop/README.md).
完了条件 (Done when)
- Catch-up (§11 step 4b, live in
act): candidates = stargazers (exhaustive list, gate (b)) with any tier-1 action undelivered per §7 and noskip excluded-*line in the current generation. Pass 1: projection repairs (supporters-appendmissing) — quota-free, identity-free. Pass 2: invitations — order-preserving dedup (unique_byover paged order;uniqueremoved at thestarsoutput and thedecidere-emit), never-invited first, oldest first, take Q with refill →GET /user/{id}→ §3 rules (roster, self, bot,type==User) →PUT{"permission":"pull"};inviteresult: ok-catchup, thensupporters-append;event: sweep,tier: 1,dedup_key <repo>:1:<id>(line()parameterised). Bounded re-invite: at most 2 invitations per generation, then oneskip excluded-unresponsive(<repo>:sweep:<id>, written byact). - Quota: B = ledger
invitelines withresult ∈ {ok, ok-backfill, ok-catchup}in the last 24 h + pending invitations (GET /invitations) created ≤ 24 h with no ledger line;already-1never counts. Re-evaluated before everyPUT; cumulative wait ≤ 3 min per sweep when the window opens imminently (dynamic per candidate, never a static slice); ceiling 45 (sweep only — the event path never computes B). Invitation-limit 422: event path →invite/comment/supporters-appendalldeferred-quota(nothing sent); sweep path → one ledgeredskip/deferred-quotafor the refused candidate, catch-up stops, run stays green. Other 422s stayerror-422. Launch gate: the invitation-limit 422 message text is probed live and pinned in a fixture before merge. - Gates: catch-up pass 2 requires (a) no red run since T, (b) exhaustive stargazers, (c) token preflight. Unstar cleanup keeps (a)–(e). Cancelled runs (
status=cancelled&created>=T, event vs schedule) counted, never gating. - Regeneration:
regenerate()= GET sha → read ledger → render → PUT(sha), restart from GET on conflict; once per sweep, on every live sweep (incl. red-run sweeps); write pacing ≤ 1 content write/s across the whole sweep. - State + notifications:
ledger/<name>.sweep-state.json(last_sweep_ts,backlog,cancelled_runs,capacity_pct,alarm_state) regenerated byactwith the ledger PAT; one Telegram summary per sweep; capacity 70 % warnings and red-run condition edge-triggered. Record-only: reduced sweep indecideruns identity + §3 and writeswould-invite/would-supporters-append(tier key) orskip excluded-*; rehearsal B ledger-only; rehearsal never touches the state file. -
starsjobtimeout-minutes: 10; output guard unchanged (400 k) until measured (tracking epic). - Fixtures (all in
supporter-loop/fixtures/workflow/):deferred-quota(event, whole bundle),ok-catchup, each §3 reason on the catch-up path, ordering across pages with duplicates, 2-invitation bound →excluded-unresponsive, excluded-once filter across both key namespaces, quota window edges incl.already-1exclusion and the 24 h boundary, stop line does not self-exclude, crash-between-actions / strandedsupporters-appendrepaired in pass 1, two-lane regeneration conflict (restart-from-GET), write-rate pacing + cumulative wait cap, record-only ≡ live parity (same ledger, empty unledgered-pending set), sweep-state derivation (state ≡ f(ledger, inputs)), interface pins (starssweep-only,contents: writeonly, single GET, no secret).check-decide-static.shre-run with its violating fixtures (edit only if parsing changes). §5.3 vocabulary fixtures accept the newresultvalues. -
supporter-loop/README.mdupdated; tests + lint green; tag + GitHub Release (v0.12.0) - 5-seat review (size H, permission boundary + supporter-facing sends); merge only after caty-ai/x-collector A1 (contract v2.0) is on
main
触るファイル / モジュール予測
.github/workflows/supporter-loop-reusable.ymlsupporter-loop/README.mdsupporter-loop/fixtures/workflow/test-decide.pysupporter-loop/fixtures/workflow/test-interface.pysupporter-loop/fixtures/workflow/(new ledger/event fixtures listed above)supporter-loop/check-decide-static.sh+ its fixtures (run; edit only if parsing changes)
想定スコープ
Everything in design §2.0 + §2.1 (timeout only). Out of scope (tracking epic): ledger snapshot, SUPPORTERS.md paging, diff-only stars→decide→act hand-off, guard raise, tier-2/3 late thanks, per-run shards, GraphQL path.
前提条件 (Blocked by)
- contract v2.0 (supporter-loop scale): catch-up + invitation queue, twice-daily sweep lane, §7 key rule, capacity §16 — child A of EPIC #119 x-collector#142 A1 (contract v2.0) merged.
- After this merges: caty-ai/x-collector A3 (caller cron twice daily).
Coordination
Open lane caty-ai/x-collector#141 (v1.11 follow-up: dispatch wording, dispatch watermark, static check covers stars) touches the same files (CONTRACT.md, caller, reusable workflow). Serial: #141 first or fold its three items into A1/B — decided at WIP time, never parallel (L0-2).
Activity
shojikumaru commentedon Sep 8, 2026
🔒 WIP (alpha session, 2026-09-08): child B — implement contract v2.0 in the reusable workflow (catch-up two-pass + invitation quota queue, sweep-path 422 stop, regenerate order, sweep-state.json + summary/alarms, record-only parity,
starstimeout 10). Writer = Codex (--profile astra), commits by Alpha (worktree sandbox cannot commit), 5-seat review. Merge only after caty-ai/x-collector PR #147 (A1) is onmain.agent: alpha (orchestrator) + codex-astra (writer)
date: 2026-09-08
Files to touch:
Branch: feat/91-supporter-loop-v2 (worktree)
Folded in from caty-ai/x-collector#141 (decided at its WIP, caty-ai/x-collector#141 (comment)): item 2 — the §11(a) watermark query becomes
event IN (schedule, workflow_dispatch) & status=success; item 3 —check-decide-static.shcovers thestarsjob with a violating fixture; item 4 —alertnaming (cosmetic).Launch gate (Done when): the invitation-limit 422 message text must be pinned in a fixture before merge. Live probing needs 51 invitations on one repo in 24 h; the proposed non-spam probe (throwaway private repo + one family-owned account, PUT/DELETE cycles) is an owner decision — requested at the A1 checkpoint. Until then the workflow matches a documented pattern constant and any unrecognised 422 stays
error-422(red run), per contract §14.shojikumaru commentedon Sep 8, 2026
Candidate a8c626a pushed as PR #92 (writer Codex GPT-6 Astra; commit by alpha; local replication of the selftest workflow green; REPORT-r1.md retained under
_handoffs/dotgithub-supporter-loop-91-impl-20260908/).Review seats (size H, permission boundary + supporter-facing sends → 5): Opus 5 / Gemini 3.8 Flash / Muse Spark 1.3 / Codex GPT-5.6 Sol launched now. Codex Sol is same-lineage as the writer (Astra) — correlated-seats exception: scope = PR #92; pair = GPT-6 Astra (writer) → GPT-5.6 Sol (seat); reason = every heterogeneous CLI seat (Kimi 403 / GLM 429 / Grok 402 / Qwen silent-stall ×2) is absent 2026-09-08; approved_by = review_council 2026-08-12 (same-family Codex seat authorised for a Codex writer) — owner ratification requested with the merge GO; date = 2026-09-08; writer condition = Sol wrote nothing in this PR.
⏳ SEAT-WAIT (fifth seat): owner = alpha · missing seat = one more heterogeneous model (GLM 5.3 expected back 2026-09-10 10:00 JST; Kimi/Grok/Qwen absent) · retry-by = 2026-09-10. The four seats above run now; the fifth runs on GLM's return (or an owner-approved substitute). Merge is gated anyway on caty-ai/x-collector PR #147 and on the invitation-limit 422 launch gate (owner probe decision pending).
fix(supporter-loop): r1 delta — catch-up admits empty re-opened gener…
test(supporter-loop): scratch directories out of the repository (r2 d…
shojikumaru commentedon Sep 8, 2026
Blocker cleared: caty-ai/x-collector PR #147 (contract v2.0) is on
mainat 935354d (v0.7.1) and the caller lane split (PR #148) at 5e26e80 (v0.7.2). PR #92 (r3 3182d67) now waits only on: the fifth seat (GLM, 2026-09-10), the invitation-limit 422 text pin (owner probe decision), and the owner'srisk-reviewedlabel.shojikumaru commentedon Sep 8, 2026
SEAT-WAIT lifted (alpha, 2026-09-08): the fifth seat ran as Qwen 3.8 Max on r3 3182d67 (owner asked; launched without the sitter supervisor, whose ~20-min stall kill had ended the two earlier Qwen launches) → GO-WITH-NITS (MINOR: static-check evasion via shell string concatenation — defense-in-depth; NITs: report staleness, silent defensive branch, stale error code, extra
schemakey). Cumulative on r3: five seats, zero blocking (Opus GO · Gemini GO · Muse GO · Codex Sol GWN · Qwen GWN). Writer delta-3 running → r4 → seat confirm → completion record. Remaining owner items: the invitation-limit 422 text probe decision andrisk-reviewedon the final head.fix(supporter-loop): r3 delta (Qwen seat) — static check resolves she…
feat(supporter-loop): contract v2.0 — catch-up + invitation quota que…
shojikumaru commentedon Sep 8, 2026
🏁 MERGED (alpha, 2026-09-09): PR #92 squash → main
81539adevidence / successor: #92 (completion record; five seats zero blocking on e4b97c5 — Opus / Gemini / Muse / Qwen GO, Codex Sol GWN under the same-lineage exception; owner
risk-reviewed; launch gate = owner decision B (2026-09-09, "推奨でいこう"): provisionalINVITE_LIMIT_PATTERN, live 422 text pinned on first real occurrence — follow-up on caty-ai/x-collector#143). Record:_handoffs/dotgithub-supporter-loop-91-impl-20260908/review/record.md. Successor: caty-ai/x-collector A3 (PR #149, caller cron twice daily) — now unblocked.release: https://github.com/caty-ai/.github/releases/tag/v0.12.0 (as declared; Release exists, verified)
shojikumaru commentedon Sep 8, 2026
Closed by the MERGED record above (PR #92 → v0.12.0). #141 items 2–4 are delivered here; caty-ai/x-collector#141 closes by pointer.