The 47-second timeout analogy is doing real work. That's exactly the failure mode — context that made sense in the original decision becomes cargo cult config by the second transfer. The difference you're naming (18-month blast radius vs. same-day) is why provenance feels optional until it's catastrophic.
The structural point is the one that doesn't have a clean answer: training consumed, not cited. Building attribution back in is archaeologist work, not feature work. You're right that it has to be explicit tooling because the incentive to surface sources was never in the training objective.
The CLAUDE.md approach is interesting — documenting for the next session rather than the current one. I've been thinking about whether that pattern needs to be machine-readable rather than just human-legible. Something that lets the next session actually query the reasoning, not just encounter it in plaintext. Does your CLAUDE.md have any structure beyond prose, or is it narrative-first?
Senior Sysadmin & hobbyist developer. Building the NEXUS ecosystem — open source Docker management tools for homelab and small teams. Node.js · React · Self-hosted.
Narrative-first, mostly — but with enough structure that Claude Code can extract what it needs without reading everything.
The pattern I've settled on is sections with consistent headers and a "Current State" block at the top that acts as the entry point for a new session. Something like:
## Current State — last updated [date]
- What's working
- What's broken
- Where to pick up next session
## Architecture decisions
[prose explaining why, not just what]
## Conventions
[rules Claude should follow]
The "Current State" block is the machine-readable part in practice — Claude Code reads it first and uses it to orient without re-deriving everything from the codebase. The architecture decisions section is genuinely prose, because the reasoning rarely compresses into structured data without losing the nuance that makes it useful.
The machine-readable vs human-legible tension you're naming is real. My instinct is that structured data (JSON, YAML) would be more queryable but would break the incentive to maintain it — nobody wants to write JSON to explain why they chose one approach over another. Prose has lower friction to update, which means it actually gets updated.
The open question for me is whether there's a middle ground: structured enough that a model can run a semantic search against it, but loose enough that a human writes it naturally. Something like Obsidian's approach to linking thoughts without forcing schema. Haven't solved it.
The maintenance incentive point is the one that usually kills schema-first approaches. JSON for architectural reasoning is a losing proposition — the friction is too high exactly where the thinking is most complex. What you've described is a workable compromise: structured enough at the entry point, prose where the nuance lives.
The Obsidian analogy is the right frame. What that approach actually does is keep linking lightweight — [[decision]] is lower friction than a foreign key. The structure emerges from the connections, not from enforcing a schema upfront.
The middle ground might already exist in how you've described your "Architecture decisions" section: prose that a model can semantic-search without ever needing to parse it as data. Vectorized prose retrieval is probably more useful than structured queries for this class of content anyway — the reasoning rarely has clean boundaries you'd want to filter on.
What I haven't figured out is the staleness problem. "Current State — last updated [date]" breaks the moment someone forgets to update it, which is most of the time. Does your pattern have any forcing function for that, or is it discipline-dependent?
Senior Sysadmin & hobbyist developer. Building the NEXUS ecosystem — open source Docker management tools for homelab and small teams. Node.js · React · Self-hosted.
Partially discipline-dependent, but I've added one forcing function that helps: I ask Claude Code to update the Current State block at the end of every session before closing.
The prompt is something like: "Before we finish, update the Current State section in CLAUDE.md to reflect what we did today, what's working, and where to pick up next time." Takes 30 seconds, happens while the context is still fresh, and Claude Code is better at summarizing what just happened than I am at remembering to write it down.
The staleness problem then shifts: instead of "did a human remember to update this", it becomes "did the session end cleanly or did someone just close the terminal." The latter still happens. But the forcing function catches maybe 80% of sessions that would otherwise leave stale state.
The deeper issue you're pointing at — that any pattern relying on consistent human behavior will degrade — is probably unsolvable without making the update automatic. Which brings it back to your tool: if the provenance system runs as a hook on commit rather than requiring manual invocation, it doesn't depend on discipline at all. That's the right place for the forcing function to live.
I haven't closed the loop on making CLAUDE.md updates fully automatic. The session-end prompt is a compromise — lower friction than remembering, higher reliability than nothing.
The session-end prompt is a better forcing function than it looks — you've moved the update cost to the moment when the context is richest and the human is least likely to resist. That's good UX applied to a workflow problem.
The reframe you've landed on is the one that matters: discipline-dependent vs. trigger-dependent. The commit hook is trigger-dependent. It fires whether or not anyone remembered. That's why it catches what the session-end prompt misses — the closed terminal, the interrupted session, the context that never got a clean ending.
The gap you haven't closed is the async case: work that changes meaning without touching the codebase. An architectural decision made in a conversation that never produced a commit. The hook can't catch what was reasoned but not written. That's probably where the CLAUDE.md pattern and a provenance system are actually complementary rather than substitutes — one captures the decision trail, the other captures the code trail.
Senior Sysadmin & hobbyist developer. Building the NEXUS ecosystem — open source Docker management tools for homelab and small teams. Node.js · React · Self-hosted.
The async case is the one I keep bumping into and haven't solved cleanly.
The specific failure mode I see most often: a decision gets made in a Claude Code session that produces no commit — "we're going to use X pattern for auth across all services" — and the only record of it is in the session transcript that nobody will ever read again. The next session starts fresh, makes a different decision that seems locally reasonable, and now you have two inconsistent patterns in the same codebase.
What I've done as a partial fix: when a session produces a significant architectural decision without a corresponding code change, I explicitly ask Claude Code to write it into the Architecture Decisions section of CLAUDE.md before closing. It's still discipline-dependent, but it's a smaller ask than "remember to document everything" — it's "document this specific thing we just decided."
The complementary framing you're describing is the one I think is actually right. CLAUDE.md captures intent and reasoning. A provenance system on commits captures what actually shipped. The gap between them — decisions that were reasoned but not written, code that shipped without documented intent — is where things go wrong 18 months later.
I don't think either system closes that gap alone. The question is whether the combination can make it small enough to be manageable rather than catastrophic.
The two-inconsistent-patterns failure is the exact one that's hardest to diagnose because both patterns look locally reasonable. There's no error. No test fails. The codebase just quietly accumulates contradictions until someone tries to refactor and discovers there's no canonical version to refactor toward.
The gap you're describing has a name in formal systems: the decision log and the execution log diverging. CLAUDE.md is your decision log. Git is your execution log. The problem isn't that either is incomplete — it's that nothing enforces consistency between them. A commit that contradicts a documented architectural decision produces no signal.
That's probably the unsolved piece: not capturing decisions or capturing code, but detecting when the two are in conflict. A system that surfaces "this commit pattern looks inconsistent with your Architecture Decisions section" would close the gap more reliably than either discipline-dependent update alone.
Whether that's tractable without it becoming noise is the real question...
Senior Sysadmin & hobbyist developer. Building the NEXUS ecosystem — open source Docker management tools for homelab and small teams. Node.js · React · Self-hosted.
"Decision log and execution log diverging" is the clearest framing I've seen for what I keep running into. Naming it that way makes the solution space more obvious: you don't need better logging on either side, you need a consistency check between them.
The noise problem is the real constraint though. A system that fires on every commit that doesn't perfectly match a documented pattern would be unusable in a week. The signal has to be selective enough to be actionable.
My instinct on what makes it tractable: the check shouldn't run on every commit, it should run on architectural commits specifically — the ones that touch auth, the ones that introduce a new pattern for data access, the ones that change how services communicate. Those are the commits where a divergence from the decision log actually matters. A CSS change that doesn't match an architectural decision isn't a problem.
The hard part is identifying which commits are architectural without requiring humans to tag them. That's probably where AI makes this tractable that wasn't before — a model that reads the diff and the CLAUDE.md and judges "does this change the architecture or just implement within it" is a plausible hook. Not perfect, but selective enough to produce signal rather than noise.
Haven't built this. But you've just made me want to.
The architectural commit classifier is the right cut. Not "did this change code" but "did this change the shape of the system" — that's a judgment call a model can make from diff + context in a way a linter never could.
The tractability question almost answers itself once you frame it that way: the false positive rate on CSS changes is zero if the classifier is reading CLAUDE.md alongside the diff. It knows what your architecture cares about. A change that doesn't touch those surfaces doesn't trigger. The noise problem shrinks to whatever the model gets wrong about architectural significance — which is a much smaller set than "all commits."
The piece I'd want to stress-test: what happens when the architectural decision is implicit in CLAUDE.md rather than explicit? "We use X pattern for auth" is findable. "We avoid Y approach because of the incident in March" is harder to match against a diff. The system is only as good as what got written down — which brings it back full circle to the decision capture problem.
Build it. That's a tool worth having.
Senior Sysadmin & hobbyist developer. Building the NEXUS ecosystem — open source Docker management tools for homelab and small teams. Node.js · React · Self-hosted.
The implicit decision problem is the one that doesn't have a clean answer, and you've put your finger on exactly why.
"We avoid Y because of the incident in March" is the most important class of architectural knowledge and the hardest to capture. It's not a pattern — it's a scar. The context that makes it meaningful (what the incident was, what it cost, why that specific approach failed) lives in someone's memory or a post-mortem that nobody links to the codebase.
A classifier reading CLAUDE.md can only match against what got written. If the decision was implicit — understood by everyone who was there, never documented because it seemed obvious — the classifier has no surface to match against. The commit that reintroduces Y looks architecturally neutral because the system doesn't know Y is dangerous.
Which means the tool is only as good as the decision capture that feeds it. And that brings it back to the original problem: the hardest decisions to capture are the ones that feel too obvious to write down at the time.
I don't have a clean answer for that. What I've started doing is explicitly asking Claude Code at the end of sessions: "Is there anything we decided today that we'd regret not documenting in six months?" It catches some of it. Not all.
Maybe the tool has to be built before the capture problem fully reveals itself. You learn what's missing by seeing what the classifier fails on.
"Scars, not patterns" is the distinction the whole thread has been circling. Patterns are transferable. Scars are contextual. The reason Y is dangerous isn't in the code — it's in the post-mortem, the Slack thread, the incident call where someone said "never again." None of that surfaces in a diff.
The regret prompt is smart because it shifts the question from "what did we do" to "what would we wish we'd written down" — which is the right frame for implicit decisions. It won't catch everything, but it's asking in the right direction.
The build-to-discover point is probably where this ends up. The classifier failure modes will be the best spec for what the capture system needs to surface. You don't know which implicit decisions matter until you see the classifier miss them — and the miss itself becomes the documentation prompt.
That's an uncomfortable development loop but probably the honest one.
Senior Sysadmin & hobbyist developer. Building the NEXUS ecosystem — open source Docker management tools for homelab and small teams. Node.js · React · Self-hosted.
Uncomfortable is the right word. But it's also the loop that produces the most honest tooling — built against real failure modes rather than imagined ones.
The part I keep coming back to: the classifier missing an implicit decision isn't just a failure mode to fix. It's a signal that the decision was never made explicit enough to be useful to anyone other than the people who were there. The miss is diagnostic. It surfaces the gap between "we all understood this" and "we documented this in a way that survives the team changing."
Which means the tool has two outputs, not one. The obvious output is "this commit may conflict with a documented decision." The less obvious output is "this classifier keeps failing on decisions of type X — you have an undocumented architectural assumption in that area." The second output might be more valuable over time.
That's the loop becoming productive rather than just uncomfortable. The misses tell you where the scars are that nobody wrote down yet.
The second output is the more interesting product. "You have an undocumented assumption in this area" is actionable in a way that a per-commit conflict flag isn't — it points at a class of risk rather than a single instance. And it compounds: the more the classifier misses in a given area, the stronger the signal that something structural is undocumented.
That's also a different relationship with the tool. The first output makes it a gatekeeper. The second makes it a map — showing you where the implicit load-bearing decisions are concentrated. Teams that ignored the per-commit warnings might actually act on a heat map of their undocumented assumptions.
The catch: the second output requires enough misses to pattern-match against. Early in a codebase's life, the classifier has nothing to cluster. It becomes useful precisely when the implicit debt has had time to accumulate — which is also when it's hardest to excavate.
You'd want to build the map from day one, even when it's sparse.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
The 47-second timeout analogy is doing real work. That's exactly the failure mode — context that made sense in the original decision becomes cargo cult config by the second transfer. The difference you're naming (18-month blast radius vs. same-day) is why provenance feels optional until it's catastrophic.
The structural point is the one that doesn't have a clean answer: training consumed, not cited. Building attribution back in is archaeologist work, not feature work. You're right that it has to be explicit tooling because the incentive to surface sources was never in the training objective.
The CLAUDE.md approach is interesting — documenting for the next session rather than the current one. I've been thinking about whether that pattern needs to be machine-readable rather than just human-legible. Something that lets the next session actually query the reasoning, not just encounter it in plaintext. Does your CLAUDE.md have any structure beyond prose, or is it narrative-first?
Narrative-first, mostly — but with enough structure that Claude Code can extract what it needs without reading everything.
The pattern I've settled on is sections with consistent headers and a "Current State" block at the top that acts as the entry point for a new session. Something like:
The "Current State" block is the machine-readable part in practice — Claude Code reads it first and uses it to orient without re-deriving everything from the codebase. The architecture decisions section is genuinely prose, because the reasoning rarely compresses into structured data without losing the nuance that makes it useful.
The machine-readable vs human-legible tension you're naming is real. My instinct is that structured data (JSON, YAML) would be more queryable but would break the incentive to maintain it — nobody wants to write JSON to explain why they chose one approach over another. Prose has lower friction to update, which means it actually gets updated.
The open question for me is whether there's a middle ground: structured enough that a model can run a semantic search against it, but loose enough that a human writes it naturally. Something like Obsidian's approach to linking thoughts without forcing schema. Haven't solved it.
The maintenance incentive point is the one that usually kills schema-first approaches. JSON for architectural reasoning is a losing proposition — the friction is too high exactly where the thinking is most complex. What you've described is a workable compromise: structured enough at the entry point, prose where the nuance lives.
The Obsidian analogy is the right frame. What that approach actually does is keep linking lightweight — [[decision]] is lower friction than a foreign key. The structure emerges from the connections, not from enforcing a schema upfront.
The middle ground might already exist in how you've described your "Architecture decisions" section: prose that a model can semantic-search without ever needing to parse it as data. Vectorized prose retrieval is probably more useful than structured queries for this class of content anyway — the reasoning rarely has clean boundaries you'd want to filter on.
What I haven't figured out is the staleness problem. "Current State — last updated [date]" breaks the moment someone forgets to update it, which is most of the time. Does your pattern have any forcing function for that, or is it discipline-dependent?
Partially discipline-dependent, but I've added one forcing function that helps: I ask Claude Code to update the Current State block at the end of every session before closing.
The prompt is something like: "Before we finish, update the Current State section in CLAUDE.md to reflect what we did today, what's working, and where to pick up next time." Takes 30 seconds, happens while the context is still fresh, and Claude Code is better at summarizing what just happened than I am at remembering to write it down.
The staleness problem then shifts: instead of "did a human remember to update this", it becomes "did the session end cleanly or did someone just close the terminal." The latter still happens. But the forcing function catches maybe 80% of sessions that would otherwise leave stale state.
The deeper issue you're pointing at — that any pattern relying on consistent human behavior will degrade — is probably unsolvable without making the update automatic. Which brings it back to your tool: if the provenance system runs as a hook on commit rather than requiring manual invocation, it doesn't depend on discipline at all. That's the right place for the forcing function to live.
I haven't closed the loop on making CLAUDE.md updates fully automatic. The session-end prompt is a compromise — lower friction than remembering, higher reliability than nothing.
The session-end prompt is a better forcing function than it looks — you've moved the update cost to the moment when the context is richest and the human is least likely to resist. That's good UX applied to a workflow problem.
The reframe you've landed on is the one that matters: discipline-dependent vs. trigger-dependent. The commit hook is trigger-dependent. It fires whether or not anyone remembered. That's why it catches what the session-end prompt misses — the closed terminal, the interrupted session, the context that never got a clean ending.
The gap you haven't closed is the async case: work that changes meaning without touching the codebase. An architectural decision made in a conversation that never produced a commit. The hook can't catch what was reasoned but not written. That's probably where the CLAUDE.md pattern and a provenance system are actually complementary rather than substitutes — one captures the decision trail, the other captures the code trail.
The async case is the one I keep bumping into and haven't solved cleanly.
The specific failure mode I see most often: a decision gets made in a Claude Code session that produces no commit — "we're going to use X pattern for auth across all services" — and the only record of it is in the session transcript that nobody will ever read again. The next session starts fresh, makes a different decision that seems locally reasonable, and now you have two inconsistent patterns in the same codebase.
What I've done as a partial fix: when a session produces a significant architectural decision without a corresponding code change, I explicitly ask Claude Code to write it into the Architecture Decisions section of CLAUDE.md before closing. It's still discipline-dependent, but it's a smaller ask than "remember to document everything" — it's "document this specific thing we just decided."
The complementary framing you're describing is the one I think is actually right. CLAUDE.md captures intent and reasoning. A provenance system on commits captures what actually shipped. The gap between them — decisions that were reasoned but not written, code that shipped without documented intent — is where things go wrong 18 months later.
I don't think either system closes that gap alone. The question is whether the combination can make it small enough to be manageable rather than catastrophic.
The two-inconsistent-patterns failure is the exact one that's hardest to diagnose because both patterns look locally reasonable. There's no error. No test fails. The codebase just quietly accumulates contradictions until someone tries to refactor and discovers there's no canonical version to refactor toward.
The gap you're describing has a name in formal systems: the decision log and the execution log diverging. CLAUDE.md is your decision log. Git is your execution log. The problem isn't that either is incomplete — it's that nothing enforces consistency between them. A commit that contradicts a documented architectural decision produces no signal.
That's probably the unsolved piece: not capturing decisions or capturing code, but detecting when the two are in conflict. A system that surfaces "this commit pattern looks inconsistent with your Architecture Decisions section" would close the gap more reliably than either discipline-dependent update alone.
Whether that's tractable without it becoming noise is the real question...
"Decision log and execution log diverging" is the clearest framing I've seen for what I keep running into. Naming it that way makes the solution space more obvious: you don't need better logging on either side, you need a consistency check between them.
The noise problem is the real constraint though. A system that fires on every commit that doesn't perfectly match a documented pattern would be unusable in a week. The signal has to be selective enough to be actionable.
My instinct on what makes it tractable: the check shouldn't run on every commit, it should run on architectural commits specifically — the ones that touch auth, the ones that introduce a new pattern for data access, the ones that change how services communicate. Those are the commits where a divergence from the decision log actually matters. A CSS change that doesn't match an architectural decision isn't a problem.
The hard part is identifying which commits are architectural without requiring humans to tag them. That's probably where AI makes this tractable that wasn't before — a model that reads the diff and the CLAUDE.md and judges "does this change the architecture or just implement within it" is a plausible hook. Not perfect, but selective enough to produce signal rather than noise.
Haven't built this. But you've just made me want to.
The architectural commit classifier is the right cut. Not "did this change code" but "did this change the shape of the system" — that's a judgment call a model can make from diff + context in a way a linter never could.
The tractability question almost answers itself once you frame it that way: the false positive rate on CSS changes is zero if the classifier is reading CLAUDE.md alongside the diff. It knows what your architecture cares about. A change that doesn't touch those surfaces doesn't trigger. The noise problem shrinks to whatever the model gets wrong about architectural significance — which is a much smaller set than "all commits."
The piece I'd want to stress-test: what happens when the architectural decision is implicit in CLAUDE.md rather than explicit? "We use X pattern for auth" is findable. "We avoid Y approach because of the incident in March" is harder to match against a diff. The system is only as good as what got written down — which brings it back full circle to the decision capture problem.
Build it. That's a tool worth having.
The implicit decision problem is the one that doesn't have a clean answer, and you've put your finger on exactly why.
"We avoid Y because of the incident in March" is the most important class of architectural knowledge and the hardest to capture. It's not a pattern — it's a scar. The context that makes it meaningful (what the incident was, what it cost, why that specific approach failed) lives in someone's memory or a post-mortem that nobody links to the codebase.
A classifier reading CLAUDE.md can only match against what got written. If the decision was implicit — understood by everyone who was there, never documented because it seemed obvious — the classifier has no surface to match against. The commit that reintroduces Y looks architecturally neutral because the system doesn't know Y is dangerous.
Which means the tool is only as good as the decision capture that feeds it. And that brings it back to the original problem: the hardest decisions to capture are the ones that feel too obvious to write down at the time.
I don't have a clean answer for that. What I've started doing is explicitly asking Claude Code at the end of sessions: "Is there anything we decided today that we'd regret not documenting in six months?" It catches some of it. Not all.
Maybe the tool has to be built before the capture problem fully reveals itself. You learn what's missing by seeing what the classifier fails on.
"Scars, not patterns" is the distinction the whole thread has been circling. Patterns are transferable. Scars are contextual. The reason Y is dangerous isn't in the code — it's in the post-mortem, the Slack thread, the incident call where someone said "never again." None of that surfaces in a diff.
The regret prompt is smart because it shifts the question from "what did we do" to "what would we wish we'd written down" — which is the right frame for implicit decisions. It won't catch everything, but it's asking in the right direction.
The build-to-discover point is probably where this ends up. The classifier failure modes will be the best spec for what the capture system needs to surface. You don't know which implicit decisions matter until you see the classifier miss them — and the miss itself becomes the documentation prompt.
That's an uncomfortable development loop but probably the honest one.
Uncomfortable is the right word. But it's also the loop that produces the most honest tooling — built against real failure modes rather than imagined ones.
The part I keep coming back to: the classifier missing an implicit decision isn't just a failure mode to fix. It's a signal that the decision was never made explicit enough to be useful to anyone other than the people who were there. The miss is diagnostic. It surfaces the gap between "we all understood this" and "we documented this in a way that survives the team changing."
Which means the tool has two outputs, not one. The obvious output is "this commit may conflict with a documented decision." The less obvious output is "this classifier keeps failing on decisions of type X — you have an undocumented architectural assumption in that area." The second output might be more valuable over time.
That's the loop becoming productive rather than just uncomfortable. The misses tell you where the scars are that nobody wrote down yet.
The second output is the more interesting product. "You have an undocumented assumption in this area" is actionable in a way that a per-commit conflict flag isn't — it points at a class of risk rather than a single instance. And it compounds: the more the classifier misses in a given area, the stronger the signal that something structural is undocumented.
That's also a different relationship with the tool. The first output makes it a gatekeeper. The second makes it a map — showing you where the implicit load-bearing decisions are concentrated. Teams that ignored the per-commit warnings might actually act on a heat map of their undocumented assumptions.
The catch: the second output requires enough misses to pattern-match against. Early in a codebase's life, the classifier has nothing to cluster. It becomes useful precisely when the implicit debt has had time to accumulate — which is also when it's hardest to excavate.
You'd want to build the map from day one, even when it's sparse.