graph-mutation-plan

star 5.5k

Cookbook for composing an apply_graph_mutations plan — stable entity_key patterns, the canonical label/edge vocabulary, evidence/invalidation/confidence discipline, and a worked example. Load this when building a non-trivial mutation plan.

potpie-ai By potpie-ai schedule Updated 6/7/2026

name: graph-mutation-plan description: Cookbook for composing an apply_graph_mutations plan — stable entity_key patterns, the canonical label/edge vocabulary, evidence/invalidation/confidence discipline, and a worked example. Load this when building a non-trivial mutation plan. version: "1.0.0" tags: [mutation, graph, ontology, reference]

Composing an apply_graph_mutations plan

Call apply_graph_mutations(plan, event_id, summary) once per logical group of mutations. The plan is idempotent on stable entity_keys, so a retried plan converges rather than duplicating. Every structural mutation must stay inside the given pot_id — never reference another pot.

Plan fields

  • summary: one-line description of what this plan records.
  • episodes: {name, episode_body, source_description, reference_time?} — narrative/source text to retain (e.g. a PR body, a note).
  • entity_upserts: {entity_key, labels, properties}.
  • edge_upserts: {edge_type, from_entity_key, to_entity_key, properties}.
  • edge_deletes: {edge_type, from_entity_key, to_entity_key}.
  • invalidations: {reason, target_entity_key?, edge_type?, from_entity_key?, to_entity_key?}.
  • evidence: {kind, ref, metadata?} — what grounds this plan.
  • confidence: float | null.
  • warnings: list[str] — anything you could not confirm.

Stable entity_key cookbook

Use these so re-ingestion (and a later live webhook for a backfilled artifact) upserts the same node:

Artifact Key pattern
Repository github:repo:<owner>/<repo>
Pull request github:pr:<owner>/<repo>:<n>
Issue github:issue:<owner>/<repo>:<n>
Module / package module:<repo>:<dotted.path>
Feature feature:<repo>:<slug>
Linear issue linear:issue:<identifier> (e.g. linear:issue:ENG-123)
Linear project linear:project:<id>
Linear document linear:document:<id>
Activity (timeline) timeline:activity:<verb>:<short_hex>
Period bucket timeline:period:daily:<pot_id>:<YYYY-MM-DD>

When no pattern fits, mint a deterministic key from stable identifiers in the source (never a random id, never a timestamp), so the same fact re-keys the same way.

Canonical vocabulary

Always give an entity at least one canonical label — never only generic Entity. Labels/edges outside the canonical vocabulary are downgraded automatically (entities → Document / Observation, edges → RELATED_TO), so prefer a canonical type when one fits.

Entity labels (topology — source of truth is domain/ontology.py): Repository, Service, Environment, DataStore, Cluster, Team, Person. Plus the work/knowledge types the playbooks reference: Activity, Feature, Decision, Fix, BugPattern, Incident, DiagnosticSignal, Module, Document.

Edge types: DEFINED_IN (Service→Repository), DEPLOYED_TO (Service→Environment), DEPENDS_ON (Service→Service), USES (Service→DataStore), HOSTED_ON (Environment→Cluster), OWNED_BY (Service/Repository→Team/Person), MEMBER_OF (Person→Team). For completed work, an Activity carries PERFORMED (→ the actor), TOUCHED (→ the modules/features it changed), and IN_PERIOD (→ the period bucket). Use RELATED_TO only when nothing canonical fits.

Discipline

  • Justify every mutation from the event payload or a tool-observed fact. If unsure, add a warning and keep the plan minimal — don't invent.
  • Supersession → invalidation. When this event makes a prior fact untrue, add an invalidation referencing the prior entity/edge rather than silently overwriting.
  • Evidence, not vibes. Link the PR/issue/commit/url that grounds the plan under evidence; set confidence lower when the inference is indirect.

Worked example — a merged PR that fixes a bug

{
  "summary": "PR #482 fixes the retry-storm in the billing worker",
  "episodes": [{
    "name": "PR #482 body",
    "episode_body": "<the PR description text>",
    "source_description": "github pull_request merged"
  }],
  "entity_upserts": [
    {"entity_key": "timeline:activity:merged:9f3a1c",
     "labels": ["Activity"],
     "properties": {"verb": "merged", "verb_class": "code", "title": "Merge PR #482"}},
    {"entity_key": "fix:billing:retry-storm",
     "labels": ["Fix"], "properties": {"title": "Bound billing retry backoff"}}
  ],
  "edge_upserts": [
    {"edge_type": "PERFORMED", "from_entity_key": "person:github:alice",
     "to_entity_key": "timeline:activity:merged:9f3a1c"},
    {"edge_type": "TOUCHED", "from_entity_key": "timeline:activity:merged:9f3a1c",
     "to_entity_key": "module:o/r:billing.worker"},
    {"edge_type": "RESOLVED", "from_entity_key": "fix:billing:retry-storm",
     "to_entity_key": "bug:billing:retry-storm"}
  ],
  "evidence": [{"kind": "pull_request", "ref": "github:pr:o/r:482"}],
  "confidence": 0.9,
  "warnings": []
}

Trivial PRs (typo/lint) need only the Activity — no Fix or Decision. Don't invent design decisions the PR body doesn't state.

Install via CLI
npx skills add https://github.com/potpie-ai/potpie --skill graph-mutation-plan
Repository Details
star Stars 5,456
call_split Forks 635
navigation Branch main
article Path SKILL.md
More from Creator