module · canonical release 0.2

commonsformat-resolver

version 0.1.3 · targets format 0.2

A resolver for Commons Format module dependencies. Takes a root module and produces a merged virtual spec by walking the dependency graph and applying the merge algorithm defined by the format.

depends on github.com/commonsformat/commonsformat-format ^0.2.0
github.com/commonsformat/commonsformat-parser ^0.1.1
license MPL-2.0
verifies ./evals.toml

Premise

The resolver takes a root module and the set of modules reachable from it via depends_on and extends, and produces a merged virtual spec per the merge algorithm defined by the format.

The resolver does not fetch dependencies from disk or network. It operates on already-loaded modules. Fetching is a separate concern handled by the fetcher (a separate spec module). The resolver assumes its input is a set of parsed modules and a description of which depends on which.

The resolver does not generate implementations. The merged virtual spec it produces is the contract a generator consumes; what the generator does with it is the generator's concern.

Interface

A resolver is a function or component that takes:

  • A root parsed module
  • A function or interface that, given a dependency declaration (spec URL, version constraint, optionally commit), returns the resolved parsed module for that dependency

And returns either:

  • A merged virtual spec — a structure containing the unioned intent, constraints, anti-patterns, examples, threat-model content, evals, and properties from all modules in the dependency closure, with the merge algorithm's rules applied
  • A resolution error — a structured description of why merging failed (cycle, conflict, unmet constraint, etc.)

The resolver is implementation-language-agnostic. The structure of the merged virtual spec and the resolution error is defined by the format; how a particular implementation represents them is the consumer's choice.

Schema

This module ships a schema.sql declaring the shape of its data. Per §8 this is a shape commitment, not a storage commitment — the generated implementation chooses a runtime representation appropriate to its intent.

-- This DDL describes data shape, not storage. Runtime representation
-- is implementation-defined; choose what is appropriate to the target
-- language and the module's intent. The resolver is a pure function
-- over already-parsed modules; the tables below are the shape of its
-- inputs and outputs, not a persistent store.

CREATE TABLE graph_nodes (
    module_id            TEXT    NOT NULL PRIMARY KEY,
    spec_url             TEXT    NOT NULL,
    version              TEXT    NOT NULL,
    resolved_commit_sha  TEXT
);

CREATE TABLE graph_edges (
    from_module          TEXT    NOT NULL,
    to_module            TEXT    NOT NULL,
    edge_kind            TEXT    NOT NULL CHECK (edge_kind IN ('depends_on', 'extends')),
    PRIMARY KEY (from_module, to_module, edge_kind),
    FOREIGN KEY (from_module) REFERENCES graph_nodes (module_id),
    FOREIGN KEY (to_module)   REFERENCES graph_nodes (module_id)
);

CREATE TABLE merged_specs (
    root_module          TEXT    NOT NULL PRIMARY KEY,
    merged_intent        TEXT    NOT NULL,
    merged_avoid         TEXT    NOT NULL,
    merged_threat_model  TEXT    NOT NULL,
    root_interface       TEXT    NOT NULL,
    completed_at_ms      INTEGER NOT NULL
);

CREATE TABLE merged_constraints (
    root_module          TEXT    NOT NULL,
    constraint_name      TEXT    NOT NULL,
    description          TEXT    NOT NULL,
    contributing_module  TEXT    NOT NULL,
    PRIMARY KEY (root_module, constraint_name),
    FOREIGN KEY (root_module) REFERENCES merged_specs (root_module)
);

CREATE TABLE merged_examples (
    root_module          TEXT    NOT NULL,
    example_name         TEXT    NOT NULL,
    content              TEXT    NOT NULL,
    contributing_module  TEXT    NOT NULL,
    PRIMARY KEY (root_module, example_name),
    FOREIGN KEY (root_module) REFERENCES merged_specs (root_module)
);

CREATE TABLE merged_eval_cases (
    root_module          TEXT    NOT NULL,
    case_name            TEXT    NOT NULL,
    case_class           TEXT    NOT NULL CHECK (case_class IN ('functional', 'adversarial', 'generator_adversary')),
    contributing_module  TEXT    NOT NULL,
    PRIMARY KEY (root_module, case_name),
    FOREIGN KEY (root_module) REFERENCES merged_specs (root_module)
);

CREATE TABLE merged_properties (
    root_module          TEXT    NOT NULL,
    property_name        TEXT    NOT NULL,
    property_value       TEXT    NOT NULL,
    contributing_module  TEXT    NOT NULL,
    PRIMARY KEY (root_module, property_name),
    FOREIGN KEY (root_module) REFERENCES merged_specs (root_module)
);

CREATE TABLE applied_overrides (
    root_module          TEXT    NOT NULL,
    element_path         TEXT    NOT NULL,
    override_value       TEXT    NOT NULL,
    declaring_module     TEXT    NOT NULL,
    PRIMARY KEY (root_module, element_path),
    FOREIGN KEY (root_module) REFERENCES merged_specs (root_module)
);

CREATE TABLE resolution_errors (
    root_module          TEXT    NOT NULL,
    ordinal              INTEGER NOT NULL,
    error_kind           TEXT    NOT NULL CHECK (error_kind IN ('cycle', 'conflict', 'unmet-version', 'missing-dependency', 'merge-bound-exceeded')),
    element_path         TEXT,
    contributing_modules TEXT,
    detail               TEXT    NOT NULL,
    PRIMARY KEY (root_module, ordinal)
);

What the resolver does

  • walks-dependency-graph — starting from the root, discovers all reachable modules via depends_on and extends declarations
  • detects-cycles — a cycle in the dependency graph is detected and reported as a resolution error
  • resolves-version-constraints — for each dependency declaration, selects the highest version satisfying the constraint
  • topological-merge-order — contributions to the merged spec are applied in topological order from leaves to root
  • detects-conflicts — conflicts in constraints, evals, properties, or examples are detected and reported
  • applies-overrides — explicit overrides declared in dependency entries resolve conflicts as specified
  • produces-deterministic-output — the same input graph produces byte-identical merged virtual specs

What the resolver does not do

  • Fetching from network or filesystem. The resolver receives modules already loaded; fetching is the fetcher's responsibility.
  • Parsing modules. Modules are already parsed when handed to the resolver.
  • Running evals. The merged virtual spec contains evals; running them is the eval runner's job.
  • Generating implementations. The merged virtual spec is input to a generator; the resolver does not invoke generation.
  • Modifying input modules. Modules passed in are read-only inputs; the merged virtual spec is a new structure.

Merge contributions

The merge algorithm is specified by format-spec §11.4. The resolver implements that algorithm; the format is canonical.

The resolver-specific concerns — how conflicts are reported, how overrides are applied, how the merge result is structured for downstream consumption — are described in subsequent sections of this spec. Those are implementation contracts the resolver adds on top of the format's algorithmic specification.

Conflicts and overrides

A conflict arises when two contributing modules declare the same named element with different content. Conflicts are detected during merging and reported with enough information to identify which modules contributed the conflicting elements.

A depending module may declare overrides for a specific dependency:

[[depends_on]]
spec = "..."
version = "..."

[depends_on.overrides]
constraints.uses-redis = "ignore"
properties.requires_logging = false

Overrides resolve conflicts at merge time. An overridden element is either omitted from the merge ("ignore") or replaced with the override's literal value. Overrides are recorded in the merge result so consumers auditing the contract can see what was suppressed.

Conflicts without overrides cause the resolver to return a resolution error. The merge does not partially complete and proceed with conflicts unaddressed.

Extension semantics

A module declaring extends follows the same merge logic as depends_on with two differences:

  • The extending module's content takes precedence on conflicts without requiring explicit overrides for every conflicting element
  • The extending module's evals are unioned with the parent's; an implementation passing the extended module's evals also semantically passes the parent's evals (since the parent's evals are now part of the extended suite)

A module may extend at most one parent. Extension does not preclude declaring additional depends_on dependencies; extension is one edge in the graph, depends_on declarations are other edges.

Threat model

The resolver operates on potentially adversarial dependency graphs. A malicious module could attempt:

  • Pathological cycles (very long, indirect)
  • Pathological diamond conflicts that obscure their conflict nature
  • Pathological merge expansions where the merged spec is much larger than any individual contributor (decompression-bomb style)
  • Override declarations that hide conflicting content from auditing

The resolver mitigates by:

  • Detecting cycles regardless of length
  • Reporting conflicts with full provenance (which modules contributed what)
  • Bounding merge output relative to inputs (refusing to produce merged specs above a configurable size limit)
  • Recording overrides explicitly in merge output so they cannot be hidden

A buggy resolver that produces incorrect merges silently is the worst failure mode. Consumers depending on the merged spec to generate implementations would generate against a contract that isn't what they declared. The resolver must be correct or fail loudly; it must not be subtly wrong.

Verification

This module's eval suite tests the resolver on synthetic dependency graphs with known expected merges. Cases cover the merge algorithm itself, conflict detection, override application, cycle detection, and version constraint resolution.

A consumer generating a resolver implementation iterates against this module's evals until conformance. They then have a working resolver that can be composed with their parser and eval runner to form a complete Commons Format toolchain.

describes commonsformat-resolver 0.1.3 · targets commons format 0.2 · generated from release 0.2 · 2026-05-28