Phase 1 Data Model — schema, model & DRG-shape changes

This mission changes no runtime storage. The "entities" are doctrine schema / model shapes and DRG projection rules. Each change below is a boundary made single-sourced or fail-loud.

E1 — _DRG_NODE_KINDS (derived set) [IC-1, #3608]

topic_resolver.py:37 (drifted 6 kinds vs NodeKind).

— exact equality (fails on missing and extra).

(if lhs not in _DRG_NODE_KINDS: return None). Post-change, every canonical kind (incl. glossary_pack, mission_step_contract, anti_pattern, asset, glossary, template) is recognized.

  • Before: hand-maintained frozenset[str] literal in
  • After: _DRG_NODE_KINDS: frozenset[str] = frozenset(k.value for k in NodeKind).
  • Invariant (pinned by drift-guard test): _DRG_NODE_KINDS == {k.value for k in NodeKind}
  • Consumer: membership gate at topic_resolver.py:236

E2 — ContextSources / AgentContextSources / profile schema [IC-2, #3629 p1]

context-sources with subfields directives, tactics, toolguides, styleguides, doctrine-layers, additional (all list[str]).

profile.py::ContextSources (and its attribute on AgentProfile), schema_models.py::AgentContextSources, and the JSON schema. Because both models use extra="forbid", a profile still authoring context-sources is rejected at load (fail-loud) — the desired boundary.

directive-references, tactic-references, toolguide-references, styleguide-references (structured {id, rationale} / DirectiveRef).

  • Before (both pydantic models + agent-profile.schema.yaml): field
  • After: context-sources block removed entirely from
  • Canonical surface (retained/authoritative): top-level *-references
  • Migration mapping (upgrade migration + the 25 shipped profiles):

toolguides/styleguides preserved); delivered content to a dispatched agent is unchanged (C-006).

  • Invariant: no authored artefact reference is lost (directives/tactics/
from context-sources.*to
directivesdirective-references (id, keep any rationale)
tacticstactic-references
toolguidestoolguide-references
styleguidesstyleguide-references
additionaldropped (freeform, no artefact/edge target)
doctrine-layersdropped (layer names, no NodeKind)

E3 — agent_profile DRG projection (extractor) [IC-2, #3629 p1]

(extractor.py:920-929) and top-level tactic-referencesrequires→tactic (:930-942).

requiresdirective (replacing the context-sources.directives loop); tactic-references unchanged; add toolguide-references/styleguide-referencessuggests (or requires) → toolguide/styleguide when authored.

content that was already delivered; net-new edges only for previously-inert authored refs now carried on *-references.

  • Before: extractor projects context-sources.directivesrequires→directive
  • After: projects from the *-references surface uniformly — directive-references
  • Invariant: the set of DRG edges minted for a given profile is unchanged for

E4 — governance-profile scope edges (fail-loud) [IC-3, #3629 p2]

raises on any selected_* target that is not a minted node (built-in path, tested). Verify the org-tier governance-profile path is equally guarded.

both built-in and org tiers; valid selections mint scope edges unchanged.

  • State: assert_governance_scope_edges_resolve (extractor.py:1406) already
  • Invariant (target end-state): a nonexistent selected_* id fails loud on

E5 — load_validated_graph org seams [IC-4, #3530]

merge_three_layers. org_roots= (_drg_helpers.py:138-182) reads only root *.graph.yaml, ignores drg/fragment.yaml, and suppresses the "no graph" warning when a fragment exists (:174). Callers executor.py:362 and action_doctrine_bundle.py:192 pass only org_roots → silent drop.

two callers thread org_fragments), and the warning is honest (no false suppression). No double-fold when both org_roots and org_fragments are given.

a genuinely missing DRG produces a real warning.

  • Before: two seams. org_fragments= folds drg/fragment.yaml via
  • After: the org_roots= seam also loads drg/fragment.yaml per root (or the
  • Invariant: an org pack's declared nodes/edges reach every consumer seam;

E6 — packs/internal/ (fixture) [IC-4/IC-5, #3530]

the on-disk directives/ dir + OPERATOR_SIGNAL_CONTRACT node.

procedures (landing-contributor-prs), directives (OPERATOR_SIGNAL_CONTRACT), and refines edges to built-in procedure:red-main-release-discipline / tactic:pr-agent-worktree-isolation.

  • Structure: already conformant — no shape change. README refreshed to list
  • Role: #3530 chain-delivery fixture (built-in layer 0 + internal org layer 1).
  • Declared kinds to verify delivered: glossary_packs (spk-internal-glossary),

E7 — extractor doc-nit [IC-6, #3629 p3]

to match the M2 WP04 re-ledger reality. No behaviour change.

  • Docstring at extractor.py:557 ("no golden-count update was required") clarified