Skip to content

Typed Mixed-DAG Consumer Contract

Status

This document defines the schema-v2 identity and relation contract for production consumers of the Encyclopedia of Abstractions hierarchy. scripts/build_dag.py builds the mixed artifacts. The site, its relationship panels and hierarchy views, the public graph downloads, and the additive mixed MCP tools now consume or publish typed schema-v2 identity. The builder still emits an explicit prime-only projection under dist/prime_dag.* for consumers that have not migrated. The MCP tools get_prime_lineage and get_prime_siblings deliberately remain on that projection so prime-oriented callers retain their existing inputs and response shapes. The historical dist/dag.* paths remain temporary aliases for other legacy consumers.

The canonical source of truth remains dag_edges in:

  • prime_abstractions/v2/*.md
  • domain_specific_abstractions/v2/*.md

The release scope is frozen by workspace/mixed_dag_2026/RELEASE_SCOPE_FREEZE_2026_07_25.yaml.

The executable contract is scripts/typed_graph_contract.py. The public record shapes are:

  • schemas/typed_dag/node.v2.schema.json
  • schemas/typed_dag/relation.v2.schema.json

The production builder emits:

  • dist/mixed_dag.nodes.jsonl: one schema-v2 record per typed node;
  • dist/mixed_dag.relations.jsonl: one schema-v2 record per logical relation;
  • dist/mixed_dag.json: nodes, relations, and collision-safe adjacency indexes in one bundle; and
  • dist/mixed_dag.manifest.json: counts, graph diagnostics, release seals, artifact hashes, and compatibility-projection status.

The compatibility artifacts are:

  • dist/prime_dag.jsonl: prime-to-prime source declarations in the historical bare-slug relation shape;
  • dist/prime_dag.json: the corresponding by_child and by_parent indexes; and
  • dist/prime_dag.manifest.json: an explicit account of projection counts, omitted domain nodes and relations, identity loss, mutual duplication, projection seals, and legacy aliases.

dist/dag.jsonl and dist/dag.json are byte-identical temporary aliases of the first two files. dist/dag.manifest.json retains the historical summary shape used by existing consumers. None of these prime-only files is the canonical mixed graph.

Public download distribution

The public Downloads page preserves these roles explicitly:

  • mixed_dag.nodes.jsonl, mixed_dag.relations.jsonl, mixed_dag.json, and mixed_dag.manifest.json are the canonical typed graph distribution;
  • schemas/typed_dag/node.v2.schema.json and schemas/typed_dag/relation.v2.schema.json are published at the same relative paths named by the canonical manifest;
  • hierarchy.jsonl is a denormalized, node-oriented convenience export of the same mixed graph, with hierarchy.manifest.json documenting its storage rule and canonical topology seal; and
  • prime_dag.jsonl, prime_dag.json, and prime_dag.manifest.json are explicitly labeled as incomplete legacy compatibility files.

downloads.manifest.json inventories every registered public download with its byte size, source provenance, and SHA-256 digest. It also names the canonical and compatibility graph entry points so automated consumers need not infer their role from filenames.

The read-only live validator is:

mcp_server/.venv/bin/python scripts/validate_typed_graph_contract.py

The complete production build-and-release gate is:

./scripts/release_acceptance_gate.sh

It composes the graph validator with MCP compatibility tests, the repository suite, a non-fast production site build, runtime smokes, deployed-route checks, and byte-exact public-download verification. The gate contract and machine-readable seal are documented in conceptual/build-and-release-acceptance-gates.md.

MCP compatibility boundary

The MCP server exposes the canonical graph additively:

  • search_abstraction and get_abstraction return collision-safe typed node identity across both corpora;
  • get_abstraction_lineage and get_abstraction_siblings traverse dist/mixed_dag.json and retain full schema-v2 relation proofs;
  • mutual relations are exposed as co-defining peers, never mislabeled as ancestors or descendants; and
  • get_prime_lineage and get_prime_siblings continue to read dist/prime_dag.* and return their historical bare-slug records.

The mixed loader is lazy and failure-isolated. A missing or malformed mixed_dag.* artifact disables only the additive typed tools; it does not prevent the server or prime-only hierarchy tools from starting.

1. Typed identity

Every node has a collision-safe node_id:

prime:<slug>
domain_specific:<slug>

node_kind is the routing and identity namespace:

  • prime includes frontmatter types prime and emergent_prime;
  • domain_specific includes frontmatter type domain_specific.

declared_type preserves that frontmatter distinction. Consumers must never use declared_type as a substitute for node_kind.

Bare slugs are a source-compatibility syntax, not graph identity. A bare reference resolves only when exactly one typed node owns that slug. A namespaced reference resolves exactly. Ambiguous references are errors; prime precedence, directory order, and alias order are not resolution policies.

Canonical routes are derived from typed identity:

prime:<slug>           -> primes/<slug>/
domain_specific:<slug> -> domain-specific/<slug>/

Consumers should receive or compute routes through the shared contract rather than constructing /primes/ links from bare slugs.

2. Relation direction

Every directed relation is stored:

child -> parent

The parent is the more foundational abstraction or machinery on which the child depends.

The edge vocabulary is:

  • subsumption: the child is a kind of the parent;
  • composition/presupposes: the child requires the parent as a precondition or substrate;
  • composition/part_of: the parent is an internal constituent of the child;
  • decompose: the child is a framed or applied realization of the parent's structural core;
  • mutual: the endpoints are co-defining and neither is structurally prior.

For composition/part_of, the mandatory interpretation is parent_in_child. “Child is part of parent” is the reverse relation and is invalid consumer wording.

3. Flavor and qualifier

Composition has two flavors:

presupposes
part_of

A blank composition flavor in canonical source normalizes to presupposes. Schema-v2 logical relations always emit the effective, non-blank composition flavor.

Qualifier is independent of edge type:

strict
typical
conditional

A missing source qualifier normalizes to strict.

The canonical corpus retains inherited flavored non-composition records as compatibility debt. They remain readable and topology-hash-preserving. A schema-v2 logical relation marks such a record with:

{"legacy_flavor_compatibility": true}

New relations may not use that marker or author a non-composition flavor.

4. Source declarations and logical relations

Directed relations have one canonical child-side source declaration.

Mutual relations have two mirrored canonical declarations with identical edge semantics, but their prose may be oriented from the declaring endpoint. They normalize to one logical relation whose mutual_endpoint_explanations array preserves both source payloads. The normalized relation orders its endpoint IDs and endpoint explanations deterministically. Mutual relations:

  • are excluded from directed cycle, depth, ancestor, and root calculations;
  • are included in weak-component and ordinary neighborhood calculations; and
  • must be exposed under both endpoints in consumer adjacency indexes.

Because neither endpoint of a mutual relation is a directed child, mutual relations do not make either endpoint non-root. Under this contract the frozen release has 187 directed-parentless roots. Earlier closure summaries reported 185 by counting the arbitrarily ordered child field of each normalized mutual record as parented; the validator retains that legacy count as a diagnostic, but consumers must use the directed count.

Counts must distinguish:

  • canonical source record count;
  • normalized logical relation count; and
  • mutual logical-pair count.

5. Endpoint-kind policy

Directed release-v2 relations allow:

prime -> prime
domain_specific -> prime
domain_specific -> domain_specific

prime -> domain_specific is forbidden. A prime may therefore have domain-specific descendants, but a prime cannot depend upward on a domain-specific abstraction in the frozen release.

This restriction is a release contract, not a claim that every future ontology must preserve it. Changing it requires a new authorized release scope, updated schemas, and explicit consumer review.

6. Required explanation fields

Every relation requires:

  • reason_short;
  • reason; and
  • condition_or_exception, emitted as an empty string when absent.

A normalized mutual relation additionally carries the two canonical endpoint-oriented payloads in mutual_endpoint_explanations. Consumers rendering a node-local neighborhood should prefer the payload whose source_node_id is the current page.

Topology identity and topology hashes exclude prose. Explanation changes do not create a new logical relation. Retyping, reflavoring, requalifying, or changing directed endpoints changes the topology fingerprint.

relation_id is derived only from the logical endpoint key. It remains stable when prose or edge semantics are refined, allowing consumers to recognize a retyped relation as the same endpoint claim.

7. Frozen release invariants

Before any schema-v2 artifact becomes production input, it must reproduce:

  • 2,567 typed nodes;
  • 1,371 prime/emergent-prime nodes;
  • 1,196 domain-specific nodes;
  • 4,207 canonical source declarations;
  • 4,204 logical relations;
  • one weak component;
  • zero isolates;
  • zero directed cycles;
  • zero prime-to-domain-specific directed relations; and
  • topology SHA-256 6f98d15a94b5b911b55e47976739f6257bbe2eb92a55b8c62d075bbe6a77dff9.

These counts are release assertions, not permanent schema constants. A later ontology release replaces the freeze deliberately; it does not relax validation silently.

8. Change discipline

Changes to identity, direction, mutual normalization, effective flavor, or logical hashing must update together:

  1. scripts/typed_graph_contract.py;
  2. the two JSON Schemas;
  3. focused contract tests;
  4. canonical-promotion regression tests;
  5. the production DAG manifest schema; and
  6. this document.

Consumer-specific presentation and filtering may evolve without changing the contract, provided typed identity, direction, complete semantics, and logical counts remain intact.