A day in the life of `/challenger`: 4 bugs, 4 hypotheses falsified before the fix
Source: Dev.to
The morning I thought it was one single day
Saturday May 16 – 08:10 am
Lukewarm coffee in Françoise’s mug — inherited from an office birthday. The overnight Sentry board shows an isolated red dot on a 3 am cron, and a voicemail from Catherine that arrived at 7:50 am:
“Hum, it bugs. But it’s quickly fixed.”
Seven words in her usual tone, neither urgent nor worried, the obviousness of a day that starts with a ticket to close before the others.
Catherine is almost never wrong on the first half of her sentence, and she’s sometimes wrong on the second. Today’s “bug” isn’t a bug; it’s four. Between the 8 am and the 6 pm incidents lies a whole day that looks like one thing from afar and four very different things up close.
We tend to count incidents by tickets, messages, sessions – i.e., by symptoms. Counting them by falsifiable hypotheses means finding four where we thought we only had one.
1️⃣ 08:00 am – Duplicate signatures in the attendance PDF
Catherine reports that one of the branch’s courses shows each student signed twice in the PDF.
Productive reflex: “The form double‑posts on double‑click; add a unique‑constraint and move on.”
Result: Fifteen lines of migration – wrong.
/challenger skill
Hypothesis (one sentence):
“The
emargements ↔ seancesjoin returns N × M rows when a course has multiple sessions generated for the same date.”
Three probes (to refute, not to confirm):
-
How many sessions for this course on this date?
SELECT cours_id, date_seance, COUNT(*) AS n_seances FROM seances WHERE date_seance = '2026-05-16' GROUP BY cours_id, date_seance HAVING COUNT(*) > 1;Result: 4 courses affected, 18 doubled sessions (school‑year filter mis‑wired).
The output refutes the double‑click hypothesis and confirms a deeper drift: the session generator ran two passes because the getAnneeScolaire(date) filter was mis‑wired between 2025‑2026 and 2026‑2027 at the start of the new school year.
Cost: probe ≈ 90 s.
Avoided rollback: ≈ 30 min (commit → deploy → Sentry → Catherine → callback).
Ratio: 6 : 1.
2️⃣ 11:00 am – Missing pedagogical notes after trainer replacement
A trainer reports that the pedagogical notes entered at the end of an attendance form don’t reappear when another trainer replaces her for the next session.
Surface hypothesis (seductive): “The form doesn’t preload the previous attendance’s notes.” → a useEffect fix.
/challenger hypothesis (reformulated)
“The
notes_formateurfield is bound to the signing user’s identifier, not to the course or session, so a replacement by another signatory legitimately masks the notes entered by the regular trainer.”
Three probes:
a. Read the schema.
b. Read the component.
c. Ask the trainer herself (no technical probe can decide if it’s a bug or a business choice).
/ask‑3‑options‑before‑code (doctrine v0.7)
Before writing a line, formulate three non‑technical options to arbitrate:
- Notes are per‑session and visible to all successive signatories.
- Notes are private to the signatory and never shared.
- Notes are shared within a course’s pedagogical team but hidden from occasional replacements.
Decision: The trainer chooses option 2.
Result: No bug, just a design choice that deserves a written decision (mini‑ADR).
Outcome: 0 lines of code, 2 min discussion.
Note – A rushed solo dev would have implemented option 1, causing three user complaints the following week (trainer’s notes exposed branch‑wide).
3️⃣ 02:00 pm – Unexpected vertical line in the planning editor
The planning editor displays a thin vertical black line on a single column, crossing the grid from top to bottom.
Eye‑test hypothesis: “CSS leak.”
/challenger hypothesis
“An orphan event surfaces an empty row that renders as a thick border because a course deletion didn’t cascade‑delete its sessions.”
Three probes:
- Inspect the DOM.
- Run a consistency query on orphan
seances. git blameon the component.
Result: The third probe wins. A recent commit added a conditional to visually separate branches, branching on an isLastOfAtelier variable mis‑calculated at the table edge. It’s an interface border, not a database ghost.
Fix: One TypeScript line, no migration, ≈ 2 min.
Had I started by searching the database, I would have wasted an hour inspecting courses and sessions that had nothing to reproach.
4️⃣ 06:00 pm – Wrong day printed on emergency paper attendance sheet
An emergency paper attendance sheet prints “Thursday 2 pm” whereas the course is “Wednesday 2 pm.”
Self‑diagnosis: “The PDF prints the session date, not the course date.” → commit without a probe.
Rollback (25 min later): All sheets now say “Wednesday,” including Thursday courses. Sentry raises three alerts in five minutes. Catherine, on her end, didn’t call back; she wrote “hum, it bugs” and left me alone with the fatigue.
Real cause (detectable with a 90‑second probe)
creneau_label is stored in LSC Cache without a refresher, diverging for three weeks for courses whose jour_semaine was corrected without propagating the label.
Lesson: Even under fatigue, a quick probe can prevent costly rollbacks.
Take‑aways
| Time | Issue | /challenger hypothesis | Probes used | Fix type | Time saved |
|---|---|---|---|---|---|
| 08:00 am | Duplicate signatures | Join returns N×M rows | SQL count query | DB migration (incorrect) → deeper fix | ~30 min |
| 11:00 am | Missing notes | Field bound to user ID | Schema, component, user interview | ADR (no code) | 2 min |
| 02:00 pm | Vertical line | Orphan event → empty row | DOM, DB query, git blame | 1 TS line | ~1 h |
| 06:00 pm | Wrong day on sheet | PDF uses session date | – (none) → rollback | Cache refresh needed | 25 min rollback + alerts |
Key principles
- Formulate a falsifiable hypothesis before diving into code.
- Run quick, targeted probes (SQL, DOM,
git blame, stakeholder interview). - Prefer non‑technical arbitration when the issue may be a design decision.
- Document decisions (mini‑ADR) to avoid future “patch‑by‑ear” fixes.
By treating each incident as a hypothesis‑testing exercise, the day that looked like a single bug turned into a disciplined, four‑step investigation—saving time, code churn, and user frustration.
Overview
The issue isn’t a PDF bug; it’s a Live/Snapshot/Cache categorisation bug that was already documented in the doctrine and flagged by the ADR‑0024 audit a month earlier as a structural incident class.
“An agent that doesn’t contradict us isn’t a counterpart, it’s a faster typist; a skill we skip in the evening is no longer a skill, it’s an abandoned rigour.
The cost isn’t in the occasional skip, it’s in what the skip reveals — that the protocol relies on human discipline, not on a material mechanism still blocking enough to intercept end‑of‑day fatigue.”
Skill definition (excerpt)
File: ~/.claude/skills/challenger/SKILL.md
name: challenger
description: |
Force the formulation of a hypothesis in 1 sentence
then the execution of 3 material probes designed to REFUTE
this hypothesis before any fix code.
Daily bug‑handling summary
| Bug # | Observation | Action | Time saved |
|---|---|---|---|
| 1 | Probe held | Fix correct | ½ hour |
| 2 | Protocol diverted toward the business question | 2 minutes (instead of a user regression) | — |
| 3 | Probe held | One‑line fix | 1 hour |
| 4 | Protocol skipped | 25 minutes rollback + Sentry alert + journal note | — |
Key insight: Three fixes prevented one rollback. The ratio speaks louder than the average. The skill doesn’t eliminate the error; it prevents the third hour of the same error.
Metaphor
“You don’t fire a piece before checking the slip layer.
The firing is the commit.
The slip is the probe.
Skipping the slip because you’re in a hurry is what makes the piece crack in the kiln.”
Time‑impact calculation
- 5–10 minutes of probing → 20–30 minutes avoided in the fix‑then‑rollback cycle.
- On a single day the math is trivial; over 60 days it becomes crushing.
- If even one of the four probes saves you the rollback you experienced yesterday evening, the protocol has already paid for itself.
References
- Skill:
/challenger, Counterpart Toolkit v0.7 R4 – Falsify before fix - Public repo:
- Article #54 of the series My ERP with Claude Code – Autopsy of one day of four chained incidents.