Skip to main content

Command Palette

Search for a command to run...

AI-DLC Powered by a Knowledge Base at Scale

A reference architecture for making coding agents work on brownfield enterprise systems

Updated
32 min readView as Markdown
AI-DLC Powered by a Knowledge Base at Scale
D
I'm Ayyanar Jeyakrishnan ; aka AJ. With over 21 years in IT, I'm a passionate Multi-Cloud Architect specialising in crafting scalable and efficient cloud solutions. I've successfully designed and implemented multi-cloud architectures for diverse organisations, harnessing AWS, Azure, and GCP. My track record includes delivering Machine Learning and Data Platform projects with a focus on high availability, security, and scalability. I'm a proponent of DevOps and MLOps methodologies, accelerating development and deployment. I actively engage with the tech community, sharing knowledge in sessions, conferences, and mentoring programs. Constantly learning and pursuing certifications, I provide cutting-edge solutions to drive success in the evolving cloud and AI/ML landscape.

Who this is for. Engineering leaders and architects who have run an AI coding pilot, seen the throughput numbers, and suspect the numbers are not telling the whole story. It assumes you operate multiple repositories per application, multiple applications per organisation, real ownership boundaries, and a change process you cannot simply opt out of.

How to read it. Sections 1–3 are the argument. Sections 4–9 are the architecture, and are the part worth stealing. Sections 10–13 are the operating model and how you know it is working. Sections 14–17 are adoption.

Contents

  1. The failure that is not a model failure

  2. Four anti-patterns, named

  3. First principles

  4. Architecture: the four planes

  5. What lives in every repository

  6. The artifact contract

  7. Three enforced flows

  8. Threat model

  9. Seven governing invariants

  10. Scaling out: twenty applications, one graph

  11. The operating model — who owns what

  12. Measurement

  13. A maturity model

  14. Resolving the hard parts

  15. Adoption roadmap

  16. Objections worth taking seriously

  17. Reference checklist


1. The failure that is not a model failure

Every enterprise AI coding programme produces the same chart at month three: pull requests up, cycle time down, developers positive. And a different chart at month nine: review load up, rework up, and a quiet decision to restrict agents to greenfield work.

The usual diagnosis is model capability. It rarely is. Watch what actually happens when an agent is asked to change a pricing rule in a fifteen-year-old lending system:

  • It loads the repository's entire documentation set. Forty files. Thirty-one are irrelevant to pricing. The context window is consumed before the relevant module is reached.

  • It reads an architecture document written eighteen months ago describing a service decommissioned two quarters back. Nothing in the document says it is stale, because nothing in the document records where its claims came from.

  • Ownership is ambiguous. Two modules both appear to touch pricing. The agent picks one — plausibly, and wrongly.

  • It produces a small, well-formatted, confident pull request implementing the wrong rule in the wrong module.

  • A reviewer approves it. The code reads well, the diff is nine lines, and the reviewer has four other PRs waiting.

None of those steps is a reasoning failure. Each is a context supply failure. And the problem does not shrink as models improve — a stronger model executes a wrong premise more convincingly and produces a diff that survives review more easily.

Greenfield conceals all of this. There is no legacy to misread, no stale document, no contested ownership. Brownfield is where context supply is the entire problem, and brownfield is where the value is, because that is where the systems that run the business already live.

The measurement trap

There is a second-order failure worth naming. Throughput metrics — PRs merged, lines changed, story points — move early and move favourably, because agents are genuinely fast at producing plausible output. Correctness metrics move late, and they move through channels that are not instrumented: reviewer fatigue, rework disguised as follow-up tickets, incidents attributed to "a change that went in last sprint."

So the programme's dashboard says succeeding for two quarters longer than the programme is actually succeeding. If you take one operational point from this post, take this: instrument context correctness before you instrument throughput, because only one of them will warn you.

2. Four anti-patterns, named

Naming failure modes is useful because it lets a room agree on what to avoid without arguing about people.

2.1 The documentation dump

Generate documentation at application, service, and module level; point the agent at all of it; regenerate nightly.

This is the instinctive response and it fails on retrieval precision. Loading forty documents to answer a question about one module is not thoroughness; it is noise injection. Precision falls, the model anchors on whichever irrelevant document happened to be most confidently written, and the failure is invisible because the output still looks good.

2.2 The post-merge generator

Regenerate documentation after merge, on a schedule.

A post-merge generator structurally cannot prevent the pull request that made the documentation stale. Every PR merges against context that is one merge behind — and in an active repository, "one merge behind" is permanent. Freshness must be enforced pre-merge or it is not enforced.

2.3 The undifferentiated claim

Documentation that does not distinguish what a human decided from what a tool inferred.

Both render as confident prose. An agent cannot weigh them differently, and neither can a new engineer. Inferred claims must be marked as inferred, and every claim must carry a pointer to the evidence it came from.

2.4 The vendor-shaped rulebook

Encode the rules in one assistant's proprietary format.

Teams run different assistants. If the rules live in Vendor A's playbook format, Vendor B's users never receive them, and you get two populations producing structurally different pull requests. The enforcement layer must be the layer both populations share: path-scoped instruction files that each tool reads natively, plus CI gates that do not care which tool produced the diff.

3. First principles

Maintain a governed, evidence-backed, portable context system that supplies the minimum correct knowledge per agent task — and prove it.

Unpacking each word, because each one rules something out:

Principle What it rules out
Governed Automation redefining what a module means
Evidence-backed Claims with no traceable source; stale claims treated as current
Minimum Bulk-loading context "just in case"
Correct Optimising for coverage instead of accuracy
Per task One context bundle for every kind of work
Portable A toolchain that cannot run on the locked-down runner
Prove it Retrieval quality asserted rather than measured

The rest of this post is the mechanism for those seven rows.

4. Architecture: the four planes

Separating these is what stops the system degenerating into a folder of markdown that everyone ignores.

Plane Holds Fails as
Knowledge Service and module context, glossary, contracts, provenance The only plane most teams build
Control Ownership, schemas, classification, policy, versioning Absent → drift within a quarter
Execution Generator CLI, gate workflows, agent adapters Absent → rules nobody applies
Evaluation Benchmark suite, retrieval and safety metrics Absent → confident self-deception

The Evaluation plane deserves an argument

Our evaluation command does not call an LLM. It assembles the exact context an agent would receive for each benchmark task and scores retrieval deterministically: expected context present, forbidden context absent, precision, recall.

That choice buys three properties that an LLM-judged benchmark cannot offer:

  • Reproducible — the same commit produces the same score, every time.

  • CI-runnable — no inference cost, no rate limits, no network on a locked-down runner.

  • Auditable — a risk function can read the scoring logic. "A model graded it" is not an answer in a regulated change process.

You lose the ability to judge subjective output quality. That is the right trade. Subjective quality is what human review is for; mechanical retrieval correctness is what humans are worst at checking and machines are best at.

5. What lives in every repository

Identical in all repositories of an application. No local variants, no exceptions — a per-repo dialect is the seed of every drift problem that follows.

/
├── AGENTS.md                    # operational rules + context routing (budgeted, generated block)
├── CLAUDE.md                    # thin adapter → AGENTS.md, no duplicated content
├── CODEOWNERS                   # module-owners block, generated from the manifest
├── knowledge-manifest.yaml      # HUMAN-OWNED: module boundaries, owners, allowlist, commands
│
├── docs/ai/
│   ├── application-context.md   # cached projection of cross-service authority
│   ├── service-context.md       # curated service depth
│   ├── glossary.md              # scoped vocabulary
│   ├── modules/<module>.md      # curated intent + AUTO-GENERATED evidence blocks
│   ├── modules/_index.md        # generated from the manifest
│   ├── drift-runbook.md
│   └── generated/               # api-surface, dependency-evidence, audit-log, eval-run
│
├── kb/                          # CLI, policy, schemas, templates, eval suite, agent hooks
├── .github/instructions/<module>.instructions.md   # path-scoped rules, one assistant
├── .claude/rules/<module>.md                       # path-scoped rules, another
└── .github/workflows/           # the two gate flows

Three decisions inside that tree carry most of the weight.

5.1 The manifest is human-owned and no command may write it

Module boundaries are semantic judgements about what a system means. Discovery may propose boundaries into a proposal file; an owner promotes them. The moment automation can silently redraw boundaries, the map stops corresponding to anything anyone agreed to, and every downstream artifact inherits that.

This is the single most important governance decision in the design, and it is the one most often conceded under delivery pressure.

5.2 Curated intent and generated evidence share a file, separated by markers

Only text inside AUTO-GENERATED:START / END markers may be machine-rewritten. The human explanation of why a module exists, what it deliberately does not do, and which historical decision constrains it — all of that survives every regeneration.

This is what makes generated documentation tolerable to the engineers maintaining it. Without it, regeneration destroys human work, engineers stop writing intent, and within two cycles the cards contain only what a parser could infer, which is the least valuable half.

5.3 Adapters are thin

One assistant's rules file is a pointer to the canonical rules, not a copy. Duplicated content across adapter files is duplicated drift. If a rule is worth stating, it is stated once, and every adapter references it.

6. The artifact contract

Reference architectures fail when they stop at boxes. These are the concrete shapes.

6.1 Provenance frontmatter — on every knowledge file

knowledge_id: urn:org:platform:card:loan-origination/pricing-service#rate-engine
source_sha: 4f2a9c1e…          # hash of the code/contract this was derived from
generator_version: 2.3.1
ownership: group:pricing-platform-eng
confidence: curated | discovered | inferred
evidence:
  - path: src/pricing/rate_engine.py
    sha: 9b13e7…
  - path: contracts/api/pricing-v2.yaml
    sha: c7740a…
last_generated: 2026-09-02T11:04:19Z

The rule that makes it load-bearing: a card whose source_sha no longer matches its evidence is stale, and stale means regenerate, not trust. Staleness is computed, never declared.

confidence is what separates evidence from authority. A discovered boundary is a hypothesis. Only curated — promoted by an owner — is authority.

6.2 Token budgets, enforced over generated blocks only

Artifact Budget Rationale
Operational rules file ~1,000 tokens Loaded on every task; long files dilute nested rules
Service context ~1,800 tokens Loaded on planning tasks only
Module card ~1,500 tokens Several may load together during review
Path-scoped instructions ~400 tokens Loaded automatically, always, per file touched

Budgets are how "minimum correct context" stops being a slogan and becomes a build failure. They apply to generated blocks only — never to curated intent, or you create pressure to delete human reasoning to fit a limit.

6.3 Classification and policy

A policy file defines hard-deny paths, sensitive-data patterns, secret patterns, prompt-injection patterns, token budgets, and the audit specification. It runs on both generate and validate. Every run appends to an immutable audit log.

The policy file lives with the code and is version-controlled, reviewed, and owned like code — because in practice it will be the artifact your risk function reads first.

7. Three enforced flows

Flow A — the pre-merge gate

Triggers on pull requests into protected branches, and on review submission, so that an approval must re-clear the owner gate rather than carrying over from a previous revision. Deliberately no manual dispatch.

PR opened / updated
  ├── job: validate         (contents:read ONLY — it executes branch-controlled code)
  │     1. validate         → schema, provenance, projection sync, budgets, staleness
  │     2. diff --mode pr   → every impacted module must carry a card update
  │     3. evaluate         → blocks on suite defects and forbidden-context routing
  │     4. upload evaluation run as an artifact
  │
  ├── job: report           (pull-requests:write, NO checkout, NO CLI execution)
  │     downloads the artifact, reads ONLY numeric fields, upserts ONE comment
  │
  └── job: codeowner-gate
        resolve required approvers per changed module
        approvals counted ONLY for the current head SHA
        authorship counts as assent (self-approval is blocked → would deadlock)
        team owners resolved via org membership; unresolvable team FAILS CLOSED

Three details that look like plumbing and are actually the design:

The impacted-module rule. Changed files are mapped to manifest modules; each impacted module must carry a card update in the same pull request. If the comparison base cannot be resolved, it fails closed. This is what makes invariant 3 real rather than aspirational.

Approvals scoped to the head SHA. An approval on revision 3 does not carry to revision 7. Obvious, and routinely absent — and it is precisely the loophole an agent-generated PR exploits when it force-pushes after approval.

Unresolvable ownership fails closed. A module whose owning team cannot be resolved does not sail through as "no reviewers required." That default is how ownership gaps become invisible.

Flow B — post-merge drift reconciliation

Triggers on push to the default branch, plus a weekly schedule and manual dispatch.

Because regeneration is idempotent, any diff is genuine drift. The reconciler resolves a comparison point robustly — handling initial pushes and force-pushes — runs the detection chain, stages only knowledge paths, and rejects any patch hunk outside those paths as a hard failure rather than a silent drop. It opens a repair pull request on a feature branch. It never pushes to the default branch, and the repair still requires owner approval.

It is explicitly a detector, not the primary generator. Freshness is enforced pre-merge, because a post-merge generator cannot stop the pull request that made the documentation stale. Flow B exists to tell you the gate leaked, not to substitute for it. If Flow B is producing frequent repair PRs, that is a defect report on Flow A, and it should be tracked as one.

Flow C — the agent loop

Tool-neutral by construction: every assistant consumes the same artifacts.

Routing. An agent editing a given path auto-loads the path-scoped rules for that path, which point at exactly one module card. Bulk-loading all cards is forbidden. Context differs by task phase:

Phase Loads
Plan Application context + service context + module index
Implement Only the touched module cards
Review Touched cards + glossary

Repo pass. Validate (allowing staleness, since the branch is mid-change) → diff against the base → discover, stopping for owner approval if boundaries changed → regenerate only impacted modules → hand-write curated intent → validate until clean with a bounded retry count then escalate → exactly one pull request on a feature branch. Never a push to a protected branch.

That "stop for owner approval if boundaries changed" step is where most of the governance value sits. A requirement that quietly redraws a module boundary is exactly the change that should not proceed autonomously, and it is exactly the change an eager agent will make without noticing.

Organisation pass. A session tied to no single repository, which observes, synthesises across applications, challenges its own conclusions, verifies provenance, and publishes a proposal for human review. It cannot promote its own findings. Cards at discovered or inferred confidence are evidence, not authority.

8. Threat model

Agent-generated pull requests change your threat surface. Four exposures and the controls that answer them.

8.1 Untrusted code execution in CI

A pull request from a branch can modify the very tooling that validates it. The privilege split is the control: the job that executes branch code holds no write token, and the job that holds the write token never executes branch code. The reporting job does not check out the branch, does not run the CLI, and reads only numeric fields from an uploaded artifact.

If you adopt one thing from this post for security review, adopt that sentence. It is what makes agent-authored PRs approvable in a regulated change process.

8.2 Prompt injection through the knowledge base

Knowledge files are context. Context is instruction-adjacent. A malicious or careless edit to a module card can attempt to steer any agent that loads it. Injection patterns are therefore part of the policy scan and run on both generate and validate, and knowledge paths carry ownership like code.

8.3 Sensitive data leaking into context

Generated evidence blocks derive from source. Source contains things that must not be replicated into a widely-loaded context file. Classification controls and hard-deny paths run on every generation, and every run appends to an audit log.

8.4 Ownership erosion

The slow one. Modules gradually accumulate no resolvable owner; gates degrade to no-ops. Fail-closed on unresolvable ownership, plus an ownership-gap query against the graph, is the answer.

9. Seven governing invariants

Each exists because its absence produced a specific, traceable failure.

  1. Humans define semantic boundaries; automation only discovers evidence. No command writes the manifest.

  2. Only text inside generated markers may be machine-rewritten. Curated intent survives regeneration.

  3. A behaviour change updates its card in the same pull request — enforced, not requested.

  4. Every knowledge file carries provenance. A card whose source hash no longer matches is stale and must be regenerated, not trusted.

  5. Token budgets are enforced over generated blocks only.

  6. Policy scanning runs on every generate and validate, and every run appends to an immutable audit log.

  7. Portability is a constraint, not a preference. Standard library plus vendored dependencies; no package installation, no network; it runs on the locked-down enterprise runner.

Invariant 7 is the one most underestimated. A toolchain requiring network access at build time cannot run where regulated workloads run, and discovering that after building it is an expensive lesson.

10. Scaling out: twenty applications, one graph

One application across six repositories is a context problem. Twenty applications is a topology problem: which service calls which, across which application boundary, owned by whom, and what breaks when this contract changes. No single repository can answer that.

10.1 Composed, never authored

Each application gets one knowledge-base repository holding an ontology file describing application flow, module-to-service and service-to-service relationships, and the service and module inventory per repository.

No human writes that file.

  6 application repos ──►  okf-fragment.yaml      generated from the manifest,
                                                   contracts, and discovered evidence
            │                   validated at the pre-merge gate
            ▼
   app knowledge repo ──►  okf.yaml               COMPOSED from fragments
                           okf.lock.json          resolved graph + content hashes
            │
            ▼
      org pipeline    ──►  graph database

A hand-authored application map is stale within a fortnight. Twenty of them are a fiction with a directory structure. The composition step also earns its place by catching what no single repository can see: duplicate service names, orphaned modules, consumers referencing APIs that nothing provides.

10.2 Do not invent an ontology

Align with an established catalogue model rather than designing your own. A mature model already covers components, APIs, resources, systems, domains, groups, and users, with directional relationships that carry a source, a target, a type, and a defined inverse — and component specifications that already express provides API, consumes API, depends on, subcomponent of, system, owner, and lifecycle.

Our concept Catalogue kind
Application System
Service Component, type service
Module Component with subcomponentOf
Contract API, via provides/consumes
Owner Group
Business line Domain

Three benefits: the relations are already directional with inverses, so the graph mapping is mechanical rather than a design argument; the same file can emit standard catalogue descriptors, making an internal developer portal an option rather than a migration; and twenty teams skip the ontology-design debate — which, at twenty teams, is worth more than elegance.

Organisation-specific fields go in a namespaced extension block, never by altering the core shape.

10.3 Identity, decided once, before the first load

The expensive mistake to make late. If each application mints local names, you get twenty disconnected subgraphs and the product-stack view never materialises.

urn:org:platform:system:loan-origination
urn:org:platform:component:loan-origination/pricing-service
urn:org:platform:component:loan-origination/pricing-service#rate-engine
urn:org:platform:api:loan-origination/pricing-v2
urn:org:platform:group:pricing-platform-eng

Two rules make cross-application edges survivable:

  • A service declares only what it owns — the contracts it serves, and by identifier the contracts it consumes, including identifiers owned by other applications.

  • Cross-application references resolve only at the organisation level. Application A cannot validate an identifier owned by B, so a dangling reference is not an A build failure. It is an organisation-level unresolved reference, tracked as a health metric, escalated warn-then-block.

Get that second rule backwards — failing A's build because B renamed something — and teams stop declaring cross-application dependencies at all, which destroys the only thing the graph was for.

10.4 The graph is a projection

Nobody edits the graph. It can be dropped and rebuilt from the knowledge files at any moment, and that property is precisely what makes it trustworthy.

// once
CREATE CONSTRAINT entity_urn IF NOT EXISTS
FOR (e:Entity) REQUIRE e.urn IS UNIQUE;

// per load — idempotent
MERGE (c:Entity:Component {urn: $urn})
SET c += $props, c.load_epoch = $epoch, c.source_sha = $sha;

MATCH (a:Entity {urn: $from}), (b:Entity {urn: $to})
MERGE (a)-[r:CONSUMES_API]->(b)
SET r.load_epoch = $epoch, r.contract_version = $ver;

// epoch-scoped stale sweep, one application at a time
MATCH (e:Entity {system: $system}) WHERE e.load_epoch < $epoch DETACH DELETE e;

The epoch sweep is what handles deletion. Upsert alone leaves a decommissioned service in the graph indefinitely, and a catalogue that only grows is worse than none — trust collapses around month four, and it does not come back.

Scope every load to one application so a malformed file in one cannot corrupt nineteen others.

10.5 What the graph is for

Three queries justify the whole investment:

  • Blast radius — which services, in which applications, consume this contract? This is the query an agent should run before fanning changes across repositories, and the query a change-approval board has been asking for in prose for a decade.

  • Ownership gaps — which components have no owning group? Feeds directly back into the fail-closed gate.

  • Coupling — which applications are most entangled, ranked by edge count? This converts an architecture opinion into an architecture fact, and it is usually the first output that changes a leadership conversation.

10.6 Contracts keep the topology honest

The fragment records a content hash for every contract it references. Validation recomputes them: if a contract changed and the fragment was not regenerated, the check fails closed. The same staleness posture already applied to prose, now applied to topology.


11. The operating model — who owns what

Architecture diagrams do not survive contact with an organisation unless ownership is explicit.

Artifact Owner Change path
Module boundaries and owners Service owning team Reviewed PR on the manifest
Curated intent in cards Module owner Reviewed PR, survives regeneration
Generated blocks Toolchain Never hand-edited; regenerate
Policy and classification Platform + risk function Reviewed PR, higher approval bar
Identifier scheme and entity schema Architecture council Versioned, in one central repository
Pipelines and gates Platform team Published centrally, consumed by reference
Graph contents Nobody Derived; rebuildable at will

Two organisational rules matter as much as any technical one:

Publish the pipeline centrally and consume it by reference. Twenty applications each carrying a vendored copy of the workflow means twenty upgrade paths, which in practice means no upgrades. Central publication with pinned versions is the difference between a platform and twenty forks.

The schema repository has an owner and a review board. The identifier scheme is the one decision that cannot be cheaply revisited once data is loaded. It deserves more governance than the code.


12. Measurement

Split leading from lagging, and do not let the lagging metrics be the first thing on the dashboard.

Leading — context health (report weekly):

Metric Why
Retrieval precision and recall on the benchmark suite The core claim of the whole system
Forbidden-context routing violations Detects bulk-loading regressions
Stale-card count and age distribution Detects gate leakage
Repair PRs opened by drift reconciliation A direct defect count against the pre-merge gate
Unresolved cross-application references Topology decay
Modules with unresolvable ownership Governance decay

Lagging — delivery outcomes:

Metric Caveat
Change lead time Moves for many reasons; never attribute solely
Change failure rate The one that matters, and the slowest to move
Rework rate Hard to instrument honestly; worth the effort
Review turnaround Watch for falling review time with rising defects — the rubber-stamp signature

Two disciplines. First, baseline before you deploy. A precision number with no before-state is an anecdote. Second, treat the benchmark suite as a product: versioned, reviewed, and grown when a new failure mode is found in production. A stale benchmark suite measures last year's problem.


13. A maturity model

Useful for locating yourself honestly and for showing a leadership team what "next" means.

Level State Characteristic signal
L0 — Ad hoc Agents read whatever is in the repository No one can say what context a PR was generated against
L1 — Documented Curated context files exist They are stale and everyone knows it
L2 — Governed Human-owned boundaries, provenance, ownership resolution Stale context is detectable
L3 — Enforced Pre-merge gates, same-PR card rule, privilege split Stale context cannot merge
L4 — Proven Deterministic retrieval benchmark gating rollout You can state a precision number and defend it
L5 — Federated Composed topology across applications, graph-derived routing Blast radius answered by query, not by meeting

Most enterprise programmes describing themselves as "AI-native" are at L1. The jump that changes outcomes is L2 to L3 — from detectable to impossible. The jump that changes the conversation with leadership is L3 to L4, because it replaces conviction with a number.


14. Resolving the hard parts

Five problems reliably surface when this architecture meets a real estate. Each has a solution, and each solution generalises — which is why they are worth stating as recommendations rather than as war stories.

14.1 Retrieval precision is low at first — treat it as a granularity problem

Early benchmark runs on a brownfield estate typically show context precision well below what the design promises. The instinct is to blame retrieval tuning or the model. Neither is usually the cause.

Low precision is almost always a card-granularity problem. A card that covers three module surfaces will be retrieved for all three and be mostly irrelevant for each. The fix sequence, in order of yield:

  1. Split cards until one card equals one module surface. Precision rises roughly in proportion.

  2. Add forbidden context to every benchmark task, not just expected context. A task that only asserts what should be retrieved cannot detect over-retrieval, which is the dominant failure.

  3. Use the glossary for query expansion. Enterprise systems have domain synonyms — the same concept named three ways across three decades of code. Expansion at retrieval time recovers substantial recall for near-zero effort.

  4. Trim generated blocks against budget before tuning anything else. An over-budget card is diluting every retrieval it wins.

Recommendation: publish a ratcheted threshold rather than a target. Set the gate at whatever you measure today, and require every release to move it or hold it — never regress. A ratchet converts an uncomfortable starting number into a managed trajectory, and it gives a leadership team something defensible immediately rather than in two quarters.

14.2 The manifest drifts — never declare what you can resolve

The manifest is human-owned, which means it can be wrong, and a wrong manifest silently misdirects the machinery that depends on it. A declared default branch that does not match the repository's actual default will point the reconciliation loop and every comparison base at the wrong place — and nothing fails loudly, because every command runs successfully against the wrong target.

Recommendation: the manifest should carry only what cannot be discovered. Default branch, repository visibility, language, owning team membership — all resolvable from the platform at validation time. Resolve them; do not declare them. Reserve human authorship strictly for semantic judgements: module boundaries, ownership intent, allowlists, commands.

Then add a manifest-versus-reality check to validation. Any declared field that contradicts a resolvable fact is a hard failure. The general principle is worth carrying into every configuration file you own: declared configuration that duplicates discoverable truth is a latent defect with a delay fuse.

14.3 Credential control belongs at the platform layer

Hardened enterprise runners frequently ship without a dedicated secret scanner and cannot reach external download hosts to fetch one. A pattern list bundled into your own toolchain works, but it is a weaker control than a purpose-built scanner, and defending it to a security review is uncomfortable.

Recommendation: move the control down a layer rather than strengthening it in the pipeline. Ask the platform team to bake a scanner into the runner image — it is a single change that improves every pipeline in the organisation, which makes it a far easier request than it appears. In the interim, run detection server-side at the push boundary rather than only in CI, and keep the bundled patterns as defence in depth rather than as the primary control.

The broader point: when a control is weak because of an environment constraint, the durable fix is usually an environment change, not a cleverer workaround. Workarounds accumulate; platform fixes compound.

14.4 Publish pipelines centrally from the first multi-application day

Vendored workflow copies are the correct way to start and the wrong way to continue. At one application it is pragmatic. At twenty it means twenty upgrade paths, which in practice means no upgrades, and a security fix that takes a quarter to propagate.

Recommendation: stand up the central actions repository at the beginning of the multi-application phase, not when the pain arrives. Publish versioned, pinned workflows; have each application consume them by reference in a few lines. Carry a canary application that upgrades first. The migration is cheap when there are two consumers and genuinely painful at twenty — the cost curve is the entire argument for doing it early.

14.5 Let evidence decide where module boundaries are worth defining

Modules are human-defined by design, and at twenty applications that is a large number of judgement calls competing with delivery work. Attempting complete module coverage before the graph is useful stalls the programme.

Recommendation: load the graph at service granularity first, then let it tell you which modules to define. Once services are loaded, fan-in ranks itself: the services with the most consumers, the most cross-application edges, and the highest change frequency are where ambiguous ownership costs the most. Define modules there first, and leave low-traffic services at service granularity indefinitely.

This inverts the usual sequence, and it is the more efficient one. Rather than spending human judgement uniformly across the estate, spend it where the evidence says imprecision is expensive. The graph pays for itself before it is complete — which is also what keeps the programme funded while it finishes.

The pattern across all five

Four of these five resolve by moving the decision to the layer that can hold it: discovery instead of declaration, the platform instead of the pipeline, central publication instead of local copies, evidence instead of uniform effort. That is the same principle the architecture applies to knowledge itself — authority sits where it can be maintained, and everything else is derived.


15. Adoption roadmap

For a team attempting this on an existing estate.

Phase 0 — Decide identity. Identifier scheme, entity kinds, relation types, schema, one worked example, agreed by a small architecture group. Days, not weeks — but before any code. This is the decision you cannot cheaply revisit.

Phase 1 — One pilot repository. Manifest written by hand. Cards reverse-engineered from code, every inferred rule marked as inferred, and an explicit Unknowns section per module. An empty Unknowns section on a large module means the tool over-claimed.

Phase 2 — The pre-merge gate on that repository only. Validation plus the same-PR card rule. Nothing else on this list changes behaviour as much.

Phase 3 — The benchmark suite, before any rollout claim. Twenty or so tasks with expected and forbidden context. Read the numbers before believing the story.

Phase 4 — Fragments and composition for one application; then the graph load for that one application. Run the three queries from 10.5 and check the answers against reality. They will disagree with reality in instructive ways.

Phase 5 — Cross-application edges. Only meaningful once two applications are loaded, so do not design it earlier than that.

Phase 6 — Scale by business line, never all at once, with the pipeline published centrally from day one of this phase.

A realistic first-application timeline is a quarter, with the bulk of the effort in Phase 1 — because reverse-engineering honest module boundaries in a fifteen-year-old system is the actual work, and no tool removes it.


16. Objections worth taking seriously

"This is a lot of machinery to make an agent work." It is. It is also mostly machinery you needed anyway: ownership resolution, contract inventory, change traceability. Agents did not create those requirements; they made the absence of them expensive enough to fix.

"Our engineers will not maintain module cards." They will not maintain cards that a generator overwrites. That is precisely why curated intent must survive regeneration, and why the same-PR rule attaches the cost to the change that created it rather than to a quarterly documentation drive.

"We already have an internal developer portal." Then you have the catalogue layer and are further along than most. What you likely lack is the enforcement layer — gates, provenance, staleness — and the evaluation layer. Align the schema and keep the portal.

"Can we not just use a larger context window?" A larger window changes the cost of the wrong answer, not its probability. Precision, not capacity, is the binding constraint — and precision degrades as you fill the window with plausible irrelevance.

"How do we justify the investment before the numbers exist?" Honestly: fund the measurement first. A deterministic retrieval benchmark is cheap, fast to build, and produces a defensible baseline within weeks. Fund the rest against that number. Any programme that cannot get funding for its own measurement should take that as information.


17. Reference checklist

Steal this.

Governance

  • [ ] Module boundaries human-owned; no command writes the manifest

  • [ ] Discovery proposes; owners promote

  • [ ] Curated intent survives regeneration via markers

  • [ ] Confidence levels distinguish evidence from authority

Freshness

  • [ ] Provenance frontmatter on every knowledge file

  • [ ] Staleness computed from source hashes, never declared

  • [ ] Behaviour change updates its card in the same pull request

  • [ ] Drift detection is a detector, not the primary generator

Precision

  • [ ] Token budgets enforced over generated blocks

  • [ ] Path-scoped rules route to exactly one card

  • [ ] Bulk-loading forbidden and detected

  • [ ] Context differs by task phase

Security

  • [ ] Privilege split between executing and writing jobs

  • [ ] Approvals scoped to the current head SHA

  • [ ] Unresolvable ownership fails closed

  • [ ] Injection and classification patterns scanned on generate and validate

  • [ ] Immutable audit log appended on every run

Scale

  • [ ] Global identifier scheme agreed before first load

  • [ ] Topology composed from per-repository fragments, never authored

  • [ ] Graph is a derived projection with epoch-scoped deletion

  • [ ] Cross-application references resolve only at organisation level

  • [ ] Pipelines published centrally, consumed by reference

Proof

  • [ ] Retrieval benchmark is deterministic and LLM-free

  • [ ] Baseline captured before deployment

  • [ ] Leading context-health metrics reported ahead of throughput

  • [ ] Known gaps published, not buried


Closing

Three sentences for a leadership audience.

Speed comes from precision, not permission. Agents get faster when context is smaller and correct — not when guardrails come off.

Governance here is executed, not documented. It lives in gates, schemas, ownership resolution, and provenance, not in a policy document that nobody reads and no agent consumes.

Measure the context before claiming the outcome. A deterministic retrieval benchmark is unglamorous, and it is the only thing standing between an AI delivery programme and a very confident wrong answer at scale.


Building something similar, or disagreeing with parts of it? I would genuinely like to compare notes — particularly on letting the graph decide where module boundaries earn human attention, which is the recommendation I expect to be argued with most.