Product guide / Loops
work that continues between sessions
A matrix row your terminal can pick up.
A Loop is a row in one of your matrices that an agent can advance from the terminal or editor you already work in. It carries the objective, the rules, what happened last time, and when to check back.
| Loop | Decision | Objective | Acceptance | Stop criteria | Trigger | Autonomy | Max iterations | Method | Output | Summary |
|---|---|---|---|---|---|---|---|---|---|---|
| Collapse connector ingestion onto one rail | ADR-0026 — One ingestion rail | Move all nine third-party connectors off their private ingest paths onto the shared rail. | Zero connectors writing outside the rail; contract tests green for all nine. | A rail change needed by one connector breaks another connector twice. | weekly | propose | 12 | runbooks/ingestion/rail-migration.md | Connector Migration | Walks the nine connectors onto the shared rail one at a time, proposing a migration PR per connector and pausing if a rail change breaks a sibling. |
| Retire the v1 metrics writer | ADR-0029 — Single metrics writer | Remove every call site of the v1 writer, then delete the module. | Module deleted; no import of metricsV1 anywhere in the tree. | A call site needs behaviour v2 cannot express — reopen the decision, never work around it. | event | apply | 20 | runbooks/metrics/retire-v1-writer.md | Call Sites | Grinds the v2-only decision through the codebase one batch of call sites at a time, stopping the moment a site needs behaviour v2 lacks. |
| Replace per-tenant schemas with row-level security | ADR-0031 — RLS over schema-per-tenant | Migrate all 340 tenant schemas to shared tables carrying RLS policies. | One schema; every table carries a policy; isolation tests pass on all 340. | P95 query latency regresses more than 15% once policy indexes land. | manual | propose | 15 | runbooks/db/rls-tenant-migration.md | Tenant Cutover | Migrates tenants in cohorts behind a latency budget, proposing each cohort and holding until the previous one is clean. |
| Route dashboard reads to the replica | ADR-0034 — Reads leave the primary | Point every dashboard query at the read replica behind a routing helper. | The primary sees zero dashboard reads for seven consecutive days. | Replica lag exceeds five seconds under peak load on two separate days. | daily | apply | 10 | runbooks/db/replica-read-routing.md | Query Sites | Moves query sites onto the routing helper and watches replica lag daily, reverting the batch itself if lag breaches the budget. |
| Consolidate three job runners into one | ADR-0037 — One scheduler | Move every scheduled job off Sidekiq and cron onto the platform runner. | One runner in production; the other two gone from the deploy manifest. | The platform runner drops a job in production even once. | weekly | propose | 12 | runbooks/platform/runner-consolidation.md | Job Inventory | Ports jobs in weekly batches, each with a shadow run against the old runner before the old definition is deleted. |
| Put every telemetry event in a typed envelope | ADR-0041 — Typed event envelope | Wrap all emitted events in the shared envelope, then reject untyped ones at the edge. | The edge rejects untyped events; 30 days with zero rejections in production. | Envelope overhead adds more than 2ms to the emit path. | event | apply | 16 | runbooks/telemetry/typed-envelope.md | Emitters | Types emitters as they are touched by other work, then flips the edge to reject-by-default once the untyped count reaches zero. |
| Deprecate the legacy CSV importer | ADR-0044 — One import path | Migrate the remaining accounts off the legacy importer, then delete it. | No account has touched the legacy path for 60 days; module deleted. | An account cannot migrate without losing its column mappings. | monthly | propose | 8 | runbooks/import/legacy-csv-sunset.md | Account Migration | Contacts remaining accounts monthly with a mapping-preserving migration, and escalates any account whose mappings the wizard cannot express. |
| Move caching from the API layer to the query layer | ADR-0048 — Cache where the cost is | Remove API-level response caching and cache at the query planner instead. | API cache removed; hit rate at the query layer above 70%. | Hit rate stays under 40% after three tuning passes. | weekly | propose | 10 | runbooks/perf/query-layer-cache.md | Cache Sites | Blocked behind the replica cutover; tunes planner cache keys once reads have moved, and abandons the decision if hit rate will not clear 40%. |
| Collapse five auth paths onto the session service | ADR-0052 — One session service | Retire the SAML, OIDC, magic-link, API-key, and legacy cookie handlers into one service. | All five paths served by the session service; the old handlers deleted. | Any enterprise SSO tenant fails to authenticate after a cutover. | weekly | propose | 18 | runbooks/auth/session-service-cutover.md | Auth Paths | Cuts one auth path over per cycle behind a flag, with a tenant watch window before the next path is touched. |
| Route every export through the policy check | ADR-0055 — No unchecked export | Ensure no export path can bypass the workspace policy check. | Every export call passes the checker; the bypass suite is green. | The checker adds more than 200ms to a 10k-row export. | event | apply | 6 | runbooks/exports/policy-gate.md | Export Paths | Closed: all six export paths now call the checker, and a bypass test guards each one against regression. |
Execution & collaboration
What it actually is.
A matrix, so loops live where the rest of your structured work already lives.
Reachable from the Operalta CLI, or from any agent connected through it.
Each pass records what changed, so the next one starts from there.
You set what finished looks like, and when to stop, up front.
Loops in the real world
We use it to ship our own architecture work.
Our architecture decisions generate a queue of changes the codebase needs. That queue is a Loops matrix, and agents pick items up from the terminal: prioritize what matters this week, do a bounded piece, record what changed, stop at the checkpoint.
Nothing about it is exotic. It is the matrix system plus the tools you already have open — which is why the loops that matter end up in one place instead of in six people’s heads.
What holds up
What it does well, and what it was never meant to do.
Constraints are a design position, not an apology. Everything on the left ships today; everything on the right we decided against.
What you can rely on in Loops
- Managed in the Loops matrix and stepped from the loop card.
- Step a loop yourself, or let a connected agent step it for you.
- Runs on demand, daily, or weekly.
What we chose not to build
- A Goal Loop is not an objective or an OKR. "Reduce churn below 1.5%" is a target a team owns; a loop is bounded work an agent can pick up, with a stated end and a stated stop.
- Only a person ends a loop, in either direction.
- Progress is written by the loop as it runs, never typed in. State, iteration count, and last delta are not fields you fill.
- A loop works inside Operalta, not across arbitrary external systems.
Outputs & automation
The loop board as CSV, through its matrix · The loop specification as an Artifact · Each pass’s recorded change, readable from the loop card or a connected agent
None of this is trapped in the interface. The same API and CLI that produce these outputs are how you drive Operalta from your own tools — a script, a terminal, or another product entirely.
Works with
Where Loops hands the work on.
Decisions rarely stop where a product does. These are the guides that pick the work up next.
For your company
See how Operalta fits your company.
Bring one current decision or process. We will map it together.