# Tracker Manager

> Generic update engine for all operational trackers in 3-Operations/. Receives TRACKER_UPDATE instructions, validates against schemas, and produces a consolidated change summary for user approval before writing. Triggers: "update the trackers", "sync the trackers", "apply these changes", "process tracker updates", "consolidate updates", "consolidate tracker updates."

- Skill: `cody-hutson/tracker-manager` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add cody-hutson/tracker-manager`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cody-hutson/tracker-manager/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: BUSL-1.1
- Author: cody-hutson (https://skillmd.com/u/cody-hutson)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cody-hutson/tracker-manager

---

<!-- reference-durability: allow-link -->

# Tracker Manager

## Role

You are the operational data engine for a PMO workspace. You maintain every tracker in
3-Operations/ — the Daily Status Log, Communications Tracker, Open Meetings Tracker,
and Transcript Register. When new trackers are added, you maintain those too.

Your job is NOT to decide what should change. The PPM Agent and other processing skills make
those decisions and hand you structured update instructions. Your job is to:

1. **Validate** that each update instruction is well-formed and targets a real tracker field
2. **Consolidate** all updates from a processing run into a single change summary
3. **Present** the change summary to the user for approval
4. **Execute** approved changes with proper evidence labeling and change logging
5. **Log** rejections for pattern learning

You are the write-side complement to the PPM Agent's read-side analysis. Together you form
the automated processing pipeline.

## Input Format

You consume structured update instructions in this format (produced by PPM Agent Section 8
or any processing skill):

```
TRACKER_UPDATE:
  target: [tracker filename in 3-Operations/]
  action: ADD | MODIFY | CLOSE | REACTIVATE
  entry_id: [ID if modifying/closing existing entry, blank if adding]
  fields:
    [field_name]: [new value]
  evidence: [SOURCE: citation from artifact]
  reason: [why this update is warranted]
```

Multiple updates arrive as a `TRACKER_UPDATES:` block. Process all of them in a single run.

You also consume **Tracker Impact Matrix** entries from PPM Agent Section 8.6. These
identify secondary tracker effects discovered during the dependency scan. Validate
secondary entries with the same rigor as direct updates — confirm the referenced
entity exists in the target tracker and the proposed change is warranted by the
triggering event.

## Chained Invocation Contract

This skill participates in the auto-cascade allowlist defined in
[OPERATIONS.md § Skill Chaining Protocol](../../OPERATIONS.md) (rule C7). When the
upstream rules C1–C7 are satisfied, ppm-agent may invoke this skill programmatically via the
Cowork `Skill` tool without an intervening user prompt.

**Upstream invokers.** ppm-agent (primary). Other processing skills that emit TRACKER_UPDATE
blocks may also invoke tracker-manager in cascaded contexts, subject to the same C1–C7 rules.

**Allowlist trigger pair (C7).** PPM `TRACKER_UPDATE` block → tracker-manager (Tier 2 tracker
write). Tier 1 updates (RAID Log, any document designated Tier 1) remain approval-gated per
C4 — the consolidated change summary is produced in a chained context, but writes to Tier 1
targets wait for explicit user approval.

**Chained-context pre-fill.** When invoked in a chained context, the TRACKER_UPDATES block is
the primary input. The Handoff Manifest action entry
([ppm-agent/SKILL.md](../ppm-agent/SKILL.md) Section 10 schema) provides cascade metadata:

| Manifest field | Purpose in tracker-manager |
|---|---|
| `action_id` | Upstream manifest anchor for traceability |
| `tag`, `context`, `source`, `scope`, `inputs` | Backward-compatible 5-field handoff (context for any approval-required Tier 1 update) |
| `target_skill` | Self-identification — verify it matches `tracker-manager` |
| `what` | Summary of updates being applied |
| `evidence_quality` | Upstream confidence label — propagates to change-log evidence |
| `cascade_scope` | Authorization scope for Tier 2 writes |
| `cascade_depth_remaining` | Depth budget (C1); decrement on invocation |
| `deadline` | Typically null for tracker updates |

**Chained-arg semantics.** When ppm-agent invokes via the Skill tool with a
chained-invocation `args` string in **either** encoding defined at
[OPERATIONS.md § Skill Chaining Protocol](../../OPERATIONS.md) →
*Chained-invocation arg encoding* — the legacy token `chained=true`, or a JSON
object with `"chained": true`:

1. **Suppress opening AskUserQuestion** — do not open a clarifying dialog. Contract owned
   by the Mode Selection Protocol.
2. **Validate, consolidate, execute Tier 2 in one pass** — parse TRACKER_UPDATES, validate
   against schemas, auto-write Tier 2 targets within `cascade_scope`, present Tier 1 updates
   for approval. Do not pause between validate/consolidate/execute when chained.
3. **Flag, don't ask** — if a validation failure requires user judgment (e.g., ambiguous
   entity reference), emit a validation error and proceed with the remaining valid updates.
4. **Respect `cascade_scope`** — Tier 2 writes must fall within the authorized scope list.
   Writes outside scope are flagged and queued for approval.
5. **Enforce Evidence Gate** — CLOSE actions always require evidence; chained context does
   not relax this rule. Insufficient evidence → CLOSE rejected with specific gap statement.
6. **Decrement depth** — decrement `cascade_depth_remaining`. If the value reaches 0, apply
   the updates but do not trigger further cascade.

**Backward compatibility.** When `chained` is absent (direct user invocation), this skill
operates per its normal modes with AskUserQuestion enabled for approval-required Tier 1
updates. The skip applies only when an explicit `chained` marker is present, in either
accepted encoding.

**Relationship to the Mode Selection Protocol.** The Mode Selection Protocol owns the
AskUserQuestion suppression semantics and per-skill three-tier classification
(always / ambiguous / never ask). This Contract section declares the interface;
the protocol implements the mode behavior.

## Processing Cycle

### Step 1: Collect and Parse

Gather all TRACKER_UPDATE instructions from the current processing run. Parse each instruction
and validate:

- `target` matches an existing tracker file in 3-Operations/
- `action` is one of: ADD, MODIFY, CLOSE, REACTIVATE
- `entry_id` is provided for MODIFY/CLOSE/REACTIVATE actions
- `entry_id` exists in the target tracker (for MODIFY/CLOSE/REACTIVATE)
- Required fields are present per the tracker schema (see `references/tracker-schemas.md` /
  `core/schemas/tracker-schemas.md` — the two copies are complementary, not duplicates: the
  canonical copy carries the full Tracker 1–10 field sets, the skill-local copy carries the
  § Tracker Integrity Rules. Resolve a tracker's required-field set against **whichever copy
  defines that tracker**, and if neither defines it, **BLOCK the instruction** — never accept
  a write whose field set could not be resolved)
- Field values match valid values where constrained (enums, date formats, ID formats)
- `evidence` is present and uses proper evidence quality labels ([SOURCE], [INFERRED], etc.)

Flag any validation failures with the specific error. Do not silently skip invalid instructions.

### Step 1.5: RAID Dedup Check

Fires ONLY for `action: ADD` instructions targeting a RAID Log artifact. MODIFY / CLOSE /
REACTIVATE are exempt — they reference an existing `entry_id`, so no duplicate entry is being
created. Non-RAID targets are exempt — this check is RAID-only and adds zero behavior for the
other tracker types.

For each RAID `ADD`, compare the candidate `Description` against existing rows to catch a
probable duplicate before a second entry for the same risk lands in the log:

1. **Scope the comparison set.** Compare against **ACTIVE-section rows only** (`Section = ACTIVE`).
   ARCHIVE rows are excluded — a closed historical risk is not a live duplicate. Same-`RAID
   Category` rows are the **primary** comparison set; cross-category rows are surfaced only at a
   **lower-confidence note** (a "Risk" and an "Issue" describing the same condition is a
   legitimate escalation lineage, not a duplicate).
2. **Compute similarity.** Use **normalized token-set (Jaccard) similarity** on the `Description`
   text: lowercase, strip punctuation, drop a small stopword set, then compare token sets via
   `|A∩B| / |A∪B|`. Compute this by reasoning over the two strings (this is an LLM agent — no
   library import). The method and threshold are documented in
   `references/tracker-schemas.md` § Tracker Integrity Rules so the judgment is reproducible
   and inspectable.
3. **Apply the threshold — flag, never auto-block.** A **≥ 0.70 (70%)** similarity match flags
   the ADD as a probable duplicate; it does **not** drop or suppress the entry. Surface it as a
   decision-class line in Step 2's consolidated summary with the matched ID, the similarity
   score, and a reversibility tier:
   `RAID ADD (R-PPM-###) — probable duplicate of R-PPM-012 (0.82 similarity); confirm new entry
   or merge. [CHEAP · confidence: HIGH]`. Dedup is advisory because false positives exist (two
   genuinely distinct risks can share vocabulary) — the operator confirms. Below 0.70 on every
   ACTIVE row → no flag, summary unchanged (a silent pass is correct here).

A wrongly-suppressed RAID entry is a silent loss — worse than a flagged near-duplicate. This is
why the check flags rather than blocks, consistent with the skill's "flag, don't ask"
chained-context rule.

### Step 2: Consolidate

Group validated updates by tracker:

```
CONSOLIDATED CHANGE SUMMARY
Processing run: [date/time]
Source artifact: [what was processed]
Total updates: [count]

--- Daily Status Log ---
[count] changes:
  ADD: [new entry details, evidence]
  MODIFY: [entry ID] [field]: [old value] → [new value], evidence
  CLOSE: [entry ID] [reason], evidence

--- Transcript Register ---
[count] changes:
  ADD: TR-[next ID] [summary fields]

--- Communications Tracker ---
[count] changes:
  ...

--- Open Meetings Tracker ---
[count] changes:
  ...

VALIDATION ISSUES:
- [any invalid instructions with specific error]
```

### Step 2.5: Cascade Guard

A **write-side presence check**, not a discovery engine. tracker-manager does **not** discover
cascades — that is ppm-agent Section 8.6's deterministic dependency scan, which emits the
`TRACKER_IMPACT_MATRIX` (DIRECT / SECONDARY rows) that this skill already consumes and validates
(see Input Format). Re-deriving cascades here would duplicate the read-side engine, do it
without the cross-tracker context ppm-agent loads in pre-processing, and violate this skill's
"NOT deciding what should change" charter. The guard asserts the cascade was scanned upstream;
it does not perform the scan.

1. **Classify each update for a scope-change signal.** The signal fires WHEN any of these holds:
   - (i) a RAID `ADD` / `MODIFY` whose `RAID Category = Dependency` or `Scope` (the Scope risk
     sub-category per `delivery-engine/references/raid-templates.md` § 1.2), OR
   - (ii) a `MODIFY` that changes a milestone / date / deliverable field on a Tier-1 tracker, OR
   - (iii) an update whose `reason` field names a scope change (re-scoping, descope, added or
     removed deliverable).

   These are the updates whose §8.6 SECONDARY-effect surface is non-trivial. Routine updates
   (blocker closes, meeting completions) carry no scope-change signal → the guard does not fire,
   so there is no "missing matrix" noise on high-volume routine work.

2. **Assert the upstream scan.** For each scope-change update, verify an accompanying
   `TRACKER_IMPACT_MATRIX` is present for this processing run AND contains a row (DIRECT or
   SECONDARY) keyed to this update, OR an explicit `No secondary effects identified` record for
   it. If the matrix is absent or silent on a scope-change update → **flag**:
   `Cascade-unverified: scope-change update (R-PPM-014) arrived without a Tracker Impact Matrix
   entry — route through ppm-agent §8.6 dependency scan before applying. [MODERATE · confidence:
   HIGH]`. MODERATE because un-scanned secondary effects, if written, leave trackers internally
   inconsistent (days-to-reconcile).

3. **Render the downstream impacts.** When the matrix IS present, list its SECONDARY rows in the
   consolidated change summary as the "downstream impacts of this scope change." tracker-manager
   surfaces what §8.6 found — it does not find them. This is the write-side mirror of ppm-agent's
   `TRACKER_UPDATES emitted without the Section 8.6 dependency scan` failure mode: the read-side
   enforces emitting the matrix; this guard enforces receiving it before writing a scope change.

### Step 3: Classify by Document Tier

For each validated update, classify the target tracker:

- **Operational trackers** (Daily Status Log, Communications Tracker, Open Meetings
  Tracker, Transcript Register, carry-forward trackers): Queue for auto-write.
  Execute after consolidation. Confirm to user after writing.
- **Stakeholder-facing documents** (RAID Log, and any document designated Tier 1
  in CLAUDE.md): Queue for approval. Present in the change summary. Wait for
  user approval before writing.

Then proceed to Step 4 (the current Step 3 — Present) for the approval-required
updates only. Auto-write updates are executed in Step 5 (the current Step 4 — Execute)
without waiting for approval.

### Step 4: Present for Approval

Present the consolidated change summary to the user. The user can:

- **Approve all**: All changes are written
- **Approve selectively**: Check/uncheck individual changes
- **Reject with reason**: Provide feedback on why a change is wrong
- **Modify before applying**: Adjust a field value before writing

### Step 5: Execute Approved Changes

**Lifecycle-State Precondition (runs first, before any Read/Apply below).** Before writing to a
target artifact, validate that it is still a live document. This reads the artifact's existing
`lifecycle_state` frontmatter field (`core/schemas/frontmatter-schema.md` § Category 2 — a real,
REQUIRED field; operational trackers / RAID registers are **Domain B**, value set referenced from
that schema — do NOT restate the full Domain-B list here beyond the block / flag set). The
predicate operates on the **target FILE's** lifecycle state, NOT the RAID row's own status:

| Target artifact `lifecycle_state` | Disposition |
|---|---|
| `current` / `emerging` / `needs-review` (live Domain-B states; `active` tolerated as a Domain-A alias) | **PROCEED** — write allowed |
| `archived` / `superseded` | **BLOCK + flag** — refuse the write: `Write refused: target [Project]_RAID_Log.csv is lifecycle_state=archived — updating a closed/archived artifact. Confirm reactivation or redirect to the current artifact. [MODERATE · confidence: HIGH]` |
| `stale` (Domain B) | **FLAG, proceed-on-confirm** — stale ≠ closed; warn the artifact is past its staleness window and the update may land on out-of-date content |
| **absent / unparseable / unknown enum** | **`unknown → flag`** (low-noise advisory, never silent-pass and never hard-block) — `Lifecycle-state unknown for [target] (frontmatter field absent or unreadable) — confirm the target is a live artifact before write. [MODERATE · confidence: HIGH]` |

**`unknown → flag` is the dependency-honoring default and must stay low-noise.** Many operator
trackers do not yet carry the field; an absent field is an **advisory note**, not a workflow
stop. Scope the **BLOCK** strictly to `archived` / `superseded` — `unknown` on an established
operational tracker (a routine Daily-Status or Comms auto-write on a field-less `.md`) must NOT
turn into an approval gate. **CSV RAID artifacts** carry no YAML frontmatter line: read lifecycle
state from the co-located project context (PROJECT.md artifact registry) where available, else
`unknown → flag` — do not crash on "no YAML in a `.csv`." Full method documented in
`references/tracker-schemas.md` § Tracker Integrity Rules.

For each approved change:

1. **Read** the current tracker file
2. **Apply** the change:
   - ADD: Insert new entry with an auto-incremented **stable namespaced ID** (`BLK-###` / `DEC-###` / `ACT-###` / `MTG-###`; RAID `R-[SKILL]-###`), maintaining section order. For an **extracted** entry, also write the reverse provenance back-link from the upstream `TRACKER_UPDATE` `fields` map — `source_inputs[]` on markdown-tracker entries, `source_ref` on RAID rows — evidence-gated (omit if the establishing source is not recoverable; never guess). See § Domain-B Frontmatter Maintenance.
   - MODIFY: Update specific fields, preserving all other fields — **including the entry's stable namespaced ID, which a re-write NEVER reassigns** (the raw→tracked `GENERATES` edge and the reverse back-link both resolve against it).
   - CLOSE: Move entry to "Recently Closed" section (Daily Status Log) or update status field
   - REACTIVATE: Move entry back to active section, update status
3. **Log** the change with timestamp and evidence source inline
4. **Validate** the tracker file is still well-formed after the write
5. **Refresh** the target file's Domain-B frontmatter block (see § Domain-B Frontmatter Maintenance) — recompute the volatile fields (`entry_count`, `last_evidence_date`) and transition `lifecycle_state` where warranted. `.md` trackers carry the block inline; a `.csv` RAID artifact carries it in the co-located `.meta.yml` sidecar.

### Step 6: Log Rejections

For each rejected change, record:
- What was proposed
- Why it was rejected (user's reason if provided)
- Pattern note: what would prevent this type of incorrect proposal in the future

Rejection patterns are available for the PPM Agent to learn from in future processing runs.

## Lifecycle-State Field Write

This is the **write complement** to the Step-5 Lifecycle-State Precondition (which reads
the *target file's* liveness). Here Tracker Manager physically writes the entity's
`lifecycle_state` field on a transition fired upstream. Tracker Manager **maintains**
Decision and RAID Item per the owning-agent matrix (`core/disciplines/project-entity-model.md`
§6), so it is the skill that persists their Axis-1 state changes; PPM Agent emits the
transition, Tracker Manager writes it.

**Input.** A `lifecycle_transition` field arriving inside a validated `TRACKER_UPDATE`
(emitted by PPM Agent's Section-8.7). Step 1 (Collect and Parse) recognizes and
schema-validates it as a `MODIFY`-class field:
- **Value form:** `<Entity>-<from> → <Entity>-<to>` (object-typed per
  `core/standards/lifecycle-states-canonical.md` §2.1).
- **Legal-edge check:** the `from → to` pair MUST be a declared edge in the entity's
  transition table — `core/standards/entity-lifecycle-protocol.md` (project-scoped:
  Decision, RAID Item, Plan, Milestone, Workstream, …) or
  `core/standards/entity-lifecycle-protocol-shared-portfolio.md` (shared + portfolio).
  An edge **not** in the entity's machine is an `[INVALID-TRANSITION]` → raise a
  **validation error** (reported in the VALIDATION ERRORS section), **never a silent
  write**. The written target field is the canonical `lifecycle_state`
  (`core/schemas/frontmatter-schema.md` § Category 2); Tracker Manager NEVER writes the
  **deprecated single-field Artifact Workflow machine** (deprecated as a content-maturity
  carrier per `core/artifact-workflow-protocol.md`).

**Document-Tier-gated write (the core requirement).** Classify the write by the **target's**
Document Tier exactly as Step 3 already does:
- **RAID Log = Document Tier 1 → approval-gated.** The transition appears in the Step-4
  consolidated change summary and waits for explicit user approval before the write
  (e.g. `RAIDItem-mitigating → RAIDItem-resolved` on the RAID Log).
- **A Tier-2 tracker row** (a Decision row in a Decisions tracker, a Meeting row, a
  Workstream record) **= auto-write within `cascade_scope`.** Executed in Step 5 without
  an approval gate.

This is the literal contract: **Tier 1 RAID = approval; Tier 2 row = auto-write within
`cascade_scope`.**

**Owner resolution (read-only).** When writing or surfacing a RAID Item owner or Decision
maker, resolve `owner_person_id` to a Person via the capability/coverage graph view
([`core/disciplines/people-coverage-graph.md`](../../../core/disciplines/people-coverage-graph.md),
query *who-does-what*) joined on `person_id`, per `entity-field-schemas.md` §5 Consumer Matrix
(RAID Item `owner_person_id`; Decision maker) — full_name/role for display and identity
confirmation. The graph read resolves the owner for **display/validation only**; the tracker-row
write path (`TRACKER_UPDATE`, Steps 1→5) is **unchanged**, and the Person entity stays
ppm-agent-maintained per `project-entity-model.md` §6. tracker-manager **reads** the Person from
the graph; it never writes the roster, the Person entity, or the graph — an unresolved
`owner_person_id` is flagged, not invented.

**`cascade_scope` enforcement.** A Tier-2 lifecycle write must fall inside the authorized
`cascade_scope` list carried on the upstream Handoff Manifest (the C6 cascade rule). An
out-of-scope target **descends to Tier 1** (approval-gated) — it does not silently
auto-write. This reuses the existing Chained Invocation Contract `cascade_scope` check
(step 4); no new mechanism.

**Evidence-gate refusal.** The Evidence Gate Enforcement extends to lifecycle writes: a
transition into a terminal/closed state (`resolved`, `closed`, `accepted`, `superseded`,
`held`, `cancelled`, `archived`) requires evidence in the same way a CLOSE action does
today. No qualifying evidence → the transition is **rejected** with a specific gap
statement (e.g. `Transition rejected for DEC-014: RAIDItem→resolved requires closure
evidence — none supplied`), surfaced in the change summary. This composes with the
existing Step-1.5 RAID dedup, the Step-2.5 cascade guard, and the Step-5 lifecycle-state
precondition (file-liveness) — all four run together; none is bypassed.

**Autonomy Tier (explicit per write).**
- **Autonomy Tier 1** — RAID-Log and Decision-of-record writes (Document Tier 1 targets;
  approval-gated).
- **Autonomy Tier 2** — scoped tracker-row writes inside `cascade_scope` (auto-write).
- **Never Autonomy Tier 0** — no governance file is a lifecycle-write target.

## Domain-B Frontmatter Maintenance

This is the **file-level write complement** to the Step-5 Lifecycle-State Precondition (which
*reads* the target file's liveness). Where that precondition reads one field, this section
*writes and refreshes* the tracker's whole **Domain-B (Managed Knowledge)** frontmatter block on
the tracker-write path — plus the per-entry reverse provenance link and the stable namespaced
ids that the raw→tracked bridge resolves against. Operational trackers are Domain-B "Living
Documents" (`core/schemas/frontmatter-schema.md` § Category 2 lifecycle-pattern mapping), so the
block is *maintained continuously on write*, never baselined.

### File-level Domain-B block (refresh on every write)

On every write to a tracker, Tracker Manager writes/refreshes the target file's Domain-B block:

```yaml
type: tracker
managed_by: tracker-manager
domain: managed              # the LIVE value — NOT "B" (frontmatter-schema.md § Category 2
                             #   deprecates the A/B/C aliases; writers emit the human-readable form)
lifecycle_state: current     # created → current on first evidence; current → needs-review past
                             #   staleness_threshold_days (per the Domain-B lifecycle enum)
trust_category: controlled-truth
last_evidence_date: <newest evidence date incorporated in this write>
entry_count: <recomputed count of active entries>
staleness_threshold_days: 14 # default per frontmatter-schema.md § Category 2
```

- **Volatile vs. identity fields.** `last_evidence_date`, `entry_count`, and `lifecycle_state`
  are **recomputed/refreshed on every write**; the identity fields (`type`, `managed_by`,
  `domain`, `trust_category`, `staleness_threshold_days`, plus the birth-stamped `file_format` /
  `project` / `folder` / `created_date` that `project-initiator` writes into the born block) are
  **written-if-absent and never churned** — so a re-write is a no-op on the static fields
  (idempotent) and the full born field set is preserved verbatim, never stripped.
- **Carrier by container.** A `.md` tracker carries the block **inline** as YAML frontmatter; a
  `.csv` RAID artifact carries **no** YAML line, so its Domain-B block lives in the co-located
  **`.meta.yml` sidecar** (the same sidecar `project-initiator` co-scaffolds at birth) — read/write
  the sidecar, never inject YAML into the CSV.
- **Born → maintained evolution (the scaffold seam).** This block is the *maintained* complement
  of the *born* block that `project-initiator` stamps on the starter tracker templates. The field
  names and the `domain: managed` vocabulary are **identical** on both sides; the only expected
  divergence is *value*, not *field* — the born template ships `lifecycle_state: created` +
  `entry_count: 0`, and Tracker Manager transitions those to `current` + the live count on the
  first write. This is a coherent born→maintained progression, not a schema conflict.
- Reversibility **CHEAP** · confidence **HIGH** (an over-written frontmatter field is reverted by
  editing the block back; no downstream commitment).

### Entry provenance — the reverse back-link (raw → tracked)

Each **extracted** tracker entry (a decision, action, risk, or meeting derived from raw evidence)
carries a reverse provenance back-link to the raw artifact it came from. Two carriers, scoped by
the entry's container (do **not** unify the names — the split preserves the frozen RAID CSV
dialect):

- **Markdown-tracker entries** (Daily Status Log `DEC-###` / `ACT-###`, Meeting `MTG-###`, and any
  extracted markdown entry) → the **`source_inputs[]`** entry field (array; value domain
  `TR-###` | `MSG-###` | source-file path — identical to `frontmatter-schema.md` § Category 3
  `source_inputs`), defined in `references/tracker-schemas.md` / `core/schemas/tracker-schemas.md`
  § Raw→Tracked Provenance.
- **RAID rows** → the SHIPPED **`source_ref`** dialect column (§ RAID Log Handling above) — the
  `frontmatter-schema.md` "carrier exception" (a CSV row has no frontmatter, so its provenance is
  the dedicated field, not a `relationships[]` edge).

Both are populated on `ADD` from the upstream `TRACKER_UPDATE` `fields` map and are
**evidence-gated**: if no establishing source is recoverable, omit the back-link rather than guess
one (identical to the existing RAID `source_ref` rule).

### The raw→tracked bridge is bidirectional — and Tracker Manager writes only the tracked half

The raw→tracked relationship is **two coordinated half-edges** resolving against the entry's stable
namespaced id:

- **Forward (raw → entries):** a `relationships: [{type: GENERATES, target: <entry-id>, …}]` edge
  on the **raw artifact's** frontmatter/sidecar (the transcript / message). Per
  `frontmatter-schema.md` § Relationship Edge Population, this edge is emitted by the **upstream
  extraction/processing agent** (ppm-agent; the transcript-intake sweep) — **NOT by Tracker
  Manager**. Skill-boundary transparency: Tracker Manager is the write-side tracker engine; it does
  **not** own or write the raw artifact's frontmatter.
- **Reverse (entry → raw):** the entry's `source_inputs[]` / `source_ref` back-link (above),
  written **here**.

"Resolvable both directions" holds via the pair: *from a transcript* → read its `GENERATES`
targets → the entry ids; *from an entry* → read its `source_inputs` / `source_ref` → the `TR-###`.
`core/schemas/tracker-schemas.md` § Raw→Tracked Provenance defines this bidirectional contract in
full; this skill writes the reverse half only.

### Stable namespaced ids survive re-writes

Extracted entries carry a **stable, namespaced, never-reused id** so the bridge edges have a fixed
anchor: `DEC-###` (decisions), **`ACT-###`** (open actions — auto-incremented per tracker,
consistent with `BLK-###` / `DEC-###`), `MTG-###` (meetings), and `R-[SKILL]-###` (RAID risks, per
OPERATIONS.md RAID ID Namespacing). A refresh/re-write of a tracker **preserves every entry's id**
(the Step-5 MODIFY rule) — renumbering would orphan every inbound `GENERATES` edge and reverse
back-link. This formalizes the existing "preserving all other fields" MODIFY behavior for the id
specifically.

### Aggregation reads the tracked layer, not the raw

Because the maintained Domain-B layer is now a complete, queryable, provenance-carrying
source-of-truth (`entry_count` + `last_evidence_date` + `trust_category: controlled-truth`, with
each entry carrying its `source_inputs` / `source_ref`), status and rollup aggregations read the
**tracked layer** and cite tracker entries + their provenance — they do **not** re-scan the raw
transcripts. The canonical declaration lives in `core/schemas/tracker-schemas.md`
§ Raw→Tracked Provenance (Aggregation source-of-truth); the read-side enforcement is the
consuming rollup skills' responsibility, not Tracker Manager's write path.

## Artifact Register Row Maintenance

The **Artifact Register** (`[Project]_Artifact_Register.md`,
`core/schemas/tracker-schemas.md` § Tracker 6) is the per-project
configuration-management catalog for the **Artifact** entity. Like every tracker
in `3-Operations/`, **Tracker Manager owns its ROW writes** — this is the
same entity-maintainer ≠ tracker-row-writer split already in production for RAID
Item and Decision. The **Artifact entity** itself stays maintained by **PPM Agent**
(creates: Artifact Generator; route: File Router) per
`core/disciplines/project-entity-model.md` §6 + `entity-field-schemas.md` §5 —
**unchanged**. Tracker Manager writes the Register *rows*, not the entity. No new
mode and no second lifecycle field: Baseline Status is the Register's own CI-state
column (defined in Tracker 6), and any artifact `lifecycle_state` write remains the
canonical `lifecycle_state` source of truth named in the Lifecycle-State Field Write
section above (`core/schemas/frontmatter-schema.md` § Category 2 /
`project-entity-model.md` Axis-1) — no divergent vocabulary.

**Row writes (reuse the existing `TRACKER_UPDATE` path).** Emit/apply a Register row
write via the same Step-1 → Step-5 consolidation path as any other tracker, with
`target: [Project]_Artifact_Register.md`:
- **ADD** a row when an artifact is generated (artifact-generate event) — populate
  Artifact Name, Artifact Type, Current Version, `Baseline Status = operational`
  (default), Last Updated, Owner, Retention.
- **MODIFY** a row's `Last Updated` / `Current Version` / `Baseline Status` when the
  artifact (or its baseline state) changes.

These are **Document Tier 2 / Autonomy Tier 2** writes — auto-write within
`cascade_scope` (the Register is a Tier-2 operational tracker; no approval gate),
identical to the Tier-2 contract in the Lifecycle-State Field Write section above.
The Step-5 **Lifecycle-State Precondition** still runs first: if the target Register's
`lifecycle_state` is `archived`/`superseded`, **BLOCK + flag** exactly as for any
other tracker — the Register row write never bypasses that guard.

**Baseline-at-phase-gate flip trigger (the update trigger).** Baseline Status follows
the Baseline Rules in Tracker 6:
- **Default** `operational` on every new row.
- **Flip to `baselined-at-phase-gate`** at a **phase-gate moment** — PRINCE2
  configuration-management baselining. The platform already models phase-gate cadence
  (`tracker-schemas.md` Methodology Variation table: Waterfall → `phase-gate-log.md`;
  PRINCE2 → `stage-boundary.md`). When a phase gate is reached, Tracker Manager flips
  the in-scope artifacts' Baseline Status to `baselined-at-phase-gate` and pins
  `Last Updated` to the gate date. This is a **Tier-2 row MODIFY** (auto-write within
  `cascade_scope`), **not** a Tier-1 approval gate — the artifact's *content* is not
  changing, only the CI baseline marker.
- **Flip to `superseded`** when a newer version supersedes the artifact — the prior
  row's Baseline Status → `superseded`, **append-only** (never delete the superseded
  row; it is the CI history the `projects/` gitignore otherwise loses).

## Estimate/Actual Pair Row Maintenance

The **Sprint Tracker** (`[Project]_Sprint_Tracker.md`,
`core/schemas/tracker-schemas.md` § Tracker 10) is the per-project iteration
tracker and the capture surface for the estimate/actual pairs feeding the
estimation-calibration loop. **Read that section for the required-field set** of
its four calibration-path sections — `## Sprint History`, `## Estimate-Actual
Pairs`, `## Capture Exceptions`, and the § Cumulative Elapsed rule. The
calculation half (the ratio, the bias/spread pair, the band, the window floor) is
owned by `estimation-standards.md` § 8 and is **not** computed here: Tracker
Manager writes rows, never derived figures.

Like every tracker in `3-Operations/`, **Tracker Manager owns its ROW writes**.
There are **two emitters at two gates**, per `estimation-standards.md` § 8.5's
two-write contract: **Delivery Engine Mode C** emits the `ADD` at the **LG-4 DoR
exit PASS** (item admission — the write that *creates* the row), and **Delivery
Engine Mode F** emits the `MODIFY` at the **LG-5 Dev Complete (DoD) exit verdict**
plus the end-of-sprint review (the write that *completes* it); this skill
validates and writes both. These are **Document Tier 2 / Autonomy Tier 2**
writes — auto-write within `cascade_scope`, no approval gate — and the Step-5
**Lifecycle-State Precondition** still runs first: an `archived`/`superseded`
target is **BLOCK + flag** exactly as for any other tracker.

Seven write rules are specific to this tracker, each failing closed:

- **The `ADD` precedes the `MODIFY`, and its absence is reported, not absorbed.**
  A close `MODIFY` whose `entry_id` resolves to no existing row is a Step-1
  validation failure (`entry_id` must exist) — **surface it as a missing
  admission**, naming the `Item Ref` and `Signal Family`, and do **not**
  manufacture the row from the close instruction. Synthesizing the missing half
  would invent an `Estimate` nobody committed to and drive the ratio toward 1.00
  by construction.
- **Exactly one record per close.** Every LG-5 exit PASS lands **either** one
  `## Estimate-Actual Pairs` row **per admitted signal family** **or** a
  `## Capture Exceptions` row for the family that has none. Zero rows for an
  admitted family, and two rows in the same family at the same `Close Ordinal`,
  are both defects to surface — a silent no-capture is never a valid outcome.
- **`Estimate` is frozen at `ADD`.** The close is a `MODIFY` whose `fields:` map
  carries `Actual` and `Actual Date` only (plus the recomputed `Elapsed` on F2).
  **Reject a close instruction that carries `Estimate`**, and never render the
  `Estimate` column in a re-score elicitation — the re-score is blind by protocol.
- **`Start Date` is write-once on EVERY path — the rule binds to the field, not
  to the action.** It is writable **only** on the admitting `ADD` at
  `Close Ordinal` 1. **Reject any later instruction that carries `Start Date`** —
  `MODIFY`, `CLOSE`, or `REACTIVATE`, in any family, at any ordinal, for any
  stated reason **including a corrective edit**. Binding this to `REACTIVATE`
  alone leaves the plain corrective `MODIFY` — a required operation, used to set
  `Excluded Reason` — free to move it.
- **The `Start Date` checks that bind are the ones that are not row-relative.**
  `Elapsed` is **recomputed here** from the **stored** `Start Date` and the row's
  `Actual Date` — never accepted as an asserted value — and on an `F2` row the
  emitter's `Actual` is checked against that recomputation. Then validate every
  row's `Start Date` against the **LG-4 DoR exit-PASS date of record in the gate
  verdict**, an anchor outside this tracker. The within-item checks (`Elapsed`
  non-decreasing in `Close Ordinal` across `F2` rows; one `Start Date` per
  `Item Ref` across all families) still run, but **a shift applied uniformly to
  every ordinal satisfies both of them** while shrinking every elapsed figure —
  only the external anchor catches that. Any mismatch is a validation failure:
  surface it; do not silently accept it and do not drop the row.
- **A genuine `Start Date` correction is an exclusion, not an edit.** Set
  `Excluded Reason: start-date-corrected` on every row of that `Item Ref` in
  every family and require a fresh admission `ADD` at the next ordinal with the
  corrected date. Never apply the correction in place.
- **`REACTIVATE` supersedes, never overwrites.** Set the prior row's
  `Excluded Reason` and write a new row at `Close Ordinal` *n+1*. Excluded rows
  are **append-only** — never deleted (the same posture as the Tracker 6
  `superseded` rule); deleting one destroys the rework signal.

## Tracker Schemas

Read `references/tracker-schemas.md` for the complete schema definitions of all tracked
artifacts. Key trackers:

### Daily Status Log
- File: `[Project]_Daily_Status_Log.md`
- Sections: Active Blockers (BLK-###), Decisions Pending (DEC-###), Open Actions by Person,
  Deferred Items, Retest Queue, Recently Closed
- **Closure rule (Evidence Gate):** Items only leave carry-forward with evidence — transcript
  confirmation, Jira status change, or person confirmation. No evidence = stays active.

### Communications Tracker
- File: `[Project]_Communications_Tracker.md`
- Entries: MSG-### with lifecycle (ACTIVE → CORE → ARCHIVE)
- **Lifecycle rules:** ACTIVE→CORE when response received + no further action + parent open.
  CORE→ARCHIVE when parent closed + 5 days. Some items never archive (escalation chains,
  decision-changing comms).

### Open Meetings Tracker
- File: `[Project]_Open_Meetings_Tracker.md`
- Entries: MTG-### with status (NEEDS SCHEDULING → SCHEDULED → COMPLETED → CANCELLED)
- Sections: Upcoming, Recently Completed (5 business days), Recurring Cadences

### Transcript Register
- File: `[Project]_Transcript_Register.md`
- Entries: TR-### with date, meeting type, project, participants, tags, 3-sentence summary, file path
- **Auto-write:** Register entries are added when the File Router processes a transcript.
  The register entry itself is auto-written; but any carry-forward tracker updates triggered
  by the transcript content still require approval.

### RAID Log
- File: `[Project]_RAID_Log.csv`
- Schema: 15-column CSV with RAID_ID, RAID Category, Description, Impact, Owner, Priority, Status, Action Plan, Due Date, Date Opened, Date Closed, Closure Comments, Tags, source_ref, Section
- Entries: RAID_ID namespaced per skill (R-PPM-###, R-DE-###, R-CM-###, R-TA-###, R-PD-###)
- `source_ref` (structured provenance back-link): which transcript / message / artifact **established** this RAID row — value domain `TR-###` | `MSG-###` | an artifact `id`-slug | a source-file path (the same token set as `source_inputs` in `frontmatter-schema.md` Category 3). This replaces stuffing provenance into the free-text `Tags` column and makes RAID provenance queryable (it joins to the establishing source node by that token domain). It is a schema **dialect** field (see [`raid-log.schema.json`](../../../core/schemas/raid-log.schema.json) `source_ref`), NOT an entity-projected column — the RAID Item entity surface is frozen. Optional: a row whose establishing source is not recoverable carries **no** `source_ref` rather than a guessed one.

### RAID Log Handling

The RAID Log uses an active/archive CSV structure. When processing RAID Log updates:

1. **Closing an entry:** Set Status = Closed, populate Date_Closed with today's date, require Closure_Comments, change Section from ACTIVE to ARCHIVE. Move the row to the ARCHIVE section of the CSV (after all ACTIVE rows).
2. **Adding an entry:** Assign RAID_ID using the originating skill's prefix per OPERATIONS.md RAID ID Namespacing. Set Date_Opened = today. Set Section = ACTIVE. **Populate `source_ref`** from the originating artifact's provenance token — the value ppm-agent (the RAID creator) supplies in its `TRACKER_UPDATE` `fields:` map (a `TR-###` / `MSG-###` / artifact `id`-slug / source-file path). If ppm-agent supplies no recoverable establishing source, leave `source_ref` empty (do NOT guess a back-link) and do NOT stuff it into `Tags`.
3. **Querying active items:** Filter on Section = ACTIVE. Never include ARCHIVE items in active co

…(truncated)
