Conversation
…/comp into chas/soa-justification
CS-424 [Improvement] Include a default justification at all times on the SoA
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
There was a problem hiding this comment.
2 issues found across 9 files
Confidence score: 3/5
- There is a concrete behavior risk in
apps/api/src/soa/utils/soa-answer-parser.ts: forcing a default justification for YES answers conflicts with the SOA rule that allows empty justification, and could hide when the model returned no justification. - A smaller UI/data-handling issue in
apps/app/src/app/(app)/[orgId]/documents/statement-of-applicability/components/SOATableRow.tsxuses||instead of??, so intentionally saved empty strings can be overwritten by defaults. - Given the medium-severity backend rule mismatch (5/10, high confidence) plus a low-severity frontend fallback issue, this looks mergeable with caution but carries real regression risk.
- Pay close attention to
apps/api/src/soa/utils/soa-answer-parser.tsandapps/app/src/app/(app)/[orgId]/documents/statement-of-applicability/components/SOATableRow.tsx- justification emptiness semantics may be unintentionally changed across parsing and display.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/api/src/soa/utils/soa-answer-parser.ts">
<violation number="1" location="apps/api/src/soa/utils/soa-answer-parser.ts:192">
P2: YES answers are now forced to store a default justification instead of allowing null/blank, which conflicts with the SOA rule to allow empty justification for applicable controls and can mask when the model provided no rationale.
(Based on your team's feedback about allowing blank justification for YES SOA answers.) [FEEDBACK_USED].</violation>
</file>
<file name="apps/app/src/app/(app)/[orgId]/documents/statement-of-applicability/components/SOATableRow.tsx">
<violation number="1" location="apps/app/src/app/(app)/[orgId]/documents/statement-of-applicability/components/SOATableRow.tsx:80">
P3: Using `||` instead of `??` causes empty-string justification values to be silently discarded, falling back to the column mapping default instead of preserving the user's explicitly saved empty value.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
| ? llmJustification | ||
| : llmJustification && !isInsufficientDataAnswer(llmJustification) | ||
| ? llmJustification | ||
| : (getInclusionJustification(closure) ?? DEFAULT_INCLUSION_JUSTIFICATION); |
There was a problem hiding this comment.
P2: YES answers are now forced to store a default justification instead of allowing null/blank, which conflicts with the SOA rule to allow empty justification for applicable controls and can mask when the model provided no rationale.
(Based on your team's feedback about allowing blank justification for YES SOA answers.) .
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/soa/utils/soa-answer-parser.ts, line 192:
<comment>YES answers are now forced to store a default justification instead of allowing null/blank, which conflicts with the SOA rule to allow empty justification for applicable controls and can mask when the model provided no rationale.
(Based on your team's feedback about allowing blank justification for YES SOA answers.) .</comment>
<file context>
@@ -163,12 +172,24 @@ export function parseAndProcessSOAAnswer(
+ ? llmJustification
+ : llmJustification && !isInsufficientDataAnswer(llmJustification)
+ ? llmJustification
+ : (getInclusionJustification(closure) ?? DEFAULT_INCLUSION_JUSTIFICATION);
send({
</file context>
| displayIsApplicable === false | ||
| ? (answerData.answer ?? question.columnMapping.justification ?? null) | ||
| : null; | ||
| answerData.answer || question.columnMapping.justification || null; |
There was a problem hiding this comment.
P3: Using || instead of ?? causes empty-string justification values to be silently discarded, falling back to the column mapping default instead of preserving the user's explicitly saved empty value.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/app/(app)/[orgId]/documents/statement-of-applicability/components/SOATableRow.tsx, line 80:
<comment>Using `||` instead of `??` causes empty-string justification values to be silently discarded, falling back to the column mapping default instead of preserving the user's explicitly saved empty value.</comment>
<file context>
@@ -77,9 +77,7 @@ export function SOATableRow({
- displayIsApplicable === false
- ? (answerData.answer ?? question.columnMapping.justification ?? null)
- : null;
+ answerData.answer || question.columnMapping.justification || null;
} else {
// Normal logic: processedResult / column mapping until user saves (then branch above)
</file context>
| answerData.answer || question.columnMapping.justification || null; | |
| answerData.answer ?? question.columnMapping.justification ?? null; |
… (CS-416) (#2995) Auditor-only members are external reviewers and aren't subject to people-security requirements. Exclude them from the background-check requirement in the people score and hide the Background Check tab/header on their detail page (the people-list row was already gated). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(background-checks): add rerunCount to BackgroundCheckRequest
* feat(background-checks): vary Identity idempotency key by attempt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(background-checks): add missing attempt field to spec callers
Three pre-existing direct calls to `BackgroundCheckIdentityClient.createBackgroundCheck()`
in the spec file were missing the newly required `attempt` field, causing TS2345 type
errors after Task 2 made `attempt: number` required in the client signature.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(background-checks): add cancelForMember with state guard
* feat(background-checks): add free reset-in-place retryForMember
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(background-checks): extract cancelForMember/retryForMember to bring service under 300 lines; add missing not-found test
- Extract `cancelForMember` and `retryForMember` to `background-check-retry.ts`
following the existing `background-check-report-snapshot.ts` helper pattern,
bringing `background-checks.service.ts` from 376 to 293 lines
- Add missing `throws when no check exists` test to the `retryForMember` suite,
matching the parallel coverage in `cancelForMember` (NotFoundException at
service.ts:304 was previously untested)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(background-checks): add deleteForMember hard delete
* fix(background-checks): ignore webhooks for cancelled checks
* feat(background-checks): add retry/cancel/delete endpoints
* feat(background-checks): admin retry/cancel/delete actions component
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* feat(background-checks): surface admin actions in employee tab
* fix(bg-check): remove redundant guard and add admin-actions wiring tests
- Remove inner `{backgroundCheck && ...}` wrapper inside the
`if (backgroundCheck)` branch — the inner condition was always truthy.
- Fix the `onChange` callback type mismatch (void vs Promise<void>).
- Add two tests that pass a non-null `initialBackgroundCheck` and assert
that Retry/Cancel buttons from `BackgroundCheckAdminActions` render.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(background-checks): apply prettier formatting to all touched files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(background-checks): address Cubic ultrareview findings
- Key Identity idempotency on the record id (not memberId) so a delete +
re-request creates a fresh vendor check instead of colliding (P1)
- Retry failure restores the prior status instead of forcing 'failed',
preserving the cancelled webhook terminal-guard (P1)
- Clear the pending delete confirmation when Retry/Cancel is clicked (P2)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…73) (#2996) * feat(background-checks): hourly reconciliation for stuck checks (CS-473) Background check status is normally driven by Identity webhooks; when one is missed the check stays stuck (e.g. Identity:Pending forever). Add an hourly Trigger.dev scheduled task that polls Identity for stale in-flight checks and applies any status it reports (same fields the webhook writes). Parses the Identity GET response defensively and no-ops when status can't be determined. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(background-checks): address Cubic review on reconciliation job - parseIdentityCheckState parses status/statuses independently so a malformed statuses object no longer drops a valid status (P2) - refresh sub-statuses even when the top-level status is unchanged, and never null out sub-statuses the GET omitted (P2 — the CS-473 symptom) - write via updateMany guarded on status IN non-terminal, so a check that became terminal/cancelled between select and write isn't resurrected (P1) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(background-checks): maxDuration is in seconds, not ms (CS-473) Trigger.dev maxDuration is specified in seconds; 1000*60*30 was ~20 days instead of 30 minutes. Use 30*60. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(background-checks): base stale cutoff on actual run time (CS-473) Use Date.now() instead of the scheduled payload.timestamp so a late cron start doesn't narrow the reconciliation window and delay recovery. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Port the Finding Templates CRUD UI from the deprecated cx-dashboard app into the main app's Admin panel, next to Timeline Templates. Consumes the existing /v1/finding-template API (mutations gated by PlatformAdminGuard); no backend, schema, or migration changes. - New admin route /[orgId]/admin/finding-templates: list with search, category filter, and pagination; create/edit Sheet (react-hook-form + zod); delete confirmation (AlertDialog) - use-admin-finding-templates SWR hook over GET /v1/finding-template - Finding Templates sidebar entry under Admin - Access auto-gated by the existing admin layout (role === 'admin') Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
2 issues found across 27 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/api/src/frameworks/frameworks-people-score.helper.ts">
<violation number="1" location="apps/api/src/frameworks/frameworks-people-score.helper.ts:22">
P2: Background-check eligibility is gated by a hardcoded `'auditor'` role string instead of RBAC role metadata, which can break custom-role behavior.</violation>
</file>
<file name="apps/api/src/background-checks/background-check-retry.ts">
<violation number="1" location="apps/api/src/background-checks/background-check-retry.ts:117">
P2: The retry error handler performs a stale status write that can clobber a successful concurrent retry.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
| .split(',') | ||
| .map((r) => r.trim()) | ||
| .filter(Boolean); | ||
| return roles.length > 0 && roles.every((r) => r === 'auditor'); |
There was a problem hiding this comment.
P2: Background-check eligibility is gated by a hardcoded 'auditor' role string instead of RBAC role metadata, which can break custom-role behavior.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/frameworks/frameworks-people-score.helper.ts, line 22:
<comment>Background-check eligibility is gated by a hardcoded `'auditor'` role string instead of RBAC role metadata, which can break custom-role behavior.</comment>
<file context>
@@ -8,6 +8,20 @@ const COMPLETED_BACKGROUND_CHECK_STATUSES = [
+ .split(',')
+ .map((r) => r.trim())
+ .filter(Boolean);
+ return roles.length > 0 && roles.every((r) => r === 'auditor');
+}
+
</file context>
| // check rather than colliding with a prior attempt's idempotency key. | ||
| idempotencyKey: `comp-background-check:${existing.id}:${attempt}`, | ||
| }); | ||
| } catch (error) { |
There was a problem hiding this comment.
P2: The retry error handler performs a stale status write that can clobber a successful concurrent retry.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/background-checks/background-check-retry.ts, line 117:
<comment>The retry error handler performs a stale status write that can clobber a successful concurrent retry.</comment>
<file context>
@@ -0,0 +1,145 @@
+ // check rather than colliding with a prior attempt's idempotency key.
+ idempotencyKey: `comp-background-check:${existing.id}:${attempt}`,
+ });
+ } catch (error) {
+ // Restore the prior status (retry is only allowed from 'failed' or
+ // 'cancelled'). Forcing 'failed' here would strip a cancelled check of the
</file context>
feat(admin): add Finding Templates management to admin panel
#2998) The Retry/Cancel/Delete buttons rendered as a stray row between the exempt toggle and the status card. Render them inside the status card at the bottom (below a divider) via a new actions slot on BackgroundCheckStatusView, so the actions sit with the check they act on. The divider lives in BackgroundCheckAdminActions so it only shows when there are buttons. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
🎉 This PR is included in version 3.67.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This is an automated pull request to release the candidate branch into production, which will trigger a deployment.
It was created by the [Production PR] action.
Summary by cubic
Adds always-on SoA justifications, improves background checks with admin retry/cancel/delete and an hourly reconciliation, and adds Admin Finding Templates management. Implements CS‑424, CS‑416, CS‑475, and CS‑473.
New Features
rerunCountand use per-attempt idempotency keys keyed to the record; ignore vendor webhooks after local cancel; hourly job polls for stale in‑flight checks and updates statuses and report snapshots.use-admin-finding-templatesoverGET /v1/finding-template.Bug Fixes
Written for commit dcd4b4d. Summary will update on new commits.