Conversation
…answer (#3395) * feat(soa): persist applicability and justification on the SoA answer Make Statement of Applicability answers first-class per-document records: each control's applicability (Yes/No) and justification are stored on the organization's own SOAAnswer, alongside the existing answer text and versioning. SOAFrameworkConfiguration stays a shared template (control list, columns, objectives). - add SOAAnswer.isApplicable (+ migration) - auto-fill and manual save persist applicability + justification on the answer - export and the answered-count read from the document's own answers - keep the justification for both applicable and not-applicable controls - desktop/mobile rows read from the document's answers via a shared resolveSoaDisplay helper Adds API and frontend unit tests. * fix(soa): render unknown applicability as N/A and unify the result type - resolveSoaDisplay now shows an answer that has no applicability value yet as unanswered (N/A) — consistent with the export — instead of assuming the control is applicable, so pre-existing documents don't render a value that was never set for them. - Consolidate the per-view processed-result types into a single shared SOAProcessedResult (used by the autofill hook and every SoA view) so the contract is defined once. * fix(soa): harden saveAnswer and answer hydration - preserve prior applicability/justification when a field is omitted from a save, so a partial edit can't wipe a previously set decision - validate that questionId belongs to the document's configuration before creating an answer, keeping the per-org answered-count accurate - require a justification when a control is marked not applicable - hydrate the answers map through a single mapper so the sync effect no longer sets savedIsApplicable (which would shadow in-session autofill results) * fix(soa): scope the answered-count to the document's configured questions countAnsweredAnswers now counts only latest answered rows whose questionId belongs to the document's active configuration, so stale or mismatched answer rows can't skew completion/progress metrics. Both callers (manual save and auto-fill) pass the configured question IDs. Adds a regression test. * fix(soa): read fully-remote applicability from the persisted answer Remove the display-only override that forced physical-security (7.x) controls to "not applicable" for fully-remote orgs on screen. The rule is already applied at generation time (auto-fill persists isApplicable=false with a justification and the field is edit-locked), so the persisted answer already reflects it. Reading it from there keeps the on-screen SoA and the exported PDF in agreement instead of applying a rule in one channel but not the other. * fix(soa): validate before writing and make answer updates atomic saveAnswer previously retired the prior answer (isLatestAnswer=false) before running the not-applicable-requires-justification check, so a rejected save could leave a control with no latest answer. Move all validation ahead of any write, and wrap the retire-previous + create-new steps in a single transaction so a failure can never leave a control without a latest answer. Apply the same atomic retire+create in the auto-fill save path. Adds a regression test asserting a failed validation does not retire the prior answer.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
There was a problem hiding this comment.
1 issue found across 18 files
Confidence score: 2/5
- In
apps/api/src/soa/soa.service.ts, switching the SOA export read path without handling legacy applicability means existing records with null values will render asApplicable: N/A, causing incorrect export output for previously decided documents after deploy — backfill/version legacy applicability data before enabling this path.
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/soa.service.ts">
<violation number="1" location="apps/api/src/soa/soa.service.ts:538">
P1: Existing SOA exports will show `Applicable: N/A` after deployment even when prior documents had saved decisions. Backfill/version legacy applicability before switching this read path; otherwise the same null rows also make subsequent answered-count recalculations regress historical documents.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
| closure: question.columnMapping?.closure ?? null, | ||
| title: question.columnMapping?.title ?? null, | ||
| control_objective: question.columnMapping?.control_objective ?? null, | ||
| isApplicable: answer?.isApplicable ?? null, |
There was a problem hiding this comment.
P1: Existing SOA exports will show Applicable: N/A after deployment even when prior documents had saved decisions. Backfill/version legacy applicability before switching this read path; otherwise the same null rows also make subsequent answered-count recalculations regress historical documents.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/soa/soa.service.ts, line 538:
<comment>Existing SOA exports will show `Applicable: N/A` after deployment even when prior documents had saved decisions. Backfill/version legacy applicability before switching this read path; otherwise the same null rows also make subsequent answered-count recalculations regress historical documents.</comment>
<file context>
@@ -532,22 +519,28 @@ export class SOAService {
+ closure: question.columnMapping?.closure ?? null,
+ title: question.columnMapping?.title ?? null,
+ control_objective: question.columnMapping?.control_objective ?? null,
+ isApplicable: answer?.isApplicable ?? null,
+ justification: answer?.answer ?? null,
+ },
</file context>
|
Both SoA findings addressed in #3397 (targets `main`, flows into this release): P2 — fully-remote 7.x controls (real, fixed). The "fully remote → physical-security (7.x) controls are Not Applicable" rule was applied at generation and edit-locked, but not on the screen/export when no answer was persisted yet — so a fresh SoA could show those controls as Applicable/N/A and disagree between screen and PDF. #3397 applies the rule identically in P1 — legacy applicability shows N/A. This is intentional, not a code defect. Documents generated before the read-path change don't carry a per-answer applicability value, and it isn't reliably recoverable from stored data — so surfacing N/A and regenerating via Auto-fill is correct, rather than backfilling an unreliable value. It's a one-time data-remediation step handled outside the PR. |
…3397) * fix(soa): apply the fully-remote physical-control rule consistently A fully remote organization's physical-security (7.x) controls are Not Applicable. That rule is enforced at generation and the field is edit-locked, but the on-screen SoA and the PDF export did not apply it when no answer was persisted yet — a freshly created SoA could show those controls as Applicable/N/A and disagree between screen and export. Apply the rule identically in resolveSoaDisplay (screen) and in the export, so a fully remote org always sees Not Applicable for physical-security controls everywhere, even before auto-fill has persisted it. Adds tests for both paths. * fix(soa): always use the remote rationale for forced-remote controls For a fully remote org's edit-locked physical-security (7.x) controls, use the remote rationale unconditionally on both screen and export, rather than falling back to a persisted justification that could be stale (e.g. written before the org went remote) and contradict the Not Applicable status. Tests assert the stale persisted text is overridden on both paths.
There was a problem hiding this comment.
All reported issues were addressed across 6 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
|
🎉 This PR is included in version 3.101.1 🎉 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
Persist applicability and justification on each organization’s SoA answer and apply the fully‑remote physical‑security (7.x) rule consistently in the UI and export. UI/PDF now read per-document answers, and completion counts and saves are scoped and validated for accuracy.
New Features
SOAAnswerand keep justification for both YES and NO.resolveSoaDisplay; fully-remote orgs see 7.x controls as Not Applicable with a standard rationale, even before auto-fill persists it.questionIdis in the document’s configured questions.Migration
SOAAnswer.isApplicable; run DB migrations. Existing answers without a value render as N/A until re-filled (physical-security controls show Not Applicable for fully-remote orgs).Written for commit 1bde95b. Summary will update on new commits.