examples gallery
The leaf gallery, on one page
The shipped examples, one per tab, every widget live: boards drag, options take a pick, diagrams render. Every project, name, and number here is invented. Switch tabs freely (that's your view alone); select any text to comment on the example it belongs to.
Where sessions live
The monolith split leaves session state homeless: today it rides the app server's memory and dies with it. Three candidates, one recommendation — Redis with a signed-cookie fallback. Click an option — or Tab to its mark and press Enter — to decide; your pick reaches the agent directly.
Constraints
- Logout must revoke immediately — support runs "log out all devices" during account-takeover response.
- Session writes happen on every request (rolling expiry), so the store sees full request volume.
- The team already operates Redis for rate limiting; nobody runs Dynamo-style infrastructure today.
Settled last week
How the session id travels was decided before this page and the client change is merged, so it reads as one line — open it if you want the alternatives.
How payments were asked
Payments settled the same question in March. Their page put it in two cards with the operating cost on the front of each, which is a framing worth copying. Their answer travels less well, since they had a tenth of our write volume and nothing that had to survive the store going down.
- Writes
- a tenth of ours
- Store down
- queue and retry
A payment is seconds long, so a Redis blip is a spinner and a retry, and nothing about their answer had to outlive the store.
- Writes
- every request
- Store down
- readers stay signed in
Rolling expiry writes on every request, and an outage must not sign the fleet out — the constraint their page never had to argue.
Options
- Revoke
- build a denylist
- Outage
- unaffected
- New ops
- none, at first
Sessions become signed tokens; no store at all. Revocation requires a denylist, which quietly reintroduces the store — with the hard parts (replication, expiry) still attached, and the account-takeover response waiting on them.
choose one- Revoke
- delete the key
- Outage
- reads ride the cookie
- New ops
- what we already do
Sessions in the Redis we already run, keyed by an opaque id; a short-lived signed cookie covers Redis outages for reads, so a blip doesn't log everyone out. Revocation is a delete — which is the shape support's "log out all devices" needs.
- Revoke
- delete the row
- Outage
- shares the database's fate
- New ops
- vacuum pressure
One table, no new moving parts. Every request writes a row (rolling expiry), so at our volume that's the primary's headroom spent on expiry bookkeeping — and a session outage becomes a database outage.
choose oneThe two cookies
One revision is waiting on you below: accept or reject it with the controls in the margin, and the next version carries whichever you chose.
What I pick up next
Whichever store wins, three jobs stand behind it, and each is argued somewhere above rather than in a card of its own. Pick the ones worth starting — click a row, or Tab to its mark and press Enter — and the box takes anything the rows don't cover, including "none of these".
Export queue backlog, 12 June
A retry storm from one malformed workspace held the export queue for 94 minutes. No exports were lost; the oldest was delayed 81 minutes.
- Detected
- 09:14, queue-depth alert
- Resolved
- 10:48, poison job quarantined
- Blast radius
- exports only; imports and sync unaffected
Timeline
Root cause
The export worker treats any failure as retryable. One workspace carried an attachment with a declared size of −1, which fails serialization every time; with retries capped by attempt count but not by queue position, the job returned to the head on each attempt and starved everything behind it.
Follow-ups
- Classify worker failures as permanent vs. retryable; dead-letter permanents on first failure.
- Re-enqueue retries at the tail.
- Alert on a single job id exceeding five attempts, not only on queue depth.
Per-token rate limits
Moves rate limiting from per-IP to per-token, so one office NAT can't exhaust the budget for every client behind it. Three files, one new bucket table, no behavior change for untokened requests.
Shape of the change
- gateway/
- limits.py+38-9
- middleware.py+6-2
- migrations/
- 0042_token_buckets.sql+11
The interesting part is
gateway/limits.py:41: the bucket key changes from the remote address to the token id when one is
present. Everything else is plumbing that key through.
The ceilings themselves
None of these numbers move. What moves is what they are counted against: a plan's ceiling used to be spent by every client behind one address, and is now spent per token.
| Plan | A minute | Burst | Counted against |
|---|---|---|---|
| Free | 60 | 120 | the token |
| Team | 600 | 1,200 | the token |
| Enterprise | 6,000 | 12,000 | the token, per environment |
| Untokened | 60 | 60 | the remote address, as before |
The core diff
gateway/limits.py+4 −2
@@ -38,9 +38,11 @@ class Limiter: - def bucket_key(self, request): - return request.remote_addr + def bucket_key(self, request): + if request.token: + return f"tok:{request.token.id}" + return f"ip:{request.remote_addr}" def allow(self, request): key = self.bucket_key(request) return self.buckets[key].take()
Why the prefixes matter
def bucket_key(self, request): if request.token: return f"tok:{request.token.id}"return f"ip:{request.remote_addr}"Unprefixed, a token id that happens to look like an IP would share a bucket with that address. The prefixes make the two namespaces disjoint.
Testing
- Unit: bucket key for tokened, untokened, and both-present requests.
- Integration: two tokens behind one address each get a full budget; two addresses on one token share one.
Both suites run under the rate-limit marker:
# the integration half needs the migration applied first
cd gateway && alembic upgrade head
pytest tests/ -m ratelimit --maxfail=1
Search relaunch, week 6
Indexing is done and dark-launched; relevance is the open question. The shadow comparison puts the new engine ahead on head queries and behind on long-tail, which is the expected trade at this stage.
Milestones
The long-tail gap
The old engine's synonym table carries fifteen years of manual curation; the new engine currently ships without it. On tail queries where a synonym was the match, we lose the document entirely, which is most of the −0.03.
Evidence: 61% of tail regressions disappear with the table patched in
A one-hour experiment loading the March export into the new engine's synonym slot recovered 214 of 349 regressed queries. The remainder split between stemming differences and genuine ranking changes.
Next week
- Import the synonym table export when it lands Tuesday.
- Re-run the shadow comparison on the tail set.
- Draft the cutover guardrails (error rate, zero-result rate, p95).
Checkout cutover rehearsal
The agent republishes this page as each check finishes. The browser is following the newest version, so statuses and counts change without a refresh. The rollback drill is running now.
Right now
Work
Blocked
Finance export reconciliation needs a fixture with a partially refunded order. The rest of the rehearsal does not depend on it; the agent left the check open and moved on.
Latest events
Release triage
Everything open against the v2.4 release. Drag cards to re-triage — or Tab to a grip and press Enter, then arrows: each move reaches the agent as an action, and the next version of this page ships with the board as you left it.
Triage notes
The migration stamp bug is the only one with data risk; it blocks the release even if the fix slips a day. The logout fix is trivial but touches the auth path, so it rides the same release train rather than a hotfix.
Atlas importer rewrite
The standing view of the rewrite: what each agent holds, where every task stands, and the decisions waiting on you. The orchestrator republishes as work moves, so the page keeps up on its own — what it needs from you is the one section below the numbers.
Needs you
Two items, one decision each. The tree's ambers are the milder tier — work finished and readable whenever you sit down; they queue, they don't interrupt. Everything else on the page is news, not a request.
Land the schema migration?
The migration adds the two nullable columns the reconciliation work writes
into. It touches schema/atlas.sql, which is in the overlap zone,
so it holds for your word rather than landing on green tests — file-disjoint
tasks still meet in this schema, which is why it is listed. Landing it
unblocks the variance report; holding it keeps main untouched but idles finch
after today. Click an option to decide.
The reconciliation fixture is yours
Reconcile ledger exports is blocked on a fixture with a partially refunded order, which only you can pull from the production replica. One command, pasted in a comment here, unblocks it.
Work
The plan as it stands, counted by its leaves. Amber means finished by its agent and waiting on your review; red is stuck, and says on what.
Agents
| Agent | Task | Branch | Last report |
|---|---|---|---|
| wren | CDATA edge cases | atlas-cdata |
12 min ago |
| finch | Schema migration | atlas-schema |
1 h ago |
| junco | Ledger reconciliation | atlas-ledger |
3 h ago |
Feed
Standing policy
Tasks are scoped not to share files, branch from the same base commit, and
merge one at a time after a test run against current main. Mechanical changes
land on green; anything touching schema/, auth/, or
a public contract holds for your word, however green the tests. The grant is
yours, recorded below — click to tighten or revoke it any time — and any
landed change is a revert away for as long as you care to look.
Release notes, drafted
Four notes cover everything user-visible in 3.2. Each is a draft you own: double-click one (or its ✎) and rewrite it until it reads right — the exact wording reaches me, and the next version of this page carries it. The framing lines are mine, and one of them is a rewrite I'm proposing: accept or reject it in the margin, or select it and comment if it needs discussing first. When the set reads well, sign off; if a note shouldn't ship at all, say so in a comment.
CLI
API
Kept deliberately dry — the Sunset header does the announcing, and the migration guide carries the detail.
Console
The run list grew a status column, so a failure now reads off the list instead of costing a click each. It is the release's only visual change.
Operations
The minute figure is from staging (1.1M rows) — rounded rather than promised.
The minute figure is from staging (1.1M rows) on a warm cache — rounded rather than promised. If operators will book a window around it, the note should give a range instead.
Left out on purpose
The dependency bumps and the flaky-test fixes stay in the changelog only — nothing a user would change behavior over. If one of them deserves a note after all, say so in a comment and a draft for it arrives in the next version.
Aviary projects, week 3
Three mini-projects run side by side; each tab below is one project's full context — status, board, decisions. Which tab is open is your view alone: switching isn't a comment and doesn't reach the agent.
The south pair is up and drawing traffic; the north pair waits on brackets. Drag cards to reprioritize — your edits reach the agent directly.
The bracket order goes in on Friday and there is room in it. These are the extras the south pair turned out to want.
The basin is level and holding water; the open question is how to keep it liquid through January. Click an option to decide.
The feed has been stable since the battery swap; one open follow-up on storage.
Next: rotate clips to the shed NAS before the card fills, likely week 4.