Skip to content

supporter-loop reusable workflow: catch-up + invitation queue + sweep state (contract v2.0, caty-ai/x-collector#142) — child B of EPIC caty-ai/x-collector#119 #91

Closed

Description

@shojikumaru

目的 (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 no skip excluded-* line in the current generation. Pass 1: projection repairs (supporters-append missing) — quota-free, identity-free. Pass 2: invitations — order-preserving dedup (unique_by over paged order; unique removed at the stars output and the decide re-emit), never-invited first, oldest first, take Q with refill → GET /user/{id} → §3 rules (roster, self, bot, type==User) → PUT {"permission":"pull"}; invite result: ok-catchup, then supporters-append; event: sweep, tier: 1, dedup_key <repo>:1:<id> (line() parameterised). Bounded re-invite: at most 2 invitations per generation, then one skip excluded-unresponsive (<repo>:sweep:<id>, written by act).
  • Quota: B = ledger invite lines with result ∈ {ok, ok-backfill, ok-catchup} in the last 24 h + pending invitations (GET /invitations) created ≤ 24 h with no ledger line; already-1 never counts. Re-evaluated before every PUT; 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-append all deferred-quota (nothing sent); sweep path → one ledgered skip/deferred-quota for the refused candidate, catch-up stops, run stays green. Other 422s stay error-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 by act with the ledger PAT; one Telegram summary per sweep; capacity 70 % warnings and red-run condition edge-triggered. Record-only: reduced sweep in decide runs identity + §3 and writes would-invite/would-supporters-append (tier key) or skip excluded-*; rehearsal B ledger-only; rehearsal never touches the state file.
  • stars job timeout-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-1 exclusion and the 24 h boundary, stop line does not self-exclude, crash-between-actions / stranded supporters-append repaired 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 (stars sweep-only, contents: write only, single GET, no secret). check-decide-static.sh re-run with its violating fixtures (edit only if parsing changes). §5.3 vocabulary fixtures accept the new result values.
  • supporter-loop/README.md updated; 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.yml
  • supporter-loop/README.md
  • supporter-loop/fixtures/workflow/test-decide.py
  • supporter-loop/fixtures/workflow/test-interface.py
  • supporter-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)

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

  1. shojikumaru commented on Sep 8, 2026

    @shojikumaru
    MemberAuthor

    🔒 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, stars timeout 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 on main.

    agent: alpha (orchestrator) + codex-astra (writer)
    date: 2026-09-08
    Files to touch:

    • .github/workflows/supporter-loop-reusable.yml
    • supporter-loop/README.md
    • supporter-loop/fixtures/workflow/
    • supporter-loop/check-decide-static.sh
    • supporter-loop/fixtures/static/
    • supporter-loop/check-ledger.sh
    • supporter-loop/fixtures/ledger/
      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.sh covers the stars job with a violating fixture; item 4 — alert naming (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.

  2. shojikumaru commented on Sep 8, 2026

    @shojikumaru
    MemberAuthor

    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).

  3. shojikumaru commented on Sep 8, 2026

    @shojikumaru
    MemberAuthor

    Blocker cleared: caty-ai/x-collector PR #147 (contract v2.0) is on main at 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's risk-reviewed label.

  4. shojikumaru commented on Sep 8, 2026

    @shojikumaru
    MemberAuthor

    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 schema key). 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 and risk-reviewed on the final head.

  5. added
    ball:humanWaiting on a human decision (owner). Alpha removes it after the decision comment.
    on Sep 8, 2026
  6. shojikumaru commented on Sep 8, 2026

    @shojikumaru
    MemberAuthor

    🏁 MERGED (alpha, 2026-09-09): PR #92 squash → main 81539ad

    evidence / 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, "推奨でいこう"): provisional INVITE_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)

  7. removed
    ball:humanWaiting on a human decision (owner). Alpha removes it after the decision comment.
    on Sep 8, 2026
  8. shojikumaru commented on Sep 8, 2026

    @shojikumaru
    MemberAuthor

    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.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions