Skip to content
GRPNR.

Groupon Agentic Refactoring — Dossier & Factory Blueprint

2026-07-18 · synthesis of 01-ground-truth.md (repo + estate recon) and 02-web-research.md (verified industry evidence). Raw agent outputs in raw-*.json.

TL;DR

The job is not “refactor 70M lines.” ~93–97% of the legacy estate is dormant; the sanctioned doctrine (Groupon’s own encore_migration_guide plugin) is clean-break with a DELETE-first audit. The real work decomposes into three programs of very different shape:

  1. Split the monorepo 1→N — all 124 Encore services sit in ONE Encore app; target is app-per-system (~10 apps) with per-service packages and gate-enforced boundaries. Mechanical, agent-friendly, but must ride the live release train (~290 PRs/month → no long-lived branches).
  2. Migrate the living legacy frontier — ~24 _proxy_to_legacy/ wrappers point at mostly-alive Java/Ruby services concentrated in sox-inscope (compliance overhead). Per-service Temporal-orchestrated migration pipelines, clean-break by risk score.
  3. Bury the dead — the dormant 93% needs a decommission ledger, not agents rewriting it.

Industry evidence supports fleets to ~64 concurrent agents with strong verification (Bun: 1M LOC, <2 weeks, $165K, 19 escaped regressions). Nothing published validates 1000 concurrent agents — plan 1000 queued work units with a staged concurrency ramp (10 → 50 → 200 → …), gated on measured regression + rework rates. The infra bet (self-hosted Temporal + Grafana + GKE in monorepo-infra) matches the evidence exactly.


1. Factory architecture

Work unit = one service (occasionally one file-class for bulk codemods). Every unit runs the Airbnb-shape state machine as a Temporal workflow:

profile → plan → [gate: human approves plan if risk ≥ threshold]
  → port/transform (agent, retry budget ≤10; long-tail ≤50 w/ escalating context)
  → verify (build + tests + impact-analysis-selected tests + parity harness)
  → conform (arch-contract, depcruise, biome, tangling check)
  → review (adversarial agent pair → tie-breaker → CodeRabbit → human if flagged)
  → PR → merge queue → post-merge watch (deploy monitor skill)
  • State machine = Temporal workflow; retries = activity retry policy; gates = activity boundaries. Fits the existing Workflow Management service + AdminIQ UI + tribe-sharded worker pools; agentic_workflow_patterns.md already documents the agent-loop-as-durable-workflow pattern in-repo.
  • Retry with feedback beats prompt perfection (Airbnb): pipe validation errors + latest file state back in; escalate context size per attempt (40k→100k tokens, up to ~50 curated related files). Context curation (which files) is the quality lever.
  • Sandboxing: GKE pod per agent, repo checkout + git worktree inside the pod; worktrees alone don’t scale past ~10 per host. Serialize builds through one build daemon per Encore app (Anthropic pattern) — 124 services × parallel encore check on shared runners is a stampede otherwise; failed builds/tests auto-enqueue as new work items (“the queue writes itself”).
  • Model routing: the ai-gateway (LiteLLM) service already exists — route by task class (cheap models for mechanical codemods/lint fixes, frontier for porting/review), log to Langfuse (project enum already has slots).
  • Merge: today there is NO merge queue (no merge_group in 36 workflows) and the staging→production train already fights generated-client drift. Fleet volume without a queue = trunk chaos. Prerequisites in order: (1) kill test flake, (2) affected-target-scoped CI (turborepo change detection exists — extend to merge-queue groups), (3) GitHub merge queue (or Aviator if speculation depth insufficient). Merge-queue guarantee is only as strong as required-check coverage — invest there first.
  • Two-lane doctrine per service (resolve the wrapper-vs-clean-break contradiction explicitly): run the existing risk score from zblut/encore_migration_guide — 0–2 clean break (default), 5+ strangler wrapper. Dead upstreams (dmapi 2016, deal-catalog 2022, GIMS 2018) are automatic clean-break/delete candidates. SOX-scoped services get the compliance checklist lane.

2. Apps to build (build-vs-buy verdicts)

App Verdict Shape
Migration ledger / orchestrator BUILD on existing Temporal stack — no off-the-shelf product survived verification The ledger is the SSOT: one row per work unit (service/file-batch) × state × attempt count × cost × assigned agent × blocking question. Temporal workflow per unit; ledger = Encore service + Postgres (dogfood: build it as an Encore service in the monorepo); UI = extend AdminIQ. Feed initial inventory from encore-enrichment.json (124 services) + C4 model (141 legacy services/21 domains) + GHE dormancy survey.
Question-triage app (“agents ask, humans answer”) BUILD THIN — HumanLayer (the only candidate) is deprecated; replicate its two primitives (1) require_approval — blocks a tool call until a human decides; (2) human_as_tool — async open question. Routing: ORR metadata beats CODEOWNERS — every service’s .orr.ts already declares service-owner/tech-lead/product-owner emails + Google Chat URL + Jira project. Deliver to Google Chat (house standard; hall-of-shame bot precedent) with Jira fallback for SLA-breach. Must-haves industry has no answer for (design it yourself): dedup/cluster identical questions before they fan out; answers write back into .agents/skills/_documentation so the fleet never asks twice (the partner-onboarding skill’s “gap stops the run, posts exact missing fields to Jira” gate is the in-house precedent); per-stakeholder rate limit + daily digest to prevent overload.
Fleet monitor ADOPT + thin layer Claude Code native OTel (CLAUDE_CODE_ENABLE_TELEMETRY=1) → Prometheus → self-hosted Grafana (monorepo-infra stack): 8 metrics free (cost/model, tokens, sessions, LOC, commits, PRs). Import community dashboard 25255 as base, fork expected. Custom layer (OTel GenAI conventions): task success rate, review-rejection rate, rework rate (unit re-opened post-merge), retry-depth histogram, cost per merged unit, queue depth per state. These custom metrics ARE the scaling gate.
Verification harness BUILD (no product exists) Per-unit: characterization/parity tests generated before transform (record legacy behavior; any change = bug — Anthropic parity-harness pattern); graph-based impact analysis (code→test map, run high-impact tests pre-submit; ~70% regression cut is the single best-evidenced mitigation); tangling detector (53.9% of agent refactorings smuggle unrelated changes — reject or auto-split PRs); smell/quality delta gate (agents don’t improve quality by default). Contract tests on Encore API boundaries; shadow/parity traffic through the existing legacy proxies for wrapper-lane services (the proxies are ready-made comparison points: same request → legacy + new, diff responses).
Review agent fleet BUILD as skills (extend .agents/skills) Specialized reviewers per failure-mode category (Bun used 8) + adversarial pairs with tie-breaker. CodeRabbit stays as an independent third opinion. Humans review: plans (not diffs) for risky units, tie-breaker escalations, SOX lane always.
Service scaffolder PORT from encore-ts-sample pnpm gen:service (plop) exists in the sample, absent in the monorepo (creation is “copy-paste ~30 lines”). Agents must create services only through the scaffolder — services born compliant with per-service package.json + arch-contract + AGENTS.md.
Decommission ledger BUILD trivial GHE dormancy data → archive/delete queue with owner sign-off. Cheapest 90% of the “70M lines”: don’t migrate them.

3. Phased ramp (concurrency gates, not calendar)

Phase 0 — Foundations (blocks everything): merge queue + flake audit + affected-target CI; per-service package.json + dependency-cruiser gate (adopt sample’s service-deps-must-be-declared, replace bespoke check scripts); scaffolder port; ledger + telemetry live; resolve Drizzle-vs-raw-SQL rules conflict in writing (pick one — recommend keeping the monorepo’s Drizzle mandate to avoid rewriting 124 services’ data layers against doctrine); question-triage MVP (the fleet stalls on unanswered questions before anything else breaks).

Phase 1 — Pilot (≤10 concurrent): one tribe’s services into per-service packages + one app-split (e.g. carve _tribe_b2c or _core_system into its own Encore app — the 1→N split is the highest-value, lowest-ambiguity agent work available). Measure: success rate, retries/unit, regression escapes, questions/unit, cost/unit.

Phase 2 — Scale (≤50–64): the evidence ceiling. Add legacy-frontier migrations (clean-break lane first: dead-upstream proxies). Gate to advance: rework rate flat, review-rejection rate not degrading, merge queue p95 stable.

Phase 3 — Fleet (200 → 1000 queued, concurrency by telemetry): uncharted territory — you’d be the first published 1000-agent deployment. Constraint math, not vibes: merge-queue throughput (units/day) and stakeholder answer bandwidth (questions/day) bound useful concurrency long before 1000; more concurrency than the queue drains = idle burn.

Cost anchor: Bun = $165K/~1M LOC (order of magnitude). 5M live LOC ≈ high-six-figures to ~$1M in tokens if migrated wholesale — DELETE-first and the dormancy ratio cut the denominator drastically. Track cost/merged-unit in the ledger from day one; log manual/batch runs per the LLM-run-evidence rule.

4. Top risks

  1. Merge-queue absence at fleet volume — trunk breakage compounds; Phase 0 non-negotiable.
  2. Verification theater — 2,060 test files but coverage enforced only as diff-coverage on one FE app; agent regressions (6% base rate) sail through weak suites. Parity harness before porting, not after.
  3. Stakeholder saturation — hundreds of questions/day vs ~101 contributors; no industry data exists on this. Dedup + knowledge write-back + rate limits from MVP.
  4. Generated-client churnpackages/encore-client conflicts already need dedicated tooling at human PR volume; fleet volume multiplies it. Serialize gen through the build daemon.
  5. SOX lane — most-wrapped legacy lives in sox-inscope; agent PRs into SOX scope need audit-trail + human sign-off by design, not exception.
  6. Doctrine drift — wrappers accrete as “temporary” and never die (24 already). Ledger tracks wrapper-retirement as first-class work units with owners and dates.

5. Open items

  • Access: monorepo-development + monorepo-infra unreachable — GRPN2 token org-blind (pending approval or personal-scoped); org name unknown. Everything above derives from groupon/groupon-monorepo (near-certainly the same codebase) — re-verify against the real repos once access lands, especially monorepo-infra’s actual Temporal/Grafana/GKE layout.
  • Regression-rate transfer to frontier models on TS/Go: unproven — measure in Phase 1, treat pilot as the experiment.
  • Mutation testing / shadow traffic quantitative value: no published evidence — pilot-measure on one wrapper-lane service.
  • 1000-concurrent orchestration: no prior art. Temporal’s own claim (one worker handles thousands of workflows) is vendor-tier; load-test the control plane in Phase 2.