Skip to main content
Feature ID: GR-18 Spec: GR-18 Competency Validation & Assessment Engine Plan: GR-18 Implementation Plan Version: 1.0 Status: 📝 Planned Last Updated: 2026-04-24 Owner: GR (Governance & Compliance) Constitution Reference: §1 Architecture — no direct core-to-core imports; cross-core via Platform Integration Layer and events.
Auto-created by validate-spec --auto-fix (2026-04-24) to satisfy the Integration Doc Existence requirement (constitution §2.1). Pre-filled from the Integration Points section of the spec; sections marked TODO require author review before Phase A migration ships.

Overview

GR-18 ships the competency assessment engine on top of GR-02 (Training & CEU Tracking). It owns assessments, attempts, responses, and the answer-key isolation pattern. It does not own courses, enrollments, or completions — those remain GR-02. Cross-core consumers (HR-22 transcripts, GR-19 in-service matrix) read assessment evidence exclusively through @/platform/training (PIL) and the assessment_passed / assessment_failed events. Architectural pattern: Same-core writer (within GR) + PF-bus event publisher + PF Platform Integration Layer consumer. No direct core-to-core imports. Related documents:

Integration Summary


Events Published by GR-18

assessment_passed

  • Channel: gr_events (PF event bus; same pattern as GR-02-EN-01.training_completed)
  • Publisher: GR-18 — gr_submit_assessment_attempt SECURITY DEFINER RPC, on the same DB transaction as the grade write (at-least-once delivery; consumers MUST dedupe on attempt_id).
  • Subscribers:
    • GR-02 completion-gating logic (intra-RPC; creates gr_training_completions row + CEU credit when linked course verification_method = 'assessment')
    • GR-19 In-Service Compliance Monitor (optional; flips cell to “compliant” when course is assessment-gated)
    • HR-22 LMS transcript surface (optional; refreshes employee transcript view)
  • Purpose: Notify downstream consumers that an employee passed an assessment and (if applicable) a GR-02 completion has been created.
  • Status: 📝 Planned
Payload Schema:
Security note: No PHI in payload. Question stems, response text, and answer keys are NEVER included. Payload is metadata only.

assessment_failed

  • Channel: gr_events
  • Publisher: GR-18 — gr_submit_assessment_attempt, same transaction as the grade write.
  • Subscribers:
    • GR-02 enrollment status updater (sets status = 'failed' when attempt_number = max_attempts and last attempt failed)
    • PF-10 notifications (TODO: register notification key for “retry available” / “no attempts remaining” messages)
    • GR-19 (optional; surfaces failure in compliance monitor)
  • Purpose: Notify downstream consumers that an employee failed an attempt; on final failure, the enrollment is marked failed and an admin reset is required.
  • Status: 📝 Planned
Payload Schema:
Security note: Same as assessment_passed. No PHI; no question content.

Events Consumed by GR-18

None. GR-18 publishes events; it does not consume events from other cores. (Future EN: may consume enrollment_overdue from GR-02-EN-01 to surface “due soon” CTAs in the assessment runtime.)

API Contracts

SECURITY DEFINER RPCs (Internal)

All GR-18 mutations go through SECURITY DEFINER functions; no direct table writes from clients. Pattern: All RPCs use SECURITY DEFINER SET search_path = public. Tenant isolation enforced inside each function via pf_current_organization_id() check; never trust client-supplied organization_id.

REST/HTTP APIs

None. GR-18 has no Edge Functions or external HTTP endpoints in v1. All client interaction is via Supabase rpc() calls to the SECURITY DEFINER functions above, plus Supabase select() against the gr_assessment_questions_safe view (employee role) or full gr_assessment_* tables (author / review roles, RLS-gated).

Platform Integration Layers Used

GR-18 exposes its own surface through @/platform/training so cross-core consumers (HR-22, GR-19) never import directly from @/cores/gr/....

Permissions

Three new permission keys, registered in PF-30 via the Phase A seed migration AND added to src/platform/permissions/constants.ts: Audit: npm run audit:permissions MUST pass (typed entries match seed migration).

Picklists

Depends on GR-02-EN-03 which adds the value assessment to the gr.training.verification_method picklist.

Cross-Core Reads (via PIL only — no direct imports)

GR-18 reads no other core’s tables directly. Cross-core touch points:
  • HR (hr_employees) — referenced by gr_assessment_attempts.employee_id FK. Read via existing GR-02 patterns (already established as same-core dependency for GR core’s training tables). No new HR PIL hook required.
  • GR-02 tables (gr_training_courses, gr_training_enrollments) — same core; FK references. Not cross-core.

Tenant Isolation & Security

  • Every GR-18 table includes organization_id (defense-in-depth).
  • RLS enabled on all 7 tables (6 entity + 1 audit log) with SECURITY DEFINER helpers pf_current_organization_id(), pf_user_has_permission(), pf_current_employee_id() (no recursive RLS — constitution §5.7).
  • Answer-key isolation pattern: employee role has NO direct SELECT policy on gr_assessment_questions; reads go through gr_assessment_questions_safe view (omits correct_answer + rationale).
  • Server-side time enforcement on submit; client timer is advisory only.
  • Attempts + responses are immutable after submission (no UPDATE policy); admin void via SECURITY DEFINER + audit-log row.
  • Event payloads contain UUIDs and metadata only — no question stems, no response text, no PHI.

Failure Modes


Validation Checklist

Per docs/architecture/integrations/CONTRACT_VALIDATION_CHECKLIST.md:
  • Event payloads documented with TypeScript schema (above)
  • No PHI in event payloads (verified above)
  • All RPCs marked SECURITY DEFINER SET search_path = public
  • Tenant isolation pattern documented (above)
  • Permission keys registered in PF-30 seed migration AND src/platform/permissions/constants.ts
  • PIL hooks exported from @/platform/training (no direct cross-core imports)
  • Cross-core matrix entry added to CROSS_CORE_INTEGRATIONS.mdTODO
  • Event contracts registered in EVENT_CONTRACTS.mdTODO

References