Skip to main content

Result Remediation Roadmap (Phase 1–2 implemented)

Scope: Phase-based (no dates). Phase 1–2 backend foundations are implemented; Phase 3+ (preview/approvals/interventions) is deferred.


0. Current State (Baseline)

Already implemented and proven via backend/tests scripts:

  • Targeted item-level remediation

    • mark_correct on single and multi-item submissions.
    • drop_item to remove flawed items from scoring.
    • replace_key to swap correct options.
  • Scoped impact

    • Only submissions containing the targeted (evaluationVersionId, questionVersionId) are rescored.
  • Multi-attempt support

    • Same user, multiple attempts; remediation batch rescoring all relevant attempts.
  • Non-destructive behaviour

    • Version snapshots and raw answers remain unchanged; only score/interpretation changes.

These are the engine primitives that all later phases build on.


Phase 1 – Domain & Audit Foundations (Implemented)

Goal: Turn remediation from “just some code” into a first-class, auditable domain concept without yet adding complex workflow.

1.1 Harden CorrectionBatch as a domain entity

Make CorrectionBatch the central audit unit for remediation.

  • Add/ensure fields:

    • id

    • tenant_id (and org_unit_id if applicable) – RLS scope

    • status (enum): initially draft and applied

      • Explicitly leave room for pending_review, approved, reverted later.
    • reason (non-null, “why we did this”)

    • created_by_user_id

    • created_at

    • applied_at

    • correction_payload (existing JSON of corrections)

Outcome: Every remediation action has a WHO / WHEN / WHY and a clear status, even with a simple draft→applied lifecycle.


1.2 Add score history / remediation log

Introduce a dedicated history structure so we can reconstruct score changes over time and support safe reversal.

  • New table (name flexible, e.g. submission_score_history):

    • id
    • submission_id
    • correction_batch_id (NULL for original scoring)
    • score
    • max_score
    • created_at
  • Invariants:

    • Initial scoring writes a row with correction_batch_id = NULL.
    • Every remediation apply writes a new row per affected submission with the batch id.
    • submissions.score and submissions.max_score are always the latest history row.

Outcome: We can always explain:

  • What a submission’s score is now,
  • How it got there,
  • Which batch changed it (if any).

This table underpins both auditability and reversal.


1.3 Engine integration & idempotency

Wire the existing remediation engine to:

  • Always:

    • Record history rows.
    • Update submissions.score/max_score atomically.
  • Ensure idempotency:

    • Re-applying the same batch does not keep boosting scores.
    • Existing idempotent behaviour from scripts is preserved and enforced via tests.

Outcome: The engine is safe to call multiple times and leaves a clean history trail.


Phase 2 – Basic Workflow Services & Reversal (Implemented, stop here)

Goal: Expose remediation as a simple, safe workflow that frontend can use, including reversal. This is the initial implementation boundary – development stops here for now.

2.1 Minimal batch lifecycle APIs

Expose a thin but coherent API so admins can see and apply batches.

  • Create batch (draft)

    • POST /results/correction-batches
    • Creates a draft batch with reason, created_by_user_id, created_at, correction_payload.
  • List batches

    • GET /results/correction-batches?status=draft|applied
    • Returns WHO/WHEN/WHY plus simple metadata (e.g. type of corrections).
  • Apply batch

    • POST /results/correction-batches/\{id\}/apply

    • Preconditions:

      • Batch is draft.
    • Effects:

      • Runs remediation engine, writes score history.
      • Updates submissions.score/max_score.
      • Sets status = "applied", applied_at = now().

(Optional but nice now or later: a lightweight GET /results/correction-batches/\{id\} for details.) Delivered: list/detail/apply/revert endpoints with status/appliedAt and history-based revert.


2.2 Reversal / undo (via compensating batch)

Deliver a reversal mechanism as part of this phase – this is considered essential.

  • Design a reversal flow using history:

    • For a given correction_batch_id, use submission_score_history to:

      • Determine the previous score/max_score per submission (pre-batch state).
    • Create a new CorrectionBatch that:

      • Restores those previous scores (or logically cancels the effects).
      • Writes new history rows with a reference to the original batch in the reason or a dedicated field.
  • API:

    • POST /results/correction-batches/\{id\}/revert

      • Creates and applies a new compensating batch.
      • Does not delete or mutate the original batch/history.

Key point: Reversal is additive, not destructive. Audit trail stays append-only.


2.3 Simple workflow contract for frontend

For the frontend team, the contract after Phase 2 is:

  • They can:

    • List existing remediation batches.
    • Drill into a batch to see its payload and meta (reason, who, when, status).
    • Apply a batch once they’re satisfied.
    • Revert a batch if needed (which internally creates a compensating batch).
  • They should not yet expect:

    • Tag-based batch creation helpers.
    • Preview of “who will pass/fail” before applying.
    • Multi-step approvals or an “Action Center” UI.

Initial Development Stop: Implementation for remediation stops at the end of Phase 2:

  • Domain & audit foundations (Phase 1) ✅
  • Basic lifecycle APIs + reversal (Phase 2) ✅
  • No further remediation features are built until a future phase.

Phase 3+ (Deferred)

  • Impact preview (who will pass/fail).
  • Approvals/dual control and intervention workflows.
  • Batch creation helpers (tag-based/bulk).

Phase 3 – Preview & Impact Analysis (LATER)

Goal: Allow admins to see the impact of a batch before confirming.

3.1 Dry-run scoring & submission-level impact

  • GET /results/correction-batches/\{id\}/preview:

    • Runs the remediation engine in dry-run mode.

    • Returns:

      • submissionsAffected

      • counts of:

        • passToFail
        • failToPass
        • outcomeUnchanged

3.2 Assignment/programme impact

Extend preview to include assignment-level deltas:

  • For each assignment/programme impacted:

    • List users who will:

      • move from pass → fail,
      • move from fail → pass,
      • stay the same.

This enables UX like:

“X submissions will be updated These 5 users will then FAIL the assignment ‹Final Safety Exam› These 2 users will then PASS…”

Frontend can decide how much detail to show (on-screen vs CSV export).


Phase 4 – Advanced Governance & Approvals (LATER)

Goal: Add enterprise-grade governance for high-stakes environments.

Possible extensions:

  • Batch status workflow:

    • draft → pending_review → approved → applied → reverted.
  • Dual-control:

    • Creator and approver must be different users.
  • Action Center UI:

    • Central place to see all batches, statuses, and key metrics.
  • Finer-grained access control:

    • Only users with specific capabilities can create, approve, apply, or revert batches.

All of this builds directly on top of Phase 1–3 foundations.


Phase 5 – Intervention & Controlled Retakes (LATER)

Goal: Tie remediation into assignment/programme lifecycle.

features (later):

  • Flags or statuses such as requires_intervention_before_retake.

  • Enforcement in create_session so:

    • learners can’t retake until an instructor reviews,
    • or a specific remediation step is completed.
  • Programme-level hooks:

    • Automatically issue remedial assignments based on outcomes.

These depend on existing assignment/programme models and the stable remediation core from Phases 1–2.


Summary

  • Now (Initial Implementation):

    • Phase 1 – Harden CorrectionBatch + add score history.
    • Phase 2 – Expose basic workflow services and implement a non-destructive reversal mechanism. → Development stops here for the first remediation release.
  • Later:

    • Phase 3 – Preview & impact analysis.
    • Phase 4 – Governance, approvals, “Action Center”.
    • Phase 5 – Intervention & controlled retakes.

This keeps the backend robust and future-proof, gives the frontend team clear, usable primitives, and leaves plenty of room to grow into a full-blown, enterprise-ready remediation experience when the time is right.