Appearance
Learnings
Durable, searchable memory of problems already solved — so the next task starts from what the last one taught instead of rediscovering it. This is Tempo's "compounding" layer: each non-trivial fix leaves a trace that planning reads before it plans.
Written by the find-learnings skill; read by find-untracked-work and build-sprint during their PLAN phase, and by anyone debugging a familiar smell.
Why markdown in the repo (not a vector DB)
Git-native, diffable, and already indexed by codegraph + grep — no second runtime, no embedding store to rebuild, survives the ephemeral web container because it's committed. A heavyweight semantic memory (e.g. mempalace) buys little for a single-user repo and costs an ops tail. Revisit only if this directory grows past the point grep can serve.
Entry format
One file per learning: YYYY-MM-DD-short-slug.md.
markdown
---
date: 2026-06-02
tags: [todoist, priority, off-by-one]
status: active # active | graduated | archived
graduated_to: # path in .claude/rules/ or CLAUDE.md, once promoted
---
# <one-line title — the trap, not the feature>
**Symptom** — what was observed (the failing test, the wrong output, the 500).
**Root cause** — the actual why, one or two sentences. No narration of the hunt.
**Fix** — what changed, with `file:line` or a commit SHA.
**Guard** — the test / rule / convention that now stops a regression. If this
hardened into a convention, say which rule file it belongs in.Lifecycle
- active — a live gotcha worth recalling.
- graduated — recurred or hardened into a standing convention; promoted into
.claude/rules/*orCLAUDE.md, and the entry'sgraduated_topoints there. Keep the entry (it's the provenance); stop treating it as loose. - archived — the code it described is gone; kept only for history.
Run find-learnings with --refresh to sweep for entries to graduate or archive.
Index
<!-- Newest first. The find-learnings skill prepends here. -->
- 2026-06-23 — Storybook serves no
public/assets withoutstaticDirs— absolute asset paths 404 - 2026-06-23 — Playwright
fullPagefloors at the viewport height — short stories capture with dead space - 2026-06-23 — reg's report is a directory tree keyed by file path — the path IS the label, no display-name field
- 2026-06-23 — A page's
<Teleport>target in the Storybook decorator leaks content into the capture unless hidden - 2026-06-23 — Most agent failures are configuration failures — debug the harness first (graduated → glossary north star)
- 2026-06-22 — A stale work branch silently disables repo-resident guardrails (docs + their hooks)
- 2026-06-22 — A
Skilllaunch that returns only "Launching…" hasn't given you the procedure — read the SKILL.md - 2026-06-22 — Minimise the cost of ownership — own only what pays for itself (min-maxing software costs) (graduated → CLAUDE.md)
- 2026-06-20 — Webhook-only state drifts silently — pair every webhook with a periodic reconcile
- 2026-06-20 —
trans_choiceauto-injects:count— passing['count' => $count]is redundant - 2026-06-20 — Running the pest-browser suite as parallel separate processes hangs
- 2026-06-19 — A wired gate that matches the wrong case never fires — and a case-mismatched fixture hides it
- 2026-06-19 — A Pest browser test's JS clock isn't faked by
travelTo— assert clock-independent values - 2026-06-18 —
orWhere([...])ORs its own array members — it's not the AND-groupwhere([...])is - 2026-06-18 — A live "regenerate the whole plan" must not rebuild on completion — it wipes the completed-row state
- 2026-06-18 — Two independently-green PRs can combine to break
main— neither re-ran against the merge - 2026-06-18 — Passport keys are needed even to return a 401 — an HTTP-auth test 500s without them
- 2026-06-18 — Assert the whole render with
toBe—toContainleaves array-element and blank-line mutants alive - 2026-06-18 — Adding a laravel/ai
ProviderTool(e.g.WebSearch) needs theTool|ProviderTooldocblock and breaks exact tool-list tests - 2026-06-16 —
wayfinder:generateneeds--with-form— a missing form variant looks like a code regression - 2026-06-16 — Pest higher-order
expect($model)->value->toBe(...)breaks —valuecollides with the Expectation's own property - 2026-06-14 —
covers()scopes mutation attribution, not just coverage (graduated → testing.md) - 2026-06-14 — A caught external-service failure must surface — not a silent sentinel (graduated → php-laravel.md)
- 2026-06-14 — Paginate Todoist list endpoints — "absent" ≠ "deleted"
- 2026-06-14 — A drift fingerprint must exclude values that float with
now() - 2026-06-14 — A non-fork subagent does NOT inherit the parent conversation — use
subagent_type: forkfor full context - 2026-06-14 — A green spike on a happy-path slice breeds false confidence — probe harder, don't stop
- 2026-06-14 — The agent's own "this is simple" is never a reason to skip a process step
- 2026-06-13 — A test that deletes a committed file must restore it in
finally, not a trailing statement - 2026-06-13 — A test that reads the real clock is a time-bomb — enforce frozen time, don't just ask for it (graduated → testing.md)
- 2026-06-13 — A
casts()method mutant is killable — it's executed code, not a declaration line (graduated → CLAUDE.md) - 2026-06-12 — reka-ui
Switchhas nocheckedprop —v-model:checkedis a silently dead binding (graduated → frontend.md) - 2026-06-12 — The sandbox's
composer auditis a false negative — a green local audit proves nothing - 2026-06-12 — Adding a browser test named after a grandfathered page fails the page-manifest guard
- 2026-06-12 — A capped browser-test run piped to
| tailhangs forever on the orphanedrun-server - 2026-06-12 — pest-browser
$page->script()runs raw JS — a top-levelreturnis a SyntaxError - 2026-06-11 — PreToolUse
file_pathis absolute — relative prefix-matching never matches - 2026-06-11 — A Write/Edit-only PreToolUse gate is trivially bypassed via Bash
- 2026-06-11 — Don't force multipart on a text-only Inertia
useFormsubmit - 2026-06-11 —
composer mutatedies at Composer's 300s process timeout (and a wrapper can mask it) - 2026-06-11 — pest-browser tests can't run locally in the root web container — verify on CI
- 2026-06-11 — A missing
pest-plugin-browserkills the whole Pest suite at collection —--exclude-group=browsercan't save it - 2026-06-10 — The agent's own confidence/judgment must never gate a de-biasing step — at a gate, the exact signal beats inferred intent
- 2026-06-10 — A required step described only in a side section gets treated as optional — wire it into the flow
- 2026-06-10 —
.claude/hooks/*Edit/Write is guarded against subagents — do hook changes from the main thread - 2026-06-10 —
AskUserQuestioncaps at 4 options — past 4, overflow via "Other" or a lettered list - 2026-06-10 —
workflow_dispatchmust live on the default branch to run the gate on any branch without a PR - 2026-06-10 — Playwright can't reliably assert native HTML5 drag-and-drop reorder
- 2026-06-10 — An agent body's "see skill-x" loads nothing — preload via
skills:frontmatter - 2026-06-09 — Consumer config co-locates with its owner; engines stay generic
- 2026-06-09 — A native GitHub Issue Type is agent-applyable on create even though
list_issue_types403s - 2026-06-09 — A PreToolUse gate hook is global across sessions — scope it by
CLAUDE_CODE_SESSION_ID - 2026-06-09 — Testing a hook that
cds to$CLAUDE_PROJECT_DIRfrom a fixture silently scans the real repo - 2026-06-09 — The ephemeral container can resync your local copy behind origin — commits land on a stale base
- 2026-06-09 —
.claude/settings.jsonis a guarded write —worktree-builder/subagents can't register hooks - 2026-06-08 — A webhook POST in
routes/web.php419s in production — and thetestingenv hides it - 2026-06-08 — Infection dropped its Pest adapter — a full migration off
pest --mutateis a dead end - 2026-06-08 — Native org Issue Fields aren't board fields & aren't agent-writable — classify with labels
- 2026-06-08 — Milestone coherence stops at epic→epic boundaries (nested epics keep their own milestone)
- 2026-06-08 — GitHub MCP expired?
$GH_TOKENcurl still writes — and Projects v2 field-sets need the issue on the board first - 2026-06-07 — A merged PR won't absorb follow-up commits — re-check state before pushing more
- 2026-06-07 — "Lost" work in an ephemeral container — search commit content, not the branch name
- 2026-06-07 — Bridge the CI-success gap with a
$GH_TOKENpoll loop whensend_lateris absent - 2026-06-07 — A stacked PR reads
dirtyafter its base merges — butgit rebaseauto-resolves it - 2026-06-07 — Pest
expect()->extendignores the closure's return value — fluent DSLs need a matcher(closure) shape - 2026-06-07 —
pest-plugin-browserpending-page proxy returns the value for value-methods,$thisfor fluent ones - 2026-06-07 —
pest-plugin-browserhas noassertSeeInOrder— usedata-testhooks +assertScript - 2026-06-07 — Shared
id = 1across different objects in a test hides bugs - 2026-06-07 — Threat-model an integration at full blast radius AND as a two-way boundary
- 2026-06-06 —
vi.stubGlobal('window', …)zeroes v8 coverage for the file under test - 2026-06-06 — Pest 4 browser tests run the app in-process — test-side fakes reach the rendered page
- 2026-06-06 —
pest-plugin-browserauto-connect needs composer plugins enabled - 2026-06-06 —
assertNoSmoke()misses console warnings (and prod builds strip Vue's) - 2026-06-06 —
laravel/aiAgent::fake()runs the REAL tool when a faked response is aToolCall - 2026-06-06 — Promoting a skill-local doc to shared: name the producer inline, single-source the consumer list
- 2026-06-06 — Projects v2 Status is writable from the web env — via GraphQL + $GH_TOKEN, not the MCP server
- 2026-06-06 — Independence gates defend the rulebook — status-quo bias at idea altitude
- 2026-06-06 — x.com fetch 402s — read a tweet via the fxtwitter/vxtwitter mirror APIs
- 2026-06-05 —
grep -qEcan't exclude one path from a directory arm — POSIX ERE has no negative-lookahead - 2026-06-05 — Acting as a separate agent GitHub account is TWO independent layers (API token + git identity)
- 2026-06-05 — GitHub native typed-backlog primitives — what actually works via the API
- 2026-06-05 —
Closes #Nfires only on merge to the default branch - 2026-06-04 — SessionStart hooks inject via stdout/additionalContext; ours is stderr-only so injects nothing
- 2026-06-04 — Issues close on merge, not on commit — work goes through a reviewed PR
- 2026-06-04 — Pairwise LLM-as-judge as a gate — the subjective twin of
harness:check - 2026-06-04 — DTO boundary-cast mutants die when you hydrate from wrong-typed / missing raw values
- 2026-06-04 — Mutants on declaration lines are un-killable (pcov never marks them executed)
- 2026-06-04 — The first (cold-cache)
pest --mutaterun mis-attributes coverage - 2026-06-03 — Workflow-gate hooks can't tell a real invocation from a string that looks like one
- 2026-06-03 — A renamed skill's new name can contain its old token
- 2026-06-03 —
git branch --mergedmisses squash/rebase merges - 2026-06-03 — A skill's command name is its directory, not
name: