Portfolio Engineering Operations Skill
Overview
This skill provides reusable instructions for operating against a portfolio engineering REST API that exposes work items, mix targets, releases, milestones, SLA policies, blockers, and dependencies. It covers three common analytical workflows: portfolio mix review, SLA aging analysis, and release readiness assessment.
Environment
The environment is accessed at <TASK_ENV_BASE_URL>. All endpoints are relative to this base URL.
Authentication
For POST /api/query only, send the header:
X-Env-Token: portfolio-readonly
All GET endpoints are unauthenticated.
Available Endpoints
| Method |
Path |
Purpose |
| GET |
/api/work-items |
List all work items |
| GET |
/api/work-items/{item_id} |
Get a single work item by ID |
| GET |
/api/mix-targets |
List portfolio mix target percentages per scope |
| GET |
/api/sla-policy |
List SLA policy rules |
| GET |
/api/releases |
List all releases |
| GET |
/api/releases/{release_id} |
Get a single release by ID |
| GET |
/api/milestones |
List all milestones |
| GET |
/api/dependencies |
List work item dependency chains |
| GET |
/api/blockers |
List blocker records |
| POST |
/api/query |
Run a restricted SQL query (requires auth header) |
Domain Model
Work Items
Work items are the central entity. Each has:
- id: A unique string identifier (e.g.,
WI-24024-P001, WI-24024-075, WI-24024-S001)
- Type signals: A work item may have a
type field, label tags, and a title. These can conflict — use the portfolio category conventions (see below) to resolve conflicting signals.
- Status: open, closed, cancelled, etc. Only closed items count toward the closed portfolio mix.
- Team: The owning engineering team.
- Product area: The product area the work belongs to.
- Owner: The person assigned to the work item. May be empty/missing.
- Quarter: The quarter the work belongs to (e.g.,
2025-Q4).
- closed_at: Timestamp when the work item was closed.
- created_at: Timestamp when the work item was created.
- SLA-related fields: deadline, severity (S1-S4), aging days.
- Duplicate/primary relationship: A work item may be a duplicate pointing at a primary (canonical) record, or may itself be a primary record that duplicates reference.
- Mirror/export fields: Some work items contain stale mirror or export status fields. These should be ignored; always use the authoritative top-level status field.
Portfolio Categories
Every work item maps to exactly one of four portfolio categories:
| Category |
Description |
NewFeature |
New feature development |
TechDebt |
Technical debt reduction |
Reliability |
Reliability, resilience, and operational improvements |
Security |
Security hardening and vulnerability remediation |
Category Resolution Rules
When a work item has conflicting category signals (e.g., its type field says one thing but its labels or title suggest another), resolve using these conventions:
- Type field takes priority over labels and title hints.
- If the type field is ambiguous or absent, check labels next.
- If still ambiguous, inspect the title for category-indicating keywords.
- Known legacy categories or mirror-category fields are ignored — only the resolved category according to the above rules is authoritative.
Mix Targets
Mix target records map a scope_id to target percentage allocations across the four portfolio categories. Each target row contains:
scope_id: The scope identifier this target applies to.
- Target percentages for
NewFeature, TechDebt, Reliability, Security (summing to 100%).
Use the mix target row whose scope_id matches the task's scope.
Releases and Milestones
- Release: Has an ID (e.g.,
REL-ORION-2026-02), a set of associated milestones, and a list of assigned work item IDs.
- Milestone: Has an ID (e.g.,
MIL-ORION-BETA), belongs to a release, and has associated work item IDs. Milestones define gates within a release.
Blockers
Blocker records associate a work item ID with a cause string and an impact level. For release readiness:
- Only unresolved blockers matter.
- Only high-impact blockers are counted in
blocker_cause_counts.
- The exact cause string from the environment is the key — do not normalize or rewrite.
Dependencies
Dependency records define chains between work items. A dependency chain is an ordered list of work item IDs from a blocked release work item to the non-complete blocking dependency.
SLA Policy
SLA policy records define the maximum allowed aging days for work items, typically scoped by category and/or severity. Compare each work item's current aging days against the applicable SLA threshold to determine overdue status.
Common Conventions
Ordering
- Team names: Sort alphabetically (A-Z).
- Product area names: Sort alphabetically (A-Z).
- Work item ID lists: Sort lexicographically unless a different order is specified (e.g.,
closed_at ascending then ID ascending for included work items).
- Duplicate clusters: Sort by
primary_id lexicographically. Within each cluster, sort duplicate_ids lexicographically.
- Milestone completion: Sort by
milestone_id ascending (lexicographic).
- Gap table / mix table rows: Always in this fixed order:
NewFeature, TechDebt, Reliability, Security.
- Under-invested categories: Most negative gap to least negative gap (i.e., most under-invested first).
- Escalation queue: Ordered by severity priority (S1 first, then S2, S3, S4) and then by aging days descending within each severity tier.
Rounding and Precision
- Percentages (completion_pct, actual_pct, target_pct, gap_pct): Round to 1 decimal place. These are percentage points (not fractions), e.g.,
66.7 not 0.667.
- Rates and scores (breach_rate, readiness_score): Round to 3 decimal places. These are ratios in the range [0, 1], e.g.,
0.545.
- Gap: Always
actual_pct − target_pct. A negative gap means under-investment; a positive gap means over-investment.
Primary vs. Duplicate Records
- Primary records: Canonical work items that represent the real work. Counted in all metrics (mix, SLA, readiness).
- Duplicate records: Non-canonical work items that point to a primary record. Excluded from primary counts and metrics. Report them in
duplicate_clusters or excluded_duplicate_ids.
- When a duplicate references a primary, the primary ID is the cluster key. A primary may have zero or more duplicates pointing at it.
Exclusion Rules
The following records must be excluded from primary analysis:
| Exclusion Type |
Condition |
Reporting Location |
| Duplicate |
Record is a duplicate pointing to another primary |
excluded_duplicate_ids or duplicate_clusters |
| Cancelled |
Record status is cancelled |
excluded_cancelled_ids |
| Distractor |
Record matches scope (team/quarter/product area) but should not be counted as primary closed portfolio work (e.g., closed outside the quarter window, or has an invalid status for the analysis) |
excluded_distractor_ids |
| Mirror/legacy |
Stale mirror fields or legacy category fields exist on the record but should not influence classification |
ignored_mirror_status_and_legacy_category: true |
Stale Mirror Fields
Some work items carry mirror or export-level status and category fields that are out of sync with the authoritative fields. Always use the top-level status field as the source of truth. Do not use mirrored fields to determine status, category, or any other computed metric.
Workflow 1: Portfolio Mix Review
Use this workflow for Q4 portfolio mix readouts, closed-work mix reviews, and similar tasks that compare actual category distribution against target mix percentages.
Steps
Fetch mix targets: GET /api/mix-targets — locate the row with the matching scope_id. Record the target percentages for all four categories.
Fetch work items: GET /api/work-items — filter to in-scope items by quarter, team, and product area. Alternative: use POST /api/query for filtered retrieval.
Classify included items: For each closed work item in scope, resolve its portfolio category using the category resolution rules. Skip items that are duplicates, cancelled, or distractor records — log them in the exclusion lists.
Compute category counts: Count primary included work items per category.
Compute actual percentages: For each category, (count / total_included) × 100, rounded to 1 decimal place.
Compute gap table: For each category, gap_pct = actual_pct − target_pct (both rounded to 1 decimal place).
Identify under-invested categories: Categories with negative gap_pct, ordered from most negative to least negative.
Determine follow-up action:
- If any category has a negative gap:
REBALANCE_CAPACITY, with primary_category = the category with the largest negative gap and secondary_category = the next most negative (or null if none). rationale_code: LARGEST_NEGATIVE_GAP.
- If no negative gaps:
MAINTAIN_CURRENT_MIX, with null categories and rationale_code: NO_NEGATIVE_GAPS.
- If data conflicts prevent a clear determination:
INVESTIGATE_DATA_QUALITY with rationale_code: DATA_CONFLICT.
Assemble the JSON answer following the provided answer template schema.
Key Output Fields
scope: scope_id, quarter, teams (alphabetical), product_areas (alphabetical), target_scope_id, total_included
included_work_item_ids: primary closed work items; ordered by closed_at ascending, then ID ascending
category_counts: integer counts per category
category_percentages or mix_table: actual vs target percentages with gaps
under_invested_categories or largest_deficit_category: the most under-invested
follow_up_action or recommended_action: rebalance recommendation
exclusion_flags or excluded_distractor_ids: what was excluded and why
Workflow 2: SLA Aging Analysis
Use this workflow to audit SLA compliance, identify overdue work items, compute breach rates, and surface hotspots.
Steps
Fetch SLA policy: GET /api/sla-policy — understand the SLA thresholds by category and/or severity.
Fetch work items: GET /api/work-items — filter by team, category (Reliability and/or Security), and other scope constraints.
Separate primary from duplicate: Identify primary records (counted in SLA metrics) and duplicate clusters (reported but not counted).
Compute aging: For each primary work item, determine its current age in days (difference between as-of date and created_at, or as reported in an aging field). Items closed within the recent closed window are not overdue.
Determine overdue status: Compare each primary item's age against the applicable SLA threshold. An item is overdue if its age exceeds the SLA deadline.
Bucket aging distribution: Count primary items by age bucket (0-3, 4-7, 8-14, 15-30, 31+ days).
Compute team overdue counts: Group overdue primary items by team; list teams alphabetically.
Identify top hotspot: Find the (team, owner) pair with the most overdue primary records. If an owner is missing for an overdue item, treat the owner as UNASSIGNED for hotspot aggregation. If multiple pairs tie, the hotspot counts as the one found.
Identify missing owners: Primary included records with no owner assigned.
Compute breach rate: overdue_primary_count / included_primary_count, rounded to 3 decimal places.
Build escalation queue (when applicable): Order overdue primary items by severity (S1 first) then by aging days descending within each severity tier.
Key Output Fields
included_primary_ids: all primary work items in scope, sorted lexicographically
overdue_primary_ids: overdue primary items, sorted lexicographically
aging_bucket_counts: counts per age bucket
team_overdue_counts: per-team overdue counts, teams alphabetical
top_hotspot: team, owner, overdue_count
duplicate_clusters: primary_id → [duplicate_ids], sorted by primary_id
missing_owner_ids: primary items with no owner, sorted lexicographically
breach_rate or sla_breach_rate: ratio rounded to 3 decimal places
Workflow 3: Release Readiness Assessment
Use this workflow to assess whether a release is ready to ship based on milestone completion, blocker status, and dependency health.
Steps
Fetch release data: GET /api/releases/{release_id} — get the release, its milestone IDs, and its assigned work item IDs.
Fetch milestones: GET /api/milestones — get milestone completion data. For each milestone, identify which of its work items are complete (closed) and which are primary.
Compute milestone completion: For each milestone, completion_pct = (complete_primary / primary_total) × 100, rounded to 1 decimal place. Sort milestones by milestone_id ascending.
Identify gating work items: Primary release work items that are not complete. These block readiness. Sort ascending, no duplicates.
Fetch blockers: GET /api/blockers — filter to unresolved, high-impact blockers associated with the release's work items. Count by exact cause string. Do not normalize cause text.
Fetch dependencies: GET /api/dependencies — find chains from blocked release work items to non-complete dependencies. Each chain is an ordered list of work item IDs. Sort chains lexicographically by the full path.
Determine ship decision:
SHIP: All milestones substantially complete, zero gating items, no unresolved high-impact blockers, no critical dependencies.
SHIP_WITH_WATCH: Near-complete with minor open items or low-impact blockers only. Some risk but acceptable.
NO_SHIP: Significant incomplete milestones, unresolved high-impact blockers, or critical dependency chains exist.
Compute readiness score: completed_primary_work_items / total_primary_work_items, rounded to 3 decimal places.
Key Output Fields
release_id: the release under review
ship_decision: SHIP, SHIP_WITH_WATCH, or NO_SHIP
milestone_completion: per-milestone completion metrics sorted by milestone_id
gating_work_item_ids: non-complete work items blocking readiness
blocker_cause_counts: unresolved high-impact blocker counts by exact cause
critical_dependency_chains: ordered dependency paths
readiness_score: ratio rounded to 3 decimal places
Using POST /api/query
The POST /api/query endpoint accepts a restricted SQL query. Send a JSON body with the query, including the X-Env-Token: portfolio-readonly header. This is useful for:
- Filtering work items by multiple criteria (team, quarter, category, status)
- Aggregating counts and computing derived fields
- Joining work items with releases, milestones, or blockers
The SQL dialect and schema depend on the environment. Start with GET endpoints to understand the schema, then use POST /api/query for efficient filtered retrieval.
Error Handling and Edge Cases
- Missing data: If a required endpoint returns empty or an entity is not found, note it explicitly rather than guessing. A missing mix target means no gap analysis is possible.
- Zero denominators: When
total_included = 0, percentages are undefined. Report 0 counts and note the empty scope.
- Conflicting signals: When a work item's type, labels, and title disagree on category, apply the resolution rules consistently: type → labels → title, ignoring mirror fields.
- Duplicates referencing non-existent primaries: If a duplicate points to a primary not in the fetched work item set, still report the cluster — list the duplicate in
duplicate_ids and use the referenced primary ID as the cluster key.
- Multiple duplicates for the same primary: Group them under a single cluster entry.
- Ties in hotspot detection: Multiple (team, owner) pairs may have the same overdue count. Report the one encountered via the ordered traversal (teams alphabetically, then owners alphabetically).
Summary Checklist
Before submitting any answer:
- Classification: Every included work item has exactly one resolved portfolio category.
- Exclusions: Duplicates, cancelled, and distractor records are in the appropriate exclusion lists, not in the primary counts.
- Ordering: Teams alphabetical, IDs lexicographic (unless
closed_at ordering applies), gap/mix table rows in fixed category order.
- Rounding: Percentages to 1 decimal place, rates/scores to 3 decimal places.
- Mirror fields ignored: No metric depends on a stale mirror or legacy field.
- Schema compliance: The output JSON matches the provided answer template exactly — no extra fields, no missing required fields, correct enum values.
1---2name: fewshot-attempt-03-483description: Portfolio Engineering Operations Skill4---5# Portfolio Engineering Operations Skill67## Overview89This skill provides reusable instructions for operating against a portfolio engineering REST API that exposes work items, mix targets, releases, milestones, SLA policies, blockers, and dependencies. It covers three common analytical workflows: **portfolio mix review**, **SLA aging analysis**, and **release readiness assessment**.1011## Environment1213The environment is accessed at `<TASK_ENV_BASE_URL>`. All endpoints are relative to this base URL.1415### Authentication1617For `POST /api/query` only, send the header:1819```20X-Env-Token: portfolio-readonly21```2223All `GET` endpoints are unauthenticated.2425### Available Endpoints2627| Method | Path | Purpose |28|--------|------|---------|29| GET | `/api/work-items` | List all work items |30| GET | `/api/work-items/{item_id}` | Get a single work item by ID |31| GET | `/api/mix-targets` | List portfolio mix target percentages per scope |32| GET | `/api/sla-policy` | List SLA policy rules |33| GET | `/api/releases` | List all releases |34| GET | `/api/releases/{release_id}` | Get a single release by ID |35| GET | `/api/milestones` | List all milestones |36| GET | `/api/dependencies` | List work item dependency chains |37| GET | `/api/blockers` | List blocker records |38| POST | `/api/query` | Run a restricted SQL query (requires auth header) |3940## Domain Model4142### Work Items4344Work items are the central entity. Each has:4546- **id**: A unique string identifier (e.g., `WI-24024-P001`, `WI-24024-075`, `WI-24024-S001`)47- **Type signals**: A work item may have a `type` field, label tags, and a title. These can conflict — use the **portfolio category conventions** (see below) to resolve conflicting signals.48- **Status**: open, closed, cancelled, etc. Only **closed** items count toward the closed portfolio mix.49- **Team**: The owning engineering team.50- **Product area**: The product area the work belongs to.51- **Owner**: The person assigned to the work item. May be empty/missing.52- **Quarter**: The quarter the work belongs to (e.g., `2025-Q4`).53- **closed_at**: Timestamp when the work item was closed.54- **created_at**: Timestamp when the work item was created.55- **SLA-related fields**: deadline, severity (S1-S4), aging days.56- **Duplicate/primary relationship**: A work item may be a **duplicate** pointing at a **primary** (canonical) record, or may itself be a primary record that duplicates reference.57- **Mirror/export fields**: Some work items contain stale mirror or export status fields. These should be **ignored**; always use the authoritative top-level status field.5859### Portfolio Categories6061Every work item maps to exactly one of four portfolio categories:6263| Category | Description |64|----------|-------------|65| `NewFeature` | New feature development |66| `TechDebt` | Technical debt reduction |67| `Reliability` | Reliability, resilience, and operational improvements |68| `Security` | Security hardening and vulnerability remediation |6970#### Category Resolution Rules7172When a work item has conflicting category signals (e.g., its `type` field says one thing but its labels or title suggest another), resolve using these conventions:73741. **Type field** takes priority over labels and title hints.752. If the type field is ambiguous or absent, check **labels** next.763. If still ambiguous, inspect the **title** for category-indicating keywords.774. Known legacy categories or mirror-category fields are **ignored** — only the resolved category according to the above rules is authoritative.7879### Mix Targets8081Mix target records map a `scope_id` to target percentage allocations across the four portfolio categories. Each target row contains:8283- `scope_id`: The scope identifier this target applies to.84- Target percentages for `NewFeature`, `TechDebt`, `Reliability`, `Security` (summing to 100%).8586Use the mix target row whose `scope_id` matches the task's scope.8788### Releases and Milestones8990- **Release**: Has an ID (e.g., `REL-ORION-2026-02`), a set of associated milestones, and a list of assigned work item IDs.91- **Milestone**: Has an ID (e.g., `MIL-ORION-BETA`), belongs to a release, and has associated work item IDs. Milestones define gates within a release.9293### Blockers9495Blocker records associate a work item ID with a cause string and an impact level. For release readiness:9697- Only **unresolved** blockers matter.98- Only **high-impact** blockers are counted in `blocker_cause_counts`.99- The exact cause string from the environment is the key — do not normalize or rewrite.100101### Dependencies102103Dependency records define chains between work items. A dependency chain is an **ordered list** of work item IDs from a blocked release work item to the non-complete blocking dependency.104105### SLA Policy106107SLA policy records define the maximum allowed aging days for work items, typically scoped by category and/or severity. Compare each work item's current aging days against the applicable SLA threshold to determine overdue status.108109## Common Conventions110111### Ordering112113- **Team names**: Sort alphabetically (A-Z).114- **Product area names**: Sort alphabetically (A-Z).115- **Work item ID lists**: Sort lexicographically unless a different order is specified (e.g., `closed_at` ascending then ID ascending for included work items).116- **Duplicate clusters**: Sort by `primary_id` lexicographically. Within each cluster, sort `duplicate_ids` lexicographically.117- **Milestone completion**: Sort by `milestone_id` ascending (lexicographic).118- **Gap table / mix table rows**: Always in this fixed order: `NewFeature`, `TechDebt`, `Reliability`, `Security`.119- **Under-invested categories**: Most negative gap to least negative gap (i.e., most under-invested first).120- **Escalation queue**: Ordered by severity priority (S1 first, then S2, S3, S4) and then by aging days descending within each severity tier.121122### Rounding and Precision123124- **Percentages** (completion_pct, actual_pct, target_pct, gap_pct): Round to **1 decimal place**. These are percentage points (not fractions), e.g., `66.7` not `0.667`.125- **Rates and scores** (breach_rate, readiness_score): Round to **3 decimal places**. These are ratios in the range [0, 1], e.g., `0.545`.126- **Gap**: Always `actual_pct − target_pct`. A negative gap means under-investment; a positive gap means over-investment.127128### Primary vs. Duplicate Records129130- **Primary records**: Canonical work items that represent the real work. Counted in all metrics (mix, SLA, readiness).131- **Duplicate records**: Non-canonical work items that point to a primary record. **Excluded** from primary counts and metrics. Report them in `duplicate_clusters` or `excluded_duplicate_ids`.132- When a duplicate references a primary, the primary ID is the cluster key. A primary may have zero or more duplicates pointing at it.133134### Exclusion Rules135136The following records must be **excluded** from primary analysis:137138| Exclusion Type | Condition | Reporting Location |139|---------------|-----------|-------------------|140| Duplicate | Record is a duplicate pointing to another primary | `excluded_duplicate_ids` or `duplicate_clusters` |141| Cancelled | Record status is cancelled | `excluded_cancelled_ids` |142| Distractor | Record matches scope (team/quarter/product area) but should not be counted as primary closed portfolio work (e.g., closed outside the quarter window, or has an invalid status for the analysis) | `excluded_distractor_ids` |143| Mirror/legacy | Stale mirror fields or legacy category fields exist on the record but should not influence classification | `ignored_mirror_status_and_legacy_category: true` |144145### Stale Mirror Fields146147Some work items carry mirror or export-level status and category fields that are out of sync with the authoritative fields. Always use the **top-level status field** as the source of truth. Do not use mirrored fields to determine status, category, or any other computed metric.148149## Workflow 1: Portfolio Mix Review150151Use this workflow for Q4 portfolio mix readouts, closed-work mix reviews, and similar tasks that compare actual category distribution against target mix percentages.152153### Steps1541551. **Fetch mix targets**: `GET /api/mix-targets` — locate the row with the matching `scope_id`. Record the target percentages for all four categories.1561572. **Fetch work items**: `GET /api/work-items` — filter to in-scope items by quarter, team, and product area. Alternative: use `POST /api/query` for filtered retrieval.1581593. **Classify included items**: For each closed work item in scope, resolve its portfolio category using the category resolution rules. Skip items that are duplicates, cancelled, or distractor records — log them in the exclusion lists.1601614. **Compute category counts**: Count primary included work items per category.1621635. **Compute actual percentages**: For each category, `(count / total_included) × 100`, rounded to 1 decimal place.1641656. **Compute gap table**: For each category, `gap_pct = actual_pct − target_pct` (both rounded to 1 decimal place).1661677. **Identify under-invested categories**: Categories with negative `gap_pct`, ordered from most negative to least negative.1681698. **Determine follow-up action**:170 - If any category has a negative gap: `REBALANCE_CAPACITY`, with `primary_category` = the category with the largest negative gap and `secondary_category` = the next most negative (or `null` if none). `rationale_code`: `LARGEST_NEGATIVE_GAP`.171 - If no negative gaps: `MAINTAIN_CURRENT_MIX`, with `null` categories and `rationale_code`: `NO_NEGATIVE_GAPS`.172 - If data conflicts prevent a clear determination: `INVESTIGATE_DATA_QUALITY` with `rationale_code`: `DATA_CONFLICT`.1731749. **Assemble the JSON answer** following the provided answer template schema.175176### Key Output Fields177178- `scope`: scope_id, quarter, teams (alphabetical), product_areas (alphabetical), target_scope_id, total_included179- `included_work_item_ids`: primary closed work items; ordered by `closed_at` ascending, then ID ascending180- `category_counts`: integer counts per category181- `category_percentages` or `mix_table`: actual vs target percentages with gaps182- `under_invested_categories` or `largest_deficit_category`: the most under-invested183- `follow_up_action` or `recommended_action`: rebalance recommendation184- `exclusion_flags` or `excluded_distractor_ids`: what was excluded and why185186## Workflow 2: SLA Aging Analysis187188Use this workflow to audit SLA compliance, identify overdue work items, compute breach rates, and surface hotspots.189190### Steps1911921. **Fetch SLA policy**: `GET /api/sla-policy` — understand the SLA thresholds by category and/or severity.1931942. **Fetch work items**: `GET /api/work-items` — filter by team, category (Reliability and/or Security), and other scope constraints.1951963. **Separate primary from duplicate**: Identify primary records (counted in SLA metrics) and duplicate clusters (reported but not counted).1971984. **Compute aging**: For each primary work item, determine its current age in days (difference between as-of date and `created_at`, or as reported in an aging field). Items closed within the recent closed window are not overdue.1992005. **Determine overdue status**: Compare each primary item's age against the applicable SLA threshold. An item is overdue if its age exceeds the SLA deadline.2012026. **Bucket aging distribution**: Count primary items by age bucket (0-3, 4-7, 8-14, 15-30, 31+ days).2032047. **Compute team overdue counts**: Group overdue primary items by team; list teams alphabetically.2052068. **Identify top hotspot**: Find the (team, owner) pair with the most overdue primary records. If an owner is missing for an overdue item, treat the owner as `UNASSIGNED` for hotspot aggregation. If multiple pairs tie, the hotspot counts as the one found.2072089. **Identify missing owners**: Primary included records with no owner assigned.20921010. **Compute breach rate**: `overdue_primary_count / included_primary_count`, rounded to 3 decimal places.21121211. **Build escalation queue** (when applicable): Order overdue primary items by severity (S1 first) then by aging days descending within each severity tier.213214### Key Output Fields215216- `included_primary_ids`: all primary work items in scope, sorted lexicographically217- `overdue_primary_ids`: overdue primary items, sorted lexicographically218- `aging_bucket_counts`: counts per age bucket219- `team_overdue_counts`: per-team overdue counts, teams alphabetical220- `top_hotspot`: team, owner, overdue_count221- `duplicate_clusters`: primary_id → [duplicate_ids], sorted by primary_id222- `missing_owner_ids`: primary items with no owner, sorted lexicographically223- `breach_rate` or `sla_breach_rate`: ratio rounded to 3 decimal places224225## Workflow 3: Release Readiness Assessment226227Use this workflow to assess whether a release is ready to ship based on milestone completion, blocker status, and dependency health.228229### Steps2302311. **Fetch release data**: `GET /api/releases/{release_id}` — get the release, its milestone IDs, and its assigned work item IDs.2322332. **Fetch milestones**: `GET /api/milestones` — get milestone completion data. For each milestone, identify which of its work items are complete (closed) and which are primary.2342353. **Compute milestone completion**: For each milestone, `completion_pct = (complete_primary / primary_total) × 100`, rounded to 1 decimal place. Sort milestones by `milestone_id` ascending.2362374. **Identify gating work items**: Primary release work items that are **not complete**. These block readiness. Sort ascending, no duplicates.2382395. **Fetch blockers**: `GET /api/blockers` — filter to unresolved, high-impact blockers associated with the release's work items. Count by exact cause string. Do not normalize cause text.2402416. **Fetch dependencies**: `GET /api/dependencies` — find chains from blocked release work items to non-complete dependencies. Each chain is an ordered list of work item IDs. Sort chains lexicographically by the full path.2422437. **Determine ship decision**:244 - `SHIP`: All milestones substantially complete, zero gating items, no unresolved high-impact blockers, no critical dependencies.245 - `SHIP_WITH_WATCH`: Near-complete with minor open items or low-impact blockers only. Some risk but acceptable.246 - `NO_SHIP`: Significant incomplete milestones, unresolved high-impact blockers, or critical dependency chains exist.2472488. **Compute readiness score**: `completed_primary_work_items / total_primary_work_items`, rounded to 3 decimal places.249250### Key Output Fields251252- `release_id`: the release under review253- `ship_decision`: SHIP, SHIP_WITH_WATCH, or NO_SHIP254- `milestone_completion`: per-milestone completion metrics sorted by milestone_id255- `gating_work_item_ids`: non-complete work items blocking readiness256- `blocker_cause_counts`: unresolved high-impact blocker counts by exact cause257- `critical_dependency_chains`: ordered dependency paths258- `readiness_score`: ratio rounded to 3 decimal places259260## Using POST /api/query261262The `POST /api/query` endpoint accepts a restricted SQL query. Send a JSON body with the query, including the `X-Env-Token: portfolio-readonly` header. This is useful for:263264- Filtering work items by multiple criteria (team, quarter, category, status)265- Aggregating counts and computing derived fields266- Joining work items with releases, milestones, or blockers267268The SQL dialect and schema depend on the environment. Start with `GET` endpoints to understand the schema, then use `POST /api/query` for efficient filtered retrieval.269270## Error Handling and Edge Cases271272- **Missing data**: If a required endpoint returns empty or an entity is not found, note it explicitly rather than guessing. A missing mix target means no gap analysis is possible.273- **Zero denominators**: When `total_included = 0`, percentages are undefined. Report 0 counts and note the empty scope.274- **Conflicting signals**: When a work item's type, labels, and title disagree on category, apply the resolution rules consistently: type → labels → title, ignoring mirror fields.275- **Duplicates referencing non-existent primaries**: If a duplicate points to a primary not in the fetched work item set, still report the cluster — list the duplicate in `duplicate_ids` and use the referenced primary ID as the cluster key.276- **Multiple duplicates for the same primary**: Group them under a single cluster entry.277- **Ties in hotspot detection**: Multiple (team, owner) pairs may have the same overdue count. Report the one encountered via the ordered traversal (teams alphabetically, then owners alphabetically).278279## Summary Checklist280281Before submitting any answer:2822831. **Classification**: Every included work item has exactly one resolved portfolio category.2842. **Exclusions**: Duplicates, cancelled, and distractor records are in the appropriate exclusion lists, not in the primary counts.2853. **Ordering**: Teams alphabetical, IDs lexicographic (unless `closed_at` ordering applies), gap/mix table rows in fixed category order.2864. **Rounding**: Percentages to 1 decimal place, rates/scores to 3 decimal places.2875. **Mirror fields ignored**: No metric depends on a stale mirror or legacy field.2886. **Schema compliance**: The output JSON matches the provided answer template exactly — no extra fields, no missing required fields, correct enum values.