RFC-0001 — Shared Correlation Key & Completion-Event Schema

Status: Accepted · Version: 1.0 · Updated: 2026-06-04 Part of the PARR spine (issue #1, #4). The product repos implement against this document.

1. Motivation

The four products — PFactory (plan) → AIFactory (act) → TFactory (verify), all observed by CFactory (cockpit) — each own one stage of one unit of work. To thread a single unit across the family (for CFactory’s observability and for an EU-AI-Act-grade audit trail), every product must agree on two things:

  1. a shared correlation key that identifies the unit of work end to end, and
  2. a normalized completion-event envelope every service emits when its stage reaches a terminal state.

This RFC specifies both. It is deliberately small and additive-friendly so a new product (or a new field) does not force a breaking change.

2. The correlation key

The correlation key is the GitHub issue number of the governed work item — the durable, human-visible artifact every stage already references.

pfactory.session_id  →  issue#  →  aifactory.task_id  →  branch / PR#  →  tfactory.spec_id

3. The completion-event envelope

A service emits one completion event when its stage reaches a terminal status. The envelope has exactly these six required fields:

Field Type Description
correlation_key string The shared key (§2) — issue number, or synthetic fallback.
service string The emitting service: pfactory | aifactory | tfactory | cfactory.
task_id string The emitter’s local identifier for this unit (PFactory: session_id; AIFactory: task_id; TFactory: spec_id).
status string The terminal status this service landed on (§5).
phase string The pipeline phase the status belongs to (e.g. emit, review, qa, test).
updated_at string ISO-8601 UTC timestamp of the terminal transition.

Example

{
  "correlation_key": "142",
  "service": "pfactory",
  "task_id": "001-refund-flow",
  "status": "emitted",
  "phase": "emit",
  "updated_at": "2026-06-04T15:14:45+00:00"
}

4. The optional correlation block

An emitter MAY include a correlation object carrying the upstream/downstream chain links it knows about, so a consumer (CFactory) can stitch the thread without a join table. All members are optional and additive:

{
  "correlation_key": "142",
  "service": "pfactory",
  "task_id": "001-refund-flow",
  "status": "emitted",
  "phase": "emit",
  "updated_at": "2026-06-04T15:14:45+00:00",
  "correlation": {
    "session_id": "001-refund-flow",
    "issue_number": 142,
    "aifactory_task_id": null
  }
}

Known link fields (extend as the chain grows): session_id, issue_number, aifactory_task_id, branch, pr_number, tfactory_spec_id.

5. Per-service contract

Each service decides its own terminal statuses and phases; the envelope normalizes the shape, not the vocabulary. The reference (PFactory) contract:

Service service task_id Terminal statusphase Emits when
PFactory pfactory session_id emittedemit, rejectedreview a plan is governed-emitted, or rejected
AIFactory aifactory task_id e.g. merged/qa_failedact/qa a build run reaches a terminal state
TFactory tfactory spec_id e.g. triaged/triaged_empty/triager_failedtest the verdict pipeline completes

phase for an unknown status SHOULD fall back to the status string itself. Consumers MUST treat unknown status/phase values as opaque (forward-compatibility).

6. Transport

Completion events are delivered best-effort — a failing delivery MUST NEVER break the emitting pipeline.

Operators opt in per service via env. PFactory’s surface (other services SHOULD mirror the names with their own prefix):

Env var Effect
PFACTORY_COMPLETION_WEBHOOK=<url> POST the envelope to <url> on terminal status.
PFACTORY_COMPLETION_WEBHOOK_TIMEOUT=<seconds> Webhook timeout (default 5).
PFACTORY_COMPLETION_SENTINEL=1 Also write a COMPLETED.json sentinel.
PFACTORY_COMPLETION_SENTINEL_DIR=<dir> Where the sentinel is written.

Consumers SHOULD treat events as idempotent by (service, correlation_key, status) — a retried or duplicated delivery for the same terminal transition is the same event.

7. Versioning & compatibility

8. Reference implementation

PFactory implements this RFC today:

AIFactory and TFactory implement the emitter side against §3–§6; CFactory implements the consumer side (idempotent ingest keyed by §7).