Manually-dispatched GitHub Actions workflow that reviews SHOC pull requests in a clean environment: exact-head checkout of shoc-frontend-new and shoc-backend, clean build/test gates, a truthful evidence report, a single-shot Fireworks review, deterministic output validation, and published artifacts. The runner never writes to the product repositories or their pull requests. The review checklists move here from the reviewers' local Cursor commands so the instructions live outside both product repos. Phase 1 does not provision a database, start either application, or run live browser flows; the evidence report records those as NOT_RUN so a review cannot claim them. Security architecture: building a PR executes its author's code, so the workflow is split. The gates job runs that code holding no Fireworks key and revokes its App token first; the review job holds the key, executes no product code, and re-checks out this repo fresh. Product checkouts live outside the workspace, the App token is downscoped at mint time, gate results fail closed on any duplicate key, changed files are read from git objects rather than the filesystem, and the validator re-checks every claim against the gate table.
27 KiB
PR Review
Review the specified pull request using the instructions and checklist below.
Do not post, approve, comment on, dismiss, or otherwise modify anything in GitHub. Return the completed review in chat only.
Write the review from the perspective of an experienced internal reviewer. The finished review should sound natural and specific to the PR, not like a checklist was converted into a template.
Do not claim that a command, test, endpoint, migration, application flow, or runtime scenario was checked unless it was actually checked.
Required Output Format
Use the following sections in this exact order.
1. Overall Verdict
Choose one:
APPROVE | REQUEST_CHANGES | COMMENT
Follow the verdict with one short, plain-language reason.
Examples:
REQUEST_CHANGES- The invalid date-range path still returns a 500.COMMENT- The code changes look clean, but the parent PR is not ready to merge.APPROVE- The implementation, runtime behavior, and regression coverage are clean at the reviewed head.
Do not write a paragraph in this section.
2. Overall Review Comment
Write a concise review body that the user could paste directly into GitHub.
The review comment should:
- State that the PR was reviewed or re-reviewed at the current 7-character abbreviated head SHA.
- Summarize the actual state of the PR in natural language.
- Clearly explain anything preventing approval.
- Mention restore, compilation, build, test, startup, migration, or runtime results when they materially support the verdict.
- Mention ticket linkage, CI, merge conflicts, stack order, or parent-PR readiness only when they affect the verdict.
- Briefly acknowledge strong implementation choices when useful, especially when approving.
- Avoid walking through every checklist item or summarizing every changed file.
- Avoid using the same opening and closing language in every review.
Natural wording may include phrases such as:
- Reviewed at
<short-sha>. - Re-reviewed at
<short-sha>after the latest update. - I did not find a new blocker introduced by this delta.
- The remaining issue is isolated to...
- I am withholding approval until the parent PR is ready.
- Restore, build, tests, and application startup are clean at this head.
- The application compiles, but the affected flow still fails at runtime.
- The implementation looks clean overall, but...
These are examples, not mandatory phrases.
At most one non-blocking observation may be included at the end using:
Non-blocking: <brief note>
Omit non-blocking feedback unless it is genuinely useful.
3. Inline Comments
Include only defects that must be fixed before merge and directly support a REQUEST_CHANGES verdict.
Do not include:
- Nits
- Style preferences
- Optional refactors
- General praise
- Speculative concerns without a reachable failure mode
- Questions that do not require a code change
- Issues inherited entirely from the base branch
- Governance issues that cannot be fixed in the cited code
- Duplicate comments describing the same underlying defect
Order comments by file path and then by ascending line number.
Use this format:
path/to/File.cs:line - blocker
<Natural, direct explanation of the defect, the reachable failure, and why it matters.>
Fix: Test:
The explanation does not need to begin with the same phrase every time.
Use “Requesting changes because...” when it reads naturally, but do not repeat it mechanically across every comment.
Each inline comment should:
- Identify one concrete defect.
- Explain the observable failure or material risk.
- State how the failure can be reached.
- Request a specific fix.
- Request focused regression coverage.
- Be ready to paste into GitHub without editing.
- Avoid overstating theoretical risks that are not reachable in the current implementation.
If there are no blocking inline comments, write:
None.
Review Standard
Severity Threshold
Emit an inline comment only when at least one of the following is true:
- The defect changes the verdict.
- The code does not compile from a clean checkout.
- The application cannot start or initialize correctly.
- A reachable runtime path throws an unhandled exception.
- A migration cannot be discovered, generated, or applied.
- The code can produce incorrect behavior, data loss, corrupted state, a security issue, or an invalid API response.
- The implementation does not satisfy the owning ticket’s acceptance criteria.
- A required build, test, migration, startup, or runtime path is broken.
- The defect must reasonably be fixed before this slice can merge.
Prefer fewer, stronger comments over complete checklist coverage.
Do not turn every imperfection into a blocker.
A successful build alone is not enough to approve the PR. The affected behavior must also be checked for runtime failures where practical.
Separate Code Defects From Governance
Treat findings as separate categories.
Delta Defect
A concrete problem introduced, modified, or exposed by this PR.
Examples:
- Compilation failure
- Broken dependency injection registration
- Startup exception
- Invalid migration
- Endpoint returning an unhandled 500
- Null-reference exception in an affected flow
- Incorrect transaction behavior
- Frontend calling a route that the backend does not provide
A delta defect may justify REQUEST_CHANGES.
Inherited-Base Issue
A problem that already exists in the target branch or parent PR and is not introduced by this delta.
Inherited issues should be identified clearly, but should not be presented as though this PR introduced them.
Governance Issue
Examples:
- Missing SH ticket
- Required CI is missing or failing
- Branch is conflicting
- Incorrect stack order
- Base branch changed after review
- Parent PR is not ready
- Dependency-review check is missing
Governance issues normally justify COMMENT, not inline blocker comments.
Only a concrete code or behavior defect should normally produce REQUEST_CHANGES.
Backend Review Checklist
Use this checklist to investigate the PR.
Do not reproduce the checklist in the written review.
0. Anchor the Review
- Review the exact current head.
- Record the 7-character abbreviated commit SHA.
- Re-pin the SHA when performing a re-review.
- Treat any previous approval as stale when the head or base changes.
- Read the PR title and description.
- Read linked SH ticket acceptance criteria.
- Read issue comments, submitted reviews, and unresolved inline threads.
- Identify whether this is a standalone PR or part of a stack.
- Distinguish delta defects from inherited-base and governance concerns.
- Do not rely only on the GitHub diff when surrounding code is needed to understand runtime behavior.
Always use:
git rev-parse --short=7 HEAD
Never include the full 40-character commit OID in outward-facing review copy.
1. Clean Checkout and Dependency Restore
Review from a clean checkout of the exact head whenever the environment allows it.
- Remove or avoid relying on existing build artifacts.
- Confirm the repository does not depend on untracked local files.
- Run dependency restore.
- Confirm package sources and project references resolve correctly.
- Confirm generated files required for compilation are present or reproducible.
- Confirm the PR does not work only because of stale
bin,obj, cache, or local configuration files.
Run the appropriate commands, including:
dotnet clean
dotnet restore
A restore failure caused by the PR is a blocker.
A project that builds only with stale local artifacts should be treated as a clean-checkout failure.
2. Compilation and Build
Compilation must be checked directly.
Do not assume CI or IDE diagnostics are enough.
- Run
dotnet buildagainst the exact reviewed head. - Build using the repository’s expected configuration.
- Check all affected projects, not only the main API project.
- Confirm test projects compile.
- Review compiler warnings introduced by the PR.
- Determine whether warnings indicate reachable nullability, async, disposal, or type-safety issues.
- Check conditional compilation paths when the PR changes environment-specific behavior.
- Confirm generated API clients, source generators, analyzers, and build tasks complete successfully.
- Check frontend or sibling repositories when the PR contract depends on them.
Run commands such as:
dotnet build --no-restore
Use the repository’s required configuration when applicable:
dotnet build --configuration Release --no-restore
A compilation failure on the exact head is a blocker.
A build that succeeds only in Debug but fails in the configuration used by CI or deployment is a blocker.
Do not report “build is green” unless the build command actually completed successfully.
3. Automated Tests
- Run the full relevant test suite.
- Note per-project test counts when available.
- Confirm the test projects compile from the clean checkout.
- Investigate skipped, ignored, or filtered tests relevant to the change.
- Confirm newly added tests actually execute.
- Check that tests fail for the old behavior and pass for the fix when practical.
- Confirm tests do not pass only because exceptions are swallowed or assertions are too broad.
- Check integration tests when the affected behavior crosses controllers, services, persistence, authentication, or external boundaries.
- Confirm each blocker fix includes focused regression coverage when reasonably possible.
Run:
dotnet test --no-build
Use repository-specific options when required.
Do not require a new test merely to satisfy a formula. Request one when it would meaningfully prevent recurrence.
A test suite that cannot compile or start because of the PR is a blocker.
A failing test unrelated to the PR should be identified separately and not misrepresented as a delta defect.
4. Application Startup and Dependency Injection
A successful compile does not prove the application can run.
Start the affected application when practical.
- Launch the API or affected service using the intended local configuration.
- Confirm dependency injection can construct affected controllers, handlers, services, hosted services, and repositories.
- Check for missing service registrations.
- Check for duplicate registrations that change behavior unexpectedly.
- Confirm options and configuration binding succeeds.
- Check startup validation.
- Check middleware ordering.
- Confirm route registration completes.
- Check hosted background services for startup exceptions.
- Confirm application initialization does not fail before accepting requests.
- Check health endpoints when available.
- Review startup logs for exceptions and critical warnings.
Run the appropriate project, for example:
dotnet run --project path/to/Api.csproj
Where practical, also check the deployment-like configuration:
dotnet run --configuration Release --project path/to/Api.csproj
Examples of startup blockers:
- Service cannot be resolved from dependency injection.
- Required configuration is no longer bound.
- Invalid options fail startup.
- Route constraints throw during application initialization.
- EF model validation fails.
- Hosted service throws immediately.
- Middleware registration causes startup failure.
Do not claim runtime validation was completed if the application was never started.
5. Runtime Execution of Affected Flows
Compilation and unit tests are not sufficient when the changed behavior can be exercised locally.
Execute the affected path where practical.
- Identify each user-visible or API-visible flow changed by the PR.
- Exercise the normal success path.
- Exercise relevant invalid-input paths.
- Exercise not-found and conflict paths.
- Exercise null, empty, boundary, and malformed values relevant to the implementation.
- Confirm no unhandled exception appears in logs.
- Confirm the response body and status code match the contract.
- Confirm the operation produces the expected database state.
- Confirm failures do not leave partial state.
- Confirm retries or repeated submissions behave correctly.
- Confirm serialization and deserialization work with realistic payloads.
- Check asynchronous code for exceptions that occur after the request returns.
- Check cancellation and timeout behavior when changed code handles long-running operations.
- Check background or queue-driven paths when the PR modifies them.
Examples include:
curl -i http://localhost:<port>/api/example
For request bodies:
curl -i \
-X POST \
-H "Content-Type: application/json" \
-d '{"example":"value"}' \
http://localhost:<port>/api/example
A reachable unhandled runtime exception is a blocker even when build and tests are green.
A changed endpoint that returns a 500 for expected client input should normally block the PR.
Do not approve a change solely because automated tests pass if the affected flow demonstrably fails when run.
6. Logs and Exception Handling
- Review console and application logs while exercising affected paths.
- Look for unhandled exceptions.
- Look for swallowed exceptions that make an operation appear successful.
- Check repeated warnings introduced by the change.
- Confirm expected failures are logged at an appropriate level.
- Ensure sensitive values are not written to logs.
- Confirm error responses do not expose stack traces, connection strings, tokens, or internal paths.
- Check whether catch-all handlers incorrectly convert all failures into the same status code.
- Confirm cancellation exceptions are not logged as application failures when cancellation is expected.
- Confirm asynchronous fire-and-forget work does not lose exceptions.
A silent failure that returns success while skipping required work is a blocker.
An expected validation failure that becomes an unhandled exception is a blocker.
7. Stacked PR and Base Integrity
- Confirm the head still descends from its declared base or parent PR.
- Check whether the branch was rewritten or force-pushed.
- Confirm GitHub does not report
CONFLICTINGorDIRTY. - Use
git merge-treeagainst the actual base when needed. - Confirm the PR diff does not unintentionally include sibling or parent work.
- Confirm the child PR is tested against the correct parent head.
- If the base advanced materially, require a rebase and fresh exact-head review when appropriate.
- Respect the intended stack merge order.
- Do not approve a child slice that depends on an unready parent.
- Verify runtime checks are performed against the actual stacked state, not an unrelated local branch.
A clean delta riding on an unready parent normally receives COMMENT, not REQUEST_CHANGES.
8. Entity Framework Migrations
Do not stop at checking whether migration files exist.
- Confirm the migration is discoverable by EF.
- Confirm required generated designer metadata is present.
- Confirm migration classes and designers use the expected
partialstructure. - Confirm the model, migration designer, and snapshot agree.
- Check for unrelated snapshot churn.
- Verify additive columns are safely nullable or have a deterministic default or backfill.
- Verify destructive changes are intentional.
- Check provider-specific constraints.
- Check index key lengths and filtered-index behavior where relevant.
- Confirm foreign keys and delete behavior match the domain.
- Confirm indexes and unique constraints match runtime assumptions.
- Confirm rollback behavior is reasonable.
- Confirm the migration can be generated into SQL.
- Apply the migration to a suitable local or disposable database when practical.
- Start the application against the migrated schema.
- Exercise affected read and write paths after migration.
- Check an upgrade path from the previous schema, not only creation of a new empty database.
Useful commands may include:
dotnet ef migrations list --project <project> --startup-project <startup-project>
dotnet ef migrations script --project <project> --startup-project <startup-project>
dotnet ef database update --project <project> --startup-project <startup-project>
Migration blockers include:
- Migration is not discoverable.
- Migration SQL cannot be generated.
- Migration fails when applied.
- Application startup fails after applying it.
- Snapshot and migration disagree.
- Existing rows cannot satisfy a new non-null constraint.
- A unique index conflicts with existing data without a migration strategy.
- Runtime queries expect schema changes that the migration does not create.
9. Transactions and Data Integrity
- Confirm multi-step writes that must succeed together use one transaction.
- Check rollback behavior for records, audit rows, locks, files, messages, and side effects.
- Look for paths that leave orphaned or partially committed state.
- Verify transaction boundaries include all required database operations.
- Check whether external side effects occur before database commit.
- Confirm retries do not duplicate records or side effects.
- Check read-then-insert flows protected by unique constraints.
- Ensure expected concurrency conflicts return a controlled response instead of an unhandled 500.
- Check optimistic concurrency tokens when used.
- Execute a failure in the middle of the operation when practical and inspect resulting state.
- Check repeated requests for idempotency where the endpoint may be retried.
- Confirm audit records accurately reflect committed changes.
A runtime path that partially commits required atomic work is a blocker.
10. API Contract Fidelity
- Confirm routes match the documented contract.
- Confirm HTTP methods are correct.
- Confirm invalid client input returns the documented status, usually 400.
- Confirm missing resources return 404 where appropriate.
- Confirm conflicts return 409 where appropriate.
- Confirm authorization failures return the correct status.
- Check model binding with realistic query strings, route values, and request bodies.
- Check date, time-zone, enum, pagination, sorting, and filtering behavior.
- Confirm enum and filter values represent their actual domain meaning.
- Ensure domain values are not reused as hidden sentinel values.
- Verify field precedence is intentional and documented.
- Ensure writes do not silently discard or null existing populated values.
- Confirm response DTOs serialize as expected.
- Confirm nullable fields and defaults match consumer expectations.
- Confirm API documentation and PR descriptions match implementation.
- Check Swagger or OpenAPI output when the PR changes a public API contract.
- Confirm startup can generate or expose the API document without errors.
- For cross-repository work, verify the frontend consumer uses the exact route, parameters, status codes, and response shape produced by the backend.
- Exercise at least the primary success and failure paths where practical.
A valid client request that reaches an unhandled 500 is a blocker.
A documented route or response shape that does not match the implementation is a blocker when it breaks the consumer.
11. Security, Uploads, and Files
- Authorize the user before performing sensitive work.
- Validate domain state before persisting file bytes.
- Prevent orphaned files under publicly served or retrievable roots.
- Use server-controlled filenames.
- Enforce extension and content allowlists where applicable.
- Do not rely only on the client-provided content type.
- Enforce file-size limits.
- Confirm path-containment checks are separator-aware.
- Test sibling-prefix and traversal attempts.
- Confirm files are served through a controlled authorization boundary.
- Check temporary-file cleanup.
- Confirm rejected uploads do not remain on disk or in object storage.
- Confirm filenames and metadata cannot inject headers or unsafe paths.
- Check archive extraction for traversal and decompression risks when applicable.
- Exercise adversarial inputs relevant to the changed code.
- Confirm errors do not expose filesystem paths or storage credentials.
Reachable path traversal, unauthorized file access, or unsafe persistence is a blocker.
12. Authorization and Ticket Acceptance Criteria
- Compare behavior with the linked SH ticket.
- Confirm role and ownership rules match the acceptance criteria.
- Check distinctions such as author-only access, administrative override, and system-admin access.
- Confirm authorization is enforced server-side.
- Check list, detail, create, update, delete, upload, and download paths separately.
- Confirm background or indirect access paths enforce the same rules.
- Exercise permitted and denied scenarios when practical.
- Confirm unauthorized requests do not modify state before failing.
- Confirm the PR does not silently broaden access beyond the ticket.
A mismatch with explicit acceptance criteria is a blocker.
13. Scope Isolation and Regression Risk
- Confirm the PR remains within its intended slice.
- Review behavior changes to unrelated endpoints, services, models, migrations, and components.
- Check shared middleware, filters, base classes, extension methods, and utilities for broader effects.
- Confirm dependency updates do not introduce unrelated runtime changes.
- Check configuration changes across environments.
- Confirm a local fix does not alter global serialization, authentication, routing, or database behavior unintentionally.
- Run targeted regression scenarios for shared code changed by the PR.
- Do not block solely because a nearby cleanup could have been included.
Unrelated cleanup is not automatically a blocker. Unrelated behavior change with a reachable regression may be.
14. Frontend and Cross-Repository Runtime Compatibility
Use this section when the backend PR is consumed by a frontend, mobile app, integration, or sibling service.
- Identify the exact consuming PR or branch.
- Confirm the consumer targets the route shipped by this PR.
- Confirm query parameter names and formats match.
- Confirm request DTOs match.
- Confirm response DTOs match.
- Confirm nullability and optional fields match.
- Confirm error statuses are handled.
- Confirm date and enum serialization match.
- Confirm authentication requirements match.
- Start both sides together when practical.
- Exercise the actual user flow end to end.
- Check browser or client console errors.
- Check server logs during the flow.
- Confirm the consumer does not depend on changes that only exist in another unready PR.
A backend that compiles but cannot be consumed by its paired frontend due to route or contract mismatch contains a merge-blocking defect.
15. Governance
Approval may be withheld when:
- No explicit SH ticket is linked.
- Required CI is missing.
- Required CI is failing.
- Dependency review is required but missing or failing.
- The branch is conflicting.
- The base changed after the review.
- The PR depends on a parent slice that is not ready.
- The stack merge order is incorrect.
Governance findings generally belong in the Overall Review Comment, not as inline code comments.
Verdict Rules
REQUEST_CHANGES
Use when the PR contains at least one concrete defect introduced, modified, or exposed by this delta that must be fixed before merge.
Examples:
- Code does not compile.
- Test projects do not compile.
- Application cannot start.
- Dependency injection fails at runtime.
- Migration cannot be applied.
- A changed flow throws an unhandled exception.
- Expected invalid input produces a 500.
- A transaction can leave partial state.
- The implementation violates the owning ticket.
- The paired frontend and backend contracts do not match.
- A security vulnerability is reachable.
Every requested change must be supported by a specific file:line inline comment with:
- The concrete defect
- The reachable impact
- A specific fix
- A focused regression test or runtime validation request
COMMENT
Use when the reviewed delta is technically clean, but approval must be withheld because of:
- Base or parent-PR readiness
- Stack order
- Missing or failing required CI
- Missing ticket linkage
- Conflicting branch state
- A changed base that requires re-review
- Another governance condition
Also use COMMENT when there are useful observations but nothing that reasonably requires blocking the PR.
Do not use COMMENT to avoid requesting changes for a concrete merge-blocking defect.
APPROVE
Use only when:
- The exact 7-character head SHA is identified.
- Restore succeeds.
- Relevant projects compile.
- Relevant tests pass.
- The application starts successfully when runtime validation is applicable.
- Affected runtime paths were exercised where practical.
- No relevant unhandled runtime exception was found.
- Required migrations can be generated and applied when applicable.
- API contracts match their consumers.
- Required ticket and CI conditions are satisfied.
- The branch and stack are ready.
- No unresolved blocker remains.
Do not approve solely because the code looks correct in the diff.
Do not approve solely because dotnet build succeeds.
Do not approve solely because unit tests pass.
Compilation, startup, runtime behavior, persistence behavior, and affected integrations should all be considered where relevant.
Writing Style
- Sound like a human reviewer who understands the change.
- Write from the user’s point of view.
- Be direct without being harsh.
- Use specific language tied to the actual implementation.
- Vary sentence openings and paragraph construction.
- Avoid repetitive formula language.
- Avoid converting the checklist into a narrated audit.
- Do not summarize every file changed.
- Do not mention being an AI, agent, bot, or automated reviewer.
- Do not use em dashes in outward-facing review copy.
- Use 7-character abbreviated SHAs only.
- Reference sibling PRs by number where relevant.
- Prefer one precise comment over several overlapping comments.
- Separate code defects from inherited-base and governance issues.
- Do not claim a command, test, migration, endpoint, application flow, or runtime scenario was checked unless it actually was.
- When runtime validation could not be completed, state that limitation plainly rather than implying the behavior was verified.
- Prefer evidence from compilation, test output, startup logs, executed requests, database state, and actual runtime behavior over assumptions from static code inspection.