0002

July 20, 2026 · View on GitHub

  • Status: Accepted
  • Date: 2025-06-09
  • Deciders: quantakrypto-tools maintainers
  • Supersedes / Superseded by:

Context

Three of the four user-facing tools — qscan (CLI), mcp (agent server), and action (CI) — answer the same question ("where is the quantum-vulnerable crypto, and what replaces it?"). If each re-implemented detection, inventory, or remediation logic, the tools would drift: a finding that fails CI might not appear in the editor, and a remediation the agent suggests might differ from the one the report prints. Sieve is the exception — it tests other people's crypto and shares no detection logic (see ADR-0004).

The crypto-analysis knowledge — detectors, the vulnerable-dependency DB, the inventory/readiness scoring, the remediation table, and the SARIF/JSON/human reporters — is the asset. It must live in exactly one place.

Decision

We will keep all cryptographic-analysis logic in @quantakrypto/core and treat its public surface (src/index.ts re-exports + the types in src/types.ts) as the contract. qscan, mcp, and action are thin shells that consume core; they do I/O and policy, never detection. (The later opt-in @quantakrypto/agent also consumes core — for the shared agent-plane types, the context redactor, and the triage/remediate rubrics — so the same contract discipline applies to it, giving core four consumers across the six workspace packages.) The MCP HOSTING.md states the rule directly: transports do I/O and policy; McpServer does protocol; @quantakrypto/core does cryptographic analysis.

The locked contract is:

  • scan(ScanOptions): Promise<ScanResult> and the walker walkFiles.
  • The data types Finding, CryptoInventory, Severity, AlgorithmFamily, FindingCategory.
  • The reporters toSarif, toJson, formatSummary and buildInventory.
  • remediationFor, the detectors array, vulnerableDependencies, VERSION.

Consumers must reuse core's primitives rather than re-derive them. (The architecture audit and/P1-3 flagged two violations here: the qScan/Action baseline fingerprint schism and the Action re-implementing fingerprint/applyBaseline/renderReport instead of importing runQscan. Both are now closed — the Action imports runQscan and the single canonical baseline module lives in core, so the divergent copies are gone. Keeping consumers thin remains conformance to this ADR, not a new decision.)

Consequences

Easier: one definition of a finding; identical verdicts across CLI/agent/CI; one place to add a detector, a CWE tag, or a CBOM exporter and have all three tools benefit; a stable public API to version (see VERSIONING.md).

Harder (costs accepted): the core surface is now a compatibility commitment — changes to Finding, ScanResult, or a reporter's output shape ripple to every consumer and, post-1.0, are breaking. We accept the discipline of treating src/types.ts as load-bearing and gating changes to it through SemVer.

Enforcement: the build's project references (see ADR-0003) make the dependency direction explicit; a future public-API reference + a review rule ("does this PR add detection logic outside core?") keep consumers thin. The baseline-unification work (P1-1) has landed: the one shared baseline module now lives in core (fingerprintFinding / applyBaseline / loadBaseline / …), so the two divergent copies cannot persist.

Alternatives considered

  • Let each tool own its slice of logic for independence. Rejected: it guarantees the drift this ADR exists to prevent and multiplies the maintenance and audit surface by three.
  • A looser "core is a library, copy what you need" convention without treating the surface as a contract. Rejected: that is the status quo that produced the baseline schism; an explicit contract with versioning is the fix.