Skip to main content
ThunderLang
← All articles
ai-engineering

The Tacit Knowledge Problem: What AI Agents Cannot Inherit From Your Spec

6 min read · 2026-09-10 · Allen Codewell

A spec that passes review is not the same as a spec that transfers intent. The gap between those two things is exactly where AI-generated code goes wrong, and most teams will not notice until the change is already in production.

The Incident That Made This Concrete

In early 2024, a team using GitHub Copilot to assist with a Postgres schema migration watched their agent produce a technically correct refactor: it consolidated two nullable columns into a single JSONB field, matched the spec to the letter, and passed all existing tests. The migration was approved and shipped. Three weeks later, a compliance audit flagged it. The original two-column structure had been intentional. A prior regulatory review had required that each field be individually auditable in the raw schema, not buried inside a JSON blob. Nobody wrote that down. It lived in the heads of two engineers who had been on the call with legal two years earlier.

The agent never had a chance. It optimized for what the spec said, because that is all it had.

Every Spec Contains Two Documents

This is the tacit knowledge problem in software specifications. Tacit knowledge refers to the context, reasoning, and constraints that practitioners carry in memory but never transcribe because, to them, it feels too obvious to write down. In human teams, this knowledge transfers through code review comments, Slack threads, architecture decision records that junior engineers are told to read before touching a module, and the institutional memory of anyone who has been around long enough to remember why the thing is shaped the way it is.

AI agents inherit none of that. They receive the explicit text of a spec, the visible structure of the codebase, and whatever context fits inside their context window. When an agent reads a requirement like "refactor the user session handling to reduce round trips", it does not know:

  • That a previous attempt to reduce round trips introduced a race condition caught only in a load test at 10x production traffic
  • That the session service sits inside a SOC 2 audit boundary, and certain logging patterns are contractually required
  • That the team explicitly rejected a Redis-backed approach eighteen months ago after a cache invalidation bug caused a four-hour incident

None of that context is in the spec. It is folklore. And agents eat folklore for breakfast and produce code that looks like the right answer from the outside.

Why Implicit Assumptions Are the Load-Bearing Walls

The implicit assumptions in a spec are not decorative. They are frequently the constraints that matter most, because they encode hard-won learning: the incident that proved a particular approach dangerous, the regulatory constraint that arrived late in a project, the architectural boundary that cannot move without touching three other teams.

Human engineers carry a mental model that includes what the spec says and what the spec assumes. When a senior engineer reviews code, they are not just checking for spec compliance. They are checking it against accumulated context. "Why did you do it this way?" is a question about tacit knowledge. "Did you know we tried this before?" is tacit knowledge surfacing in review.

An AI agent generating code from a spec will satisfy the letter of the requirement with high reliability. GPT-4 and Claude 3 Opus can produce syntactically correct, idiomatically reasonable code for most well-scoped tasks. The failure mode is not syntax. The failure mode is semantic correctness against constraints that were never stated. That is not a model quality problem. It is a spec completeness problem.

Surfacing the Invisible: Treating Assumptions as First-Class Constraints

The fix is not to write better prose specs. Prose is too ambiguous and too cheap to write to be reliable. The fix is to treat implicit assumptions as machine-verifiable constraints that live in the spec itself, not in someone's memory.

Consider a spec for the session refactor scenario. A prose spec says:

Refactor the session handler to reduce database round trips without changing the public API surface.

A constraint-complete spec says the same thing, but also declares:

constraints:
  - id: audit-log-preservation
    type: invariant
    description: All session lifecycle events must emit structured logs to the audit sink before and after state transitions.
    rationale: SOC 2 CC6.8 requires tamper-evident audit trails for authentication events.
    check: grep -rn 'auditSink.emit' src/session/ | wc -l >= BASELINE_COUNT

  - id: no-redis-session-cache
    type: prohibition
    description: Session state must not be cached in Redis or any external cache layer.
    rationale: ADR-047 documents the cache invalidation incident of 2022-11-14. Risk was accepted to accept higher latency.
    check: "! grep -rn 'redisClient' src/session/"

  - id: concurrent-request-safety
    type: invariant
    description: The refactored handler must pass the existing load test suite at 10x traffic before merge.
    check: make load-test SCALE=10 EXIT_ON_FAILURE=true

Now the agent, and the verification layer that gates the agent's output, can actually check these things. The tacit knowledge is no longer tacit. It is executable.

This is the model that ThunderLang's intent-verification loop is built around: constraints are declared alongside intent, and AI-generated diffs are checked against both before they can merge. The spec's letter and the spec's spirit are both represented in a form a machine can evaluate.

The Three Categories of Implicit Assumptions You Need to Surface

Not all tacit knowledge is the same kind. When auditing a spec before handing it to an agent, I look for three categories.

Regulatory and compliance constraints. These are the most dangerous to leave implicit because they have external enforcement. If a field layout, a logging pattern, or a data retention behavior is required by a contract or regulation, that requirement belongs in the spec as a verifiable constraint with a citation. Prose rationale is not enough. The check has to be automatable.

Rejected alternatives. Architecture decision records that document why an approach was ruled out are exactly the kind of context agents need and never have. When you write a constraint that prohibits a particular pattern, include the ADR reference. An agent that sees rationale: ADR-047 has something it can surface to a human reviewer even if it cannot read the ADR itself.

Incident-derived invariants. Production incidents teach things that no theoretical spec process captures. If a load test at 10x caught a race condition, the load test becomes a required gate, not an optional check. If a particular coding pattern caused a memory leak in a prior refactor, that pattern becomes a prohibited form. These constraints feel obvious to the engineers who lived through the incident. They are completely invisible to everyone else, including agents.

The Org-Level Problem

Here is the uncomfortable part: most organizations do not have the tooling or the culture to surface tacit knowledge before it becomes a problem.

ADRs exist in theory at many companies. In practice, they are written inconsistently, linked to from nowhere, and searched only after something breaks. Compliance constraints live in legal documents that engineers never read. Incident learnings go into postmortem docs that atrophy within six months.

When you introduce AI agents into this environment, you are adding a high-velocity code producer with zero access to institutional memory. The agents do not know what they do not know. They will produce code that is confidently, fluently, plausibly wrong in ways that are hard to catch in review, because the violation is not in the code itself but in what the code fails to preserve.

The solution is not to slow down agent usage. It is to treat spec completeness as an engineering discipline with the same rigor as test coverage. A spec with unverified implicit assumptions is a spec with known gaps. Shipping AI-generated code against a gapped spec is a known risk, not an unknown one.

ThunderLang lets you declare what a change must satisfy and then gates AI-written code against that intent with a verify-diff command and durable proof artifacts that travel with the PR. It is the closest thing I have seen to making tacit knowledge auditable by default.

Gate Your First AI Change

The fastest way to find your implicit assumptions is to watch an AI agent violate them in a controlled environment before it does it in production. ThunderLang lets you declare what a change must satisfy, then gates AI-written code against that intent with a verify-diff and durable proof artifacts. Try it here.

The spec you wrote is not the spec the agent read: close that gap before you close the PR.