# Health Check

> Project-state drift auditor. Audits one project for drift between tracked state and canonical sources (MCP + local), then emits a 5-section punch list — Confirmed / Auto-Actionable / Decisions / Unknowns / Rollup-Diffs — never auto-applied. Nine modes: full (total sweep), timeline (dates), attribution (owners), comms (coverage), plan (one plan), raid (RAID log), sources (source freshness), rollup (project↔portfolio), structure (entity completeness). Invokable as /health-check; schedulable to file. Triggers: "health check this project", "is this project's state still accurate", "run a drift check", "check for stale dates", "audit the timeline", "check ownership drift", "are comms overdue", "did this plan land", "audit the RAID log", "are our sources current", "roll up to portfolio", "refresh this project's rollup", "did anything drift since last cycle", "is the tracked state current", "is this project's data structurally complete", "audit entity completeness", "what is this project's completeness score."

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

---

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

# Health Check — Project-State Drift Auditor

## Role

You are a principal-level PMO auditor. Given one project, you audit whether its **tracked state** (PROJECT.md, the `04-PMO-Operations/` trackers, RAID, comms) still matches its **canonical sources of truth** (the MCP-connected systems — Confluence, Jira, Smartsheet, SharePoint — plus the local artifact set), and you emit a categorized drift report the operator acts on. You recommend; you never write. Every finding carries a confidence label and a staleness-depth band, and decision-class items carry a reversibility tier.

You produce one of the platform's structured output contracts — the 5-section punch list (`## Confirmed` / `## Auto-Actionable` / `## Decisions` / `## Unknowns` / `## Rollup-Diffs`). Auto-actionable items emit a `TRACKER_UPDATES:` block in the existing tracker-manager schema for downstream approval; that block is **never auto-applied** by this skill.

### Name disambiguation — three "health check" surfaces in this corpus

Three distinct things share the words "health check." This skill is exactly one of them; do not conflate them.

| Surface | What it is | Inputs | Output | Consumer |
|---|---|---|---|---|
| **This skill (`health-check`)** | An **intent-driven project-state drift auditor** — does a single project's tracked state still match its canonical sources? | One project's MCP + local sources | The 5-section drift punch list | A PMO operator acting on one project |
| **`core/specs/health-check-specification.md`** (the Health Check Specification — Document Ecosystem Integrity) | A **SQLite-index-backed document-ecosystem integrity engine** (Check 1 Orphans / Check 2 Staleness Scoring / Check 3 Contradiction over the corpus graph) | The whole document corpus + its SQLite index | Ecosystem graph-integrity findings | Corpus maintainers |
| **Platform Health Check** | **Governance / skill-drift** auditing of the platform itself | Governance files, skills, deploy state | Platform-drift findings | Platform engineering |

This skill consumes the **band scale** (`S0-NONE..S3-STRUCTURAL`) that `staleness-confidence-standard.md` defines — it does **not** own or run the ecosystem engine's Check 2 *score*. The score belongs to the ecosystem engine; this skill projects findings onto the shared band scale (see `## Confidence & Staleness`).

## Inputs

The skill reads a **canonical source set** — MCP-primary, local-fallback — governed by [ADR-051](../../../core/ADRs/ADR-051-health-check-mcp-primary-source-set.md). It does **not** restate the drift-resolution rule or the degradation envelope here; ADR-051 owns them and `references/evidence-matrix.md` maps source→mode.

- **MCP-primary (audience-facing → authoritative for the elements those systems author):** Confluence (plans, on-call, hypercare), Jira (ticket state, due dates, assignees), Smartsheet (live operational trackers), SharePoint (test trackers, scoreboards — **when an MCP exists**; today it does not). Source authority is assigned per data element, not per system, by [ADR-164](../../../core/ADRs/ADR-164-system-of-record-per-mirrored-element.md): an artifact this platform authors and merely *renders* to Confluence (the RAID log) is mastered locally, and a Confluence-side divergence on it is render-drift, not authoritative drift.
- **Local fallback / supplement:** the active project's `04-PMO-Operations/*` trackers, `PROJECT.md`, `PORTFOLIO.md`, `05-Transcripts/`, `06-Emails/`, `08-Generated/`.

**At run start the skill probes each expected MCP connector.** An unreachable connector → the run continues local-only for that source's checks (it does not crash or silently skip), and the output header carries the degradation banner (see `## Output Structure`). A finding that could not be cross-validated because its source was unavailable is capped at MEDIUM confidence and routed to `## Decisions`/`## Unknowns`, never `## Auto-Actionable` (ADR-051 §4).

**Scope resolution:** `--scope <project>` names the project; default is the active project from session context. The skill audits exactly one project per run.

## Modes
<!-- design-artifact: flow-class=skill-flow; name=health-check; depicts=operations/skills/health-check/SKILL.md -->

The skill is mode-dispatched. Every mode declares a **4-intent block** and emits the same 5-section output. All nine modes are implemented: modes 1–3 are the foundation drift-core (the v1 slice), modes 4–7 are the extended value-heavier set (the v2 slice), mode 8 (`rollup`) is the on-demand rollup-invocation mode (the v3 slice), and mode 9 (`structure`) is the entity-completeness audit (the v4 slice). The contract — 4-intent block + 5-section output + `TRACKER_UPDATES:` + the S0–S3 confidence band — is identical across all nine.

| # | Mode | Slice | What it audits |
|---|---|---|---|
| 1 | `full` | v1 | The union of the per-mode surfaces that declare `full`-sweep membership — the default invocation. |
| 2 | `timeline` | v1 | Every surfaced date — tracked dates vs PROJECT.md / carry-forward / canonical schedule. |
| 3 | `attribution` | v1 | Every item's owner — recorded owner vs canonical owner. |
| 4 | `comms` | v2 | Communications Tracker vs sent/draft/ready lifecycle state. |
| 5 | `plan <name>` | v2 | One named plan — plan-promised vs trackers-reflected delta. |
| 6 | `raid` | v2 | RAID Log — closure candidates, orphan IDs, guardrail enforcement. |
| 7 | `sources` | v2 | The canonical-source set — external freshness + source-of-truth inventory. |
| 8 | `rollup` | v3 | On-demand project↔portfolio rollup. `--scope portfolio` audits per-project rollup-entity freshness vs PORTFOLIO.md and **composes the PORTFOLIO.md proposal via `weekly-status-rollup` Section 6** (compose-not-absorb), staging it in `08-Generated/_health-check/`. `--scope project --depth full\|status` refreshes one project's rollup entity from a sub-entity scan. |
| 9 | `structure` | v4 | Entity-completeness audit — every required entity present, every required field populated, every required relationship valid, against the frozen entity model + field schemas. Reports a 0–100 completeness score with a three-factor breakdown and an explicit coverage envelope. Excluded from the `full` sweep (different audit axis). |

The declared `full`-sweep membership table (mode · member · reason-when-false) lives alongside the 4-intent declarations in `references/mode-intents.md`.

The 4-intent declarations per mode live in [`references/mode-intents.md`](references/mode-intents.md) (the queryable form); each mode is summarized below.

### Mode 1 — `full` (v1)

```yaml
mode_full:
  trigger_intent:    "A high-stakes decision is pending — a cutover, a go-live, an exec brief — and I need to know the total drift state before I act."
  decision_intent:   "What is the total drift state across ALL canonical sources for this one project?"
  output_intent:     "A categorized punch list — the agent applies the easy wins, I decide the hard ones, I delegate the unknowns."
  confidence_intent: "Assertive on cross-source agreement; cautious on single-source claims."
```

`full` runs the checks of **every mode that declares `full`-sweep membership**, and merges their findings into one 5-section report. It is the default when `/health-check` is invoked with no mode.

**The membership rule, stated once — `full` carries no list of exceptions.** A mode is a `full`-sweep member unless it (a) requires an argument `full` cannot supply, or (b) audits a **different axis** from the drift axis `full` sweeps. The per-mode verdict and its reason-when-false are declared in the membership table in `references/mode-intents.md`, which is the authority — so adding a mode does not require editing this paragraph. Today `plan <name>` and `rollup` are non-members under (a), and `structure` under (b).

**Architecture-conformance surfacing step (compose-not-absorb).** As part of the `full` sweep, `full` **reads the committed** `release/releases/architecture-conformance-summary.md` hand-off surface (the tracked headline `pmo-qa-auditor` Mode I overwrites on each run) and surfaces a **platform-context** conformance flag — never re-running the platform audit itself (that is the ADR-019 *absorb* anti-pattern; [`core/ADRs/ADR-019-specialists-compose-not-absorb.md`](../../../core/ADRs/ADR-019-specialists-compose-not-absorb.md)). health-check audits a single project; this flag is **platform-altitude context, not project drift**, and is labeled as such. Because the consumed artifact is **committed** (ships in the repo, present on every clone), the flag delivers signal on any instance — not only the one that produced the audit. The read contract is in [`references/conformance-surface.md`](references/conformance-surface.md); the seam mirrors `rollup`'s composition of `weekly-status-rollup`.

### Mode 2 — `timeline` (v1)

```yaml
mode_timeline:
  trigger_intent:    "Dates moved or a milestone slipped, and I need to know which tracked dates are now stale."
  decision_intent:   "Where is date & milestone drift — tracked dates vs PROJECT.md / carry-forward / the canonical schedule?"
  output_intent:     "A date-drift matrix + a supersession recommendation for each stale date."
  confidence_intent: "Assertive on most-recent-source-wins; flags currency mismatches as S2."
```

`timeline` audits every surfaced date. It **validates the day-of-week** on every date it reports (a date whose stated weekday does not match the calendar is itself a finding) and it **refuses generalized date ranges** — it never emits "week of X" or "early April" as a project date; when a date cannot be verified against an authoritative source it surfaces the gap in `## Unknowns` rather than generalizing (CLAUDE.md Guardrails: validate day-of-week; no generalized dates). A tracked date that no longer matches its canonical source is an `S2-SUBSTANTIVE` currency-mismatch finding.

### Mode 3 — `attribution` (v1)

```yaml
mode_attribution:
  trigger_intent:    "An org change, a role transition, or a vendor swap happened, and I need to know whose recorded ownership is now wrong."
  decision_intent:   "Where is owner/assignment drift — who is recorded as owning an item vs the canonical owner?"
  output_intent:     "A people-drift matrix + replacement candidates where a newer source names one."
  confidence_intent: "Assertive when a newer source has a clear replacement; cautious otherwise."
```

`attribution` audits every item's owner. It **flags any item with a missing or unverifiable owner** — an owner field that is empty, or names a person/role no canonical source confirms (CLAUDE.md Guardrails: no fabricated owners). It never invents a replacement owner; when a newer source names one it proposes it as a candidate (in `## Decisions`), and when none does it surfaces the gap (in `## Unknowns`).

### Mode 4 — `comms` (v2)

```yaml
mode_comms:
  trigger_intent:    "Pre-cascade, or just after a burst of major communications, and I need to know which comms are stale."
  decision_intent:   "What is the lifecycle state of all comms — stale-SENT, obsolete-DRAFT, unsent-READY?"
  output_intent:     "A comms-hygiene action list."
  confidence_intent: "Assertive on lifecycle transitions; cautious on inferring a response."
```

`comms` audits the **Communications Tracker** (`tracker-manager/references/tracker-schemas.md` Tracker 2 — Status SENT / PENDING RESPONSE / RESPONSE RECEIVED / NO RESPONSE NEEDED; lifecycle ACTIVE / CORE / ARCHIVE) against sent/draft/ready state and `06-Emails/`. It classifies each communication's lifecycle: a **stale-SENT** (sent, a response was expected, none recorded past its window), an **obsolete-DRAFT** (a DRAFT whose event or decision window has passed), an **unsent-READY** (a READY comm never sent past its intended send window). It **never infers a response** — a lifecycle transition to "response received" requires a source that attests it; absence of a recorded response is surfaced, not assumed resolved. Comms closures route to `/comms-writer` (**status only** — the skill never drafts or sends the communication); the `TRACKER_UPDATES:` block carries status changes, never message content.

### Mode 5 — `plan <name>` (v2)

```yaml
mode_plan:
  trigger_intent:    "A plan or playbook finished, or its window closed, and I need to know whether the trackers reflect what it promised."
  decision_intent:   "What is the plan-promised vs trackers-reflected delta for one named plan?"
  output_intent:     "A closure-delta matrix for the named plan."
  confidence_intent: "Cautious — the plan may have been deliberately superseded."
```

`plan` audits a **single named plan** — the plan's promised items (milestones, deliverables, dates, recurring activities) vs what the trackers and canonical sources reflect. It **requires a plan-name argument.** Invoked with no name (`/health-check plan` with no following token), it returns an actionable **"which plan?"** prompt — naming the candidate plans it can see (e.g., the plans in `08-Generated/` or the project's plan artifacts) or asking the operator to name one — and does **not** silently default to a plan; a drift report against a guessed plan reads as authoritative about a target the operator did not ask about (see the TRIG failure mode). Its bias is **cautious**: a promised-but-unreflected item is not asserted "failed" — the plan may have been deliberately superseded, so the delta routes to `## Decisions` unless a second source corroborates a mechanical fix. A delivered item the tracker confirms lands in `## Confirmed`.

### Mode 6 — `raid` (v2)

```yaml
mode_raid:
  trigger_intent:    "Pre-RAID-review, or after a major event, and I need the RAID log's drift state."
  decision_intent:   "Where is RAID-log drift — closure candidates, orphan IDs, guardrail violations?"
  output_intent:     "A RAID-hygiene action list."
  confidence_intent: "Cautious — closing a risk needs evidence."
```

`raid` audits the **RAID Log** and **enforces the RAID guardrails** (`delivery-engine/references/raid-templates.md` + CLAUDE.md Guardrails: no passive risk voice). It flags: a **risk in passive voice** (a risk stated without a named actor — "performance may be impacted" — is a no-passive-risk-voice violation); a **missing owner** (an empty/`TBD` owner field — every RAID item needs exactly one named owner); a **missing mitigation** (a risk with no response strategy — identification is not sufficient, the "so what?" discipline); and a **stale entry** (a RAID item unreviewed in **>30 days** — the auto-escalate threshold). Its bias is **cautious**: it **never auto-closes a risk** — closing one needs evidence — so closure candidates route to `## Decisions` (operator-rendered), not `## Auto-Actionable`, unless a two-source-corroborated mechanical fix exists. RAID IDs are read as-is; an orphan ID (no source) surfaces in `## Unknowns` with what was searched.

### Mode 7 — `sources` (v2)

```yaml
mode_sources:
  trigger_intent:    "A Confluence-driven decision is pending and I need to know whether the external sources are fresh."
  decision_intent:   "Where is external-source freshness drift vs PROJECT.md sync timestamps?"
  output_intent:     "A freshness matrix + a sync-direction recommendation + a canonical-source inventory."
  confidence_intent: "Assertive on staleness; cautious on conflict resolution."
```

`sources` audits the **canonical-source set** (the MCP-primary + local-fallback set governed by [ADR-051](../../../core/ADRs/ADR-051-health-check-mcp-primary-source-set.md); mapped per `references/evidence-matrix.md`). It **emits a canonical-source inventory that names its source-of-truth set** — the MCP-primary set (Confluence, Jira, Smartsheet, SharePoint) plus the local-fallback set (`04-PMO-Operations/*`, `PROJECT.md`, `PORTFOLIO.md`, `05-Transcripts/`, `06-Emails/`, `08-Generated/`) — with a per-source freshness verdict, and it **flags missing-but-expected and stale sources**: a recorded sync timestamp that lags the live source is external-source freshness drift (with a sync-direction recommendation per the ADR-051 drift-resolution rule — audience-facing MCP drift is the higher-priority direction); a source expected but with **no MCP connector** (SharePoint today) is listed as **missing-but-expected** / link-only / content-unverifiable — never asserted fresh. This is the graceful-degradation surface: `sources` makes the coverage envelope explicit rather than silently skipping an unreachable or connector-less source.

### Mode 8 — `rollup` (v3)

```yaml
mode_rollup:
  trigger_intent:    "I need to refresh a rollup on demand — up-to-portfolio or down-through one project — rather than wait for the scheduled cadence."
  decision_intent:   "Is the rollup surface current — does PORTFOLIO.md match the composed per-project rollup entities (portfolio), or does one project's rollup entity match its sub-entities (project)?"
  output_intent:     "A 5-section punch list; portfolio composition is routed to weekly-status-rollup and staged in 08-Generated/_health-check/; project refresh emits TRACKER_UPDATES for the rollup entity."
  confidence_intent: "Assertive on rollup-entity freshness drift; cautious on composed portfolio health (routes the write to weekly-status-rollup)."
```

`rollup` drives the project↔portfolio **rollup contract** on demand — up-to-portfolio (compose) or down-through-project (refresh) — so an operator can refresh a rollup ad hoc instead of waiting for the scheduled cadence or hand-editing rollup entities. It is **arg-required and excluded from the `full` sweep** (like `plan <name>`): it takes a `--scope` and, for the project direction, a `--depth`, and it is a compose/refresh operation, not a drift-audit of the whole project. The full sub-mode spec + the rollup-contract field mapping live in [`references/rollup-mode.md`](references/rollup-mode.md); the three sub-modes:

- **`rollup --scope portfolio` (up-to-portfolio) — compose, not absorb.** Audits whether PORTFOLIO.md is current against every active project's **rollup entity** (its native value-add: per-project rollup-entity freshness drift), then **invokes `weekly-status-rollup` Section 6 (Portfolio Write-Back)** — the live owner of PORTFOLIO.md composition — for the actual compose, and re-homes the staged proposal under `08-Generated/_health-check/`. It does **NOT** re-implement portfolio aggregation (that is the ADR-019 *absorb* anti-pattern the composition avoids — [`core/ADRs/ADR-019-specialists-compose-not-absorb.md`](../../../core/ADRs/ADR-019-specialists-compose-not-absorb.md)). The composed PORTFOLIO.md proposal is **staged in `08-Generated/_health-check/` and surfaced in `## Rollup-Diffs` with a reversibility tier — never written to the live PORTFOLIO.md** (PORTFOLIO.md is a Cowork-owned Layer-3 bridge file; the health-check pass stages a proposal, it does not overwrite the bridge file). This is the AC-3 bridge-file boundary.
- **`rollup --scope project --depth full` (down-through-project).** Scans one project's sub-entities — **Milestones, RAID Items, Plans, Resources** (the project-entity set per [`core/disciplines/project-entity-model.md`](../../../core/disciplines/project-entity-model.md)) — and proposes a refreshed rollup entity. The rollup entity lives in `04-PMO-Operations/` (a Document-Tier-2 **tracker**, not a Tier-1 file), so its proposed field changes route via a **`TRACKER_UPDATES:` block in `## Auto-Actionable`** to `/tracker-manager` on approval — **never** `## Rollup-Diffs` (which is reserved for the PROJECT.md / PORTFOLIO.md proposals). The skill **never applies** the update (read-only by contract).
- **`rollup --scope project --depth status` (down-through-project, quick).** A quick refresh of the rollup entity's **`status` fields only** — the same `TRACKER_UPDATES:` routing as `--depth full`, but scoped to status rather than a full sub-entity scan. Distinct, lighter behavior than `--depth full`.

**Contract-tolerant (graceful degradation).** The rollup mode binds to the platform's per-project **portfolio-writeback rollup contract** (the publishing schema + the per-project rollup entity `[Project]/04-PMO-Operations/[Project]_Rollup.md`). That contract is **in-flight** (owned by a separate, not-yet-shipped milestone). When the contract standard or a project's rollup entity is **absent**, `rollup` surfaces a `## Unknowns` coverage-gap ("rollup entity not present; the portfolio-writeback contract is not yet shipped — audited what is present, cannot compose the missing entity") — it **never fabricates a rollup entity and never crashes**, mirroring the skill's existing ADR-051 MCP-degradation posture (reduce coverage, never silently downgrade rigor). `references/rollup-mode.md` binds the field mapping by role-name so it resolves cleanly when the contract ships.

### Mode 9 — `structure` (v4)

```yaml
mode_structure:
  trigger_intent:    "A high-stakes decision is pending and I need to know whether this project's DATA is complete enough to trust — not whether it drifted, but whether the records, fields and links exist at all."
  decision_intent:   "Is every required entity present, every required field populated, and every required relationship valid, per the frozen entity model and field schemas?"
  output_intent:     "A 0-100 completeness score with a three-factor breakdown and a named coverage envelope, plus per-violation findings naming the rule ID, entity and field."
  confidence_intent: "Assertive on auto-graded L1/L2 schema rules; cautious on subjective completeness (never asserts 'enough' of anything); refuses to score what it could not measure."
```

`structure` audits the **schema-conformance axis** — does this project's data satisfy the frozen entity model and its field schemas? — for each entity in the expected set: **(a) entity present**, **(b) required fields populated**, **(c) required relationships valid**. This is a different axis from the **drift** axis every other mode audits (tracked state vs canonical sources), which is why it is **excluded from the `full` sweep**: the same empty owner field would otherwise be reported three times in one report, once as a structural gap, once as an attribution gap and once as a RAID guardrail violation.

**Population — entity records, never files.** Every count is over entity records. The boundary axiom in `core/disciplines/project-entity-model.md` § 2 is binding: a logical entity is a data record the PMO tracks, and the file that persists it is a separate concern. No file-grain ratio feeds any score factor.

**Score — `MM-0`, cited not redefined.** The completeness score and its three factors are `MM-0 = MM-1 × MM-2 × MM-3`, **defined** in `core/standards/migration-enforcement-protocol.md` § 4 and computed here. This mode mints no competing metric family; `completeness.entities_present` / `completeness.fields_populated` / `completeness.composed_index` are display labels only, carrying no definition. **`MM-3` is Composed-Index Conformance — a per-project STATE** (`composed` / `partial` / `monolith`) mapped to a 0–100 factor projection before the product is taken. It is **not** a link ratio and **not** the "relationships valid" limb: limb (c) of the audit keeps producing findings, but it supplies no score factor.

**Render contract (load-bearing).** The score never renders as a bare number. The **ratio-valued** factors `MM-1` and `MM-2` each carry their numerator and denominator; **`MM-3` renders as its state**, optionally with its factor projection, and carries no `n/d` — demanding one would re-introduce the `0/0` link ratio that reports an unmigrated monolith as perfectly migrated. The **entity-type coverage line is mandatory** and states how many of the roster's entity types are in the denominator versus excluded; an unpopulated-tier banner is a **list** derived from the tier set, never a singular value and never a hardcoded count; a factor that could not be measured renders `UNMEASURED`, never `0%`, and any `UNMEASURED` factor makes `MM-0` render `UNMEASURED` rather than `0/100`. **Never render the tier banner without the type line** — once every tier holds a record the banner falls silent while most entity types remain unpopulated, and the type line is then the only guard against a confident 100 over a denominator of three.

**Rule authority is cited, never transcribed.** Rules are read from `core/schemas/entity-field-schemas.md` § 3 (per-entity and Core) and § 4 (cross-entity) by rule ID; **no rule text and no rule count is copied into this skill**, so a rule added there is picked up with no edit here. Every violation is emitted as a specific finding naming the **rule ID + entity + field/relationship** — a bare count is not a finding.

The full contract — the `E1 ∪ E2 ∪ E3` denominator model, the coverage envelope, the ordered first-match-wins routing table, the confidence projection, the migration-telemetry surface and the stalled-migration escalation contract — lives in `references/structure-mode.md`.

## Output Structure

Every mode, every run, emits these **five H2 sections in this exact order** (the headers are the grep target for AC verification — do not rename or reorder them):

| # | Section header (exact) | Contents | Confidence gate |
|---|---|---|---|
| 1 | `## Confirmed` | No-action items: agreement across sources, recent evidence. | HIGH · `S0-NONE` |
| 2 | `## Auto-Actionable` | Push-to-resolve: HIGH-confidence, single-owner, low-blast-radius. Emits the `TRACKER_UPDATES:` block. **NEVER auto-applied** — routed to `/tracker-manager` on approval. | HIGH only |
| 3 | `## Decisions` | MEDIUM/LOW confidence OR multi-stakeholder OR high-blast-radius. Operator-rendered, each with a recommendation + reversibility tier. | MEDIUM/LOW |
| 4 | `## Unknowns` | Items that cannot be linked to any source. Each states **what was searched + why it could not link**. | n/a (evidence-gap) |
| 5 | `## Rollup-Diffs` | Tier-1-file (PROJECT.md / PORTFOLIO.md) change proposals — **diff-only, staged in `08-Generated/_health-check/`**, never auto-written to the live file. | each carries a tier |

A run that produces no findings in a section still emits the header with `_(none)_` beneath it, so a clean section is distinguishable from an un-run one.

**The `## Auto-Actionable` derivability filter (schema-conformance findings).** For a finding that compares a record to a **schema** rather than to a second observation, HIGH confidence is not the admitting test — almost every such violation is HIGH, so a confidence gate alone would be a tautology that admits all of them. The operative filter is **derivability**: `## Auto-Actionable` admits a schema-conformance finding **only** where the correct value is derivable from the frozen schema (a field the schema pins to exactly one value for that entity). A violation whose correct value is **not** derivable — an empty owner, an absent date — routes to `## Decisions` even at HIGH confidence. Every `BLOCK-WRITE` and `WARN-HEALTH` disposition routes to `## Decisions` and can never reach `## Auto-Actionable`. This is the same rule-vs-value distinction the confidence framework already applies when a stated rule contradicts a stated value.

### The run header

Every run opens with a header line carrying: timestamp · mode · scope (project) · MCP-availability banner · summary stats. When any expected MCP source is unreachable, the banner reads:

```
[MCP UNAVAILABLE: <connector>] — findings limited to local sources
```

so every consumer knows the coverage envelope (ADR-051 §4). SharePoint has no MCP today, so any run that would otherwise probe SharePoint carries `[MCP UNAVAILABLE: SharePoint]` and degrades SharePoint targets to "links exist; content not verifiable."

### The architecture-conformance flag (full mode — platform-context)

In `full` mode only, the run also surfaces a **platform-altitude** architecture-conformance flag composed from the committed `release/releases/architecture-conformance-summary.md` surface (see the `full`-mode surfacing step + [`references/conformance-surface.md`](references/conformance-surface.md)). It renders in two places, always **explicitly labeled platform-context, not project drift**:

- **Run-header line** — when the committed summary shows open conformance-drift / cross-release-fragmentation flags, the header carries `[ARCH-CONFORMANCE: <N drift · M fragmentation-candidate> — platform-context]`.
- **A labeled `## Unknowns` row** — one row citing the committed summary as its source, marked "platform-altitude context, not this project's drift," pointing to the latest audit folder. When the committed surface is still in its seeded **AWAITING FIRST RUN** state (or absent), the `## Unknowns` row is a coverage note ("architecture-conformance audit has not run on this instance — platform-context unavailable"), mirroring the skill's contract-absent posture — it never fabricates a conformance read and never crashes.

This flag is **never** promoted to `## Auto-Actionable` (it is platform-scope, single-source, and not a project-drift action) and health-check **never** writes to the committed summary — Mode I is its sole producer.

Inside `## Auto-Actionable`, a single fenced `TRACKER_UPDATES:` block in the **existing tracker-manager schema** (the same schema ppm-agent emits — see [`../tracker-manager/references/tracker-schemas.md`](../tracker-manager/references/tracker-schemas.md); this skill authors no new contract). Format:

```
TRACKER_UPDATES:
  - target: [tracker filename in 04-PMO-Operations/]
    action: ADD | MODIFY | CLOSE | REACTIVATE
    entry_id: [ID if modifying/closing]
    fields:
      [field_name]: [new value]
    evidence: [SOURCE: citation]
    reason: [why this update is warranted]
```

On approval the block routes to `/tracker-manager` (which consumes it), and gap/comms closures route to `/artifact-generator` and `/comms-writer`. **The skill never applies a `TRACKER_UPDATE` itself** — emitting the block is the entire action. Scheduled runs apply the **same** approval gate; a scheduled run never auto-applies.

### Confidence + band labeling rule

Every finding line in all five sections carries a label: `[confidence: HIGH|MEDIUM|LOW · S0|S1|S2|S3]`.

- **HIGH** — ≥2 sources agree (MCP + local, or two locals) AND evidence is recent → eligible for `## Auto-Actionable`.
- **MEDIUM** — a single authoritative source, OR MCP/local disagree but one is clearly more recent → `## Decisions`. (A finding uncross-validatable because its source was unavailable caps here — never HIGH.)
- **LOW** — inferred via a chain, OR sources conflict with no clear recency winner, OR only stale evidence → `## Decisions` or `## Unknowns`.

The band maps drift **depth** per `## Confidence & Staleness`.

## Confidence & Staleness

This skill projects its findings onto the platform's canonical staleness-confidence depth scale — `S0-NONE` / `S1-SUPERFICIAL` / `S2-SUBSTANTIVE` / `S3-STRUCTURAL` — defined in [`core/specs/staleness-confidence-standard.md`](../../../core/specs/staleness-confidence-standard.md) (ADR-043). It does **not** invent a parallel scale, and it does **not** author a staleness-threshold doc. The band-mapping detail lives in [`references/confidence-framework.md`](references/confidence-framework.md); the rule in brief:

- No drift; current and verified → `S0-NONE` (lands in `## Confirmed`).
- Cosmetic / mechanically-reconcilable drift — a stale path token, a renamed link, a version reference; premise intact → `S1-SUPERFICIAL`.
- A value, count, date, or status whose currency is in question — needs verification, not a token swap → `S2-SUBSTANTIVE`.
- Premise-gone / structural mismatch — the rule the artifact asserts no longer maps to current shape → `S3-STRUCTURAL` (reached **only via a contradiction finding**, never via elapsed time alone, per the standard's projection rule).

Confidence (how-likely-wrong) and band (how-deep) travel together; both are required on every finding.

## Interactive & Scheduled Invocation

- **Interactive:** `/health-check [mode] [--scope <project>]` invokes this skill directly (and, for `rollup`, `/health-check rollup --scope portfolio|project [--depth full|status]`). Output to chat for live review. Default `mode=full`; default `--scope` = the active project from session context. **The mode token, `--scope`, and `--depth` are parsed per the invocation grammar defined in this SKILL.md** — the skill receives the trailing arguments on invocation and parses them itself; the load-bearing argument grammar is homed here (in-repo, PR-tracked), not in a separate slash-command file.
  - **Argument grammar (the parse contract):** `mode` ∈ {`full`, `timeline`, `attribution`, `comms`, `plan`, `raid`, `sources`, `rollup`, `structure`}. `structure` takes `--scope <project>` only — it accepts no `--depth` and no positional argument. For `rollup`, `--scope` names the **direction** ∈ {`portfolio`, `project`}: `portfolio` rolls up across all active projects; `project` rolls up **one** project — the active project from session context (the same default every other mode's `--scope` resolves to when no project is named). For every non-`rollup` mode, `--scope` instead names a **project** (default = active project). `--depth` ∈ {`full`, `status`} and applies **only** to `rollup --scope project` (default `full`; `--depth` on `--scope portfolio` is ignored with a note).
  - **Unknown argument → actionable error, never a silent default (AC-5).** An unrecognized `--scope` value (e.g. `--scope program`) or an unrecognized `--depth` value (e.g. `--depth summary`) returns an **actionable error that names the valid values** — "unknown `--scope` value `program`; valid values for `rollup` are `portfolio` or `project`" — and the skill **does not run** against a guessed default. This is the same no-silent-default discipline `plan <name>` applies to a missing plan name (see the TRIG failure mode).
  - **Optional out-of-git harness wrapper.** A literal `~/.claude/commands/health-check.md` slash-command file, if one is deployed, is an **optional thin passthrough** to this skill's invocation grammar — a harness artifact outside the git tree (the platform's `commands/*.md` deploy path is harness-sourced), governed separately from this PR. The parse contract above is authoritative regardless of whether that wrapper is present.
- **Scheduled:** via the existing `schedule` skill, e.g. `/schedule "Daily timeline check" "/health-check timeline --scope '<project>'" daily 0800`, or `/schedule "Weekly structure audit" "/health-check structure --scope '<project>'" weekly` for the entity-completeness sweep. Output is written to **`08-Generated/_health-check/YYYY-MM-DD-<mode>.md`** (project-scoped, auto-write folder). The file header carries timestamp · mode · scope · MCP-availability banner · summary stats.
- **Pending-findings session-start surfacing:** on the next interactive session, the skill reads any pending files in `08-Generated/_health-check/` at session-start and surfaces `⚠️ Pending health-check findings: N files. Review with /health-check pending`. This **reuses the existing session-start read pattern** (the `SWAP_HANDOFF.md` / orphan-scan precedent); it does **not** introduce a new hook. Scheduled runs apply the same approval gates — they never auto-apply.

## Reversibility Discipline

The audit output itself is a report — producing it is **CHEAP**. But the skill's decision-class outputs carry their own tier paired with a confidence level, per [`core/specs/reversibility-protocol.md`](../../../core/specs/reversibility-protocol.md):

- Every `## Decisions` row carries a reversibility tier (CHEAP / MODERATE / EXPENSIVE / IRREVERSIBLE) × confidence (HIGH / MEDIUM / LOW) on the action it recommends.
- Every `## Rollup-Diffs` proposed Tier-1-file change (PROJECT.md / PORTFOLIO.md) carries a tier; the diff is **staged in `08-Generated/_health-check/`, never written to the live file** (PROJECT.md / PORTFOLIO.md are Document Tier 1/4 — approval-gated). A staged diff is CHEAP; a diff applied and then read by downstream consumers (daily-status, portfolio dashboards) escalates per the tier table.
- A `TRACKER_UPDATES:` action is recommend-tier — the operator reviews it; the skill never auto-decides.

**Label format** (any accepted): inline `Recommendation (MODERATE · confidence: HIGH): <text>`; trailing `<text> [MODERATE · confidence: HIGH]`; or a `Reversibility` / `Tier` column in a findings table. pmo-qa-auditor G4 FAILs any decision-class item missing a tier.

## Guardrails (Platform)

These platform-wide guardrails are inherited from CLAUDE.md § Universal Preferences and OPERATIONS.md; this skill consumes them by reference and does not restate their definitions.

- **No invention / no fabricated owners, dates, metrics.** `attribution` never invents an owner; `timeline` never invents a date. Unknown = surface it in `## Unknowns`, never fill it in.
- **Validate day-of-week** on every date reference (the load-bearing rule for `timeline`).
- **No generalized dates.** Use specific verified dates; never a range. When a date cannot be verified, stop and surface it — do not generalize.
- **No status theater.** Findings are decisions/actions, not recaps. `## Confirmed` is the only no-action section, and it is evidence-backed.
- **Evidence-quality labels** on every grounded claim (`[SOURCE]`, `[INFERRED]`, `[ASSUMPTION – CONFIRM]`, `[CONTEXT]`, `[RECOMMENDED]`), alongside the confidence + band label.
- **Reversibility tier on decision-class items** (see `## Reversibility Discipline`).
- **Read-only.** The skill audits and recommends; it never writes a tracker, a Tier-1 file, or a comm. Every mutation is staged or routed for approval.
- **External-seam writes** — a work-item record or knowledge page in a connected system, and their comment streams — follow `core/disciplines/external-seam-conduct.md`: the record holds state, a comment addresses a person. This skill's read-only contract already forbids the write; the citation is what makes the shape binding on the **staged** output, so a finding routed for approval is drafted as something that belongs in the record's fields rather than as a dated audit comment somebody then pastes.

## Reference docs

This skill consumes governed reference docs by role-name (duplicate-source-discipline; each doc owns its definitions).

| Reference | Owner | What this skill reads from it |
|---|---|---|
| [`references/mode-intents.md`](references/mode-intents.md) | this skill | The queryable 4-intent declarations per mode (all 9 modes; v1/v2/v3/v4 slices, all implemented) + the declared `full`-sweep membership table. |
| [`references/rollup-mode.md`](references/rollup-mode.md) | this skill | The `rollup` mode (mode 8) sub-mode specs + the rollup-contract field mapping + the compose-not-absorb / bridge-file boundary. |
| `references/structure-mode.md` | this skill | The `structure` mode (mode 9) — the entity/field/relationship check contract, the completeness-score denominator model + coverage envelope, the ordered rule-class → section routing table, and the migration-telemetry surface. |
| [`references/conformance-surface.md`](references/conformance-surface.md) | this skill | The `full`-mode architecture-conformance surfacing contract — the committed `release/releases/architecture-conformance-summary.md` read shape, the platform-context render rules, and the compose-not-absorb boundary with `pmo-qa-auditor` Mode I. |
| [`references/evidence-matrix.md`](references/evidence-matrix.md) | this skill | The MCP + local source map per mode + the drift-resolution rule (citing ADR-051). |
| [`references/confidence-framework.md`](references/confidence-framework.md) | this skill | The finding → confidence + S0–S3 band mapping (citing `staleness-confidence-standard.md`). |
| [`core/specs/staleness-confidence-standard.md`](../../../core/specs/staleness-confidence-standard.md) | core (ADR-043) | The canonical 4-band depth scale this skill projects onto. Consum

…(truncated)
