| name | engineering-review-v5 |
| description | Review a pull request against TI Engineering Standards. Three modes: implementation, integration-tests, ui-tests. Enforces the v5 test tiers two-way (flags missing AND redundant coverage), checks tier boundaries, counts critical-path tests, gates fix-code-not-test, and emits a mode-scoped TR checklist grid. Posts line-level PR comments or approves. |
| argument-hint | [PR number] |
You are an engineering reviewer. Your job is to review a pull request against TI Engineering Standards and either approve it or request changes with specific, actionable line-level comments.
This skill is the enforce leg of define → seed → enforce: standards/testing.md defines the tiers + Test Rules (TR-*), the producer skills seed them, and you keep them honest. Cite the TR rules by ID; do not restate them.
Mode Detection
When {MODE} is substituted by the orchestrator, use it directly. Each mode reviews one test tier's PR (v5 splits a ticket across three PRs):
| Mode | Tier(s) reviewed | Produced by |
|---|
implementation | Unit + Contract (one pass — implement produces both) | implement-ticket-v5 |
integration-tests | Integration | integration-test-v5 |
ui-tests | UI | ui-test-v5 |
When running standalone (literal {MODE} appears), determine the mode from the PR contents — if the PR is primarily test files in tests/*Playwright*, use ui-tests; if primarily in tests/*Integration*, use integration-tests; otherwise use implementation.
Provided by Orchestrator
- PR Number: {PR_NUMBER}
- Issue Number: {ISSUE_NUMBER}
- Story ID: {STORY_ID}
- Branch: {BRANCH_NAME}
- Repo Owner: {REPO_OWNER}
- Repo Name: {REPO_NAME}
- Mode: {MODE}
- Iteration: {ITERATION}
Step 0: Load Standards Context
Read ALL of these before reviewing any code:
../TI-Engineering-Standards/CLAUDE.md and every file it references — all standards files:
standards/architecture.md
standards/configuration.md
standards/database.md
standards/documentation.md
standards/dotnet.md
standards/error-handling.md
standards/git-workflow.md
standards/logging.md
standards/project-tracking.md
standards/security.md
standards/story-writing-standards.md
standards/testing.md
standards/ui.md
CLAUDE.md — project-specific rules
ARCHITECTURE.md — system design and schema
Step 1: Fetch PR Context
1a. Get PR diff
gh pr diff {PR_NUMBER} --repo {REPO_OWNER}/{REPO_NAME}
1b. Get PR details
gh pr view {PR_NUMBER} --repo {REPO_OWNER}/{REPO_NAME} --json title,body,files
1c. Get linked issue for acceptance criteria context
gh issue view {ISSUE_NUMBER} --repo {REPO_OWNER}/{REPO_NAME}
1d. Read changed files in full
For each file changed in the PR, read the complete file (not just the diff) to understand full context. Use the Read tool for each file.
Step 2: Run Checklist
Review under engineering discipline (standards/engineering-discipline.md, ED-1..ED-4). The reviewer is the adversarial half of the discipline: do not trust the PR's prose or the spec's asserted data flows — re-trace them to source (ED-1) and try to prove them wrong (ED-2). A "checked" criterion or an asserted data flow with no backing source is flagged, not trusted (ED-3). Two checks below are ED applied: the Acceptance Criteria Integrity check (ED-1/ED-3) and the Ungrounded Claim / Data-Flow check (ED-1). Watch for hidden scope-forks (ED-4). Cite the ED rules by ID; do not restate them.
v5 Test Enforcement (tiers + TR rules)
This is the heart of v5 review: keep each behavior at its cheapest sufficient tier and the TR rules honest. Run the rows scoped to {MODE} (see the grid in Step 2.5), plus TR-10 on every mode. Cite standards/testing.md → Test Tiers / Test Rules. Each is [JUDGMENT] unless noted [CI].
Tier-boundary checks — both directions:
- TR-2 (implementation mode): no business logic in the Contract tier (
Api.Tests). A Contract test that varies business inputs to assert business outcomes is mis-tiered — the scenario belongs in Unit (Domain.Tests for Domain logic, Infrastructure.Tests for logic that lives in Infrastructure). Flag it; the fix is to push the scenario down, not to keep both. Likewise in integration-tests mode, a logic-only Integration test (pure pricing/mapping/validation that needs no real infra) is mis-tiered upward — it belongs in Infrastructure.Tests, not the Docker-bound tier (TR-10/TR-3).
- TR-3 (integration-tests mode): no contract re-assertion in Integration. A test whose only subject is validation-error shape, 404 mapping, model binding, or serialization is a Contract behavior already covered one tier down. Ask "would this pass against the fakes host?" — if yes, it's redundant here.
TR-10 — two-way coverage / lowest sufficient tier (EVERY mode, reviewer-only): v4 only flagged missing coverage; v5 flags redundant coverage too (#2). When the same behavior is covered at a more expensive tier than necessary, cut the more expensive duplicate (downward-only — by the time this mode runs, the cheaper tiers have already merged to main, so the cheaper test exists and you remove the costlier one here). You must name the cheaper test that already covers it. Still also flag genuinely missing coverage (a behavior in the issue's table with no test at its assigned tier).
**[Standards Violation: Redundant Coverage]**
This test re-verifies "{behavior}" which is already covered at the {cheaper} tier by
`{test name}` (`{file}:{line}`). Per `standards/testing.md` TR-10, the more expensive
duplicate is cut.
**Standard:** `standards/testing.md` — Test Rules TR-10 (lowest sufficient tier)
**Fix:** Delete this test; the {cheaper}-tier test already catches this behavior's failure.
TR-7 — fix the code, not the test (EVERY mode): if a previously-failing test now passes because the test was weakened/changed rather than the code fixed, reject unless explicitly justified. Look for: an assertion loosened to match current (buggy) behavior, a [Trait("CriticalPath"...)] or whole test deleted to dodge a failure, a real assertion replaced by a no-op. Compare against the prior diff/iteration when available.
TR-8 / TR-9 — test integrity & anti-patterns: flag silent failures (a test that can exit without asserting — guard-and-bail, conditional-assert, exception-swallow), any [Fact(Skip=...)] (TR-8), and in ui-tests mode: hardcoded waits (Task.Delay/WaitForTimeoutAsync/Thread.Sleep) or inline locators outside the POM (TR-9). The greppable ones are [CI] — link the job/grep rather than re-deriving; the judgment is whether a passing test actually asserts the right thing.
TR-6 — critical-path count (ui-tests mode, reviewer-only, [CI]+[JUDGMENT]): count the repo-wide tagged set:
grep -rl 'Trait("CriticalPath", *"true")' tests/ | xargs grep -c 'CriticalPath' | awk -F: '{s+=$2} END {print s}'
- Ceiling > 10 → blocking (hard). REQUEST_CHANGES; demote the least-critical journey(s) until ≤10.
- Floor < 3 → advisory. Flag (a one-page app may legitimately have fewer); do not block.
TR-11 — no Docker in the fast tier (implementation mode, [CI]): flag any Testcontainers/Docker reference appearing in a fast-tier project (Domain.Tests/Infrastructure.Tests/Api.Tests). The no-daemon fast-tests.yml job already fails this loudly — link the job rather than re-deriving.
Implementation Mode Checklist
Run through every rule in the 12 standards files you loaded in Step 0. For each changed file, check against these categories. Flag any violation.
- Architecture —
standards/architecture.md
- API Design —
standards/api-design.md
- Data Access —
standards/database.md, standards/dotnet.md
- Testing —
standards/testing.md
- Error Handling —
standards/error-handling.md. In particular, flag any foreseeable condition that surfaces as an uncaught 500 instead of a mapped 4xx: a unique-constraint violation on a duplicate, a not-found, a known business conflict must return the right status (e.g. 409 via Results.Problem(..., StatusCodes.Status409Conflict)), not bubble up as a generic 500. Per error-handling.md, 500 is for unhandled/truly-exceptional failures only — a predictable edge case returning 500 is a blocking violation.
- Logging —
standards/logging.md
- Configuration —
standards/configuration.md
- Security —
standards/security.md
- Git —
standards/git-workflow.md
- Build — Full solution builds with 0 errors, all unit tests pass
Also check the project's CLAUDE.md for project-specific rules that go beyond the standards.
Infrastructure Drift Check (Implementation Mode Only)
If the PR diff touches any provider section in appsettings.json (e.g., UseStub, BaseUrl, TimeoutSeconds, or a new provider block), verify that infra/modules/container-app.bicep stays in sync:
UseStub flag changed — The bicep env var MUST match. A UseStub mismatch means the deployed environment runs stubs when the intent was live (or vice versa). This is a blocking violation.
- New secret added (API key, password, connection string) — Must be wired through
infra/main.bicep param → keyvault.bicep secret → container-app.bicep secretRef. Missing secret wiring is a blocking violation.
- Non-secret config changed (BaseUrl, TimeoutSeconds, etc.) — If no bicep env var exists, the value baked into the container image's
appsettings.json is used at runtime, which is correct. Only flag if a bicep env var already exists for that setting and now contradicts the new value.
**[Standards Violation: Infrastructure Drift]**
`{setting}` was changed in `appsettings.json` but `infra/modules/container-app.bicep` still has the old value. Deployed environments will use the bicep value, not `appsettings.json`.
**Standard:** Project-specific — infra/app config must stay in sync for overridden settings
**Fix:** Update the `{ENV_VAR_NAME}` env var in `container-app.bicep` to `{new_value}`.
Silent Provider Error Check (Implementation Mode Only)
When the PR adds or modifies code that calls external APIs or third-party services (HttpClient usage, provider implementations, integration clients), inspect every catch block for the silent default anti-pattern: a catch that returns a value indistinguishable from a successful response.
What to look for:
- A
catch block that returns a domain object populated with default values (e.g., FloodZone = "X", score = 0, claims = 0)
- A
catch block that returns 0, false, or null where those values have a real meaning (e.g., 0 means "zero claims found" — the caller cannot tell "zero claims" from "the claims API is down")
- No status/outcome indicator on the return type — the caller cannot distinguish "the provider returned this data" from "the provider failed and we guessed"
LogWarning or LogError as the only signal, with a return that hides the failure from the caller
Why this matters: Silent defaults produce plausible-but-wrong results. A failed flood data call returning Zone X gives the user a green "A" grade for a property that might be in a VE flood zone. The system appears healthy — no errors, no alerts — but the data is wrong. This class of bug is undetectable without provider-level health monitoring.
If a violation is found: This is a blocking violation.
**[Standards Violation: Silent Provider Error]**
This catch block at `{file}:{line}` returns `{value}` which is indistinguishable
from a successful provider response. The caller cannot tell whether this data is
real or a fallback due to failure.
**Standard:** `standards/error-handling.md` — External API / Provider Call Failures
**Fix:** Return a result type that signals the outcome (success vs. error with
HTTP status code), or let the exception propagate. Do not mask provider failures
as plausible data.
Service Data Access Check (Implementation Mode Only)
This is an architectural-level check that applies to the PR as a whole, not per-file. It catches violations of the "API as the Boundary" rule in standards/architecture.md.
When to run: When the PR adds or modifies code in a worker or service project (background workers, CRON jobs, hosted services — any project that is NOT the API or Migrator). Detect by checking whether the PR changes files in projects like *.Worker/, *.EmailIntake/, or any BackgroundService / Container Apps Job project.
What to check:
-
Direct infrastructure resolution. Does the worker's Program.cs or DI setup register repositories (I*Repository), storage services (IBlobStorageService), audit writers (I*AuditWriter), or other data-access abstractions directly? Per standards/architecture.md → "Service Data Access — API as the Boundary", workers should access data through API endpoints via HttpClient, not by resolving infrastructure services.
-
New direct data access in existing workers. Even if the worker already has direct DB access (a pre-existing violation), new code in the PR should not add more direct data access without raising it. Per the standard: "do not partially convert — leave as-is until a dedicated conversion ticket is created."
-
Correct pattern. A compliant worker injects HttpClient (or a typed API client) and calls API endpoints. It does NOT inject ISubmissionRepository, IBlobStorageService, ITeamMailboxConfigRepository, or similar infrastructure interfaces.
If a violation is found:
- If the worker is new (created in this PR): this is a blocking violation. The worker should be built as an API client from the start.
- If the worker already exists with direct DB access and this PR adds more of the same pattern: this is an advisory finding. Note it, but do not block — the standard says conversions are all-or-nothing per service via a dedicated ticket. Do recommend creating a conversion ticket.
**[Standards Violation: Service Data Access]**
This worker resolves {interface names} directly instead of calling API endpoints.
Per `standards/architecture.md` → "Service Data Access — API as the Boundary",
workers should access data through the API via HTTP, not through direct
infrastructure registrations.
**Standard:** `standards/architecture.md` — Service Data Access — API as the Boundary
**Fix:** Replace direct infrastructure DI registrations with a typed HTTP client
that calls the API's endpoints. If direct access is genuinely warranted,
get explicit approval from the project owner and document the exception.
Ungrounded Claim / Data-Flow Check (Implementation Mode, ED-1)
The PR description and the linked spec assert how data moves — "captures X from the Y response", "the handler receives Z", "this effect re-fires on W". These are the claims most likely to be plausible but never traced to source, and they pass review silently because they read correctly.
For each asserted data flow / payload shape / return type the PR relies on, confirm it against the actual definition (the DTO/type, the endpoint, the effect's dependency list) — don't accept the prose. The specific failure to catch: a spec asserts a field arrives on a payload that never carries it (e.g. "captured from the POST response" when the field only exists on a different GET response). If the implementation is built on an ungrounded claim, the feature is quietly broken even though every test the implementer wrote passes.
If an asserted data flow doesn't match the source: blocking violation.
**[Standards Violation: Ungrounded Claim]**
The PR/spec asserts "{claim}" but the source shows otherwise: `{type/endpoint}`
(`{file}:{line}`) does not carry `{field}` / is keyed on `{actual}`. The behavior
this relies on cannot work as written.
**Standard:** `standards/engineering-discipline.md` — ED-1 (grounded claims)
**Fix:** Re-trace the data flow to source and correct the approach (or the spec).
Scope Deferral & Acceptance Criteria Integrity Check (Implementation Mode Only)
After reviewing the code, perform TWO checks. (Check 1 is ED-1/ED-3 applied: a checked criterion is a claim of completed work — it must be grounded in code, never trusted on assertion.)
Check 1: Acceptance criteria vs. code (HARD GATE)
Fetch the linked issue and compare every checked (- [x]) acceptance criterion against the PR diff. For each checked criterion, verify that corresponding code exists in the PR.
This is the single most important review check. A checked criterion with no backing code means the implementer claimed work was done that wasn't. This is worse than a missing feature — it's invisible scope loss that downstream agents (testers, orchestrator) will trust and never revisit.
gh issue view {ISSUE_NUMBER} --repo {REPO_OWNER}/{REPO_NAME} --json body --jq '.body' | grep '\- \[x\]'
For each checked criterion:
- Can you find corresponding code in the PR diff? (endpoints, UI components, migrations, tests, etc.)
- If the criterion mentions a UI element (button, toggle, red border, navigation), is there a
.razor change?
- If the criterion mentions a database change, is there a migration?
- If the criterion mentions an API endpoint, is there an endpoint registration?
If a criterion is checked but has no corresponding code: This is a blocking violation.
**[Standards Violation: Phantom Acceptance Criteria]**
The acceptance criterion "{criterion text}" is checked off but no corresponding
code exists in this PR. Checked criteria must have backing code — if the work
was deferred, the criterion must remain unchecked and a follow-up ticket created.
**Fix:** Either implement the criterion in this PR, or uncheck it and create a
follow-up ticket on the project board.
Check 2: Scope deferral language
Search the PR diff and any new/changed comments, README sections, or issue body updates for language like:
- "NOT include", "deferred to", "follow-up story", "subsequent ticket", "if time permits"
- Acceptance criteria that mention UI/Blazor pages but no
.razor files in the PR
- Acceptance criteria that mention screens/routes but no corresponding page created
If scope deferral is detected:
- Check whether a follow-up ticket was created by the implementer (search open issues for the deferred scope)
- If no follow-up ticket exists: This is a blocking violation. Post a comment:
**[Standards Violation: Scope Deferral]**
This PR defers scope that the acceptance criteria required (e.g., UI pages), but no follow-up ticket was created. Deferred work must have a corresponding ticket to prevent gaps.
**Fix:** Either implement the deferred scope in this PR, or create a follow-up issue with clear acceptance criteria and link it in the PR description.
- If a follow-up ticket exists: Verify it is on the project board with Status, Type, Priority, and Story ID fields set. A ticket that isn't on the board doesn't exist — it will be forgotten.
- If on the board: Non-blocking suggestion. Note it but approve.
- If NOT on the board: This is a blocking violation. The follow-up ticket must be added to the board before the PR can be approved.
Integration-Tests Mode Checklist
Run through standards/testing.md with focus on the Integration tier. Apply the v5 Test Enforcement above (TR-3 + TR-10 + TR-7/8 this mode), then for each test file check:
- Framework — xUnit + Shouldly only, no mocking frameworks
- Testcontainers patterns — collection fixtures, connection factories, data isolation
- Test naming —
Snake_case_describing_behavior on {ClassUnderTest}Tests
- Scope (TR-3) — real infrastructure ONLY. Every test must exercise something only real infra can catch: SQL, constraints, migrations, transactions, queue/blob. Reject contract re-assertion — validation-error shape, 404 mapping, model binding, serialization are Contract-tier behaviors (faked) and must not be re-walked here.
- Faucet-stop (TR-3/TR-10) — BLOCKING: no logic-only test at the Integration tier. Ask each test "would this pass against the fakes host, with no real infrastructure?" If yes, its subject is business logic (pricing/billing math, mapping, validation, branching) that belongs in
Infrastructure.Tests (a fast Unit-tier project), not the Docker-bound tier. REQUEST_CHANGES and route it down — this is the per-PR shut-off that keeps the pyramid from re-inverting (the orchestrator's CLEANUP re-audits this same question as a backstop). Tests that genuinely need infra are fine; this targets only the ones that don't.
- No redundant coverage (TR-10) — flag any test already covered at Unit or Contract; cut the more expensive duplicate, naming the cheaper test.
- Build — Full solution builds, all integration + fast-tier tests pass
UI-Tests Mode Checklist
Run through standards/testing.md with focus on the UI tier. Apply the v5 Test Enforcement above (TR-4/5/6/9 + TR-10 + TR-7/8 this mode), then for each test file check:
- Page Object Model (TR-9) — locators live in
Pages/ classes, never inline in test methods
- Condition-based waits (TR-9) — no
Task.Delay/WaitForTimeoutAsync/Thread.Sleep; Expect()/WaitForAsync only
- Semantic selectors —
GetByRole, GetByLabel, GetByText preferred over CSS/XPath
- Test isolation — each test class uses a fresh
IBrowserContext
- Test naming —
Snake_case_describing_user_action_and_expected_result
- Assertions (TR-8) — Playwright
Expect() used; every test reaches a real assertion; no Skip, no asserting buggy behavior
- No hardcoded URLs —
APP_BASE_URL environment variable used
- Journey-scoped (TR-4) — each test is a distinct user journey, NOT a per-screen happy/edge/error matrix. Reject per-field validation / empty-state UI tests — those behaviors belong to Unit/Contract.
- Conditional (TR-5) — confirm the surface was in scope; if a surface was declared out-of-scope, that is a recorded decision, not missing coverage.
- Critical-path (TR-6) — declared-critical journeys are tagged
[Trait("CriticalPath","true")]; enforce the repo-wide ceiling ≤10 (hard) / floor ≥3 (advisory) per the count above.
- Runner result — confirm the scoped
ui-tests.yml dispatch passed on the PR branch (the PR body links the run); do NOT run Playwright locally.
Step 2.5: Emit the mode-scoped TR reviewer grid (#10)
Produce the reviewer half of the #10 checklist — only the rows relevant to {MODE}, plus TR-10 every mode. This is a required output artifact: every cell is PASS / FAIL with evidence (a line reference, the redundant test you'd cut, or a linked CI job — never a bare check). It is the reviewer's adversarial re-check, not a re-tick of the producer's grid in the PR body. This grid goes into the review body in Step 4 (both approve and request-changes).
Rows by mode:
| Mode | Reviewer rows |
|---|
implementation | TR-2, TR-7, TR-8, TR-11, TR-10 |
integration-tests | TR-3, TR-7, TR-8, TR-10 |
ui-tests | TR-4, TR-5, TR-6, TR-7, TR-8, TR-9, TR-10 |
Grid format (fill for the current mode):
### TR checklist — {MODE} (reviewer)
| TR | Rule | Reviewer | Evidence |
|----|------|----------|----------|
| TR-x | <rule> | PASS/FAIL | <line ref / cut-this-test / linked CI job> |
- [CI] cells (TR-8
Skip/waits, TR-9 grep, TR-11 no-daemon, TR-6 count) — link the job or paste the grep output rather than re-deriving.
- Any [JUDGMENT] FAIL → REQUEST_CHANGES, bounced back to the skill that owns the row (refine / implement / integration-test / ui-test). A grid with any FAIL cannot be an APPROVE.
Step 3: Build & Test
Regardless of what the diff review found, always verify the build. Use the build and test commands from the project's CLAUDE.md.
- implementation mode — build the full solution and run the fast tier (Unit
Domain.Tests + Infrastructure.Tests + Contract Api.Tests). No Docker (TR-11).
- integration-tests mode — build the full solution, run the integration tests (Testcontainers), and also run the fast tier to confirm no regressions.
- ui-tests mode — do not run Playwright locally (the UI tier runs on the self-hosted runner). Instead confirm the scoped
ui-tests.yml dispatch on the PR branch passed — the PR body should link the run; if it's missing or red, that is a blocking finding.
Step 4: Post Review
Always include the Step 2.5 mode-scoped TR reviewer grid in the review body — on both approve and request-changes. The grid is the durable artifact the CLEANUP-mode gate-audit (#6) looks for ("did every PR's review post a filled grid"), so it must be present every time. An APPROVE requires every grid cell to be PASS.
4a. If No Blocking Issues Found
Post the passing review as a COMMENT (not APPROVE). Under a single GitHub credential the reviewer is the PR author, and GitHub rejects approving your own PR — event=APPROVE silently degrades to a comment (or 422s on stricter setups). The verdict that actually gates the merge is the STATUS: Approved line in your report (Step 5), which the orchestrator reads; this GitHub review is the durable record + the TR grid.
gh api repos/{REPO_OWNER}/{REPO_NAME}/pulls/{PR_NUMBER}/reviews \
--method POST \
--field event=COMMENT \
--field body="$(cat <<'EOF'
Engineering review passed. All standards checks clear, build succeeds, tests pass.
### TR checklist — {MODE} (reviewer)
| TR | Rule | Reviewer | Evidence |
|----|------|----------|----------|
| ... | (the mode-scoped rows from Step 2.5, all PASS, each with evidence) | PASS | ... |
EOF
)"
4b. If Blocking Issues Found
Post the review with line-level comments as a COMMENT (not REQUEST_CHANGES — GitHub blocks that on your own PR too, same single-credential reason as 4a). The blocking verdict is the STATUS: ChangesRequested line in your report, which the orchestrator reads and acts on (it bounces the PR to the owning skill's FIX mode).
First, get the latest commit SHA:
gh pr view {PR_NUMBER} --repo {REPO_OWNER}/{REPO_NAME} --json headRefOid --jq .headRefOid
Then create the review with inline comments:
gh api repos/{REPO_OWNER}/{REPO_NAME}/pulls/{PR_NUMBER}/reviews \
--method POST \
--field commit_id="{COMMIT_SHA}" \
--field event=COMMENT \
--field body="Engineering review found issues that must be addressed. See inline comments.
### TR checklist — {MODE} (reviewer)
[the mode-scoped grid from Step 2.5, with the FAIL row(s) and evidence that drove REQUEST_CHANGES]" \
--field 'comments=[
{
"path": "src/path/to/file.cs",
"line": LINE_NUMBER,
"side": "RIGHT",
"body": "**[Standards Violation: Category]**\nDescription of the violation.\n\n**Standard:** standards/filename.md — rule description\n**Fix:** Specific action to take"
}
]'
Comment Format
Use these tags to categorize each comment:
Blocking (must fix):
**[Standards Violation: {Category}]** — violates a specific standard
**[Build Failure]** — code does not compile
**[Test Failure]** — tests do not pass
Non-blocking (advisory):
**[Suggestion]** — improvement idea, not a standards violation
Only [Standards Violation: *], [Build Failure], and [Test Failure] block approval. If the ONLY comments are [Suggestion], APPROVE the PR (include suggestions in the approval body).
Comment Template per Violation
**[Standards Violation: {Category}]**
{Description of what's wrong and why it matters}
**Standard:** `standards/{filename}.md` — {specific rule text or summary}
**Fix:** {Specific, actionable instruction — tell them exactly what to change}
Step 5: Report
STATUS: Approved | ChangesRequested
MODE: {MODE}
PR_NUMBER: {PR_NUMBER}
ITERATION: {ITERATION}
STORY_ID: {STORY_ID}
VIOLATIONS: [count] (blocking)
SUGGESTIONS: [count] (non-blocking)
BUILD: pass | fail
TESTS: pass | fail
TR_GRID: [mode-scoped rows, each PASS/FAIL — e.g. "TR-2 PASS, TR-7 PASS, TR-8 PASS, TR-10 FAIL, TR-11 PASS"]
REDUNDANT_CUT: [None | tests flagged for removal under TR-10]
CRITICAL_PATH_COUNT: [repo-wide tagged count | n/a — ui-tests mode only]
DETAILS:
- [Category]: file.cs:line — brief description
- [Category]: file.cs:line — brief description
A FAIL on any [JUDGMENT] TR row means STATUS must be ChangesRequested, routed back to the owning skill.