Portfolio In-Flight Triage
Implements the audit half of spec/portfolio/portfolio-inflight-management/ as a Claude Code skill in the nolte-shared plugin. Single operation: periodic, on-demand cross-repository inspection that surfaces stalled in-flight work (open issues, open PRs, branches without active PR, unresolved review-comment threads, open Discussions) across every nolte Portfolio-Member repository, classifies each finding through the four-axis severity matrix, attaches a recommended specialist (skill or agent slug) per finding, and persists a dispatch-ready Findings-Report under .audits/portfolio-inflight/<YYYY-MM-DD>.md.
Why this is a skill, not an agent
- Mid-flow user confirmation on threshold overrides and roster-gap escalations. Two interactive checkpoints are load-bearing: confirming that a Portfolio-Member's
project/inflight.yml per-repo threshold override should be honoured over the spec default (operator sees default + override side-by-side), and confirming the upgrade of a roster-gap finding to "author a new specialist" when the 3-recurrence threshold from continuous-improvement §Portfolio gap closure triggers. An agent's fire-and-forget shape would lose those checkpoints.
- Persistent on-disk artefact as deliverable. The audit writes
.audits/portfolio-inflight/<YYYY-MM-DD>.md in claude-shared. Skills own persistent on-disk state; agents return structured reports into the caller's context but don't own write paths.
- Context-window-protective data collection via agent. The audit delegates raw per-repository data collection to the
portfolio-inflight-collector agent, which fetches the four primary data sources via read-only gh api calls and returns a pre-reduced structured per-repository summary. Raw issue / PR / branch / review-comment / discussion bodies never enter the orchestrating conversation, matching the §Findings-Report shape MUST NOT clause on raw-body inclusion.
- Skill-orchestrates-agent-executes is the explicit spec rule. §Audit operation requires
MUST be implemented as a dedicated skill … MUST NOT be implemented as a Claude Agent and MUST dispatch a read-only specialist agent portfolio-inflight-collector for per-repository data-source collection. The spec pins the hybrid pattern here verbatim; this skill is the orchestrator half.
- Counter-dimension considered: a tool-restricted agent could cleanly perform classification and matrix-axis derivation in isolation, given that the data-collection volume is already handled by the collector agent. The decisive counter is the two mid-flow user-confirmation gates and the persistent on-disk write target — both are skill-side per
spec/claude/skill-vs-agent/.
Follows the same orchestrator pattern as portfolio-audit (which dispatches portfolio-manifest-collector).
User-language policy
Detect the user's language and respond in it. The Findings-Report under .audits/portfolio-inflight/ follows the conventions of spec/claude/review-plan/: section headings (## Scope, ## Summary, ## Findings, ## Processing log) stay English so downstream tooling can grep them deterministically; the body may be written in the user's language. Finding identifiers (<repo>/<source>/<id>), matrix-axis names (security_relevance, release_blocking, age_multiplier, cross_repo_blocking), severities (Critical / Warning / Suggestion / Info), and bracketed spec citations ([portfolio-inflight-management §...]) stay English verbatim regardless of conversation language.
Detection: am I in the right repository?
This skill writes its single output artefact (.audits/portfolio-inflight/<YYYY-MM-DD>.md) inside the claude-shared repository, the same repository that hosts .audits/portfolio/ for portfolio-audit. Detection: presence of .claude-plugin/plugin.json AND a spec/portfolio/portfolio-inflight-management/ directory.
When invoked inside any other Portfolio-Member repository (the typical adopter), stop and route the operator to claude-shared for the audit — the Findings-Report write path lives there, matching the §Audit operation SHOULD and mirroring portfolio-audit's detection rule. Don't try to write the report into the active checkout.
Operations
1. Run
Runs the cross-repository in-flight audit per spec/portfolio/portfolio-inflight-management/ §Audit operation. End-to-end produces one Findings-Report under .audits/portfolio-inflight/<YYYY-MM-DD>.md.
Detect Portfolio-Member set per §Portfolio scope MUST — reuse the portfolio-management resolution. Either dispatch portfolio-manifest-collector (Agent) when the active conversation hasn't already collected the set, or instruct portfolio-inflight-collector to resolve fresh via gh api orgs/nolte/repos --paginate (it applies the same archived: false / private: false / portfolio: excluded filters). Record portfolio: excluded and per-source inflight: skip-<source> markers as Info-grade entries so omissions stay inspectable.
Dispatch the collector — invoke portfolio-inflight-collector (Agent) with the resolved list, all four data sources enabled, and release-drafter draft collection enabled (needed for the release_blocking matrix axis). Wait for its structured collection report. Per §Findings-Report shape MUST NOT, raw issue / PR / branch / review-comment / discussion bodies never enter this conversation — the agent reduces to a structured summary and discards bodies before returning.
Fetch overrides and confirm — gate (one). For every repository whose collector report carries inflight.yml override present: yes, parse the verbatim YAML from inflight.yml raw content. Present the spec defaults (Issue 30d, PR 7d/14d/14d/conflict, Branch 30d, Review-comment 7d, Discussion 30d) and the per-repo override side-by-side; ask the operator whether to honour the override for this run. Record the decision in ## Processing log. Repositories without overrides use the spec defaults silently.
Apply stalling thresholds per §Stalling thresholds using the per-repository thresholds confirmed in step 3:
- Issue: open longer than
issue.maxAge (default 30 days), no priority label, no assignee, no maintainer comment in issue.maxQuietWindow (default 30 days). Per §Stalling thresholds MUST NOT, first drop any issue whose collector author is renovate[bot], dependabot[bot], or github-actions[bot] from the issue/stalled-issue-no-triage class (permanent bot dashboards, not triage signal); branch/stalled-branch-no-pr stays in scope regardless of authorship.
- Pull request: open longer than
pr.maxAgeRedChecks (default 7d) with red required checks, OR pr.maxAgeDraft (default 14d) as draft, OR pr.maxAgeNoReview (default 14d) with no reviewer activity, OR mergeable: CONFLICTING against develop (no threshold for the conflict driver — conflicts block merge regardless of age, per §Stalling thresholds MUST).
- Branch without active PR:
daysSinceLastPush > branch.maxAge (default 30d).
- Unresolved review comment:
daysSinceLastComment > reviewComment.maxAge (default 7d) with no maintainer reply.
- Discussion:
daysOpen > discussion.maxAge (default 30d) with daysSinceLastMaintainerReply == "never" or beyond the same window.
Sub-threshold items are excluded per §Stalling thresholds MUST NOT. A Critical finding may still surface a sub-threshold item when another matrix axis demands it per §Stalling thresholds SHOULD.
Derive the four matrix axes per §Classification and prioritisation for every stalled item. Read references/matrix-axes-and-report.md when running this step — it carries the detection MUSTs for all four axes.
Classify into the canonical four severities (Critical / Warning / Suggestion / Info) per §Classification and prioritisation and spec/claude/review-plan/ §Severity scale. Read references/matrix-axes-and-report.md when running this step — it carries the per-severity mapping and the higher-severity tie-break.
Attach a recommended specialist per §Specialist recommendation to every finding:
- Match the catalog. Read every
description line across all catalog roots (skills/*/SKILL.md, agents/*.md, plugins/*/skills/*/SKILL.md, plugins/*/agents/*.md); name the matching slug verbatim (for example dependency-audit, workflow-health-triage, feature-decompose, pull-request-merge, vocab-drift-audit).
- Red-check exclusivity. When a PR finding's only driver is a red required check (
requiredChecksState: FAILURE), name workflow-health-triage; MUST NOT route the same red-check driver to any other specialist. Other drivers of the same PR (stale draft, unresolved review comments, conflicts) MAY produce additional findings with their own specialists; the exclusivity is per-driver, not per-PR.
- Slash-command verbatim. When the recommended action targets a specific PR / branch / issue, include the slash-command invocation verbatim plus the target identifier (for example
/nolte-shared:pull-request-merge against PR #142). Operator dispatches by copy-paste; the skill never auto-dispatches.
- Roster-gap recording. When no matching specialist exists, record a
Suggestion-grade finding tagged with a stable lowercase snake-case <finding-class-token> (the unmatched specialist slug when one would naturally apply, otherwise a descriptive token like discussion_no_maintainer_reply).
- Recurrence counting and gate (two). For every roster-gap finding,
Glob the prior .audits/portfolio-inflight/*.md and Read the lexicographically last one. Count occurrences of <data-source>/<finding-class-token> across that prior artefact plus the current run. When the count reaches 3 (per spec/project/continuous-improvement/ §Portfolio gap closure), trigger User-confirmation gate (two): ask whether to escalate the recommendation to "author a new specialist <proposed-slug>". Record the decision in ## Processing log. When no prior artefact exists, recurrence is the in-run count only.
Pre-write confirmation — gate (three). Before any file write, present the per-severity finding counts (Critical: <n>, Warning: <n>, Suggestion: <n>, Info: <n>) plus the per-repository counts (top 5 + total). Ask Write Findings-Report to .audits/portfolio-inflight/<YYYY-MM-DD>.md with these counts? [yes / show-findings / abort]. On show-findings, render the full per-severity list inline and re-ask. On abort, stop. On yes, proceed.
Write the Findings-Report at .audits/portfolio-inflight/<YYYY-MM-DD>.md in the claude-shared repository, conforming to spec/claude/review-plan/. Read references/matrix-axes-and-report.md when running this step — it carries the frontmatter, the four required sections, the structure rules, and the per-finding format.
Confirm in the user's language — the path of the new Findings-Report, the per-severity counts, the count of roster-gap findings (if any), and the next step (open the report and triage Critical items first via the recommended slash commands; route roster-gap escalations through continuous-improvement-triage).
The Run operation is observational per §Operator authority: it never mutates any Portfolio-Member and writes only .audits/portfolio-inflight/<YYYY-MM-DD>.md in claude-shared (see Hard rules).
Reference: spec anchors
This skill implements spec/portfolio/portfolio-inflight-management/; read it when in doubt. Sections touched:
- §Portfolio scope, §Data sources, §Stalling thresholds, §Classification and prioritisation, §Specialist recommendation, §Audit operation, §Findings-Report shape, §Integration with continuous-improvement, §Operator authority.
Also touches spec/claude/review-plan/ (the artefact frame) and spec/project/continuous-improvement/ (§Specialist dispatch, §Portfolio gap closure — the matching pattern and 3-recurrence rule in step 7).
When the spec disagrees with this skill, the spec wins. Propose a skill update rather than silently diverging.
Examples
- Read
examples/01-stalled-pr-with-red-checks.md when triaging an audit finding for a PR whose only driver is a red required check (the workflow-health-triage exclusivity routing applies).
- Read
examples/02-release-blocker-detection.md when an open PR carries a release-blocker label or its head SHA appears in an open release-drafter draft (the release_blocking matrix-axis detection MUSTs apply).
- Read
examples/03-roster-gap-3-recurrence.md when a finding class without a matching specialist crosses the 3-recurrence threshold from the prior audit artefact (the "author a new specialist" escalation user-confirmation gate applies).
- Read
examples/04-security-relevance-lifts-to-critical.md when a finding touches a security-sensitive surface and the security_relevance axis lifts its severity to Critical.
- Read
examples/05-cross-repo-blocking-lifts-to-critical.md when a project/roadmap.md / project/sprints/*.md cross-reference makes an item block another repo and the cross_repo_blocking axis lifts it to Critical.
- Read
examples/06-zero-findings-run.md when the in-flight surface is empty and the run still writes a valid zero-findings report rather than short-circuiting.
Gotchas
- The Findings-Report write path lives in
claude-shared, not in the calling repo. Writing .audits/portfolio-inflight/ from a non-claude-shared working directory is a structural error; confirm cwd resolves to the claude-shared checkout (see §Detection) before any write in step 9.
cross_repo_blocking detection is exact-string only. The project/roadmap.md / project/sprints/*.md scan looks for the literal short cross-reference (nolte/<repo>#<number>) or the full GitHub URL. Don't infer from titles, branch names, or partial SHAs — per §Classification and prioritisation MUST the scan is read-only text matching at the snapshot, no fuzzy matching.
release-drafter-draft head-SHA membership requires the collector's draft list. When the collector report lacks the Open release-drafter drafts block, only the release-blocker label signal applies for release_blocking — don't fetch drafts inline; the collector owns every gh api call per §Audit operation.
- Threshold-override confirmation happens once per audit, not per-finding. Step 3 surfaces each repository's
project/inflight.yml override once; the confirmed thresholds apply to every finding from that repository in step 4. Re-prompting per-finding would be operator-hostile and isn't what the user-confirmation gate is for.
- Recurrence counts the most recent prior
.audits/portfolio-inflight/*.md plus the current run. The step-7 3-recurrence escalation walks only the immediately previous artefact, not older ones; with no prior artefact, recurrence is the in-run count only per §Specialist recommendation MUST.
- Bot-authored dashboards are out of the stalled-issue class. Per the 2026-07-24 in-flight audit's gate-2 decision (recorded in #445 / #468 and
.audits/portfolio-inflight/2026-07-24.md) and §Stalling thresholds MUST NOT, step 4 drops renovate[bot] / dependabot[bot] / github-actions[bot] issues from issue/stalled-issue-no-triage; branch/stalled-branch-no-pr is unaffected — a stale branch is a one-line disposition, not a dashboard.
gh api rate limits scale with N repos × M open PRs. The collector prechecks headroom (its §Preconditions step 2), but a full run still eats a non-trivial slice of the hourly budget; check gh api rate_limit before back-to-back audits. Tooling (optional GitHub MCP): the collector's four data-source reads are MCP-preferred with a gh fallback (spec/claude/mcp-tool-preference/); gh api rate_limit stays gh (OQ-D).
- An empty in-flight surface still produces a Findings-Report. Per the spec's S-7 acceptance criterion, zero stalled items across the portfolio produces a valid Findings-Report with zero findings under each severity rather than no report at all. Step 9 always writes, never short-circuits on emptiness.
Hard rules
- Never close any GitHub issue, merge any PR, delete any branch, mark any review comment resolved, or close any Discussion. The audit is observational only per §Operator authority.
- Never invoke
gh api with -X POST, -X PATCH, or -X DELETE against any repository — including claude-shared. The underlying agent enforces this at the harness level; the skill also doesn't issue such calls per §Operator authority.
- Never modify any file in any Portfolio-Member repository other than
claude-shared. The single write path is .audits/portfolio-inflight/<YYYY-MM-DD>.md per §Operator authority.
- Never dispatch the recommended specialist automatically. Emit the slash-command invocation verbatim in the report; the operator dispatches by copy-paste per §Specialist recommendation
MUST NOT and §Operator authority MUST.
- Never use a severity outside the canonical four (
Critical / Warning / Suggestion / Info). ALL-CAPS variants and extra levels (HIGH, P0, …) are forbidden per spec/claude/review-plan/ §Severity scale and §Classification and prioritisation MUST NOT.
- Never invent matrix-axis values without the detection signals named in §Classification and prioritisation.
release_blocking requires the label or the release-drafter-draft head-SHA membership; cross_repo_blocking requires the exact-string cross-reference scan; security_relevance requires a CVE / supply-chain / leaked-credential indicator. No inference or fuzzy matching.
- Never scan repositories outside the resolved Portfolio-Member set, even when the operator names another
nolte/<other> repository, per §Portfolio scope MUST NOT. Scope expansion happens via portfolio-management, never ad-hoc.
- Never include raw issue / PR / branch / review-comment / discussion bodies in the Findings-Report per §Findings-Report shape
MUST NOT. The audit reduces every finding to a structured summary; verbatim source bodies stay in GitHub, reachable via the finding identifier.
- Never bypass the three user-confirmation gates: threshold-override honour (step 3), roster-gap 3-recurrence escalation (step 7), and pre-write per-severity-counts confirmation (step 8). The interactive checkpoints are the spec's reason this is a skill rather than an agent; bypassing them undermines
spec/claude/skill-vs-agent/.
- Never invoke the Skill tool from this skill's body during the data-collection or classification phase — the collector dispatch is an Agent invocation, not a Skill invocation. Calling another skill sequentially (for example
continuous-improvement-triage to route the report) is allowed and matches the spec/claude/skill-vs-agent/ hybrid-pattern SHOULD on chaining.
- When
spec/portfolio/portfolio-inflight-management/ disagrees with this skill, the spec wins. Propose updating this skill rather than silently diverging.
Resumability
Per spec/claude/resumable-work/, this skill is resumable: true. State is persisted to .resume/portfolio-inflight-triage/<run-id>.yml after every successful user-approval gate (threshold-override honour in step 3, roster-gap escalation in step 7, pre-write confirmation in step 8) and after each named phase boundary (collector dispatch complete, classification complete). On re-invocation, scan that directory for files with status: in_progress whose inputs: snapshot matches the current invocation; if one matches, prompt the operator with Resume run <run_id> from phase <phase> (last checkpoint <last_checkpoint_at>)? [resume / start-new / discard]. The state-file envelope (schema_version, run_id, inputs, phase, decisions[], status, …) and the fail-closed semantics on schema or YAML errors are load-bearing in the spec; don't duplicate those rules here.
1---2name: portfolio-inflight-triage3description: Runs the read-only periodic in-flight audit across nolte/* per `spec/portfolio/portfolio-inflight-management/`. Dispatches `portfolio-inflight-collector` for the four data sources (open issues, open PRs incl. drafts, branches without active PR, unresolved review threads + Discussions), applies spec stalling thresholds with optional `project/inflight.yml` overrides, classifies findings via the four-axis matrix into `Critical`/`Warning`/`Suggestion`/`Info`, attaches a specialist slug per finding, and writes a dated Findings-Report under `.audits/portfolio-inflight/`. Invoke when the user asks to "audit the portfolio in-flight", "run the in-flight triage", "check stalled PRs / issues / branches", or equivalent German-language requests. Don't use to merge / close / delete / resolve anything (operator dispatches), for per-repo CI triage (use `workflow-health-triage`), or for capability allocation (`portfolio-audit`). Supports resume on re-invocation per `spec/claude/resumable-work/`.4---56# Portfolio In-Flight Triage78Implements the audit half of `spec/portfolio/portfolio-inflight-management/` as a Claude Code skill in the `nolte-shared` plugin. Single operation: periodic, on-demand cross-repository inspection that surfaces stalled in-flight work (open issues, open PRs, branches without active PR, unresolved review-comment threads, open Discussions) across every nolte Portfolio-Member repository, classifies each finding through the four-axis severity matrix, attaches a recommended specialist (skill or agent slug) per finding, and persists a dispatch-ready Findings-Report under `.audits/portfolio-inflight/<YYYY-MM-DD>.md`.910## Why this is a skill, not an agent1112- **Mid-flow user confirmation on threshold overrides and roster-gap escalations.** Two interactive checkpoints are load-bearing: confirming that a Portfolio-Member's `project/inflight.yml` per-repo threshold override should be honoured over the spec default (operator sees default + override side-by-side), and confirming the upgrade of a roster-gap finding to "author a new specialist" when the 3-recurrence threshold from `continuous-improvement §Portfolio gap closure` triggers. An agent's fire-and-forget shape would lose those checkpoints.13- **Persistent on-disk artefact as deliverable.** The audit writes `.audits/portfolio-inflight/<YYYY-MM-DD>.md` in `claude-shared`. Skills own persistent on-disk state; agents return structured reports into the caller's context but don't own write paths.14- **Context-window-protective data collection via agent.** The audit delegates raw per-repository data collection to the `portfolio-inflight-collector` agent, which fetches the four primary data sources via read-only `gh api` calls and returns a pre-reduced structured per-repository summary. Raw issue / PR / branch / review-comment / discussion bodies never enter the orchestrating conversation, matching the §Findings-Report shape `MUST NOT` clause on raw-body inclusion.15- **Skill-orchestrates-agent-executes is the explicit spec rule.** §Audit operation requires `MUST be implemented as a dedicated skill … MUST NOT be implemented as a Claude Agent` and `MUST dispatch a read-only specialist agent portfolio-inflight-collector for per-repository data-source collection`. The spec pins the hybrid pattern here verbatim; this skill is the orchestrator half.16- **Counter-dimension considered:** a tool-restricted agent could cleanly perform classification and matrix-axis derivation in isolation, given that the data-collection volume is already handled by the collector agent. The decisive counter is the two mid-flow user-confirmation gates and the persistent on-disk write target — both are skill-side per `spec/claude/skill-vs-agent/`.1718Follows the same orchestrator pattern as `portfolio-audit` (which dispatches `portfolio-manifest-collector`).1920## User-language policy2122Detect the user's language and respond in it. The Findings-Report under `.audits/portfolio-inflight/` follows the conventions of `spec/claude/review-plan/`: section headings (`## Scope`, `## Summary`, `## Findings`, `## Processing log`) stay English so downstream tooling can grep them deterministically; the body may be written in the user's language. Finding identifiers (`<repo>/<source>/<id>`), matrix-axis names (`security_relevance`, `release_blocking`, `age_multiplier`, `cross_repo_blocking`), severities (`Critical` / `Warning` / `Suggestion` / `Info`), and bracketed spec citations (`[portfolio-inflight-management §...]`) stay English verbatim regardless of conversation language.2324## Detection: am I in the right repository?2526This skill writes its single output artefact (`.audits/portfolio-inflight/<YYYY-MM-DD>.md`) inside the `claude-shared` repository, the same repository that hosts `.audits/portfolio/` for `portfolio-audit`. Detection: presence of `.claude-plugin/plugin.json` AND a `spec/portfolio/portfolio-inflight-management/` directory.2728When invoked inside any other Portfolio-Member repository (the typical adopter), stop and route the operator to `claude-shared` for the audit — the Findings-Report write path lives there, matching the §Audit operation `SHOULD` and mirroring `portfolio-audit`'s detection rule. Don't try to write the report into the active checkout.2930## Operations3132### 1. Run3334Runs the cross-repository in-flight audit per `spec/portfolio/portfolio-inflight-management/` §Audit operation. End-to-end produces one Findings-Report under `.audits/portfolio-inflight/<YYYY-MM-DD>.md`.35361. **Detect Portfolio-Member set** per §Portfolio scope `MUST` — reuse the `portfolio-management` resolution. Either dispatch `portfolio-manifest-collector` (Agent) when the active conversation hasn't already collected the set, or instruct `portfolio-inflight-collector` to resolve fresh via `gh api orgs/nolte/repos --paginate` (it applies the same `archived: false` / `private: false` / `portfolio: excluded` filters). Record `portfolio: excluded` and per-source `inflight: skip-<source>` markers as `Info`-grade entries so omissions stay inspectable.37382. **Dispatch the collector** — invoke `portfolio-inflight-collector` (Agent) with the resolved list, all four data sources enabled, and `release-drafter` draft collection enabled (needed for the `release_blocking` matrix axis). Wait for its structured collection report. Per §Findings-Report shape `MUST NOT`, raw issue / PR / branch / review-comment / discussion bodies never enter this conversation — the agent reduces to a structured summary and discards bodies before returning.39403. **Fetch overrides and confirm — gate (one).** For every repository whose collector report carries `inflight.yml override present: yes`, parse the verbatim YAML from `inflight.yml raw content`. Present the spec defaults (Issue 30d, PR 7d/14d/14d/conflict, Branch 30d, Review-comment 7d, Discussion 30d) and the per-repo override side-by-side; ask the operator whether to honour the override for this run. Record the decision in `## Processing log`. Repositories without overrides use the spec defaults silently.41424. **Apply stalling thresholds** per §Stalling thresholds using the per-repository thresholds confirmed in step 3:43 - **Issue**: open longer than `issue.maxAge` (default 30 days), no priority label, no assignee, no maintainer comment in `issue.maxQuietWindow` (default 30 days). Per §Stalling thresholds `MUST NOT`, first drop any issue whose collector `author` is `renovate[bot]`, `dependabot[bot]`, or `github-actions[bot]` from the `issue/stalled-issue-no-triage` class (permanent bot dashboards, not triage signal); `branch/stalled-branch-no-pr` stays in scope regardless of authorship.44 - **Pull request**: open longer than `pr.maxAgeRedChecks` (default 7d) with red required checks, OR `pr.maxAgeDraft` (default 14d) as draft, OR `pr.maxAgeNoReview` (default 14d) with no reviewer activity, OR `mergeable: CONFLICTING` against `develop` (no threshold for the conflict driver — conflicts block merge regardless of age, per §Stalling thresholds `MUST`).45 - **Branch without active PR**: `daysSinceLastPush > branch.maxAge` (default 30d).46 - **Unresolved review comment**: `daysSinceLastComment > reviewComment.maxAge` (default 7d) with no maintainer reply.47 - **Discussion**: `daysOpen > discussion.maxAge` (default 30d) with `daysSinceLastMaintainerReply == "never"` or beyond the same window.48 Sub-threshold items are excluded per §Stalling thresholds `MUST NOT`. A `Critical` finding may still surface a sub-threshold item when another matrix axis demands it per §Stalling thresholds `SHOULD`.49505. **Derive the four matrix axes** per §Classification and prioritisation for every stalled item. Read `references/matrix-axes-and-report.md` when running this step — it carries the detection MUSTs for all four axes.51526. **Classify into the canonical four severities** (`Critical` / `Warning` / `Suggestion` / `Info`) per §Classification and prioritisation and `spec/claude/review-plan/` §Severity scale. Read `references/matrix-axes-and-report.md` when running this step — it carries the per-severity mapping and the higher-severity tie-break.53547. **Attach a recommended specialist** per §Specialist recommendation to every finding:55 - **Match the catalog.** Read every `description` line across all catalog roots (`skills/*/SKILL.md`, `agents/*.md`, `plugins/*/skills/*/SKILL.md`, `plugins/*/agents/*.md`); name the matching slug verbatim (for example `dependency-audit`, `workflow-health-triage`, `feature-decompose`, `pull-request-merge`, `vocab-drift-audit`).56 - **Red-check exclusivity.** When a PR finding's only driver is a red required check (`requiredChecksState: FAILURE`), name `workflow-health-triage`; **MUST NOT** route the same red-check driver to any other specialist. Other drivers of the same PR (stale draft, unresolved review comments, conflicts) **MAY** produce additional findings with their own specialists; the exclusivity is per-driver, not per-PR.57 - **Slash-command verbatim.** When the recommended action targets a specific PR / branch / issue, include the slash-command invocation verbatim plus the target identifier (for example `/nolte-shared:pull-request-merge against PR #142`). Operator dispatches by copy-paste; the skill never auto-dispatches.58 - **Roster-gap recording.** When no matching specialist exists, record a `Suggestion`-grade finding tagged with a stable lowercase snake-case `<finding-class-token>` (the unmatched specialist slug when one would naturally apply, otherwise a descriptive token like `discussion_no_maintainer_reply`).59 - **Recurrence counting and gate (two).** For every roster-gap finding, `Glob` the prior `.audits/portfolio-inflight/*.md` and `Read` the lexicographically last one. Count occurrences of `<data-source>/<finding-class-token>` across that prior artefact plus the current run. When the count reaches 3 (per `spec/project/continuous-improvement/` §Portfolio gap closure), trigger **User-confirmation gate (two):** ask whether to escalate the recommendation to "author a new specialist `<proposed-slug>`". Record the decision in `## Processing log`. When no prior artefact exists, recurrence is the in-run count only.60618. **Pre-write confirmation — gate (three).** Before any file write, present the per-severity finding counts (`Critical: <n>, Warning: <n>, Suggestion: <n>, Info: <n>`) plus the per-repository counts (top 5 + total). Ask `Write Findings-Report to .audits/portfolio-inflight/<YYYY-MM-DD>.md with these counts? [yes / show-findings / abort]`. On `show-findings`, render the full per-severity list inline and re-ask. On `abort`, stop. On `yes`, proceed.62639. **Write the Findings-Report** at `.audits/portfolio-inflight/<YYYY-MM-DD>.md` in the `claude-shared` repository, conforming to `spec/claude/review-plan/`. Read `references/matrix-axes-and-report.md` when running this step — it carries the frontmatter, the four required sections, the structure rules, and the per-finding format.646510. **Confirm in the user's language** — the path of the new Findings-Report, the per-severity counts, the count of roster-gap findings (if any), and the next step (open the report and triage `Critical` items first via the recommended slash commands; route roster-gap escalations through `continuous-improvement-triage`).6667The Run operation is observational per §Operator authority: it never mutates any Portfolio-Member and writes only `.audits/portfolio-inflight/<YYYY-MM-DD>.md` in `claude-shared` (see Hard rules).6869## Reference: spec anchors7071This skill implements `spec/portfolio/portfolio-inflight-management/`; read it when in doubt. Sections touched:7273- §Portfolio scope, §Data sources, §Stalling thresholds, §Classification and prioritisation, §Specialist recommendation, §Audit operation, §Findings-Report shape, §Integration with continuous-improvement, §Operator authority.7475Also touches `spec/claude/review-plan/` (the artefact frame) and `spec/project/continuous-improvement/` (§Specialist dispatch, §Portfolio gap closure — the matching pattern and 3-recurrence rule in step 7).7677When the spec disagrees with this skill, the spec wins. Propose a skill update rather than silently diverging.7879## Examples8081- Read `examples/01-stalled-pr-with-red-checks.md` when triaging an audit finding for a PR whose only driver is a red required check (the `workflow-health-triage` exclusivity routing applies).82- Read `examples/02-release-blocker-detection.md` when an open PR carries a `release-blocker` label or its head SHA appears in an open `release-drafter` draft (the `release_blocking` matrix-axis detection MUSTs apply).83- Read `examples/03-roster-gap-3-recurrence.md` when a finding class without a matching specialist crosses the 3-recurrence threshold from the prior audit artefact (the "author a new specialist" escalation user-confirmation gate applies).84- Read `examples/04-security-relevance-lifts-to-critical.md` when a finding touches a security-sensitive surface and the `security_relevance` axis lifts its severity to Critical.85- Read `examples/05-cross-repo-blocking-lifts-to-critical.md` when a `project/roadmap.md` / `project/sprints/*.md` cross-reference makes an item block another repo and the `cross_repo_blocking` axis lifts it to Critical.86- Read `examples/06-zero-findings-run.md` when the in-flight surface is empty and the run still writes a valid zero-findings report rather than short-circuiting.8788## Gotchas8990- **The Findings-Report write path lives in `claude-shared`, not in the calling repo.** Writing `.audits/portfolio-inflight/` from a non-`claude-shared` working directory is a structural error; confirm `cwd` resolves to the `claude-shared` checkout (see §Detection) before any write in step 9.91- **`cross_repo_blocking` detection is exact-string only.** The `project/roadmap.md` / `project/sprints/*.md` scan looks for the literal short cross-reference (`nolte/<repo>#<number>`) or the full GitHub URL. Don't infer from titles, branch names, or partial SHAs — per §Classification and prioritisation `MUST` the scan is read-only text matching at the snapshot, no fuzzy matching.92- **`release-drafter`-draft head-SHA membership requires the collector's draft list.** When the collector report lacks the `Open release-drafter drafts` block, only the `release-blocker` label signal applies for `release_blocking` — don't fetch drafts inline; the collector owns every `gh api` call per §Audit operation.93- **Threshold-override confirmation happens once per audit, not per-finding.** Step 3 surfaces each repository's `project/inflight.yml` override once; the confirmed thresholds apply to every finding from that repository in step 4. Re-prompting per-finding would be operator-hostile and isn't what the user-confirmation gate is for.94- **Recurrence counts the most recent prior `.audits/portfolio-inflight/*.md` plus the current run.** The step-7 3-recurrence escalation walks only the immediately previous artefact, not older ones; with no prior artefact, recurrence is the in-run count only per §Specialist recommendation `MUST`.95- **Bot-authored dashboards are out of the stalled-issue class.** Per the 2026-07-24 in-flight audit's gate-2 decision (recorded in #445 / #468 and `.audits/portfolio-inflight/2026-07-24.md`) and §Stalling thresholds `MUST NOT`, step 4 drops `renovate[bot]` / `dependabot[bot]` / `github-actions[bot]` issues from `issue/stalled-issue-no-triage`; `branch/stalled-branch-no-pr` is unaffected — a stale branch is a one-line disposition, not a dashboard.96- **`gh api` rate limits scale with N repos × M open PRs.** The collector prechecks headroom (its §Preconditions step 2), but a full run still eats a non-trivial slice of the hourly budget; check `gh api rate_limit` before back-to-back audits. **Tooling (optional GitHub MCP):** the collector's four data-source reads are MCP-preferred with a `gh` fallback (`spec/claude/mcp-tool-preference/`); `gh api rate_limit` stays `gh` (OQ-D).97- **An empty in-flight surface still produces a Findings-Report.** Per the spec's S-7 acceptance criterion, zero stalled items across the portfolio produces a valid Findings-Report with zero findings under each severity rather than no report at all. Step 9 always writes, never short-circuits on emptiness.9899## Hard rules100101- Never close any GitHub issue, merge any PR, delete any branch, mark any review comment resolved, or close any Discussion. The audit is observational only per §Operator authority.102- Never invoke `gh api` with `-X POST`, `-X PATCH`, or `-X DELETE` against any repository — including `claude-shared`. The underlying agent enforces this at the harness level; the skill also doesn't issue such calls per §Operator authority.103- Never modify any file in any Portfolio-Member repository other than `claude-shared`. The single write path is `.audits/portfolio-inflight/<YYYY-MM-DD>.md` per §Operator authority.104- Never dispatch the recommended specialist automatically. Emit the slash-command invocation verbatim in the report; the operator dispatches by copy-paste per §Specialist recommendation `MUST NOT` and §Operator authority `MUST`.105- Never use a severity outside the canonical four (`Critical` / `Warning` / `Suggestion` / `Info`). ALL-CAPS variants and extra levels (`HIGH`, `P0`, …) are forbidden per `spec/claude/review-plan/` §Severity scale and §Classification and prioritisation `MUST NOT`.106- Never invent matrix-axis values without the detection signals named in §Classification and prioritisation. `release_blocking` requires the label or the `release-drafter`-draft head-SHA membership; `cross_repo_blocking` requires the exact-string cross-reference scan; `security_relevance` requires a CVE / supply-chain / leaked-credential indicator. No inference or fuzzy matching.107- Never scan repositories outside the resolved Portfolio-Member set, even when the operator names another `nolte/<other>` repository, per §Portfolio scope `MUST NOT`. Scope expansion happens via `portfolio-management`, never ad-hoc.108- Never include raw issue / PR / branch / review-comment / discussion bodies in the Findings-Report per §Findings-Report shape `MUST NOT`. The audit reduces every finding to a structured summary; verbatim source bodies stay in GitHub, reachable via the finding identifier.109- Never bypass the three user-confirmation gates: threshold-override honour (step 3), roster-gap 3-recurrence escalation (step 7), and pre-write per-severity-counts confirmation (step 8). The interactive checkpoints are the spec's reason this is a skill rather than an agent; bypassing them undermines `spec/claude/skill-vs-agent/`.110- Never invoke the Skill tool from this skill's body during the data-collection or classification phase — the collector dispatch is an Agent invocation, not a Skill invocation. Calling another skill sequentially (for example `continuous-improvement-triage` to route the report) is allowed and matches the `spec/claude/skill-vs-agent/` hybrid-pattern `SHOULD` on chaining.111- When `spec/portfolio/portfolio-inflight-management/` disagrees with this skill, the spec wins. Propose updating this skill rather than silently diverging.112113## Resumability114115Per `spec/claude/resumable-work/`, this skill is `resumable: true`. State is persisted to `.resume/portfolio-inflight-triage/<run-id>.yml` after every successful user-approval gate (threshold-override honour in step 3, roster-gap escalation in step 7, pre-write confirmation in step 8) and after each named phase boundary (collector dispatch complete, classification complete). On re-invocation, scan that directory for files with `status: in_progress` whose `inputs:` snapshot matches the current invocation; if one matches, prompt the operator with `Resume run <run_id> from phase <phase> (last checkpoint <last_checkpoint_at>)? [resume / start-new / discard]`. The state-file envelope (`schema_version`, `run_id`, `inputs`, `phase`, `decisions[]`, `status`, …) and the fail-closed semantics on schema or YAML errors are load-bearing in the spec; don't duplicate those rules here.