Skip to content

Interaction Cookbook

Twelve recipes for common cross-reference patterns. Each recipe includes the YAML entry, Python code, and guidance on when to use the pattern.

Prerequisites

All recipes assume you have the cross-reference matrix loaded:

from fcc.personas.cross_reference import CrossReferenceEntry, CrossReferenceMatrix
from fcc.personas.registry import PersonaRegistry

matrix = CrossReferenceMatrix.from_yaml("data/personas/cross_reference.yaml")
registry = PersonaRegistry.from_yaml_directory("data/personas/")

When: You have created a new persona and need to connect it to the existing workflow.

Pattern: Define at least one upstream handoff (input) and one downstream handoff (output).

# New persona: APT (API Tester) — receives from BC, sends to BV
- source_id: BC
  target_id: APT
  relationship_type: handoff
  interaction: Provides API specifications for test case generation
  strength: primary

- source_id: APT
  target_id: BV
  relationship_type: handoff
  interaction: Submits API test results for quality validation
  strength: primary
# Programmatic equivalent
matrix.add(CrossReferenceEntry(
    source_id="BC", target_id="APT",
    relationship_type="handoff",
    interaction="Provides API specifications for test case generation",
    strength="primary",
))
matrix.add(CrossReferenceEntry(
    source_id="APT", target_id="BV",
    relationship_type="handoff",
    interaction="Submits API test results for quality validation",
    strength="primary",
))
matrix.to_yaml("data/personas/cross_reference.yaml")

Validation: After adding, verify the persona appears in matrix.all_persona_ids() and has both upstream and downstream entries.


Recipe 2: Create a Peer Coordination Relationship

When: Two personas must stay synchronized but neither produces deliverables for the other.

Pattern: Add two coordination entries (one in each direction) with matching interaction descriptions.

- source_id: CIA
  target_id: STE
  relationship_type: coordination
  interaction: Aligns index schemas with semantic taxonomy
  strength: primary

- source_id: STE
  target_id: CIA
  relationship_type: coordination
  interaction: Aligns taxonomy definitions with catalog index schemas
  strength: primary

Tip: Coordination entries should come in pairs. If persona A coordinates with persona B, there should be entries for both A -> B and B -> A.

# Verify coordination pair exists
ab = matrix.between("CIA", "STE")
ba = matrix.between("STE", "CIA")
coord_ab = [e for e in ab if e.relationship_type == "coordination"]
coord_ba = [e for e in ba if e.relationship_type == "coordination"]
assert len(coord_ab) > 0 and len(coord_ba) > 0, "Missing coordination pair"

Recipe 3: Add a Governance Oversight Relationship

When: A persona must demonstrate compliance to a governance authority before proceeding.

Pattern: Add a governance entry from the reporting persona to the governance authority, plus a feedback entry from the authority back.

- source_id: DGS
  target_id: GCA
  relationship_type: governance
  interaction: Reports compliance status for governance audit
  strength: primary

# Optional: add feedback from authority back to reporter
- source_id: GCA
  target_id: DGS
  relationship_type: feedback
  interaction: Reviews data governance findings for audit completeness
  strength: secondary

When to use governance vs feedback: If the target persona has authority to block downstream progress, use governance. If it only provides non-blocking observations, use feedback.


Recipe 4: Create a Champion Persona with Orchestration

When: You want to elevate a base persona into a coordinated team.

Pattern: Create the champion-of entry, orchestration handoffs to each team member, and inter-champion links.

# Step 1: Champion-of entry (exactly one per champion)
- source_id: TSCH
  target_id: TS
  relationship_type: champion-of
  interaction: Champions and elevates the Traceability Specialist persona
  strength: primary

# Step 2: Orchestration handoffs to team members
- source_id: TSCH
  target_id: TS
  relationship_type: handoff
  interaction: Orchestrates traceability verification
  strength: primary

- source_id: TSCH
  target_id: BV
  relationship_type: handoff
  interaction: Orchestrates quality validation integration
  strength: primary

# Step 3: Inter-champion link
- source_id: RBCH
  target_id: TSCH
  relationship_type: handoff
  interaction: Hands off operational context for testing orchestration
  strength: primary

- source_id: TSCH
  target_id: RBCH
  relationship_type: feedback
  interaction: Receives operational context for testing
  strength: primary

Validation checklist:

  • Exactly one champion-of entry exists
  • Every orchestrated persona has a handoff from the champion
  • At least one inter-champion link connects to the pipeline

Recipe 5: Trace the Full Impact Chain from a Requirement Change

When: A requirement changes at the RC level and you need to know every persona affected.

def trace_impact(matrix, start_id, visited=None):
    """Recursively trace all downstream personas affected by a change."""
    if visited is None:
        visited = set()
    if start_id in visited:
        return visited
    visited.add(start_id)
    for entry in matrix.downstream(start_id):
        if entry.relationship_type in ("handoff", "champion-of"):
            trace_impact(matrix, entry.target_id, visited)
    return visited

affected = trace_impact(matrix, "RC")
print(f"Personas affected by RC change: {sorted(affected)}")

Output:

Personas affected by RC change: ['BC', 'BV', 'DE', 'RB', 'RC', 'SCP', 'TS', 'UG', 'UGCH', 'UMC']

This shows that a change in RC's research output can cascade through BC, DE, and eventually to the publishing layer.


Recipe 6: Find All Personas Affected by a Governance Policy Change

When: A governance policy changes at DGS and you need to know the blast radius.

def governance_blast_radius(matrix, governance_id):
    """Find all personas that receive governance or handoff from this persona."""
    affected = set()
    for entry in matrix.downstream(governance_id):
        affected.add(entry.target_id)
        # Follow handoffs from governance targets
        if entry.relationship_type in ("governance", "handoff"):
            for downstream in matrix.downstream(entry.target_id):
                affected.add(downstream.target_id)
    return affected

blast = governance_blast_radius(matrix, "DGS")
print(f"DGS policy change affects: {sorted(blast)}")

Output:

DGS policy change affects: ['AMS', 'BC', 'BV', 'CO', 'DE', 'GCA', 'PTE', 'STE', 'TS']

Recipe 7: Map a Champion's Team and Their Deliverable Flow

When: You need a complete picture of what a champion coordinates and where deliverables go.

def map_champion_team(matrix, registry, champion_id):
    """Map a champion's orchestrated team and their downstream deliverables."""
    champion = registry.get(champion_id)
    print(f"\n{champion_id} ({champion.name})")
    print(f"  Champion of: {champion.champion_of}")
    print(f"  Orchestrates: {champion.orchestrates}")

    print("\n  Orchestration handoffs:")
    for entry in matrix.downstream(champion_id):
        if entry.target_id in champion.orchestrates:
            print(f"    -> {entry.target_id} [{entry.relationship_type}]: {entry.interaction}")

    print("\n  Team member deliverables:")
    for member_id in champion.orchestrates:
        for entry in matrix.downstream(member_id):
            if entry.target_id not in champion.orchestrates and entry.target_id != champion_id:
                print(f"    {member_id} -> {entry.target_id} [{entry.relationship_type}]: {entry.interaction}")

map_champion_team(matrix, registry, "RCHM")

Output:

RCHM (Research Crafter Champion)
  Champion of: RC
  Orchestrates: ['RC', 'CIA', 'STE', 'RIC']

  Orchestration handoffs:
    -> RC [champion-of]: Champions and elevates the Research Crafter persona
    -> RC [handoff]: Orchestrates core research activities
    -> CIA [handoff]: Orchestrates catalog indexing activities
    -> STE [handoff]: Orchestrates taxonomy engineering activities
    -> RIC [handoff]: Orchestrates research automation activities

  Team member deliverables:
    RC -> BC [handoff]: Delivers research inventory; clarifies context
    RC -> DE [handoff]: Provides annotated references for cross-linking
    RC -> RB [handoff]: Flags operational scenarios for automation
    RC -> UG [handoff]: Compiles user pain points for onboarding guides
    RC -> TS [handoff]: Provides requirements for traceability linking
    CIA -> BC [handoff]: Supplies catalog data for blueprint context
    CIA -> GCA [handoff]: Reports coverage gaps for compliance review
    ...

Recipe 8: Add a Feedback Loop Between Two Personas

When: A reviewer needs to send corrections back to a producer.

Pattern: Add a feedback entry from the reviewer to the producer. If the original handoff does not exist yet, add that too.

# The original handoff (producer -> reviewer)
- source_id: BC
  target_id: BV
  relationship_type: handoff
  interaction: Submits blueprints for quality validation
  strength: primary

# The feedback loop (reviewer -> producer)
- source_id: BV
  target_id: BC
  relationship_type: feedback
  interaction: Returns quality validation results on blueprints
  strength: primary

Verification:

# Verify the feedback loop exists
forward = matrix.between("BC", "BV")
reverse = matrix.between("BV", "BC")
has_handoff = any(e.relationship_type == "handoff" for e in forward)
has_feedback = any(e.relationship_type == "feedback" for e in reverse)
print(f"Handoff BC->BV: {has_handoff}, Feedback BV->BC: {has_feedback}")

When: Two personas in different FCC phases need to share context without a formal handoff.

# Find-phase persona coordinates with Critique-phase persona
- source_id: STE
  target_id: DE
  relationship_type: coordination
  interaction: Validates terminology against documentation standards
  strength: secondary

# Create-phase persona coordinates with stakeholder
- source_id: RS
  target_id: RC
  relationship_type: coordination
  interaction: Coordinates research milestones with project timeline
  strength: secondary

Tip: Cross-phase coordination entries are typically secondary strength because they enhance quality without blocking progress.


Recipe 10: Validate Cross-Reference Completeness Programmatically

When: You want to check that the matrix satisfies QG-XREF-001, QG-XREF-002, and QG-XREF-003.

def validate_xref_coverage(matrix, expected_ids):
    """QG-XREF-001: Every persona ID appears at least once."""
    matrix_ids = matrix.all_persona_ids()
    missing = expected_ids - matrix_ids
    if missing:
        print(f"FAIL QG-XREF-001: Missing personas: {sorted(missing)}")
        return False
    print(f"PASS QG-XREF-001: All {len(expected_ids)} personas covered")
    return True


def validate_xref_types(matrix):
    """QG-XREF-002: All 5 relationship types are used."""
    required_types = {"handoff", "feedback", "coordination", "governance", "champion-of"}
    found_types = {e.relationship_type for e in matrix}
    missing = required_types - found_types
    if missing:
        print(f"FAIL QG-XREF-002: Missing types: {sorted(missing)}")
        return False
    print(f"PASS QG-XREF-002: All 5 relationship types present")
    return True


def validate_no_orphans(matrix, registry):
    """QG-XREF-003 (partial): No orphan persona IDs."""
    matrix_ids = matrix.all_persona_ids()
    registry_ids = set(registry.ids)
    orphans = matrix_ids - registry_ids
    if orphans:
        print(f"FAIL QG-XREF-003: Orphan IDs not in registry: {sorted(orphans)}")
        return False
    print(f"PASS QG-XREF-003: No orphan persona IDs")
    return True


# Run all checks
all_24 = {
    "RC", "BC", "DE", "RB", "UG",
    "CIA", "UMC", "STE", "TS", "BV", "RIC", "GCA",
    "DGS", "PTE", "AMS",
    "CO", "SMC", "EC", "RS", "SCP",
    "RCHM", "BCHM", "UGCH", "RBCH",
}

validate_xref_coverage(matrix, all_24)
validate_xref_types(matrix)
validate_no_orphans(matrix, registry)

Recipe 11: Generate a Relationship Diagram from the Matrix

When: You need a visual representation of interactions for a specific persona or category.

def generate_mermaid(matrix, persona_ids, title="Cross-Reference Diagram"):
    """Generate a Mermaid diagram for a subset of personas."""
    lines = [f"graph TD"]
    lines.append(f"    %% {title}")
    seen_edges = set()
    for entry in matrix:
        if entry.source_id in persona_ids or entry.target_id in persona_ids:
            edge_key = (entry.source_id, entry.target_id, entry.relationship_type)
            if edge_key not in seen_edges:
                seen_edges.add(edge_key)
                style = "-->" if entry.strength == "primary" else "-.->"
                lines.append(
                    f"    {entry.source_id} {style}|{entry.relationship_type}| "
                    f"{entry.target_id}"
                )
    return "\n".join(lines)


# Generate diagram for governance personas
gov_ids = {"DGS", "PTE", "AMS", "GCA"}
mermaid = generate_mermaid(matrix, gov_ids, "Governance Interactions")
print(mermaid)

Output:

graph TD
    %% Governance Interactions
    DGS -->|handoff| BC
    DGS -->|coordination| STE
    DGS -->|governance| GCA
    DGS -->|handoff| PTE
    PTE -->|feedback| DGS
    PTE -.->|coordination| STE
    PTE -->|governance| GCA
    PTE -->|handoff| AMS
    AMS -->|feedback| DE
    AMS -.->|feedback| PTE
    AMS -->|governance| GCA
    AMS -->|feedback| BC
    GCA -->|feedback| DE
    GCA -.->|feedback| BV
    GCA -.->|feedback| TS
    GCA -->|handoff| CO
    ...

Recipe 12: Query the Matrix in a CI/CD Pipeline

When: You want cross-reference validation as part of your continuous integration checks.

#!/usr/bin/env python3
"""CI script: validate cross-reference matrix integrity."""

import sys
from pathlib import Path

from fcc.personas.cross_reference import CrossReferenceMatrix
from fcc.personas.registry import PersonaRegistry


def main():
    data_dir = Path("data/personas/")
    matrix = CrossReferenceMatrix.from_yaml(data_dir / "cross_reference.yaml")
    registry = PersonaRegistry.from_yaml_directory(data_dir)

    errors = []

    # QG-XREF-001: Coverage
    expected_ids = set(registry.ids)
    matrix_ids = matrix.all_persona_ids()
    missing = expected_ids - matrix_ids
    if missing:
        errors.append(f"QG-XREF-001 FAIL: Missing personas: {sorted(missing)}")

    # QG-XREF-002: Type completeness
    required_types = {"handoff", "feedback", "coordination", "governance", "champion-of"}
    found_types = {e.relationship_type for e in matrix}
    missing_types = required_types - found_types
    if missing_types:
        errors.append(f"QG-XREF-002 FAIL: Missing types: {sorted(missing_types)}")

    # QG-XREF-003: No orphans
    orphans = matrix_ids - expected_ids
    if orphans:
        errors.append(f"QG-XREF-003 FAIL: Orphan IDs: {sorted(orphans)}")

    # Report
    if errors:
        for e in errors:
            print(f"ERROR: {e}", file=sys.stderr)
        sys.exit(1)
    else:
        print(f"All cross-reference quality gates passed ({len(matrix)} entries, "
              f"{len(matrix_ids)} personas)")
        sys.exit(0)


if __name__ == "__main__":
    main()

Save as scripts/validate_xref.py and add to your CI pipeline:

# .github/workflows/ci.yml (excerpt)
- name: Validate cross-references
  run: python scripts/validate_xref.py

Summary

Recipe Pattern Key Relationship Type
1 New persona with links handoff
2 Peer coordination coordination
3 Governance oversight governance
4 Champion orchestration champion-of + handoff
5 Impact chain tracing handoff (recursive)
6 Governance blast radius governance + handoff
7 Champion team mapping champion-of + handoff
8 Feedback loop feedback
9 Cross-phase coordination coordination (secondary)
10 Completeness validation All types
11 Diagram generation All types
12 CI/CD validation All types

Next Steps