runward

RW™ · V0.22.0

Docs · Décisions · ADR-0037

ADR-0037.

`runward characterize` detects infrastructure and framework/DB config signals (presence only)

Date: 2026-07-20 Status: proposed Deciders: Thibault Souris (maintainer) Method: decision-loop — resume-existing audit finding, reality-checked against detectContainers (characterize.ts:143, a short fixed list) and the M2 need for an architecture note that starts from real signals.

Context

detectContainers (characterize.ts:143) checks a small fixed list (Dockerfile, compose, vercel/netlify/fly, Procfile, Chart.yaml). It misses the signals that most define a modern system's architecture: Infrastructure-as-Code (Terraform, Pulumi, Kubernetes manifests, serverless.yml, AWS SAM) and framework/DB configuration (next.config.*, vite.config.*, nuxt.config.*, tsconfig.json, prisma/schema.prisma, drizzle.config.*, alembic.ini). For brownfield mode M2 — join a project in flight, the architecture note is reconstructed "by observation" — but characterize hands the observer almost nothing on the infra/architecture axis. These are pure-presence facts sitting at rest in the repo.

Decision

characterize adds two presence-only detectors and reports them as facts, feeding --mine candidates.

  • Infrastructure & deployment. Detect presence of *.tf/*.tf.json (bounded walk), Pulumi.yaml, Kubernetes manifests (a k8s//kubernetes/ dir or kustomization.yaml), serverless.yml/serverless.yaml, template.yaml/samconfig.toml (SAM). Report under a new "Infrastructure & deployment" section, sorted.
  • Framework / DB config. Detect presence of next.config.*, vite.config.*, nuxt.config.*, svelte.config.*, astro.config.*, tailwind.config.*, tsconfig.json, prisma/schema.prisma, drizzle.config.*, alembic.ini, knexfile.*. Report under "Framework / DB config", sorted.
  • Presence, never intent. The report says "a Terraform configuration is present", never "infrastructure is well-managed" or "the DB schema is X". Pure existence; parsing the content into an architecture claim is the operator's job (ADR-0013).
  • Feeds --mine. A detected IaC/framework signal becomes a candidate DRAFT (ADR-0038) — a hypothesis with provenance, why: UNKNOWN, never an asserted architecture.

Deterministic (sorted), read-only, zero-LLM.

Alternatives discarded

  • Parse the IaC/config to extract the real topology (resources, providers, the DB schema). Rejected: heavy, per-tool, and interpretive — it manufactures an architecture claim from a machine read, the overclaim ADR-0014 forbids. Presence is a fact; topology is reconstructed by the operator.
  • One ever-growing flat "deploy descriptors" list. Rejected: infra and framework/DB config answer different questions (how it ships vs what it is built on); two labelled sections are more legible and map to the architecture note's structure.
  • Deep-walk for every possible config filename. Rejected as unbounded/noisy; a curated, bounded set of high-signal markers (the ones that actually define architecture) via the existing bounded walk() and root checks.

Consequences

  • Positive. The M2 architecture note starts from real infra/framework signals instead of zero. --mine gains meaningful structural candidates beyond stack/CI/deps. Still offline, reproducible, fact-only.
  • Negative, accepted. A curated marker list will lag new tools; extending it is a one-line addition per marker (and a reopening trigger watches for the gap). Presence without parsing can feel thin — deliberately, to stay on the fact side.
  • On other boundaries. Inventory grows infra + frameworkConfig lists; renderCharacterization grows two sections; mineDrafts (ADR-0038) consumes them. The gate is untouched.

Reevaluation trigger (mandatory, dated)

Reopen if (a) a common IaC/framework marker is repeatedly missing from real repos — extend the curated list; (b) operators need parsed topology (resource inventory, schema tables) badly enough to justify per-tool parsing behind the read-only contract — then design it as labelled facts or --mine hypotheses, never an asserted architecture; or (c) the presence lists prove too noisy (false positives on vendored configs).

Trigger set on: 2026-07-20 · Watched via: dogfooding characterize on infra-heavy repos.

References

  • ADR-0014 — the read-only/fact-only contract this extends.
  • ADR-0013 — presence-fact vs operator-reconstructed architecture.
  • src/lib/characterize.ts (detectContainers neighbours, renderCharacterization, mineDrafts) — edited.
  • The resume-existing / brownfield audit (2026-07-20).
← Tous les ADR