Engineering Portfolio Review
Reusable procedure for tasks that ask you to analyze an engineering work-item
portfolio against the shared "portfolio" environment and return one JSON object
matching a provided answer_template.json.
When to use
Use this skill when a task points you at a shared environment reached via
environment_access.md and asks for a single JSON answer over work-item data.
Three review archetypes live here (a task is one of them):
- Portfolio-mix review — classify closed work into 4 categories, compare the actual count-based mix to a target mix, report gaps, under-invested categories, and a rebalance action.
- SLA aging / breach audit — over reliability & security work: find overdue primary items, aging buckets, owner/team hotspots, duplicate clusters, missing owners, and the breach rate.
- Release-readiness assessment — ship decision, milestone completion, gating work items, unresolved high-impact blocker causes, critical dependency chains, and a readiness score.
If the task gives you input/payloads/answer_template.json and says "return only
a JSON object" over this environment, you are in the right place.
Environment access — read environment_access.md every time
environment_access.md (staged alongside the task input) contains
GDPEVO_ENV_BASE_URL, the X-Env-Token header value, and the allowed endpoint
list. Rules:
- Send the
X-Env-Tokenheader on every request. - Do not hardcode the URL or token, and do not use any other access path —
environment_access.mdis the only authorized way to reach the environment. - Typed GET endpoints:
/api/work-items,/api/work-items/{id},/api/mix-targets,/api/sla-policy,/api/releases,/api/releases/{id},/api/milestones,/api/dependencies,/api/blockers. - SQL endpoint:
POST /api/querywith JSON body{"sql": "<read-only SELECT>"}. Returns{columns, row_count, rows (array of arrays), truncated}. Use it for joins, filters, and aggregations across the 7 tables. Iftruncatedis true, re-query with a tighterWHERE/LIMIT.PRAGMAis not supported — inspect a table's columns viaSELECT * FROM <t> LIMIT 1or the matching GET endpoint. - Full table/field schema and categorical value spaces: see
references/data_model.md.
Core correctness rules (apply to every archetype)
These rules are what separate a correct answer from a plausible one. They follow directly from the data model.
Authoritative fields only. Use the
statusfield as truth; ignoremirror_status.mirror_statusis a stale mirror/export field that frequently disagrees withstatus(it may readDone/Complete/Openwhen the authoritative status isCancelled/Verified/In Progress). When a prompt says "do not use stale mirror fields" or "use authoritative fields," it means this.Ignore
legacy_category. It is a deprecated free-text category (bug,feature,security,tech-debt, …) that conflicts with reality. Resolve the portfolio category yourself per rule 4. Several templates make this explicit with anignored_mirror_status_and_legacy_category: trueflag.Primary vs duplicate. A record is a duplicate when
status == "Duplicate"ORduplicate_ofis non-null.duplicate_ofholds the canonical primary id. Count primaries only in every count, total, denominator, and rate. Report duplicates (grouped by theirduplicate_ofprimary) in the answer's duplicate-cluster / exclusion lists — never in the counts. A duplicate can still carry a terminalstatus(e.g.status: "Closed"withduplicate_ofset); theduplicate_offield decides, not the status.Cancelled excluded. Records with
status == "Cancelled"are out of the primary population; report them in an exclusion list if the template has one. Theirmirror_statusmay misleadingly readDone.Closed / complete status set. Treat
{Closed, Done, Deployed, Verified}as terminal (closed/complete). Non-terminal:Backlog,In Progress,Review,Reopened. (CancelledandDuplicateare excluded per rules 3–4.) This is the observed terminal set; confirm it against the prompt's wording.Portfolio category resolution (4 categories:
NewFeature,TechDebt,Reliability,Security). Scanwork_type+labels+title(case-insensitive) for keyword signals, then assign by precedence Security > Reliability > TechDebt > NewFeature (first match wins;NewFeatureis the default when nothing matches).Category Keyword signals (in work_type / labels / title) Security security,cve,encryption,authReliability reliability,outage,latency,flaky,incidentTechDebt refactor,cleanup,migration,tech-debtNewFeature feature,rollout,enhancement(also the default)Trust structured
labels/work_typesignals over a title's narrative — a title like "...with stale security label" does not nullify an actualsecuritylabel. Do not uselegacy_category.Stable ordering (templates enforce these):
- ID lists: ascending / lexicographic.
- Teams: alphabetical (unless the template pins a specific order).
- Category tables (
gap_table/mix_table): rows in the orderNewFeature, TechDebt, Reliability, Security. - Duplicate clusters: sorted by
primary_id; each cluster'sduplicate_idssorted ascending. - Dependency chains: sorted lexicographically by the full path.
milestone_completion: sorted bymilestone_idascending.included_work_item_ids(portfolio): ordered byclosed_atascending, thenidascending.
Rounding.
- Percentages (
actual_pct,target_pct,gap_pct,completion_pct): 1 decimal place. - Rates (
breach_rate,sla_breach_rate,readiness_score): exactly 3 decimal places. gap_pct = actual_pct − target_pct.target_pctcomes frommix_targetspercentage fractions × 100 (the table stores a fraction like0.25, not the percentage25.0).
- Percentages (
Output format. Return exactly one JSON object matching
input/payloads/answer_template.json. RespectadditionalProperties: falseand therequiredlist. Useconst/enumvalues verbatim. No prose outside the JSON. Field sets differ between templates — e.g. some portfolio templates split exclusions into separateexcluded_duplicate_idsandexcluded_cancelled_idsflags, while others merge them into oneexcluded_distractor_idslist. Follow the given template, not a remembered shape.
General procedure
- Parse the prompt. Identify the archetype and the scope: teams,
product_area(s), quarter,
scope_id/ targetscope_id,as_ofdate,recent_closed_window_days, categories, and/orrelease_id. - Read
environment_access.mdfor the base URL, token, and endpoint list. - Read
input/payloads/answer_template.jsonand lock the exact output schema before computing anything. - Fetch the data you need (GET endpoints or SQL). See
references/data_model.mdfor table/field semantics. - Apply scope filters + the core rules (primary/duplicate, cancelled, closed/complete set, category resolution).
- Compute the archetype metrics — see
references/archetypes.mdfor the per-archetype playbook, including the verified formulas (overdue, aging, readiness, gating, escalation order). - Assemble the JSON per the template; verify ordering, rounding, and required fields; emit only the JSON.
Archetype playbooks
Step-by-step per archetype live in references/archetypes.md:
- A. Portfolio-mix review — mix vs target, gaps, under-invested categories, rebalance action, exclusion flags.
- B. SLA aging / breach audit —
overdue = as_of > due_at, aging buckets, owner/team hotspot, duplicate clusters, missing owners, breach rate, escalation queue. - C. Release-readiness assessment — ship decision, milestone completion, gating items, blocker-cause counts, dependency chains, readiness score.
Common pitfalls
- Using
mirror_statusinstead ofstatus→ wrong population and wrong overdue/complete calls. - Counting duplicates in totals/rates → inflated counts (duplicates point at a primary; the primary is already counted).
- Letting
legacy_categoryor a title's "stale" wording override reallabels/work_typesignals → wrong category. - Forgetting that
Cancelledrecords are excluded. - Mis-keying
mix_targets: the target row is selected byscope_id(named in the prompt), and its*_pctfields are fractions (×100 for percentage points). - Averaging milestone percentages for
readiness_score— it is the pooled ratiosum(complete_primary) / sum(primary_total), not a mean. - Adding fields the template does not allow, or omitting required ones.
- Emitting prose alongside the JSON.