Skip to content

Instantly share code, notes, and snippets.

@aviadr1
Created March 26, 2026 21:58
Show Gist options
  • Select an option

  • Save aviadr1/a9881c9249b64e8e055d89d32bf83e0a to your computer and use it in GitHub Desktop.

Select an option

Save aviadr1/a9881c9249b64e8e055d89d32bf83e0a to your computer and use it in GitHub Desktop.
Planning Quality Research — Round 1: Foundation (Decision Theory, Cognitive Ethnography, Signal Archaeology)

The Tacit Judgment: A Cognitive Ethnography of "This Needs Design First"

A cognitive science exploration for the kaizen project Round 1 — March 2026


1. The Expert Cognition Model: How Senior Engineers Actually Make This Judgment

The framing of "checklist vs. intuition" is a false dichotomy, and it points to the exact cognitive science literature we need. Gary Klein's Recognition-Primed Decision (RPD) model describes how experienced practitioners make decisions under time pressure and uncertainty: they don't evaluate options against criteria. They pattern-match a situation to a prototype, which immediately surfaces a candidate action, which they then mentally simulate. If the simulation runs without catastrophic failure, they act. They don't compare alternatives — they evaluate one option.

The "ultrathink" trigger is RPD pattern recognition firing. When Aviad looks at a proposed design and something feels wrong, he is not running through his five categories consciously. He is experiencing what Klein calls anomaly detection: the current situation fails to match the prototype for "this should work." The mismatch is felt before it is articulated. The five categories he named are not the cognitive process — they are a post-hoc rationalization of the pattern, a reverse-engineering of why the anomaly detector fired.

This is important: expert engineers don't recognize bad designs by checking conditions. They recognize good designs by pattern completion, and they notice when the pattern fails to complete. The "ultrathink" moment is not a positive trigger ("ah, this has property X that requires design thinking"). It is a negative signal ("something about this doesn't fit"). The absence of fit is the alarm.

Klein studied firefighters, nurses, and military commanders. The finding that transfers directly here: experts build a library of situation prototypes over years of experience. Each prototype is a bundle: a situation shape, an expectation about dynamics, a set of responses that worked, and — critically — a set of ways this class of situation went wrong. When a new situation arrives, the brain matches it to the closest prototype. When features of the current situation contradict the prototype's predictions, the anomaly detector fires. The expert pauses.

In Aviad's domain, the prototypes are things like: "distributed state ownership without clear contract = interface breaks under partial failure," or "multi-agent store pattern with late persistence = data loss on crash." He doesn't enumerate these at decision time. The prototype fires, the simulation runs, the anomaly is felt.


2. The Tacit Knowledge Problem: What Exactly Does Aviad Have?

Using the vocabulary of cognitive science, Aviad's tacit knowledge appears to be a compound of at least four distinct types:

Episodic memory organized as a failure library. He has seen specific failures. Not "state resilience is important" in the abstract, but "that time we stored findings at the end and lost everything when the session died mid-review." These episodic memories are indexed by their failure signature, not their surface features. The "orchestrator-batch vs. agent-stores" case retrieved from episodic memory not because it looked the same but because its failure signature — late binding of critical state to session lifecycle — matched prior failures.

A causal model of system dynamics. Beyond episodic memory, Aviad has a working model of how this class of system fails. This is what Polanyi called "indwelling" — not explicit knowledge about the system, but tacit skill in inhabiting the system's perspective, seeing from within it. He can mentally simulate "what happens if this design runs and then the process dies at step N" because he has built a causal model through repeated exposure. This is different from recalling a specific incident; it is the ability to reason forward from a design to failure modes without having seen those specific failures before.

Option-space awareness. Senior engineers know there is almost always more than one design. They carry a rough map of the option space for common problem types. The agent in the concrete example never asked "what are the other ways to do this?" because it did not know there was an option space to explore. Aviad's anomaly detector partly fires because he sees that the agent has committed to one design without noticing the field. This is meta-cognitive: knowing that you need to check for alternatives before committing.

Irreversibility weighting. Perhaps the deepest piece: expertise includes a calibrated sense of which decisions are hard to undo. This is not just "can we refactor this?" It is a rich estimate of: how many other things does this decision constrain? If we discover this was wrong in three weeks, what breaks? Junior engineers treat most design decisions as reversible. Senior engineers have experienced enough "we built on the wrong foundation" events that irreversibility itself becomes a first-class property they track.

Polanyi's formulation — "we know more than we can tell" — is precisely apt here. Aviad's five categories are the parts he can tell. The part he can't tell is the shape of the prototypes themselves, the exact features that trigger pattern completion or anomaly detection. These are stored procedurally, not declaratively. You cannot list them; you can only exercise them.


3. The AI Agent's Cognitive Gap: Where the Failure Is Located

The agent's failure in the concrete example was not a logic error or a missing step. It was an absence — it never entered the cognitive mode where design alternatives are considered. More precisely:

No anomaly detection trigger. The agent has no mechanism corresponding to "this doesn't fit the prototype." Every design looks equally normal to it, because it has no prototypes. Without a baseline of expected patterns, there is nothing to deviate from. The agent saw "store review findings" as a task to execute, not as a design decision with a shape. It found a valid solution and executed it. The normal-seeming surface of the orchestrator-batch pattern triggered no alarm, because the agent has no alarm to trigger.

No failure mode library. The agent has broad world knowledge about distributed systems failures, but it does not have indexed episodic memory of "what happened last time this class of design was used in this codebase." It knows that session crashes are theoretically possible. It does not have the visceral episodic weight of having watched data loss happen, which is what makes the failure mode salient rather than theoretical.

No option space initialization. The agent does not naturally ask "what are the other designs?" before committing. This is not because it cannot generate alternatives when asked — it clearly can. It is because the trigger for alternative generation is absent. The trigger for an expert is the felt sense that the first candidate solution is too easy, or that the problem has the shape of a class that typically has non-obvious alternatives. The agent has no such felt sense.

Commitment bias amplified. Once the agent begins implementing, it enters a regime where the current design is true and the task is to execute it correctly. This is normal for execution mode. The problem is the transition: expert engineers have a deliberate "design pause" phase before execution, triggered by anomaly detection. The agent lacks the trigger that would put it in design-pause mode before switching to execution mode.

No causal simulation. More precisely: the agent can simulate causally when prompted, but does not spontaneously run the simulation "what happens if this process dies at step N?" before choosing a design. The expert runs this simulation habitually, almost involuntarily, for certain classes of decision. It is a learned reflex.


4. Cognitive Tools That Could Help: Scaffolding the Gap

The cognitive science literature on expert decision support suggests tools that externalize the cognitive operations experts perform internally.

Pre-mortem analysis (Klein). Klein developed this explicitly for teams whose members have insufficient experience to generate anomaly detection organically. The instruction: "Assume this design is implemented, deployed, and has failed catastrophically. It is six months later. What went wrong?" The pre-mortem forces backward simulation from failure, which is exactly the causal reasoning experts perform forward spontaneously. For an AI agent, this means: before committing to a design, generate two or three catastrophic failure narratives for it. If the failure narratives reveal state resilience issues, interface ambiguities, or irreversibility traps — pause and explore alternatives.

Inversion (Charlie Munger, via Hannibal Lecter's technique from military planning). "How would this design fail?" is structurally different from "will this design work?" The second question has a strong confirmation bias: the agent already found a path to "yes." The first question bypasses confirmation bias by asking for disconfirmatory evidence. Applied at design time: before implementing, generate the top three failure modes. If any of them are catastrophic and unrecoverable, that is the anomaly detector's result made explicit.

Option forcing. Before analyzing a design, require the agent to name at least two alternative designs. Not evaluate them — just name them. The act of generating the option space changes the epistemic stance from "execute this" to "choose among these." Research on naturalistic decision making shows that the most dangerous decision states are those where only one option is perceived. Option forcing breaks single-track commitment before it forms.

Causal chain tracing under adversarial conditions. Walk the happy path once, then walk the path assuming the most disruptive possible mid-execution interruption. In distributed/agent systems, the most natural adversarial condition is: the process dies after step N. This is not a generic fault injection; it is the specific failure mode that expertise in this domain has repeatedly surfaced. Formalizing it as a required step ("now trace the causal chain with a crash after each state transition") encodes the expert's learned reflex as a procedure.

Analogy to past failures (case-based reasoning). The agent lacks episodic memory, but the kaizen system accumulates documented incidents. A structured search for "which past kaizen issues have failure signatures similar to this design?" converts the incident archive into a functional analog of episodic memory. This is the cognitive science concept of case-based reasoning (Schank, Kolodner): retrieve the most similar past case, adapt the solution, verify the adaptation. The kaizen issues list is exactly this archive if the retrieval step is made explicit.


5. The Articulation Problem: Can Tacit Knowledge Be Made Explicit?

Cognitive science offers a sobering answer: partially, with irreducible residue.

Dreyfus and Dreyfus's skill acquisition model distinguishes five levels from novice to expert. The critical transition happens between competent and proficient: the competent practitioner applies rules analytically; the proficient practitioner sees the situation holistically and recognizes which rules apply. Expertise is the transition from rule-following to pattern recognition. Once expertise is achieved, the rules that were explicitly followed early in learning are replaced by recognition that cannot be fully re-translated back into rules without loss.

This is not mystical. It is the consequence of neural encoding. Procedural memory (how to ride a bike, how to read a face, how to recognize a bad design) uses different neural substrates than declarative memory (explicit propositions you can state). Procedural knowledge was built by repeated exposure, and its compression is one-way: the original rule set is discarded as the procedure is automatized. You cannot fully reverse this.

For Aviad's case: his five categories are the parts that could be articulated because they were, at some point, explicit hypotheses he tested. The residue that cannot be articulated is the specific feature-weight combination inside each prototype — exactly which design properties, in which combination, at what magnitude, trigger the "something is wrong" signal. This is stored as a multi-dimensional threshold function learned over hundreds of cases, and that function is not accessible to introspection.

The practical implication: checklists derived from expert articulation will always be incomplete. They capture the articulable structure but miss the continuous feature weighting that makes expert judgment sensitive and specific. A checklist trained on Aviad's five categories will catch the cases he can name and miss the cases he recognizes but cannot yet name. This is not a reason to abandon articulation — it is a reason to combine it with other mechanisms.

What cognitive science does suggest is tractable: critical incident debriefing (Klein's method) can surface tacit knowledge that experts cannot generate through direct introspection. By walking through specific past cases in detail — "what did you notice first? what didn't fit? what simulation ran through your head?" — the interviewer can extract feature details that the expert could not volunteer. Applied to kaizen: systematic debriefing of "Aviad said ultrathink" incidents, asking what specifically triggered it, could over time build a richer prototype library than direct articulation alone.


6. The Training Paradox: No Experience Across Sessions

Here the cognitive science challenge becomes structural. Expertise in Klein's model requires thousands of hours of high-quality feedback loops: act, observe outcome, update prototype. The chess master's pattern recognition was built from tens of thousands of games. The firefighter's situational awareness was built from hundreds of fires. The senior engineer's design intuition was built from years of implementations that worked and failed.

AI agents, currently, have no persistent episodic memory across sessions. Each session begins at the same baseline. There is no mechanism by which seeing the orchestrator-batch failure this week makes next week's agent more sensitive to that failure mode. The "experience" that drives expertise cannot accumulate.

Cognitive science suggests several partial alternatives:

Compiled cases as substitute for episodic memory. Cognitive models of expertise distinguish between compilation (converting episodes into rules) and chunking (compressing patterns into retrievable units). Both happen inside individual human experts, but the compiled output can be externalized. Klein's approach to knowledge engineering is essentially this: extract compiled cases from experts through critical incident technique, encode them in retrievable form, and inject them at decision time. The kaizen incident archive, if structured and retrievable, is this mechanism.

Schema injection at task initialization. Developmental psychology (Piaget) and schema theory (Rumelhart) suggest that much expert performance can be scaffolded by activating the right schema at the right moment. The expert's anomaly detector fires because the current situation activates a schema that predicts a different configuration. If the schema is externalized and injected at design-time, the agent does not need to have learned it — it is given it. The question becomes: can we inject a "design review schema" that asks the right questions before implementation begins?

Outcome feedback through structured reflection. The kaizen reflection loop is the closest existing mechanism to experience accumulation. When a design choice is made and the outcome is documented in a kaizen issue, a feedback signal exists. The barrier is retrieval: the agent that made the choice is gone; the next agent does not automatically learn from the issue. Bridging this requires either retrieval augmentation (search the issue archive at design time) or schema update (generalize the incident into a design principle that is injected into future sessions). Both are tractable engineering problems.


7. A Concrete Proposal: The Design Stance Protocol

Based on the foregoing, the most promising mechanism is not a checklist but a stance shift — a mandatory transition into a distinct cognitive mode before design commitment, triggered by recognizable surface features of the task.

The expert's anomaly detection is a sophisticated classifier that fires on subtle features. We cannot replicate that classifier directly. But we can replicate the consequence of that classifier firing: entering a phase of deliberate, adversarial evaluation before committing to a design. The expert does this automatically when the pattern doesn't fit; we need to trigger it by other means.

The proposal: a set of lightweight surface triggers that mandate design-pause mode, followed by a compact protocol that performs the cognitive operations experts perform internally.

Triggers (recognizable without expertise):

  • The task involves storing or transmitting state that will be consumed by a different process or session boundary
  • Multiple agents or sub-processes will read or write shared state
  • The decision is described in terms of "how to implement X" rather than "whether and how to implement X" (option space is already collapsed)
  • The problem has appeared in the kaizen issue archive before, regardless of how it was resolved

These triggers are deliberately conservative. They will fire on cases that do not need design exploration. That is acceptable — a false positive costs one design-pause conversation; a false negative costs a catastrophic failure.

The protocol (mimicking expert internal operations):

Step 1 — Option generation. Name at least two other ways to accomplish the same goal. Do not evaluate. Just name them. (Breaks single-track commitment before it forms.)

Step 2 — Failure-first simulation. For each named option, including the proposed one: what is the worst outcome if the process dies or is interrupted at its most vulnerable moment? (Encodes the expert's causal simulation under adversarial conditions.)

Step 3 — Irreversibility assessment. If this design is wrong, at what point does that become apparent? What would have to be undone? (Activates the irreversibility-weighting that experts carry implicitly.)

Step 4 — Archive retrieval. Does the failure signature of any option match a pattern in the kaizen issue archive? (Case-based reasoning as substitute for episodic memory.)

Step 5 — Design selection with explicit rationale. Choose a design with a one-sentence justification that names the failure modes of the alternatives it was chosen over. (Forces explicit comparison rather than first-candidate execution.)

This protocol does not replicate expert intuition. It replicates the output of expert intuition in cases where the intuition fired: a brief period of adversarial evaluation before commitment. The expert does this in seconds, almost unconsciously. The agent will do it in a few minutes, explicitly. The result — a considered design choice with documented failure-mode reasoning — should be equivalent.

The deeper point is epistemic: the agent does not need to have felt something was wrong in order to perform the cognitive work that follows from the expert feeling that something was wrong. The trigger can be exogenous. The operations can be explicit. The outcome — a more resilient design — is what matters.

The kaizen principle applies: instructions are necessary but never sufficient. A prompt that says "consider design alternatives" is L1. A trigger condition that mandates design-pause mode before state-ownership decisions is L2. An architecture that makes the design-pause protocol a required gate before implementation commits to a storage strategy is L3. The question is not which level is theoretically sufficient — it is which level the failure mode requires.

Given that the orchestrator-batch failure was not a logic error but an invisible option space, L2 is the minimum viable level: a hook or gate that detects the trigger conditions and requires the protocol before proceeding. L1 instructions will be forgotten. L3 architecture would catch it mechanistically regardless of instructions. L2 hooks are the achievable near-term target.


This document is a first-round cognitive ethnography. Its claims are hypotheses, not commandments. The kaizen principle applies: when practice contradicts a principle here, update this document.

Design Pause: A Decision-Theoretic Analysis

When should an agent stop and explore design alternatives before implementing?


1. The Core Model: When Is the Expected Value of a Pause Positive?

Frame the problem as a two-action decision at time T=0, before any implementation work begins.

Action A: Proceed immediately. Implement the first viable design that comes to mind.

Action B: Pause. Enumerate design alternatives, evaluate them against the five risk categories, select deliberately, then implement.

Let:

  • C_pause = cost of the pause itself (agent time, latency for the human, context consumed)
  • P_wrong = probability that Action A picks the wrong design
  • C_rework = expected cost of reworking the wrong design once the mistake is discovered
  • D_discover = probability the mistake is ever discovered before the cost is fully paid (mistakes in resilience often aren't discovered until session death occurs)

The expected value of pausing is positive when:

EV(pause) > 0
⟺ P_wrong × C_rework × D_discover > C_pause

This is the design pause threshold. All four variables are estimable, even if roughly.

What makes P_wrong high?

  • Multiple feasible designs exist (the decision is genuinely ambiguous)
  • The agent has no strong prior about which design the admin prefers
  • The decision touches one of the five risk categories

What makes C_rework high?

  • The design is deeply woven into other components (interface ownership decisions)
  • Data is written in a format that must be migrated (state resilience decisions)
  • Other agents or skills depend on the choice (L1-only contracts)

What makes D_discover high?

  • The failure mode is catastrophic and immediately visible (data loss, not silent degradation)
  • The system has good observability

The immediately practical insight: C_pause is typically 2-10 minutes of agent time. C_rework on a wrong architectural choice is typically hours. So even P_wrong = 0.1 clears the threshold unless D_discover is very low — the bug is silent for a long time, then cheap to fix when found.


2. Real Options Framing: The Right to Switch Designs

Real options theory treats irreversible decisions differently from reversible ones. An option — the right but not the obligation to take an action later — has value precisely because circumstances may change before you need to commit.

A design pause is not itself an option. It is the act of buying an option: paying C_pause now in exchange for the right to choose among designs with full information rather than defaulting to the first.

The Black-Scholes intuition translates imperfectly but usefully:

  • Underlying asset: The correct design, which has a "true value" that the agent doesn't know yet
  • Strike price: The cost of rework if you commit to the wrong design now
  • Time to expiry: The window before the decision becomes locked in (before other code builds on top of it)
  • Volatility: How much designs differ in their failure modes

Option value is higher when volatility is higher. In software terms: designs that differ only in aesthetics have low volatility — the rework cost is similar regardless of which you pick. Designs that differ in failure modes have high volatility — one survives session death, one doesn't. The option to pause is worth more in high-volatility design spaces.

The concrete failure example reframed: "orchestrator-batch" and "agent-stores" differ in one critical dimension: which process holds state at the moment of session death. Under orchestrator-batch, in-flight state is held by the orchestrator and dies with it. Under agent-stores, each subagent has already committed its state before the orchestrator knows about it. The volatility on this dimension is extreme — one design loses everything, the other loses nothing. Option value was high. Pause was warranted. Agent didn't pause.

When is option value near zero?

  1. Designs converge under all failure modes (true reversibility — rework is cheap)
  2. Session death probability is negligible (batch jobs under 5 minutes with no I/O gates)
  3. The decision is purely aesthetic and future code is unlikely to build on top of it

The practical test: "If this session died right now, which design survives?" is a rough volatility probe that takes 30 seconds and correctly identifies high-volatility design spaces.


3. The Information Economics Problem: Not Knowing You're at a Decision Point

Here is where formal decision theory collides with the actual problem.

Classical decision theory assumes you can enumerate the option set. The challenge for AI agents is not choosing among known options — it is noticing that a choice exists at all. The agent in the failure example didn't weigh orchestrator-batch against agent-stores and pick the wrong one. It never perceived the choice as a choice.

This is a meta-decision problem: deciding whether the current situation is a decision situation.

Define the value of option-set awareness (VOSA) as:

VOSA = E[V | I know I'm at a choice point] - E[V | I don't know I'm at a choice point]

VOSA is always non-negative — knowing you're at a choice point can only help. But acquiring the information that "this is a choice" is itself costly (requires the agent to step back, recognize the ambiguity, and enumerate alternatives rather than proceeding).

The deeper problem: awareness is not uniformly distributed. Agents are more likely to notice "I'm making a choice" when:

  • The problem statement explicitly names alternatives ("should we use X or Y?")
  • The decision is syntactically visible (a fork in the code, a conditional)
  • The decision maps to a pattern the agent has seen flagged before

Agents are systematically less likely to notice "I'm making a choice" when:

  • The decision is structural rather than syntactic (who holds state is invisible until session death)
  • The "obvious" path is technically correct (orchestrator-batch works — until it doesn't)
  • Speed pressure exists (the agent is mid-task and the decision feels like an implementation detail)

This asymmetry is the core problem. The agent's prior over "is this a decision point?" is biased toward no. Every implementation path feels like "the path" until a forcing function reveals alternatives.

What is the VOSA of a generic trigger? If we give the agent a checklist — "before implementing anything that touches state, interface ownership, or irreversibility, pause and enumerate alternatives" — the VOSA of that rule is the expected benefit across all decisions it triggers on, minus the false-positive cost (pauses on non-decisions). A rule that triggers 10 times and is warranted 4 times has positive expected value if each warranted pause saves more than 1.5x the false-positive cost.


4. A Practical Scoring Formula

The following is not a precise formula. It is a decision instrument — a rough calculation that takes less than 60 seconds and has better-than-chance performance on the threshold question.

Design Pause Score (DPS):

DPS = (R × I × S) - C_pause_normalized

Where:
  R = Recurrence weight (0-3): Has this category failed in recent history?
      0 = no recent failures in this category
      1 = one failure in last 30 days
      3 = multiple failures or active incident

  I = Irreversibility weight (0-3): How expensive is rework?
      0 = trivially reversible (rename a variable)
      1 = moderate (refactor callers, but no data migration)
      2 = expensive (data migration, or multiple dependent systems)
      3 = catastrophic (data loss, or requires session history replay)

  S = Survival divergence (0-2): Do candidate designs differ in survival under failure?
      0 = all designs fail identically
      1 = designs differ in graceful degradation
      2 = designs differ in data loss under session death

  C_pause_normalized = 0 if pause cost is under 10 minutes, 1 if material
  • DPS > 2: Pause warranted. Enumerate alternatives explicitly before writing code.
  • DPS 1-2: Surface the choice to the admin in one sentence before proceeding.
  • DPS < 1: Proceed, log the design choice in the implementation notes.

Applied to the failure example:

  • R = 1 (state resilience has failed in kaizen before — the review-findings incident)
  • I = 3 (data written mid-session, session death means full loss)
  • S = 2 (orchestrator-batch loses everything; agent-stores loses nothing)
  • C_pause_normalized = 0 (10-minute enumeration)

DPS = (1 × 3 × 2) - 0 = 6. Unambiguously pause. The formula would have caught this.

The five risk categories map directly onto the formula: interface ownership raises I; state resilience raises S; irreversibility raises I; recurrence risk raises R; L1-only contracts raise I (because you can't enforce a correction without re-implementation).


5. The Meta-Paradox: Does Universal Pausing Create Overhead?

If the agent pauses on every decision with DPS > 2, what is the marginal cost?

Assume an agent executes 50 decisions per session. If 10% have DPS > 2, that's 5 pauses per session, each costing 5-10 minutes. Total pause overhead: 25-50 minutes per session. This is a non-trivial tax.

The calibration question is whether the threshold should be 2, 3, or 4 — and this is not a philosophical question. It is an empirical one, answerable from kaizen's own incident history: how many past incidents involved a design choice that a DPS > 2 rule would have caught? How many false positives would the rule have generated?

But there is a deeper meta-paradox. If the agent applies DPS to every sub-decision recursively, including the decision of "should I apply DPS here?", the overhead explodes. Meta-application must be bounded. The fix is to scope DPS to structural decisions only — decisions that touch persistence, interfaces, or enforcement contracts — not to every implementation detail.

The more interesting paradox: pausing too often degrades agent effectiveness in a different way. It signals low confidence, requires constant admin attention, and destroys the value of autonomy. An agent that checks in every 10 minutes is more expensive than a human developer. The point of autonomy is to defer to agent judgment on routine decisions and escalate only the genuine forks.

The calibration target is not "zero wrong designs." It is "the agent handles routine decisions autonomously and flags genuinely ambiguous structural choices." The DPS formula is useful precisely because it has a non-trivial threshold — most decisions score below 2 and proceed without pausing.


6. What Decision Theory Gets Wrong Here

Decision theory assumes you can enumerate the option set. It has tools for uncertainty over outcomes (probabilistic), uncertainty over payoffs (stochastic), even uncertainty over your own preferences (ambiguity aversion). But it has no native tool for uncertainty over whether you're in a decision situation at all.

This is not a minor gap. It is the central failure mode.

When an agent proceeds without recognizing a design choice, it is not making a bad decision. It is not making a decision at all. It is executing. Decision theory is a theory of choosing among enumerated options. It has nothing to say about the act of perception that precedes choice.

The adjacent literature is in attention economics (Kahneman's System 1 vs. System 2) and meta-cognition (thinking about whether you're thinking about the right thing). System 1 proceeds fluently along the first viable path. System 2 interrupts, asks "wait, is there another path?", and only then hands off to decision theory.

The problem for AI agents is that System 2 interruption requires a trigger. Human experts develop triggers through domain experience — a senior engineer who has seen state-resilience failures will feel a faint unease when writing session-scoped state, even before articulating why. That unease is System 2 activating.

AI agents don't carry that embodied experience across sessions. The DPS formula is an attempt to externalize the trigger: instead of relying on internal pattern-matching that may not fire, give the agent a structural checklist that provokes System 2 activation at the right moments.

The honest limitation: DPS only catches design choices that map to the five known risk categories. A genuinely novel failure mode — one that doesn't resemble interface ownership, state resilience, irreversibility, recurrence, or L1-contracts — will pass through the filter undetected. The formula is not a solution to the meta-decision problem. It is an approximation that works for known risk topologies.

The residual problem is precisely what kaizen's Level B horizon discovery is for: when a new failure mode appears that the DPS formula doesn't catch, that failure is evidence of an unknown risk category. File the issue. Update the formula. The formula is a hypothesis; incidents are data.


7. Connection to Established Frameworks

DORA metrics measure deployment frequency, lead time, change failure rate, and mean time to recovery. The design pause question maps most directly onto change failure rate and MTTR. A wrong architectural choice raises MTTR dramatically — recovery requires not just a fix but a rearchitecture. DORA's implicit recommendation is that small, frequent changes with fast feedback loops are safer than large infrequent changes. The design pause is consistent with this: it slows down the first commit in exchange for dramatically shorter MTTRs downstream.

Technical debt theory distinguishes deliberate vs. inadvertent debt (Fowler's quadrant). A wrong design choice made without awareness of alternatives is inadvertent reckless debt — the worst kind, because it isn't even visible in the ledger. The design pause converts inadvertent debt into deliberate debt at worst (the agent knows the tradeoff, chooses the faster path, documents it) and eliminates it at best (the correct design is chosen from the start). Deliberate debt is manageable. Inadvertent debt compounds silently.

Google's software engineering vs. programming distinction (Winters et al., "Software Engineering at Google") frames software engineering as "programming integrated over time." A decision that is optimal for the current moment but costly to change over time is a programming decision disguised as a software engineering decision. The design pause is a forcing function for software engineering thinking: before committing, explicitly ask "what is the time-integrated cost of this choice?" The survival divergence dimension of DPS (S) is a direct operationalization of this: designs that fail differently under session death have divergent time-integrated costs even if they have identical current-moment costs.

Real options in infrastructure investment (Dixit and Pindyck) has a parallel that is rarely cited in software contexts: the optimal investment rule under uncertainty is to wait longer than NPV calculations suggest, because irreversible investments destroy option value. Applied here: the optimal implementation rule under design uncertainty is to pause longer than task-completion pressure suggests, because locking in the wrong design destroys the option to choose correctly. The bias toward "just start coding" is the software equivalent of the bias toward "just build the factory" — it destroys option value in exchange for the psychological comfort of forward motion.


Synthesis

The design pause problem is not primarily a decision problem. It is a perception problem with a decision-theoretic solution.

The agent doesn't need better decision theory. It needs a trigger that converts invisible choices into visible ones. The DPS formula is that trigger — a structured System 2 activation mechanism that forces the enumeration step before the decision step.

Once the choice is visible, classical expected value analysis applies and the math is not close: the threshold for pausing is low because C_rework on wrong architectural choices is an order of magnitude larger than C_pause. The puzzle is not whether to pause when you see a choice. The puzzle is seeing the choice at all.

This is why the five risk categories matter less as a decision framework and more as a perception training set: they teach the agent where choices are likely to hide. Interface ownership decisions hide in "who should call this function?" thoughts. State resilience decisions hide in "where should I store this?" thoughts that feel like implementation details. The categories are a pattern library for noticing.

Kaizen's zen principle applies directly: "the horizon you can name, you can climb. The horizon you can't name climbs you." The five categories are names for decision horizons that were previously invisible. The agent that has internalized them will perceive choices that the agent without them will execute through without noticing.

The meta-problem — novel risk categories that don't fit the existing five — is handled recursively: every wrong-design incident that passes through the DPS filter undetected is evidence for a new category. File the issue. Update the formula. The improvement system improves itself.

That's the bet.

Signal Archaeology: Observable Precursors to Expensive Design Failures

Before implementation begins, what can an agent actually see?


Framing

The companion document r1-decision-theory.md establishes when a design pause is warranted using formal frameworks: expected value thresholds, real options, the VOSA (value of option-set awareness). It concludes correctly that the core problem is a perception problem, not a decision problem. The agent that doesn't notice it's at a design choice never reaches the decision step.

This document addresses the perception half: what observable signals — in the codebase, in git history, in the issue tracker — precede expensive design failures and could mechanically trigger that perception?

The hypothesis under examination: the five risk categories (interface ownership, state resilience, irreversibility, recurrence risk, L1-only contracts) always leave observable traces before implementation begins. An agent running a 90-second scan could detect most of them.

We will test that hypothesis rigorously.


The Signal Taxonomy

Seven to ten signals with real detection commands. Each assessed for false positive rate and mapped to the risk categories.

Signal 1: Competing Patterns for the Same Concern

What it looks like: Two or more distinct implementation styles handle the same concern in different parts of the codebase. Storage in one place is via file write; in another place via GitHub comment. Two hooks solve the same problem with incompatible state formats.

Why it matters: Competing patterns are the codebase's memory of past design debates — or evidence that the design was never debated. When a new feature must choose, both options appear "correct" because both have precedent. The agent picks whichever it sees first.

Detection commands:

# Find multiple state directories with overlapping names
find /tmp -name "*.state" -o -name "*.gate" 2>/dev/null | sed 's|/[^/]*$||' | sort | uniq -d

# Find functions with similar names implementing similar purposes
grep -rn "function store\|function save\|function write\|function persist" src/ --include="*.ts" -l

# Count distinct patterns for a specific concern (e.g., review state)
grep -rn "storeReview\|saveReview\|writeReview\|postReview" src/ --include="*.ts"

Mapped to: Interface ownership, irreversibility.

False positive rate: ~40%. Many competing patterns are intentional specializations rather than design ambiguity. The signal is meaningful when the patterns handle identical inputs with different output locations. Two write functions that write to different things for different reasons are not competing. Two write functions that write the same data to different locations are.

Real-world case: In the kaizen review battery, review findings were stored in two places: session-local JSON state and PR comments. This was fine — different purposes. But when the store-review-finding CLI was added, it wasn't clear which of the two storage targets was authoritative. Three months later, a fix read from the wrong source. The competing patterns had been visible in the codebase the entire time.


Signal 2: Recent Commit Churn in the Target Area

What it looks like: The files you are about to modify have been touched by 3+ commits in the last 30 days, with different authors or different issue references — suggesting the area is actively contested or frequently broken.

Why it matters: Churn is a proxy for instability. High-churn areas have unclear ownership, evolving contracts, and a history of designs that didn't hold. A new feature implemented in a high-churn area is more likely to conflict with in-flight changes or to encode assumptions that have already been disproven.

Detection commands:

# Find files changed most frequently in last 30 days
git log --since="30 days ago" --name-only --pretty=format: | sort | uniq -c | sort -rn | head -20

# Check churn on specific files you're about to touch
git log --since="30 days ago" --oneline -- src/structured-data.ts src/cli-structured-data.ts

# Find fixes that were themselves fixed (double-fix pattern — strong recurrence signal)
git log --oneline --since="60 days ago" | grep -i "^[a-f0-9]* fix" | wc -l
git log --oneline --since="60 days ago" | grep -i "fix.*fix\|re-fix\|fix again"

Mapped to: Recurrence risk.

False positive rate: ~35%. Active development produces churn that is healthy and expected. The signal strengthens significantly when combined with commit messages that contain "fix" or "revert" — churn from feature additions is different from churn from corrections.

Real-world case: In this codebase, src/hooks/lib/gate-manager.ts was touched 7 times in 30 days across 5 different PRs (#886, #890, #891, #894, #903). Any new feature touching gate management should have paused: this area had a live design argument visible in the commit history.


Signal 3: TODOs or FIXMEs Mentioning Design Uncertainty

What it looks like: Comments in the target area that say "TODO: figure out who owns this", "FIXME: this should probably be in X", "NOTE: this is a workaround until we decide", or equivalent.

Why it matters: TODOs and FIXMEs are the codebase's unresolved design debates. They are evidence that a previous implementer recognized a design question, couldn't resolve it, and deferred it. A new implementation in the same area will encounter the same unresolved question.

Detection commands:

# Find design-uncertainty TODOs in target area
grep -rn "TODO\|FIXME\|HACK\|XXX\|WORKAROUND\|who owns\|figure out\|decide later\|temporary" \
  src/ .claude/hooks/ --include="*.ts" --include="*.sh" | grep -v ".test."

# Focus on uncertainty language specifically
grep -rn "unclear\|ambiguous\|TBD\|should this\|or should\|decide" \
  src/ .claude/hooks/ --include="*.ts"

Mapped to: Interface ownership, L1-only contracts.

False positive rate: ~25%. Most TODOs are implementation reminders ("TODO: add error handling"), not design questions ("TODO: figure out who should call this"). The signal is specifically strong when the TODO mentions ownership, location, or "which approach".

Real-world case: The src/hooks/lib/gate-manager.ts file had a comment noting that gate clearing was "temporary" until a unified stop hook was built. This note was present for two full sprints. Two features were implemented during that period that encoded the temporary approach as permanent. When the unified stop hook (src/hooks/stop-gate.ts) was finally built, both features required rework.


Signal 4: Missing Test Coverage for State Transitions

What it looks like: The target area writes state but has no tests that verify what happens when state is partially written (session death mid-write, partial completion). Tests exist for the happy path but not for the failure path.

Why it matters: Missing failure-path tests are a strong predictor of state-resilience choices that weren't examined. A developer who writes a state-write function and doesn't test "what if we crash here?" has almost certainly not thought through which design survives session death. The test gap reveals the design gap.

Detection commands:

# Find source files with state-writing functions that have no corresponding crash/partial tests
grep -rn "writeFile\|appendFile\|createWriteStream\|fs.write" src/ --include="*.ts" -l | \
  while read f; do
    base=$(basename "$f" .ts)
    test_file="${f%.ts}.test.ts"
    if [ -f "$test_file" ]; then
      if ! grep -q "crash\|partial\|interrupted\|die\|fail.*mid\|mid.*fail" "$test_file" 2>/dev/null; then
        echo "MISSING FAILURE TESTS: $f"
      fi
    else
      echo "NO TEST FILE: $f"
    fi
  done

# Alternative: scan for resilience test presence across the repo
grep -rn "crash\|resilience\|partial\|interrupted\|survive" src/ --include="*.test.ts" | wc -l

Mapped to: State resilience.

False positive rate: ~30%. Many state-writing functions are idempotent or write to durable stores where partial writes are automatically handled. The signal is strongest when the code writes to files, in-memory state, or session-scoped storage — not when it writes to GitHub (which is durable by default).

Real-world case: The review-findings storage that preceded the store-review-finding CLI had comprehensive happy-path tests and zero crash tests. The crash scenario (orchestrator dies mid-batch after storing half the findings) was not tested because nobody asked "what happens if we crash here?" The gap was detectable: 0 test lines containing "crash" or "partial" in the review state test files.


Signal 5: Interface Called From Multiple Sites Without a Single Owner

What it looks like: A function or module is imported and called from 4+ different files, but there is no file that is clearly "the owner" — no single file that defines the interface contract, validates inputs, or handles errors. The callers each make slightly different assumptions.

Why it matters: When an interface has no single owner, adding a new feature must either pick one caller's assumptions (silently breaking others) or implement a new calling convention (creating another variant). Interface ownership ambiguity compounds with every new feature.

Detection commands:

# Find modules imported in 4+ files (potential ownership ambiguity)
grep -rn "import.*from" src/ --include="*.ts" | \
  sed "s/.*from '//; s/'.*//" | sort | uniq -c | sort -rn | head -20

# Find specific high-import modules and count their callers
grep -rn "from '.*structured-data\|from '.*gate-manager\|from '.*state-utils" \
  src/ --include="*.ts" | grep -v "\.test\." | wc -l

# Find functions called with different argument patterns (interface drift)
grep -rn "storeReviewFinding\|store_review_finding" src/ --include="*.ts" | head -20

Mapped to: Interface ownership.

False positive rate: ~50%. High import counts are normal for utility libraries. The signal is meaningful specifically when: (a) the imported module makes side effects (writes state, posts to GitHub), and (b) callers pass different arguments suggesting different assumptions about what the function does.

Real-world case: The cli-structured-data.ts module was invoked from 6 different scripts (review workflows, auto-dent scripts, manual skill invocations) with subtly different assumptions about which --repo flag was correct. When a new feature needed to call it, there was no canonical example to follow. Three of six callers were wrong in edge cases.


Signal 6: Multiple Open Issues Referencing the Same Area

What it looks like: The GitHub issue tracker has 2+ open issues (not PRs) that mention the same files, functions, or concepts as your planned implementation.

Why it matters: Open issues about an area indicate known problems that haven't been resolved. Implementing new features on top of known problems encodes the problem into the new feature's architecture. Two open issues about the same area is strong evidence of a design question that isn't settled.

Detection commands:

# Find open issues mentioning your target area
gh issue list --state open --json number,title,body --limit 100 | \
  jq -r '.[] | select(.body | test("structured-data|review-finding|gate-manager"; "i")) |
    "#\(.number): \(.title)"'

# Count open issues by label to find problem clusters
gh issue list --state open --json labels --limit 200 | \
  jq -r '.[].labels[].name' | sort | uniq -c | sort -rn | head -20

# Find issues referencing specific files or concepts
gh issue list --state open --search "state-utils OR gate-manager" --json number,title | \
  jq -r '.[] | "#\(.number): \(.title)"'

Mapped to: Recurrence risk, L1-only contracts.

False positive rate: ~20%. Issues in the tracker are about the area for a reason. This signal has one of the lowest false positive rates in the taxonomy because it directly encodes human judgment that "this area has a problem." The main false positive is issues that are purely additive (requesting new features) rather than diagnostic (reporting failures or design problems).

Real-world case: Before the worktree-isolation rules were added to policies.md, there were three open issues about cross-worktree contamination. Two features were built during that period that read state from /tmp/.pr-review-state/ directly (without worktree filtering), reproducing the exact problem. The issues were visible. The connection to the implementation decision was not.


Signal 7: Enforcement Only at L1 (Instructions) for a Known Failure Mode

What it looks like: A behavior that has failed before is enforced only through documentation — a line in CLAUDE.md, a policy in policies.md, a comment in the code — with no corresponding hook that would block the wrong behavior mechanically.

Why it matters: L1-only enforcement is brittle by definition. The kaizen zen says it directly: "instructions are necessary but never sufficient." If the behavior has failed once before and the only correction was to add a CLAUDE.md line, the same failure can recur in any session that doesn't read that line carefully.

Detection commands:

# Find policies in docs/CLAUDE.md that mention a behavior without a corresponding hook
grep -n "never\|always\|must\|should not\|do not" .claude/kaizen/policies.md | head -20

# Check if a specific behavior is enforced in hooks or only in docs
grep -rn "worktree-isolated\|BRANCH\|currentWorktree" .claude/hooks/ src/hooks/ \
  --include="*.ts" --include="*.sh" | wc -l
grep -rn "worktree-isolated" .claude/kaizen/policies.md

# Cross-check: list hook names and see which policies have no corresponding hook
ls .claude/hooks/ src/hooks/ 2>/dev/null | grep -v test | sort

Mapped to: L1-only contracts.

False positive rate: ~15%. This signal is highly reliable because it directly tests the enforcement level. The main false positive: policies that are L1-enforced intentionally because the behavior is so rare that a hook would have more overhead than the occasional failure. The signal strengthens dramatically when combined with a git history showing the behavior has already failed.

Real-world case: Policy #5 in policies.md — "Hooks MUST be worktree-isolated" — was an L1-only policy for two sprints after the first cross-contamination incident. During that time, two new hooks were written that violated the policy. When the second violation occurred, it escalated to L2 (the isStateForCurrentWorktree check was added to state-utils.ts). Both violations were preventable with a lint check.


Signal 8: Data Format Written by Multiple Components With No Schema

What it looks like: JSON or structured data is written to a file or GitHub comment by more than one component, but there is no schema definition, TypeScript interface, or validation function that all writers share. Each writer hard-codes its assumptions about the format.

Why it matters: When a format has no schema, every writer encodes its own assumption about what the data looks like. When a new feature writes to the same format (or must read what others wrote), it has no authoritative contract to reference. Subtle format drift goes undetected until a consumer breaks.

Detection commands:

# Find JSON writes without schema references nearby
grep -rn "JSON.stringify\|JSON.parse" src/ --include="*.ts" | grep -v ".test." | \
  grep -v "import\|interface\|type " | head -20

# Find state file formats — check for schema definition
grep -rn "interface.*State\|type.*State\|interface.*Gate\|type.*Gate" \
  src/ --include="*.ts" | grep -v ".test." | head -10

# Find places writing structured data without importing a type for it
grep -rn "JSON.stringify({" src/ --include="*.ts" | grep -v ".test." | head -10

Mapped to: Irreversibility.

False positive rate: ~35%. Many JSON writes are truly one-off and don't need schemas. The signal matters when multiple components (hooks, skills, CLI commands) read and write the same logical data. The test: "if I changed one field name, how many files would break?" More than 3 is a schema smell.

Real-world case: The kaizen gate state files in /tmp/.pr-review-state/ were written by 3 hooks and read by 2 others, with no shared TypeScript interface defining the expected fields. When a new hook added a BRANCH field, two existing readers broke silently because they didn't know to expect it.


Signal 9: The Feature Touches a Boundary Between Two Components

What it looks like: The planned implementation sits at the junction of two subsystems — e.g., hooks and skills, orchestrator and subagents, CLI and GitHub API — where each subsystem has its own error handling, state model, and failure modes.

Why it matters: Boundary implementations must answer a structural question: which side owns the contract? Who handles errors? Who retries? Where does state live? These questions are invisible when you're thinking about what to implement but become visible immediately when implementation starts. The boundary is where design ambiguity concentrates.

Detection commands:

# Find files that import from both subsystem A and subsystem B (boundary files)
for f in $(grep -rln "from '.*hooks" src/ --include="*.ts"); do
  if grep -q "from '.*structured-data\|from '.*cli" "$f" 2>/dev/null; then
    echo "BOUNDARY FILE: $f"
  fi
done

# Find the seam — functions that translate between two representations
grep -rn "transform\|convert\|map.*to\|serialize\|deserialize\|adapt" \
  src/ --include="*.ts" | grep -v ".test." | head -20

# Check if either side of the boundary has had recent failures
git log --since="60 days ago" --oneline | grep -i "fix.*hook\|fix.*gate\|fix.*state"

Mapped to: Interface ownership, state resilience.

False positive rate: ~45%. Boundary files are normal and necessary. The signal is meaningful specifically when the boundary is newly established (first feature to cross it) or when the two sides have historically had different failure modes. Check: "has either side of this boundary experienced a failure in the last 60 days?"

Real-world case: The stop-gate.ts implementation sat at the boundary between the TypeScript hook infrastructure and the gate state files. The first version made an interface ownership assumption: that the TypeScript hook was responsible for reading all gate files and synthesizing a response. That assumption turned out to be wrong — some gates were owned by bash hooks and needed to remain bash-readable. The boundary was visible; the ownership ambiguity at the boundary was not.


Signal 10: Admin Has Not Explicitly Confirmed the Design

What it looks like: The task description or issue body describes what to build but not how. There is no explicit admin statement like "use the agent-stores pattern" or "orchestrator batches findings." The agent is inferring the design from the description of the desired behavior.

Why it matters: Admin intent is not always inferrable from behavioral description. Two designs can produce identical behavior under normal conditions and diverge only under failure. If the admin hasn't stated a design preference, the agent's inferred preference may not match the admin's actual preference — and the mismatch is only discovered when the wrong failure mode occurs.

Detection commands:

# Check the issue body for explicit design language
gh issue view <N> --json body | jq -r '.body' | \
  grep -i "use\|pattern\|approach\|design\|architecture\|store.*in\|write.*to\|who.*calls\|ownership"

# Check if there's a plan attachment with design rationale
npx tsx src/cli-structured-data.ts retrieve-plan --issue <N> --repo "<REPO>" 2>/dev/null | \
  grep -i "design\|pattern\|approach\|alternative\|tradeoff"

# Check the PR description if one exists
gh pr view <N> --json body 2>/dev/null | jq -r '.body' | \
  grep -i "design\|chose.*because\|instead of\|tradeoff"

Mapped to: Interface ownership, all five categories.

False positive rate: ~60%. Most issue descriptions don't specify design because the behavior description is sufficient for straightforward implementations. This signal only has meaning when combined with at least one other signal (state writes, boundary crossing, recurrence in the area). Alone, it is noise.

Real-world case: The review-findings storage issue described "store review findings per round per dimension." It did not specify whether the reviewing agent or the orchestrating agent should call the storage CLI. Both are valid readings. The implementation chose orchestrator-batch by default because that's what the description implied. The alternative (agent-stores) would have required reading the description against the five risk categories — which the agent didn't do.


The Signal Scan Procedure

A 90-second scan an agent runs mechanically before any implementation that touches state, interfaces, or persistence. Steps are ordered by signal quality (high-signal first).

#!/usr/bin/env bash
# Design Pause Signal Scan — run before implementing
# Usage: Set TARGET_FILES, TARGET_AREA, ISSUE_N, REPO before running

TARGET_FILES="src/structured-data.ts src/cli-structured-data.ts"
TARGET_AREA="review"
ISSUE_N="123"
REPO="Garsson-io/kaizen"

echo "=== SIGNAL SCAN ==="

echo ""
echo "--- Signal 6: Open issues in target area (lowest FP rate) ---"
gh issue list --state open --search "$TARGET_AREA" --json number,title --limit 10 2>/dev/null | \
  jq -r '.[] | "#\(.number): \(.title)"' | head -5

echo ""
echo "--- Signal 7: L1-only enforcement check ---"
grep -n "never\|must not\|do not.*$TARGET_AREA\|$TARGET_AREA.*must" \
  .claude/kaizen/policies.md CLAUDE.md 2>/dev/null | head -5
echo "Corresponding hooks:"
ls .claude/hooks/ src/hooks/ 2>/dev/null | grep -i "$TARGET_AREA" | head -5

echo ""
echo "--- Signal 2: Recent churn in target files ---"
git log --since="30 days ago" --oneline -- $TARGET_FILES 2>/dev/null | head -10

echo ""
echo "--- Signal 3: Design-uncertainty TODOs ---"
grep -rn "TODO\|FIXME\|who owns\|figure out\|TBD\|decide\|should this" \
  $TARGET_FILES .claude/hooks/ 2>/dev/null | grep -v ".test." | head -10

echo ""
echo "--- Signal 1: Competing patterns ---"
grep -rn "store\|save\|write\|persist" src/ --include="*.ts" 2>/dev/null | \
  grep -i "$TARGET_AREA" | grep -v ".test." | head -10

echo ""
echo "--- Signal 4: Missing resilience tests ---"
for f in $TARGET_FILES; do
  test_f="${f%.ts}.test.ts"
  if [ -f "$test_f" ]; then
    count=$(grep -c "crash\|partial\|interrupted\|die\|session.*end" "$test_f" 2>/dev/null || echo 0)
    echo "$f -> $count resilience test lines"
  else
    echo "$f -> NO TEST FILE"
  fi
done

echo ""
echo "--- Signal 10: Admin design specification check ---"
if [ -n "$ISSUE_N" ]; then
  gh issue view "$ISSUE_N" --json body --repo "$REPO" 2>/dev/null | jq -r '.body' | \
    grep -i "design\|pattern\|approach\|who.*calls\|ownership\|store.*in\|write.*to" | head -5
  echo "(empty output = no explicit design spec in issue)"
fi

echo ""
echo "=== SCAN COMPLETE ==="
echo "0-1 signals: proceed. 2+ signals: enumerate design alternatives before writing code."

The scan surfaces signals. The agent reads the output, counts how many signals fire, and applies the threshold rule: 2+ signals warrant pausing to enumerate alternatives before writing code.


Calibration: Where Is the Threshold?

Two signals firing simultaneously is the practical threshold. The reasoning:

Any single signal is prone to 25-50% false positives. Two independent signals firing simultaneously drops the false positive rate to roughly 10-25% (assuming partial independence between signals). At 10-25% false positive rate, the EV calculation from r1-decision-theory.md strongly favors pausing — C_rework on a wrong architectural choice is an order of magnitude larger than C_pause for a 10-minute design enumeration.

Three signals makes the case overwhelming. Proceed without pausing only with a conscious decision to accept the risk, logged in the implementation notes.

The signals do not carry equal weight. Ordered by reliability (lowest false positive rate first):

  1. Signal 7 (L1-only enforcement for known failure): ~15% FP
  2. Signal 6 (multiple open issues in area): ~20% FP
  3. Signal 3 (design-uncertainty TODOs): ~25% FP
  4. Signal 4 (missing resilience tests): ~30% FP
  5. Signal 2 (recent churn + fix commits): ~35% FP
  6. Signal 8 (unschemaed format, multiple writers): ~35% FP
  7. Signal 1 (competing patterns for same concern): ~40% FP
  8. Signal 9 (boundary between subsystems): ~45% FP
  9. Signal 5 (interface called from many sites): ~50% FP
  10. Signal 10 (no admin design spec): ~60% FP

Combination rules: If Signal 7 fires plus any one other, pause. Signal 10 is too weak to count alone — it only contributes when paired with Signal 4 or Signal 2. Signals 1 and 9 together (competing patterns at a subsystem boundary) are a particularly reliable combination even though each individually has a high false positive rate.


Blind Spots: What Signal Archaeology Cannot See

Blind Spot 1: Novel failure modes. If the design choice involves a failure mode not analogous to any of the five risk categories, no signal will fire. A genuinely new class of failure — one that doesn't involve interface ownership, state resilience, irreversibility, recurrence, or L1-contracts — is invisible to this taxonomy. Kaizen's response: when such a failure occurs, it is evidence for a new risk category. File the issue, update the taxonomy.

Blind Spot 2: Correct-but-suboptimal designs. The signals detect design ambiguity and risk of catastrophic failure. They do not detect "the agent picked a design that works but is harder to maintain." A choice between two designs that both survive session death and both have clear interface ownership might still be a 10x maintenance difference. No signal fires on that distinction.

Blind Spot 3: Clean codebases with undocumented history. A fresh codebase with no TODOs, no churn, no open issues, and clean separation of concerns will produce no signals — even if the design space is genuinely ambiguous. All signals are retrospective: they require previous evidence of problems. A first-of-kind decision in a clean area leaves no trace.

Blind Spot 4: Decisions made in instruction documents rather than code. Several important design decisions in kaizen live in policies.md and zen.md rather than in code or tests. Signals that scan code and git history won't surface these. Signal 7 partially covers this, but only when the policy has been violated before.

Blind Spot 5: Decisions that appear as implementation details. The motivating failure case — orchestrator-batch vs. agent-stores — looks like an implementation detail ("where do I call the CLI?") until you think about failure modes. No signal fires on "where do I call a function?" unless state resilience in that area has failed before (Signal 4) or there are competing patterns (Signal 1). A genuine first occurrence of this class of decision leaves no trace.

This last blind spot is significant. Estimate: 30-40% of expensive design mistakes will not be preceded by detectable signals. The signal scan is necessary but not sufficient.


The Meta-Question: Is Signal Detection the Right Frame?

The honest answer is: partially, but the frame has a structural weakness.

Signal detection solves the perception problem by externalizing pattern recognition. Instead of relying on the agent to develop intuitions about where design choices hide (which requires cross-session memory that agents lack), the scan mechanically checks the places where choices typically hide and surfaces them. This is the right approach for the risk categories we can enumerate.

The structural weakness: all ten signals are retrospective. They detect that something has been wrong before, or that the area has characteristics known to correlate with problems. They cannot detect genuinely novel failure modes or first-occurrence wrong designs in clean areas. The scan has systematic survivorship bias: it learns from past failures but cannot anticipate novel ones.

The deeper question is whether signal detection is the right frame at all, or whether the right frame is design space enumeration. The DPS formula from r1-decision-theory.md points toward enumeration: before choosing a design, explicitly ask "what are the alternatives? How do they differ under failure?" Signal detection just triggers that question — it doesn't answer it.

The two approaches are complementary:

  • Signal detection (this document): a fast 90-second scan that raises the probability of noticing a choice exists
  • Design space enumeration (prompted by the scan): a slower 5-10 minute exercise that explicitly names alternatives and evaluates them under the five risk categories

Neither alone is sufficient. The signal scan without enumeration is an alarm with no response procedure. Enumeration without the signal scan relies on the agent noticing it's at a decision point — the original failure mode.

What might work better than either alone: a pause trigger embedded in the task description itself, where the admin specifies "this decision involves state writes — explicitly evaluate designs before implementing." This is L1 enforcement, but it is active L1 (admin deliberately names the choice) rather than passive L1 (agent hopes to notice the choice on its own). Active L1 has a substantially better track record than passive L1 in kaizen's own history.

The escalation path then becomes: active L1 (admin names the decision) → signal scan (automated trigger for unnamed decisions) → DPS formula (quantifies whether to pause) → design enumeration (makes the choice explicit). Each layer catches what the layer below misses. This is the enforcement stack applied to the perception problem.


Synthesis

The hypothesis is partially confirmed: most expensive design failures do leave observable signals in the codebase and history before implementation begins. Seven of the ten signals have detection commands that a 90-second scan can execute mechanically. The two-signal threshold catches the highest-risk decisions while keeping false positive overhead manageable.

The hypothesis is not fully confirmed: 30-40% of expensive design mistakes occur in areas where signals don't fire — novel failure modes, first occurrences in clean areas, and decisions that look like implementation details until they fail. Signal archaeology is a meaningful first line of defense, not a complete solution.

The practical recommendation: run the signal scan as a standard step before any implementation touching state persistence, interface contracts, or enforcement mechanisms. When 2+ signals fire, explicitly enumerate design alternatives before writing code. Log the enumeration and the choice in the implementation notes.

The scan itself is kaizen's five risk categories made executable. The categories were always the right frame; the gap was making them detectable without relying on the agent's intuition.

Specs are hypotheses. Incidents are data. The categories in this taxonomy are hypotheses. The failures that escape this scan are the data that will improve it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment