Skip to main content

Canonical Project Record (CPR)

The Canonical Project Record (CPR) is a source-agnostic project-data schema that decouples internal project-data representation from source products (such as Jira, Asana, and MS Project).

Architecture Overview

The pipeline is implemented by a single CanonicalWriter (api/src/cpr/canonical-writer.ts) that owns all project_memory writes, drift capture via captureTransitions, and RAG upsert via RagService. Connectors (ADO/Asana) call it with CanonicalProjectRecord[] produced by SourceAdapter implementations.

Structured sources use declarative TransformerMapping objects (ADO_MAPPING, JIRA_MAPPING, ASANA_MAPPING in api/src/cpr/structured-mappings.ts) fed to structuredTransformer (api/src/cpr/structured-transformer.ts). Unstructured resolvers (e.g. ConfluenceResolver sketch in api/src/cpr/resolver-sketch.confluence.ts) satisfy the same SourceAdapter contract but emit ProgramAssociationProposal[] routed to the sign-off gate; the sketch is foundation only — not yet wired.

Core Schema Categories

The CPR schema is structured around 6 core categories:

  1. Identity: Core identifiers.
  2. Hope: Target states and baselines.
  3. Reality: Actual progress and lifecycle state.
  4. Gap: Schedule health and deviations.
  5. Narrative: Embedded status updates and summaries.
  6. Provenance: Multi-source trust, audit trails, and status fidelity.

Status and Lifecycle (Two Axes)

Rather than a single status field, CPR separates status into two distinct axes:

  • Lifecycle (Reality): Core states (not_started, active, done) mapped from language-agnostic keys, plus enriched states (blocked, on_hold, in_review, cancelled).
  • Schedule-health (Gap): Health indicators (on_track, at_risk, late, unknown).

Baseline and Trustworthiness

  • Baseline Source: Tracks how the baseline was established (native_baseline, recovered_from_history, first_ingest_snapshot, or unknown).
  • Honesty Principle: A late project must never look on-track via snapshot baseline (no slippage-laundering).

Granularity and Hierarchy

  • Granularity: One CPR per node at any level. Hierarchy is maintained via parent_id and type links (altitude, not structure).
  • Trajectory: Lightweight gap-history time-series (cpr_id, observed_at, gap_days, schedule_health) are recorded for trajectory tracking and risk modeling.