# Weekly Status Rollup

> Generates a weekly executive status roll-up across all active projects. Covers project health, key risks, decisions made/pending, and upcoming milestones. Writes back updated health indicators to PORTFOLIO.md. Triggers: "generate the weekly roll-up", "weekly status", "SteerCo prep deck", "executive status", "cross-project health summary", "refresh the health indicators".

- Skill: `cody-hutson/weekly-status-rollup` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add cody-hutson/weekly-status-rollup`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cody-hutson/weekly-status-rollup/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/weekly-status-rollup

---

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

# Weekly Status Roll-Up Workflow

## Role

You produce the weekly executive summary across all active projects in the PMO portfolio.
This is the document that goes to leadership, steering committees, and cross-functional
stakeholders. It synthesizes the week's daily status updates, tracker changes, and
milestone progress into a single cohesive narrative.

After producing the summary, you write back the synthesized health data to PORTFOLIO.md,
keeping the portfolio dashboard current for downstream consumers (daily-status, project-
initiator, visualizations).

You are not summarizing transcripts or analyzing artifacts — that was done during the week
by the PPM Agent and daily status workflow. You are rolling up the results.

## Inputs

Read these files in order before generating:

1. **PORTFOLIO.md** — List of all active projects with governance models and key dates
2. For each active project (every item below is a **tracked-layer** read — see the read-side
   aggregation contract that follows):
   a. **PROJECT.md** — Current phase, milestones, health status
   b. **Daily Status Log** — this week's `DEC-###` / `ACT-###` entries (Monday through current day)
   c. **Daily Status Log carry-forward** — the open `DEC-###` / `ACT-###` entries carrying current
      blockers, decisions, and actions
   d. **Communications Tracker** — `MSG-##` rows for key communications this week (escalations, exec messages)
   e. **RAID entries** — Any new or updated risk/issue rows from this week
3. **GitHub Issues** — Any improvement proposals created this week: `gh issue list --label "improvement" --json number,title,createdAt --created ">YYYY-MM-DD"` (where date = 7 days ago)

**Read-side aggregation contract (tracked layer only).** This roll-up aggregates **from the
maintained tracked (Domain-B) layer** — the `DEC-###` / `ACT-###` / `MTG-###` tracker entries and the
RAID rows — and **never re-scans raw transcripts to re-derive them**. The tracked layer is
`trust_category: controlled-truth`, and every extracted entry already carries its provenance
back-link: `source_inputs` on markdown-tracker entries, `source_ref` on RAID rows, each resolving to
the `TR-###` / `MSG-###` / source file the entry was extracted from. The declared inputs above are
therefore **tracker entries plus those back-links**, never the raw evidence behind them.

- **Cite provenance; do not re-derive it.** When a roll-up line must show where a decision, action,
  or risk came from, resolve and cite that entry's `source_inputs` / `source_ref` — do not open the
  transcript and re-read it.
- **A missing entry is a tracked-layer gap, not a licence to re-scan.** When an item is absent from
  the tracked layer, surface it as a gap for `tracker-manager` to add on the write side; do not
  reconstruct it from raw evidence inside the roll-up.
- **Why:** re-deriving a roll-up from raw evidence bypasses the controlled-truth layer and
  re-introduces the un-cited, un-provenanced aggregation that the raw→tracked bridge exists to
  eliminate. Write-side maintenance of the layer belongs to `tracker-manager`; read-side enforcement
  is this skill's responsibility. The governing definition is the Aggregation source-of-truth rule in
  the Raw→Tracked Provenance section of `core/schemas/tracker-schemas.md`.

## Reference docs

This skill consumes governed reference docs by **role-name** — it does not restate their
content (duplicate-source-discipline; each doc owns its definitions). The Section 7 (Portfolio
Governance) sub-blocks and the Section 1 dominance check below cite these by role:

| Reference | Owner / module | Consumed by | What this skill reads from it |
|---|---|---|---|
| [`metric-registry.md`](references/metric-registry.md) | this skill (`weekly-status-rollup`) — intra-module | Section 1 health logic + Section 7 per-metric decision-rule validation + lag/lead audit | The cross-level metric → RAG-band → `WHEN…THEN…` decision-rule index. Each reported metric cites its governing rule verbatim from the registry row; this skill follows REFERENCED rows to their owning doc (`channel-formats.md`, `capacity-model.md`, `backlog-health.md`) for the live band rather than re-deriving thresholds. |
| [`watermelon-detection.md`](../../../core/skills/pmo-qa-auditor/references/watermelon-detection.md) | `pmo-qa-auditor` — **core module (via-public-api)** | Section 7 Watermelon Scan + the Section 1 dominance feedback | The **canonical home of the 8-signal watermelon set (W1–W8)** with severity tiers, false-positive filters, and the verdict-composition rule. This skill runs the signals **by reference** — it does **not** fork or restate them. The `operations → core` direction is the sanctioned cross-module flow enumerated in [`operations/README.md` § Cross-Module Dependencies](../../README.md) (markdown-doc-link reference per ADR-007; cross-module consumption posture per [ADR-028](../../../core/ADRs/ADR-028-operations-consume-core-safety-controls-via-public-api.md)). |
| [`capacity-model.md`](../delivery-engine/references/capacity-model.md) | `delivery-engine` — intra-module (operations) | Section 7 Capacity Dashboard synthesis | The §1 effective-capacity formula and §9 Demand-Supply Gap RAG bands. The cross-project capacity view aggregates per-project Capacity Utilization (whose registry row already references this doc) into a portfolio view; it does **not** restate the formula or bands. |

## Output Structure

> Any roll-up artifact persisted to `08-Generated/` is named per the artifact naming standard ([`../../../core/standards/artifact-naming-standard.md`](../../../core/standards/artifact-naming-standard.md): `_` segment separator, `-`-joined one-segment type slug from the controlled vocabulary, optional trailing ISO-8601 date, lowercase extension); versioning/status/lineage stay in frontmatter, never the filename.

### Section 1: Portfolio Health Dashboard

A quick-reference table covering all active projects:

```
| Project | Phase | Health | Sprint/Milestone | Days to Next Gate | Key Risk |
|---------|-------|--------|-----------------|-------------------|----------|
| [Name]  | [Phase] | 🟢/🟡/🔴 | [Sprint X / Phase Y] | [N] | [One-line] |
```

Health color logic:
- 🟢 GREEN: On track, no active blockers, milestone dates holding
- 🟡 YELLOW: At risk — active blockers exist but mitigation in progress, or timeline
  pressure without confirmed slip
- 🔴 RED: Blocked or slipped — confirmed timeline impact, unresolved escalations,
  or critical path broken

### Section 2: Per-Project Summary

For each active project, generate:

**[Project Name] — [Phase] — [Health Color]**

**This Week:**
- 3-5 bullet points covering what happened this week (from daily status updates)
- Focus on outcomes and movement, not activity descriptions
- Include specific numbers where available (bugs resolved, tests passed, decisions made)

**Key Risks & Blockers:**
- Active blockers from carry-forward (with age in business days)
- New risks identified this week
- Escalations in progress

**Decisions Made This Week:**
- Decisions closed (from DEC-### entries that moved to MADE status)
- Include decision-maker and impact

**Decisions Pending:**
- Open DEC-### entries with deadlines
- **Overdue blocking-decision escalation (thresholded + routed).** For each open
  DEC-### entry, compute the overdue clock `today − Deadline` in **business days** (carries
  `[INFERRED: today − Deadline]`; the deadline-keyed clock per
  `../ppm-agent/references/proactive-follow-up-tracking.md` §Aging "starts from the deadline
  date"). The escalation fires only for **blocking-class** decisions (the entry's
  `blocking: true` field — go/no-go, launch-sequence, and similar gating decisions). Apply the
  two-stage, due-date-keyed ladder:
  - **WARN at `> 3 business days` past due** — emit a `[RECOMMENDED]` nudge to the
    decision-maker in the rollup output. **No tier change** (parallel to the Stale-RAID
    Warning band).
  - **ESCALATE at `> 5 business days` past due** — emit an **escalation action** that bumps the
    decision **one tier up** the existing routing ladder in
    `../ppm-agent/references/escalation-thresholds.md` §2 (Team → Project → Program →
    Program-Critical/Sponsor → Portfolio). The escalate action names the decision, the
    decision-maker, the breached `5bd` threshold, and the routed tier. This consumes the
    existing tier ladder by reference — it does **not** author a parallel tier scheme.
  - **Coverage gap on absent `blocking`:** a DEC-### entry with no `blocking` field → treat as
    **non-blocking** (no escalation) and flag the missing classification as a coverage gap on
    first encounter; **never** silently default to blocking.
  - **Cross-skill ownership (mirrors the Stale-RAID split):** this skill **surfaces** the
    overdue-decision escalation in the roll-up; `ppm-agent` (which owns DECISION escalations) is
    the **router**; `delivery-engine` Mode G is where the decision artifact is updated. See the
    OPERATIONS.md **Overdue-Decision Escalation Protocol**. Reversibility **CHEAP** /
    recommend-tier — a flag + routed tag the operator reviews; never auto-decides the decision
    or mutates the tracker without approval (carry the tier per § Reversibility Discipline).

**Next Week Focus:**
- Top 3 priorities for next week
- Upcoming milestones or deadlines
- Required actions or decisions

**Dual-Framing Bridge (conditional):**
Only include when `PROJECT.md` has `dual_framing_enabled: true`.

```
Agile Track: [Sprint progress, velocity, backlog health]
Waterfall Track: [Milestone status, phase gate progress, deliverable status]
Both tracks converge on: [single unified priority or action]
```

### Section 3: Cross-Project Items

- Dependencies between projects
- Shared resource conflicts
- Items that affect multiple projects

#### Section 3.6: Cross-Project RAID Aggregation (S6 fill logic)

The cross-project items above are rolled up into the composed **`## Cross-Project RAID`**
portfolio section (S6, staged in Section 6) as a ranked, passive-voice-free risk view. S6 is
**contract-driven**: the aggregation reads the three cross-project risk fields of the
[portfolio write-back contract](../../../core/standards/portfolio-writeback-contract.md) §4
(S6) — it never re-derives them and never hand-types a risk list — so the deterministic
composer renders the rows from fields, not from agent-synthesized prose. This sub-block defines
the 3-leg source union and the per-leg row projection that FILLS the S6 shell (whose columns,
placement, and empty-state are defined in Section 6); it does not author a parallel cross-project
risk section — S6 is the single cross-project risk surface.

**3-leg source union** — aggregate the project-scoped leg, surface the two portfolio-tier legs:

| Leg | Contract field (backing entity) | Read filter — risk-bearing states only | Aggregate vs. surface |
|---|---|---|---|
| 1 | `top_risks[]` — RAID Item (project-scoped `[Project]/`) | `lifecycle_state ∈ {open, in-progress, mitigating}` AND (`severity` High OR cross-project `impact`) | **aggregate** — roll each project's active RAID up to the portfolio view |
| 2 | `key_dependencies[]` — Cross-Project Dependency / XPD (portfolio `projects/_config/`) | `state ∈ {open, broken}` (a `satisfied` / `waived` dependency is not a live risk) | **surface** — already portfolio-tier |
| 3 | `cross_project_conflicts[]` — Cross-Project Resource Conflict / XRC (portfolio `projects/_config/`) | `state ∈ {detected, acknowledged}` (a `resolved` conflict is not a live risk) | **surface** — already portfolio-tier |

The resource-conflict leg reads the `cross_project_conflicts[]` **contract field** (not the
entity directly), so all three legs are contract fields and S6 renders fully from the contract —
the composer stays deterministic and no S6 row is agent-synthesized.

**Per-leg row projection → the S6 shell columns** (`Type · Item · Owner · Mitigation · Source-Tier · Projects-Affected`):

| Shell column | Leg 1 — `top_risks[]` (RAID) | Leg 2 — `key_dependencies[]` (XPD) | Leg 3 — `cross_project_conflicts[]` (XRC) |
|---|---|---|---|
| **Type (R/A/I/D)** | RAID `raid_type` | `D` (dependency) | `R` (resource-contention risk) |
| **Item** (risk) | RAID `summary` + `impact` (what is at stake) | `{from}` → `{to}` dependency is `{state}` | `{conflict}` — resource over-allocated across the competing projects |
| **Owner** | RAID `owner_person_id` → Person | depended-on project lead / recorded dependency owner | resource manager resolving the contention |
| **Mitigation** | RAID `action_plan` | resolution path (satisfy / waive / escalate) | reallocation / sequencing plan |
| **Source-Tier** | `Project` | `Portfolio` | `Portfolio` |
| **Projects-Affected** | the sourcing project | `{from}` + `{to}` projects | `projects_affected[]` |

`Source-Tier` is the escalation-ladder tier defined by the S6 shell (Team → Project → Program →
Program-Critical/Sponsor → Portfolio), seeded by each entity's storage tier: a project-scoped RAID
roll-up starts at `Project` (escalating per its severity), a portfolio-tier dependency/conflict at
`Portfolio`.

**Aggregation rules (bind the fill):**
- **Rank:** `severity` descending, then `impact` (the queryable key) — highest-signal risks first, not an unordered dump.
- **Passive-voice-free (hard gate):** every S6 row carries all three of {risk, owner, mitigation}. A row whose contract field lacks an owner or a mitigation renders `[DRIFT: incomplete risk record — <field> missing]` (a repair flag) — never a passive "a risk exists" / "is being monitored" statement (CLAUDE.md § Guardrails, "No passive risk voice").
- **≥ 3 cross-component risk categories:** the 3 legs ARE the categories — **timeline contention** (open / broken dependencies + RAID schedule risks), **shared bottlenecks** (resource over-allocation), and **cross-project / vendor dependency risk** (dependencies + RAID `Dependency`-type items).
- **Sourced, not hand-typed:** the population reads the authoritative RAID / XPD / XRC records through the contract fields, so the profile stays current — there is no hand-maintained risk list.
- **Staleness:** consumes the single `last_published` / `[STALE]` marker owned by the contract (§3); a field aged past cadence renders `[STALE]` — no parallel freshness field.
- **Dedup:** a cross-project risk appears in **S6 only**; the per-project **S5** (`### Top Risks`) references it with `see Cross-Project: [item]` (the existing "cross-project items live in Section 3 only" convention). S6 (risk-roll-up lens: risk / owner / mitigation) and S7 / S8 (state-register lens: from / to / state; person / projects / pct) are distinct lenses on the same entities, not duplicated content.

**Scope boundary (methodology-neutral):** this produces the neutral rolled-up rows only. The PMI
"Risk Profile" *presentation* a methodology pack renders on top of these rows is out of scope
here — owned by the portfolio-framework methodology pack, not this aggregation. *(Boundary scope: this excludes the methodology-pack **presentation** layer only; reading `delivery_approach` to project neutral kinds/fields is done per the OPERATIONS.md Methodology Awareness Protocol and is distinct from the presentation the pack owns.)*

#### Section 3.x: Cross-Project Correction Recurrence

Detect a behavioral correction recurring across projects — a redirect that is not
project-specific after all, but a latent platform guardrail. This is the **spatial**
recurrence axis (same correction active in ≥2 projects now), complementary to the
**temporal** axis owned by `OPERATIONS.md § CORRECTIONS Graduation & Expiry Protocol`
(a correction that has driven ≥2 course-corrections over time). This sub-block detects
the signal and **routes it into that existing intake path** — it does NOT author a
parallel `improvement.yml` mechanism.

**Procedure (per weekly run):**
1. Enumerate each active project's `[Project]/CORRECTIONS.md` (best-effort; a project
   with no file contributes zero entries — never read absence as a signal).
2. Tag each correction with its `(domain, theme)` tuple using the two-pass heuristic in
   `../../../core/disciplines/decision-discipline.md` §4.3 (cited, not restated).
3. Group corrections by `(domain, theme)` **across projects**. A group whose entries
   span **≥2 distinct projects** fires as a cross-project recurrence candidate (the
   canonical N=2 emergence number per `decision-discipline.md` §4.2, applied to the
   project-count axis — same number, not a new threshold).
4. **Emit an actionable candidate** (never a bare count): `{ what recurs — the
   (domain,theme) + representative correction text · which projects — the ≥2 project
   names + the entry from each · proposed guardrail — a one-line candidate governance
   rule }`.
5. **Route via the intake path** — surface the candidate in Section 3 output AND log it
   as a CORRECTIONS-graduation candidate for the Pattern Review pipeline
   (`OPERATIONS.md § CORRECTIONS Graduation & Expiry Protocol` Rule 3 field-mapping).
   `release-planner` Mode D drafts the `improvement.yml`; the operator renders
   PROMOTE / KEEP / EXPIRE. This roll-up **never files the issue itself** (preserves the
   LITERAL-body operator gate and the human-in-the-loop write posture).

**Single-project rule (no false positive):** a `(domain, theme)` group whose entries all
come from **one** project has project-span 1 < 2 → does NOT fire. A correction unique to
one project produces no cross-project candidate ("a single instance is data, not pattern").

**Reversibility:** the candidate is a decision-class output — carry a reversibility tier +
confidence per § Reversibility Discipline (an unpromoted candidate surfaced for operator
review is CHEAP; a guardrail acted on downstream escalates per the tier table).

**Single-project portfolio note:** when only one project is active this sub-block is a
no-op (no ≥2-project span possible) — omission is the correct signal, not a gap.

### Section 4: Process Health

- File Router performance this week (files classified, misclassifications corrected)
- Tracker Manager stats (updates applied, rejected, evidence gate blocks)
- Unclassified queue status (items pending, age)
- Improvement proposals submitted (from GitHub Issues with `improvement` label created this week)

### Section 5: Looking Ahead (2-Week View)

- Milestones in the next 14 calendar days (across all projects)
- Required decisions with deadlines
- Scheduled meetings (SteerCo, phase gates, reviews)
- Resource or scheduling conflicts

### Section 6: Portfolio Write-Back

After producing the executive summary (Sections 1-5), update PORTFOLIO.md with the
synthesized data. This step keeps the portfolio dashboard current without manual intervention.

**Consume the per-project rollup entity (do not re-derive).** For each active project,
`ppm-agent` emits a `[Project]_Rollup.md` composed rollup entity per the **portfolio write-back
contract** ([`../../../core/standards/portfolio-writeback-contract.md`](../../../core/standards/portfolio-writeback-contract.md)) — a 7-field
per-project publishing schema (`status`, `top_risks[]`, `key_dependencies[]`, `capacity_signal`,
`milestone_delta`, `cross_project_conflicts[]`, `last_published`). This section CONSUMES those
fields and composes the PORTFOLIO.md sections (the contract's S1–S8 section-schema map) from
them **rather than re-deriving each field**. In production the deterministic composer is invoked
with `--as-of=today`; it honors the `[STALE]` marker — a field whose age (`today − last_published`,
**business days**) exceeds `3 bd` renders `[STALE]` inline, and `> 5 bd` auto-degrades. The one
staleness mechanism lives in the contract; the health-score layer supplies only the threshold
values. `cross_project_conflicts[]` makes the Cross-Project RAID (S6) and Resource Conflicts (S8)
sections render deterministically from fields, not agent-synthesized prose.

**Portfolio Health Hard-Gate (Rules 1-3) — the right-sized health-scoring layer.** The portfolio
`Health` summary is governed by a three-rule hard gate applied to the composed output at the
Section-6 human checkpoint (below) — NOT by a parallel numeric scorer. The gate is right-sized
deliberately: it KEEPS the pain-sourced freshness-validation + hard-gate core and TRIMS the
article-sourced elaboration. An A–F letter grade, a multi-layer category-score rubric, and an
integrity multiplier are **not** introduced — the worst-component dominance rule (Rule 1) already
delivers "cannot show Green over a failing component," so a parallel numeric multiplier would fork
the RAG health SSOT. The `WHEN…THEN` scoring logic **is** these three rules; the deterministic
composer's `SECTION_REGISTRY` renders the sections, so this layer supplies the gate logic + the
section schemas below, never a second renderer.

- **Rule 1 — worst-component dominance (live; cite, do not re-derive).** A project's `Health`
  cell is driven by its worst component and CANNOT read 🟢 GREEN while any component RAG is worse
  than green. This is the existing watermelon-prevention dominance rule — §7.1 W2 plus the
  Section 7 ↔ Section 1 worst-component feedback below, owned by
  [`channel-formats.md`](../comms-writer/references/channel-formats.md)
  § RAG Threshold Standards and registered in
  [`metric-registry.md`](references/metric-registry.md) § Project-Level RAG Composition ("does
  not define a divergent composition algorithm"). Rule 1 binds that OUTCOME at the summary cell;
  it authors no new algorithm.
- **Rule 2 — freshness auto-degrade arm.** The per-project `Last-Validated` stamp (the
  `last_published` field consumed above) drives the ONE staleness mechanism owned by the portfolio
  write-back contract ([`portfolio-writeback-contract.md`](../../../core/standards/portfolio-writeback-contract.md)
  §3; age = `today − last_published`, business days). This layer supplies only the two threshold
  **values** that parameterize it — no second freshness field is authored: age `> 3 bd` renders
  `[STALE]` inline on `Last-Validated`; age `> 5 bd` **auto-degrades** — the field is treated as
  not-Green and the `Health` cell CANNOT read 🟢 GREEN, annotated `[STALE:DEGRADED]` (the
  composer's degrade marker). Rationale for `> 5 bd`: a report one full weekly-rollup cycle plus a
  grace day unrefreshed is no longer trustworthy as green.
- **Rule 3 — non-override-to-Green.** A 🟢 GREEN that contradicts Rule 1 or Rule 2 is REJECTED at
  the Section-6 human checkpoint — a silent hand-edit to green is not accepted. To change a derived
  color the operator fixes the component SSOT (which re-derives the summary) OR attaches an
  evidence-tagged **Override Record** — `rationale · owner · date` — surfaced alongside the
  write-back proposal, never a silent recolor. This preserves the existing posture that a flag is
  an evidence-integrity finding, not a unilateral re-coloring. An Override Record is a
  decision-class action and carries its reversibility tier per § Reversibility Discipline.

**What gets written back:**

For each active project in PORTFOLIO.md:

1. **Portfolio Health Summary table (S1)** — Update the row:
   - `Phase`: Current phase from this week's analysis
   - `Health`: 🟢/🟡/🔴 as determined in Section 1, **subject to the Portfolio Health Hard-Gate
     above** — Rule 1 (worst-component dominance) and Rule 2 (freshness auto-degrade on a
     `[STALE:DEGRADED]` `Last-Validated`) can each block a 🟢 GREEN, and Rule 3 rejects a
     non-derived green at the checkpoint.
   - `Critical Path Item`: Top blocker or next milestone from Section 2
   - `Go-Live`: Updated if date changed during the week (evidence-tagged)
   - `Last-Validated`: The rollup's `last_published` (ISO date) — the per-project freshness
     stamp that drives the `[STALE]` / `[STALE:DEGRADED]` marker (Rule 2). Distinct from the
     portfolio-level `Last Updated` meta line (item 4), which stays.

2. **Health Indicators table** — Update each dimension:
   - `Schedule`: Status + 1-line evidence from this week
   - `Scope`: Status + 1-line evidence
   - `Quality`: Status + 1-line evidence
   - `Stakeholders`: Status + 1-line evidence
   - `Integration Risk`: Status + 1-line evidence (if applicable)

3. **Top Risks (S5)** — Replace with the current top risks (max 5) as passive-voice-free
   `risk · owner · mitigation` triples sourced from the `top_risks[]` contract field (RAID Item —
   `summary` + `impact` → risk; `owner_person_id` → Person → owner; `action_plan` → mitigation),
   ranked `severity` descending then `impact`. Each row names the risk, a named owner, and a named
   mitigation; a row missing an owner or a mitigation renders `[DRIFT: incomplete risk record —
   <field> missing]`, never a passive statement (CLAUDE.md § Guardrails, "No passive risk voice").
   A cross-project risk is not restated here — it lives in the S6 `## Cross-Project RAID` roll-up
   (Section 3.6) and is referenced with `see Cross-Project: [item]` (dedup — one surface). Renders
   `[STALE]` per the contract's freshness marker when the source ages past cadence.

4. **Last Updated** — Set to today's date

**Portfolio-level health-score sections (S3 / S4 / S6 — composed + staged).** Beyond the
per-project row above, the health-score layer stages three portfolio-level sections. Each is
rendered by the deterministic composer's `SECTION_REGISTRY` from the contract fields — this layer
owns the SCHEMA (columns + degrade rules), never a parallel renderer, and stages the result at the
Section-6 checkpoint (never a Claude-side `projects/` write):

- **S3 — `## Capacity Dashboard`** (absorbed capacity-view scope). Per-project rows
  `Project | Utilization | Demand-Supply Gap (RAG) | Over-committed?` plus a portfolio roll-up
  line, reading `capacity_signal {utilization, gap_rag}` from the contract. This STAGES the
  existing §7.5 Capacity Dashboard synthesis — which already applies
  [`capacity-model.md`](../delivery-engine/references/capacity-model.md) §1 (effective-capacity)
  and §9 (Demand-Supply-Gap RAG bands: `≤ 0.85` GREEN … `> 1.00` RED over-committed) by
  reference — it does not re-derive the formula or bands. **Graceful degrade:** a project with no
  tracked managed-delivery-team allocation renders `capacity: n/a — no managed-team allocation`;
  never fabricate a utilization (the capacity model applies to a managed delivery team, not to the
  single-operator platform).
- **S4 — `## Portfolio R-G-T Allocation`** (absorbed investment-mix scope). Run / Grow / Transform
  counts (or effort-weighted shares where effort is available) plus an explicit `Unclassified`
  coverage-gap line. This STAGES the existing §7.3 R-G-T synthesis, reading each active project's
  optional `investment_class: Run|Grow|Transform`. **No-invention (already codified §7.3):** a
  project with no `investment_class` is `Unclassified` and surfaced as a coverage gap — never
  heuristically auto-classified from phase or type. (R-G-T investment classification is not the
  `capacity-model.md §5` 60/20/20 capacity effort-split.)
- **S6 — `## Cross-Project RAID` (shell + fill).** Placed immediately after
  `## Cross-Project Dependencies` (both are portfolio-tier cross-project surfaces). Shell columns:
  `Type (R/A/I/D) | Item | Owner | Mitigation | Source-Tier | Projects-Affected`. Each populated
  row is a passive-voice-free `risk · owner · mitigation` triple; **Source-Tier** enumerates the
  existing escalation ladder ([`escalation-thresholds.md`](../ppm-agent/references/escalation-thresholds.md)
  §2: Team → Project → Program → Program-Critical/Sponsor → Portfolio). **Empty-state:**
  `No cross-project RAID items — [N] per-project risks tracked in project details` (an honest empty
  state, not a blank section). The shell — columns, placement, and
  empty-state — is defined here; its **rows are filled** by the 3-leg cross-project risk
  aggregation in Section 3.6 above: Leg 1 aggregates the project-scoped `top_risks[]` (RAID Item,
  ranked `severity` then `impact`), Leg 2 surfaces `key_dependencies[]` (Cross-Project Dependency,
  `open` / `broken`), Leg 3 surfaces `cross_project_conflicts[]` (Cross-Project Resource Conflict,
  `detected` / `acknowledged`) — each projected into the shell columns as a passive-voice-free
  `risk · owner · mitigation` triple with its `Source-Tier`. Because all three are contract fields,
  the deterministic composer renders S6 from them (no agent-synthesized rows), staged at the
  Section-6 human checkpoint (never a Claude-side `projects/` write). S5 (per-project
  `### Top Risks`) and S6 (cross-project aggregated) are distinct scopes of ONE risk model —
  composed, never a parallel section.

**Write-back rules:**
- Only update fields where the weekly analysis produced new evidence
- Tag every changed field with the evidence source: `[SOURCE: Daily Status 3/17]`, `[SOURCE: RAID R-PPM-052]`, etc.
- If a field hasn't changed this week, leave it as-is (don't rewrite identical content)
- If health color changes (e.g., 🟢 → 🟡), note the reason inline
- Present the proposed PORTFOLIO.md changes as a summary for user approval before writing
- Format: "PORTFOLIO.md Update: [N] fields changed for [Project Name]. [1-line summary of most significant change]."

**Human-in-the-loop checkpoint:**
After producing the executive summary and before writing to PORTFOLIO.md, present:
```
📊 Portfolio Write-Back Summary:
- [Project 1]: Health 🟡→🟢 (all blockers resolved this week). Phase unchanged.
- [Project 2]: Phase "Testing" → "Issue Resolution". 3 risk updates.
Approve these changes to PORTFOLIO.md? (Or provide corrections)
```
Wait for user confirmation before writing. If running as a scheduled task, produce the
summary and changes as a draft — flag for approval at next interaction.

### Section 7: Portfolio Governance

Sections 1–6 surface and write back portfolio **state**. Section 7 applies portfolio
**governance discipline** to that state: it catches green-on-the-outside-red-on-the-inside
projects, audits the metric set's balance, reports the investment mix, validates every
reported metric against its governing rule, and synthesizes a portfolio capacity view.
All five sub-blocks consume governed reference docs **by role** (see `## Reference docs`) —
they do not restate thresholds, signals, or formulas.

Run Section 7 over **every** active project — including a single-project portfolio (the
dashboard/cross-project sections are skipped at one project per § Multi-Project Handling, but
the per-project watermelon scan and metric validation still run).

#### 7.1 Watermelon Scan (8-signal, per project)

For **each** active project, run the 8-signal watermelon scan **W1–W8 by reference** per
[`watermelon-detection.md`](../../../core/skills/pmo-qa-auditor/references/watermelon-detection.md)
(owned by `pmo-qa-auditor` — core module, consumed via-public-api; do **not** restate or fork
the signals). The signals key off the bands owned by `metric-registry.md`:

| ID | Signal (by reference) | Severity |
|---|---|---|
| W1 | Persistent-green under recurring RAID | STRONG |
| W2 | Green project-RAG over Amber/Red component-RAG | STRONG |
| W3 | Stale / overdue RAID under green *(the headline path)* | STRONG |
| W4 | Velocity spike beyond credible band | WEAK |
| W5 | Zero open risks on an active project | WEAK |
| W6 | Milestone dates not aging (flat %-complete) | WEAK |
| W7 | 100% task completion under slipping features / scope | WEAK |
| W8 | Self-reported RAG without objective derivation | WEAK |

**Apply each signal's false-positive filter** (per the canonical doc) before counting it as
fired, then compose the per-project **verdict by reference** to `watermelon-detection.md`
§ Verdict Composition:

- **≥1 STRONG signal (W1/W2/W3)** fires → **WATERMELON-FLAG (Tier 1)**. Cite the firing STRONG
  signal + its evidence (e.g., for W3: the overdue RAID IDs + the Overdue-RAID-Count registry band).
- **≥2 *independent* WEAK signals (W4–W8)** fire on the same project → **WATERMELON-FLAG (Tier 2)**.
  Cite the ≥2 corroborating signals. (W8 corroborates only a non-W8 WEAK; same-evidence items
  de-dup to their highest-severity facet once.)
- **≥1 signal un-evaluable** (missing artifact / metric) and no STRONG independently fired →
  **INDETERMINATE / EVIDENCE-GAP** — record the gap; **never** report this as clean.
- **All signals evaluable and none survived** → **NO-FLAG (CLEAN)** — record the signals
  evaluated and the FP filters that explained near-misses, so a clean result is distinguishable
  from an un-evaluated one.

Output, per project: the verdict (Tier 1 / Tier 2 / INDETERMINATE / NO-FLAG), the firing
signals with evidence, and — for any flag — a one-line statement that the project's Section 1
color is contradicted by the scan. A flag is an **evidence-integrity finding**, not a unilateral
re-coloring: route it to the worst-component dominance check below and the failure-mode rule.

#### 7.2 Lag-to-Lead Balance Audit

Classify each metric in `metric-registry.md` that the roll-up reports this week as a **lagging**
or **leading** indicator (the classification is a property of the registry rows — see the
registry's lag/lead column; **no new PROJECT.md field**), and report the **lag : lead ratio**
across the reported set. A set dominated by lagging indicators (outcomes already realized — SPI,
CPI, overdue counts) with few leading indicators (predictive — velocity variance, capacity
utilization, dependency health) is surfaced as a balance risk: the portfolio is being steered
by the rear-view mirror. Cite the registry rows; do not re-derive the metrics.

#### 7.3 Portfolio R-G-T Allocation

Report the portfolio **Run / Grow / Transform** investment allocation. Read each active project's
**optional** `investment_class: Run|Grow|Transform` field from its `PROJECT.md` (see
`project-md-template.md` — the field is optional). Compose the portfolio split as the
Run / Grow / Transform counts (or effort-weighted shares where effort is available).

**Default when the field is absent:** a project with no `investment_class` is classed
**`Unclassified`** and surfaced as an explicit **coverage gap** — it is **never** silently
bucketed into Run/Grow/Transform, and it is **never** heuristically auto-classified from phase
or project-type (that would fabricate an investment call the operator did not make — a
no-invention violation). The R-G-T block therefore works **with or without** the field: present
field → real split; absent field → `Unclassified` with the coverage gap named. Do not block the
roll-up on missing `investment_class`.

> **Disambiguation:** R-G-T (investment classification) is **not** the `capacity-model.md §5`
> 60/20/20 capacity effort-split — a different concept that happens to share digits. Do not
> conflate the two.

#### 7.4 Per-Metric Decision-Rule Validation

For **each** metric surfaced anywhere in the roll-up (Sections 1–2 health logic, Section 7
sub-blocks), **cite its governing `WHEN…THEN…` decision rule verbatim** from its
`metric-registry.md` row and confirm the reported RAG matches the rule's output. This is pure
consumption: follow REFERENCED rows to their owning doc (`channel-formats.md`, `capacity-model.md`,
`backlog-health.md`) for the live band; do **not** re-derive a threshold (duplicate-source-
discipline). A reported color that does not match its rule's output is itself a finding (a
likely W2 or W8 watermelon contributor) — surface it, do not silently re-color.

#### 7.5 Capacity Dashboard

Synthesize a **cross-project capacity view**: aggregate each active project's **Capacity
Utilization** (the `metric-registry.md` Team row, which already references
[`capacity-model.md`](../delivery-engine/references/capacity-model.md)) into a portfolio
capacity dashboard, applying `capacity-model.md` §1 (effective-capacity formula) and §9
(Demand-Supply Gap RAG bands) **by reference**. Report per-project utilization + the portfolio
roll-up, flagging any project breaching the §9 RED band (`> 1.00` utilization) as over-committed.
Reproduce the source's inclusivity (`≤ 0.85` is GREEN); do **not** restate the formula or bands.

#### 7.6 Portfolio Dormancy Sweep

For **each** tracked project, run a dormancy sweep that detects a project producing **no
artifact activity at all** across a defined window and routes it to an explicit **disposition
decision** — distinct from the §7.1 W6 signal and the "Roll-up generated as a substitute for
the week's unprocessed work — TRIG" failure mode, which detect *stale content within a
reported week*; §7.6 detects *whole-project no-activity* and routes to disposition, not a
watermelon flag.

- **Artifact-activity signal set (per project):** the most-recent modification across {Daily
  Status Log entries, any `04-PMO-Operations/` tracker update, any `05-Transcripts/`
  arrival}. "Activity" = a **substantive** entry/update, mirroring the Stale-RAID "substantive
  update resets the clock" rule (`../ppm-agent/references/escalation-thresholds.md` §3) — a
  cosmetic re-save does **not** count.
- **Dormancy clock:** `today − last-artifact-activity-date`, in **business days** (carries
  `[INFERRED: today − last-activity-date]` per the platform's existing age-computation
  precedent — there is no codified business-day calendar primitive yet).
- **Fire condition — `> 10 business days` (= 2 weekly-rollup cycles):** emit a **dormancy
  prompt** for that project naming (a) the project, (b) the last-activity date + its source,
  (c) the computed dormancy age, and (d) the three disposition options — **proceed / shelve /
  close**. The window is **10 business days**: it requires a project to miss *two consecutive*
  rollup windows (the rollup runs weekly per § Generation Schedule) and reuses the platform's
  existing 10-business-day "inactivity → disposition" cadence (`08-Generated/` auto-archive).
- **Disposition routing (Autonomy Tier 1 — recommend):** the prompt is an **evidence-integrity
  finding surfaced to the operator**. The sweep **never** auto-shelves or auto-closes;
  disposition is an operator decision (mirrors §7.1's "a flag is an evidence-integrity
  finding, not a unilateral re-coloring"). The dormancy prompt is a decision-class output —
  carry a reversibility tier per § Reversibility Discipline (an internal pre-confirmation
  dormancy flag is CHEAP; a close disposition acted on downstream escalates per the tier
  table).
- **Coverage-gap honesty (composes with the "Daily-log coverage gap read as a quiet week —
  INPUT" failure mode):** if the activity signal cannot be computed (no trackers present yet —
  a just-initiated project), emit `dormancy: not assessable — no tracker baseline` and flag it
  as a coverage gap; **never** read "no trackers" as "dormant" (that would converge with the
  "absence of evidence becomes evidence of absence" anti-pattern the skill already guards).
- **De-registration sub-case:** a project that is *archived but still on the active list* fires
  the same sweep → the disposition prompt's **close** option doubles as the de-registration
  trigger (drop from PORTFOLIO.md active list). This sweep is the **detector**;
  `project-initiator` Mode B is the **executor** (the closure-entry dormancy hook in that
  skill acts on what this sweep detects).

**Section 7 ↔ Section 1 feedback (worst-component dominance).** The watermelon scan's W2 signal
(green project-RAG over a worse component) requires the **worst-component dominance rule** to
detect a violation of. Section 1's project color is therefore composed by the transparent-roll-up
rule — **the project color is driven by its worst component** (the dominance reading of the
**Watermelon detection rule** under [`channel-formats.md` § RAG Threshold
Standards](../comms-writer/references/channel-formats.md), which requires component-level RAGs to
roll up transparently to the project-level RAG; "worst component" is this platform's name for that
r

…(truncated)
