Real Examples
These are real files from building Backdrop, a crypto intelligence platform (read the case study). They’ve been sanitized but not polished. This is what the system looks like after months of daily use.
A real sprint doc
This is from a 48-hour launch sprint covering article publication, interactive site deployment, and distribution. Notice how the sprint changed shape after it started — that’s normal.
# Sprint 11 — 48-Hour Launch: Substack + Interactive Site + Distribution
**Status:** In Progress**Duration:** 2026-02-25 to 2026-02-27
## Sprint Order
| # | Ticket | Title | Status | Est ||---|----------|------------------------------------|------------------|---------|| 6 | TASK-004 | Create OG Image / Social Card | ✅ COMPLETE | 1 hr || 7 | TASK-005 | Final Polish Substack Draft | ✅ COMPLETE | 1.5 hr || 8 | TASK-019 | Make Substack CTAs More Visible | ✅ COMPLETE | 0.5 hr || 9 | TASK-020 | LinkedIn Distribution Post | ✅ DRAFT COMPLETE| 0.5 hr || 10| TASK-021 | Instagram Story | 🔲 OPEN | 0.25 hr || 11| TASK-022 | Facebook Distribution Post | 🔲 OPEN | 0.25 hr || 12| TASK-006 | X / Reddit / HN Distribution | 🔲 OPEN | TBD |
## Key Decisions
- **TASK-019** — Reader feedback: both interactive companion CTAs were invisible when skimming. Bolded and cleaned up copy. (This was discovered after publication — not planned.)
- **BUG-050** — Briefing endpoint was returning misleading errors. Root cause: Anthropic API credit balance depleted, not rate limits. Fix made error messages actionable.
- **BUG-051** — During manual testing at 6:24 AM UTC, system allowed generating "evening" briefing when it should auto-detect "morning." Added time-of-day detection logic.
## Remaining Work (prioritized)
1. BUG-051 — Auto-detect briefing type (code ready, testing)2. TASK-020 — Publish LinkedIn post3. TASK-021 — Instagram story4. TASK-022 — Facebook distribution post5. TASK-006 — X / Reddit / HN distributionWhat to notice: The sprint changed shape after it started. TASK-019 came from reader feedback after publication. BUG-050 was found during testing. BUG-051 was found while verifying BUG-050. None were in the original plan. All were documented immediately and prioritized against existing work. The “Key Decisions” section explains why, not just what — that’s the context that prevents the same misdiagnosis next time.
Real ADRs
ADR-001: Use Sonnet over Haiku for Briefings
This wasn’t just a config change. It set a precedent — quality over cost for customer-facing features — and recorded evidence that would otherwise be lost.
# 001. Use Claude Sonnet for Briefing Generation
**Date:** 2025-12-29**Status:** Accepted
## ContextThe briefing agent was using Claude Haiku (cheaper, faster) to generatedaily intelligence briefings. Testing revealed Haiku consistentlyhallucinated content despite explicit anti-hallucination prompts.
Problems observed with Haiku:- Added non-existent facts ("FalconX CEO", "SEC restructuring")- Mentioned entities not in source data ("Binance CEO CZ")- Couldn't reliably follow complex instruction sets- Generic filler language despite explicit prohibitions
## DecisionUpgrade to Claude Sonnet for all briefing operations.Haiku remains in use for entity extraction (batch, low-complexity).
## Key Tradeoff- Cost: ~12x more per token ($0.18 vs $0.015 per briefing)- Monthly impact: ~$11/month (up from ~$1/month)- Quality: Zero hallucinations in 10+ test briefings (from frequent)
## Why not just improve the prompts?Multiple prompt iterations already failed. Haiku fundamentally struggleswith complex instruction sets. The quality risk for customer-facingbriefings was unacceptable.The “Why not just improve the prompts?” section is the most valuable part. Without it, someone would reasonably suggest exactly that. The ADR explains why that path was already tested and failed.
ADR-003: Compute-on-Read for Signal Scoring
This changed the fundamental data architecture — from background pre-computation to on-demand calculation.
# 003. Signal Scoring: Compute on Read
**Date:** 2026-01-05**Status:** Accepted
## ContextSignal scores were stale — 1145 entities had scores, but none updatedin 24+ hours. Root cause: the background worker only refreshed entitiesmentioned in the last 30 minutes. If an entity wasn't mentioned for 2hours, its score became stale because old mentions didn't "age out."
Key finding: Briefings (the primary consumer) use narratives, notsignal scores. Signals serve as supplementary context only.
## DecisionCompute on read: calculate signal scores on-demand when the API iscalled, cache for 60 seconds in Redis.
## Alternatives rejected
**Time-bucketed aggregates:** Pre-compute hourly stats, sum on read.Rejected as over-engineered for current usage patterns.
**Fix the worker:** Expand refresh scope to all entities with scores.Rejected as a band-aid that doesn't address the root issue — pre-computation isn't necessary for the current use case.
## Consequences- Signals are always fresh (no stale data ever)- Simpler architecture (removed background worker complexity)- First request each minute may be slower (2-5s compute)- Cannot easily query historical signal trendsNotice how the context section identifies the root cause precisely — not just “scores were stale” but exactly why. That level of detail means the decision can be re-evaluated later with full information, not guesswork.
ADR-012: Redis-Cached Entity Articles
A multi-phase performance redesign that introduced new infrastructure dependencies and staleness tradeoffs.
# 012. Redis-Cached, Time-Bounded Entity Articles for Signals
**Date:** 2026-02-25**Status:** Implemented
## ContextEntity articles endpoint hitting 43-48 second latency for high-volumeentities (Bitcoin). MongoDB Atlas M0 can't handle the $lookup-basedaggregation. Signals page effectively unusable.
## Decision1. Enforce strict 7-day timeframe filter2. Replace $lookup with two-pass query (mentions → article IDs → articles)3. Cache in Redis with 15-minute TTL4. Add concurrency guard to prevent Mongo stampedes5. Keep lazy-loading in frontend
## Implementation (5 phases)- Phase 1: Time-bounded cutoff → <1s warm, <3s cold ✅- Phase 2: Redis cache layer → <200ms warm ✅- Phase 3: Cache warmer for high-traffic entities ✅- Phase 4: UI cleanup ✅- Phase 5: Observability and parameter validation ✅
## ResultSignals page: <5s cold (from 52s)Entity articles: <1s warm (from 48s)This one’s unusually detailed for an ADR because of the phased implementation. For a multi-phase performance fix, the execution history is part of the decision record.
A real ticket
This is from the Backdrop build. Tickets are the most frequently created file — every fix, feature, and discovery becomes one.
---ticket_id: TASK-019title: Make Substack CTAs More Visiblepriority: mediumseverity: lowstatus: COMPLETEdate_created: 2026-02-25effort_estimate: 0.5 hr---
# TASK-019: Make Substack CTAs More Visible
## Problem Statement
Reader feedback after publication: The interactive companion links were invisible when skimming. Two CTAs for the interactive companion were buried in body copy without visual prominence.
---
## Task
1. Find both interactive companion CTAs in the Substack article2. Bold them and clean up surrounding copy3. Test on mobile (Substack reader layout)
---
## Verification
- [ ] Both CTAs are visually distinct (bold)- [ ] Copy flows naturally with bolding- [ ] Mobile rendering looks good in Substack app
---
## Acceptance Criteria
- [ ] Interactive companion CTAs bolded- [ ] Copy edited for clarity- [ ] Deployed to Substack and testedWhat to notice: This ticket came from reader feedback after publication — not from planning. It was discovered during the sprint, documented immediately with the same format as planned work, and prioritized against existing tasks. The effort is small (0.5 hr) because the problem statement is specific and actionable. Whoever picks this up (you or an AI agent) knows exactly what changed, why it matters, and how to verify it’s done.
A real session-start file
This is from mid-sprint. It’s not polished — it’s functional. It tells you and the agent exactly what’s happening and what’s next.
# Session Start — Briefing Generation & Distribution Posts
**Date:** 2026-02-26**Status:** 🔧 IN PROGRESS
---
## Previous Session: ✅ COMPLETE
- ✅ TASK-019: Made Substack CTAs more visible (bolded, cleaned up copy)- ✅ TASK-020: LinkedIn post drafted and finalized
## Current Session: 🔧 IN PROGRESS
### BUG-050: Briefing Force Parameter (FIXED & DEPLOYED ✅)Fixed the /api/v1/briefing/generate endpoint which was not providingclear feedback when force=true. Key discovery: briefing generationfailures were caused by depleted Anthropic API credit balance, notrate limits.
**File:** src/crypto_news_aggregator/api/v1/endpoints/briefing.py
### BUG-051: Auto-Detect Briefing Type (IN PROGRESS)During manual testing at 6:24 AM UTC, system allowed generating"evening" briefing when it should auto-detect "morning."Fix implemented, testing in progress.
---
## Next Up (prioritized)
1. BUG-051 — Complete testing of auto-detect briefing type2. TASK-020 — Publish LinkedIn post + link in first comment3. TASK-021 — Draft + post Instagram story4. TASK-022 — Draft + post Facebook distribution post5. TASK-006 — X / Reddit / HN distribution posts
---
## Key Links
- Substack article: [link]- Interactive companion: [link]- Vercel site: [link]
---
## Files
- Sprint doc: current-sprint.md- Tickets: task-020.md, task-021.md, task-022.mdWhat to notice: It starts with what just happened — instant context without reading the full sprint doc. Active work includes the key discovery (credit balance, not rate limits), not just the fix. “Next Up” is a prioritized list an agent can act on immediately. Key Links and Files are reference pointers — session-start doesn’t contain all context, it points to where context lives. That’s what keeps it short and fast to read.
How it gets updated: At the end of every session, the agent moves completed work to “Previous Session,” updates “Current Session” with what’s in progress, re-orders “Next Up,” and adds any new blockers or discoveries. The file is always a snapshot of right now — not a history log.