Skip to content

Develop#14

Merged
nerikebosch merged 36 commits intomainfrom
develop
Jan 17, 2026
Merged

Develop#14
nerikebosch merged 36 commits intomainfrom
develop

Conversation

@nerikebosch
Copy link
Copy Markdown
Collaborator

@nerikebosch nerikebosch commented Jan 17, 2026

User description

v0.0.2 release.
Finished calibration , added unit tests, added documentation, fixed accuracy and other metric algorithms, added results page.


PR Type

Enhancement, Tests, Bug fix


Description

  • Comprehensive unit test suite: Added 1000+ lines of tests covering iris tracking, saccade detection, accuracy calculation, Firebase operations, Redux store, and UI components with mocks and edge case handling

  • Iris tracking refactoring: Implemented local eye coordinate system using getRelativeIrisPos() for improved accuracy, replacing raw landmark indices with normalized positioning

  • Adaptive threshold system: Added per-trial velocity-based threshold calculation in velocityConfig.js and integrated throughout saccade detection and analysis pipeline

  • Webcam-optimized accuracy metrics: New accuracyAdjust.js module with quality-weighted fixation analysis, saccadic gain calculation, and ADHD biomarker detection tailored for 30fps webcam tracking

  • Clinical interpretation layer: Enhanced Results view with research-based ADHD thresholds, dual doughnut accuracy charts, and detailed clinical findings based on Karatekin et al. (2010) and Lee et al. (2020)

  • Calibration improvements: Ridge regression support with cross-validation, enhanced UI with permission handling, animated demo visualization, and synchronization guards

  • Validation relaxation: Loosened saccade detection constraints (time delta, binocular requirements, disparity handling) for improved real-world webcam performance

  • CI/CD pipeline: Added GitHub Actions workflow with automated testing across Node.js versions, coverage reporting, and quality gates

  • Firebase mocking infrastructure: Created comprehensive mock modules for auth, Firestore, and storage for testing

  • Route restructuring: Moved GameTest outside layout wrapper for fullscreen support


Diagram Walkthrough

flowchart LR
  A["Iris Tracking<br/>Local Coordinates"] -->|normalized positions| B["Adaptive<br/>Thresholds"]
  B -->|per-trial velocity| C["Saccade<br/>Detection"]
  C -->|validated saccades| D["Accuracy<br/>Calculation"]
  D -->|quality metrics| E["Clinical<br/>Interpretation"]
  E -->|ADHD thresholds| F["Results<br/>Dashboard"]
  G["Calibration<br/>Ridge Regression"] -->|trained model| D
  H["Unit Tests<br/>1000+ lines"] -.->|validates| A
  H -.->|validates| C
  H -.->|validates| D
Loading

File Walkthrough

Relevant files
Tests
18 files
iris-facemesh.test.js
Comprehensive unit tests for iris face mesh tracker           

src/tests/utils/iris-facemesh.test.js

  • Added comprehensive unit test suite with 614 lines covering
    IrisFaceMeshTracker class functionality
  • Tests include constructor initialization, iris position calculation,
    calibration model setup, gaze prediction, trial context management,
    saccade detection, and CSV export
  • Includes integration tests for multi-frame tracking and bilateral eye
    consistency
  • Mocks MediaPipe FaceLandmarker and detectSaccade dependencies
+614/-0 
saccadeData.test.js
Unit tests for saccade data analysis module                           

src/tests/utils/saccadeData.test.js

  • Added comprehensive unit tests for saccade data analysis functions
    (analyzeSaccadeData, aggregateTrialStatistics, compareProVsAnti)
  • Tests cover saccade detection, latency classification
    (express/normal/delayed), invalid frame handling, and pro vs
    anti-saccade comparisons
  • Includes tests for edge cases like insufficient data and error
    handling
  • Mocks dependencies including accuracy calculations and velocity
    configuration
+280/-0 
accuracyAdjust.test.js
Unit tests for accuracy calculation module                             

src/tests/utils/accuracyAdjust.test.js

  • Added 217 lines of unit tests for the calculateAccuracy function
  • Tests cover perfect accuracy scenarios, hypometric/hypermetric saccade
    detection, fixation stability assessment, and binocular disparity
    handling
  • Includes edge cases like missing saccade data and poor tracking
    quality
  • Mocks calibration store dependencies
+217/-0 
detectSaccade.test.js
Unit tests for saccade detection module                                   

src/tests/utils/detectSaccade.test.js

  • Added 167 lines of unit tests for saccade detection functions
    (detectSaccade, calculateAdaptiveThreshold, detectSaccadeRaw)
  • Tests validate time delta checking, calibration data requirements,
    velocity threshold detection, and binocular disparity handling
  • Includes tests for adaptive threshold calculation with various
    velocity distributions
  • Mocks velocity configuration with realistic screen and saccade
    parameters
+167/-0 
auth.test.js
Firebase authentication unit tests                                             

src/tests/firebase/auth.test.js

  • Added 180 lines of Firebase authentication tests covering user
    registration, login, logout, and profile updates
  • Tests include error handling for invalid credentials and user not
    found scenarios
  • Includes full authentication flow tests (registration and login/logout
    sequences)
  • Uses Firebase mock implementations
+180/-0 
firestore.test.js
Firestore database operation unit tests                                   

src/tests/firebase/firestore.test.js

  • Added 161 lines of Firestore operation tests covering document
    creation, retrieval, and user data operations
  • Tests include error handling for permission denied and network errors
  • Includes tests for non-existent documents and user data flow on
    registration/login
  • Uses Firestore mock implementations
+161/-0 
authSlice.test.js
Redux authentication slice unit tests                                       

src/tests/store/authSlice.test.js

  • Added 151 lines of Redux auth slice tests covering reducer actions
    (login, logout, setLoading, setError)
  • Tests include selector functions and state transitions for full
    login/logout flows
  • Includes error flow handling and state immutability verification
+151/-0 
firebaseConfig.test.js
Firebase configuration and setup tests                                     

src/tests/firebase/firebaseConfig.test.js

  • Added 121 lines of Firebase configuration tests verifying environment
    variables and config structure
  • Tests validate auth domain and storage bucket formats
  • Includes tests for Firebase mock exports (auth, db, storage functions)
+121/-0 
Results.test.js
Results view component unit tests                                               

src/tests/views/Results.test.js

  • Added 114 lines of component tests for the Results view
  • Tests cover authentication state, loading states, empty results, and
    dashboard rendering with charts
  • Mocks Chart.js components and Firebase Firestore operations
+114/-0 
GameTest.test.js
GameTest view component unit tests                                             

src/tests/views/GameTest.test.js

  • Added 118 lines of component tests for the GameTest view
  • Tests cover start modal rendering and test initiation with fullscreen
    API
  • Mocks IrisFaceMeshTracker, saccade analysis utilities, and Firebase
    operations
+118/-0 
store.test.js
Redux store configuration unit tests                                         

src/tests/store/store.test.js

  • Added 90 lines of Redux store configuration tests
  • Tests verify store structure, auth reducer integration, and action
    dispatching
  • Includes state immutability verification
+90/-0   
firebase.js
Firebase mock module for testing                                                 

src/mocks/firebase.js

  • Created comprehensive Firebase mock module with auth and Firestore
    functions
  • Includes mock implementations for createUserWithEmailAndPassword,
    signInWithEmailAndPassword, signOut, updateProfile
  • Includes Firestore mocks for doc, setDoc, getDoc, and collection
    operations
  • Added helper functions mockAuthenticatedUser and
    mockUnauthenticatedUser for test state management
+96/-0   
Input.test.js
Input component unit tests                                                             

src/tests/components/Input.test.js

  • Added 70 lines of unit tests for Input component
  • Tests cover rendering, placeholder, onChange callback, controlled
    values, labels, and input types (password, email)
  • Includes tests for name attribute and default CSS classes
+70/-0   
Button.test.js
Button component unit tests                                                           

src/tests/components/Button.test.js

  • Added 56 lines of unit tests for Button component
  • Tests cover rendering, onClick callbacks, type attributes, variant
    classes (primary/secondary), and fullWidth styling
+56/-0   
Instructions.test.js
Instructions view component unit tests                                     

src/tests/views/Instructions.test.js

  • Added 43 lines of component tests for Instructions view
  • Tests verify content rendering and navigation to game test on button
    click
  • Mocks useNavigate and Helmet components
+43/-0   
auth.js
Firebase auth mock module                                                               

src/mocks/firebase/auth.js

  • Created Firebase auth mock module with getAuth,
    createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut,
    updateProfile, and onAuthStateChanged functions
+24/-0   
app.js
Firebase app initialization mock module                                   

src/mocks/firebase/app.js

  • Created Firebase app initialization mock module with initializeApp,
    getApps, and getApp functions
+16/-0   
storage.js
Firebase Storage mock module                                                         

src/mocks/firebase/storage.js

  • Created Firebase Storage mock module with getStorage, ref,
    uploadBytes, and getDownloadURL functions
+7/-0     
Enhancement
16 files
iris-facemesh.js
Refactor iris tracking with local coordinates and enhanced
documentation

src/views/GameTest/utils/iris-facemesh.js

  • Refactored iris position calculation to use local eye coordinates
    (relative to eye corners) instead of raw landmark indices
  • Added getRelativeIrisPos() method implementing vector projection for
    normalized iris positioning
  • Enhanced predictGaze() with metadata-aware coordinate system detection
    and fallback normalization
  • Improved camera initialization with explicit frame rate and resolution
    settings
  • Added comprehensive JSDoc documentation for all public methods
  • Enhanced frame processing with diagnostic logging and improved data
    point structure
  • Refactored saccade detection to always store velocity and optional
    debug information
+223/-58
dotCalibration.js
Calibration refactored to use local eye coordinates           

src/views/Calibration/utils/modules/dotCalibration.js

  • Replaced raw iris landmark indices with local eye coordinate system
    using getRelativeIrisPos()
  • Updated getDotPoints() to return both pixel and normalized coordinates
    for calibration points
  • Added skip-first-N-frames logic (3 frames) to avoid transient tracking
    artifacts
  • Enhanced diagnostic logging for calibration point collection with
    detailed landmark information
  • Improved margin calculation using percentage-based approach (5%
    margins) instead of magic numbers
  • Added JSDoc documentation for all exported functions
+207/-42
index.js
Add clinical interpretation and ADHD threshold analysis to results

src/views/Results/index.js

  • Added research-based ADHD thresholds for latency, accuracy, and
    variability metrics
  • Implemented interpretation memo that generates clinical findings based
    on threshold comparisons
  • Enhanced bar chart with reference threshold line for ADHD likelihood
  • Refactored accuracy chart to display dual doughnut (pro and
    anti-saccade) with custom legend
  • Added "Analysis & Interpretation" card with summary and detailed
    findings list
  • Included disclaimer with citations to Karatekin et al. (2010) and Lee
    et al. (2020)
  • Updated consistency card with reference values for control vs ADHD
    groups
  • Improved chart labels and helper text for clarity
+195/-26
saccadeData.js
Integrate adaptive thresholds and gain-based accuracy metrics

src/views/GameTest/utils/saccadeData.js

  • Updated to use new calculateAccuracy from accuracyAdjust module
  • Added adaptive threshold calculation using per-trial velocity analysis
  • Enhanced latency classification with express/normal/delayed/invalid
    categories
  • Added saccadic gain metrics to trial analysis and aggregation
  • Improved error handling in compareProVsAnti() with safety checks and
    fallback values
  • Added gain-based ADHD marker detection (hypometric saccade tracking)
  • Enhanced logging with trial-specific threshold and latency
    classification output
+163/-78
accuracyAdjust.js
New webcam-optimized accuracy calculation with adaptive ROI

src/views/GameTest/utils/accuracyAdjust.js

  • New module implementing webcam-adjusted accuracy calculation with
    adaptive ROI
  • Calculates frame quality scores based on binocular consistency and
    velocity plausibility
  • Implements quality-weighted sustained fixation analysis (60% weight)
    over landing precision
  • Uses relaxed thresholds appropriate for 30fps webcam tracking (70%
    stability vs 80% desktop)
  • Includes saccadic gain calculation with hypometric/hypermetric
    detection
  • Provides ADHD-specific biomarkers (poor fixation stability, unstable
    tracking)
  • Returns detailed component scores and tracking quality metrics for
    debugging
+299/-0 
index.js
Implement adaptive per-trial thresholds and improved calibration
validation

src/views/GameTest/index.js

  • Added comprehensive JSDoc header describing test flow and phases
  • Implemented per-trial adaptive threshold calculation based on fixation
    window velocities
  • Enhanced calibration validation with retry logic (up to 50 attempts,
    100ms intervals)
  • Improved trial timing with explicit fixation start/end time tracking
  • Updated saccade analysis to use adaptive threshold instead of fixed
    value
  • Added detailed console logging for saccade analysis and phase
    transitions
  • Refactored dot appearance time calculation using getRelativeTime()
    method
  • Enhanced error handling and user feedback for missing calibration
+81/-28 
mathUtils.js
Enhanced calibration math utilities with regression algorithms

src/views/Calibration/utils/modules/mathUtils.js

  • Replaced simple matrix operations with robust regression
    implementations: leastSquares (OLS) and ridgeRegression (L2
    regularization)
  • Added gaussianElimination function for solving linear systems with
    pivoting and singular matrix detection
  • Implemented findOptimalLambda function using k-fold cross-validation
    to find optimal regularization parameter
  • Added comprehensive JSDoc documentation explaining mathematical
    concepts and parameters
+197/-36
display.js
Calibration model fitting with ridge regression support   

src/views/Calibration/utils/modules/display.js

  • Updated displayPredictionModel to support both OLS and Ridge
    Regression methods via useRidge parameter
  • Added per-eye movement analysis with detailed logging of iris position
    ranges and symmetry checks
  • Integrated findOptimalLambda for cross-validation-based lambda
    selection
  • Enhanced calibration metadata storage with method, samples, and
    coordinate system information
  • Improved console logging with calibration results and RMSE values
+117/-25
index.js
Calibration UI improvements and permission handling           

src/views/Calibration/index.js

  • Updated accuracy threshold check to use data.metrics?.accuracy instead
    of data.metrics?.details
  • Changed threshold value from 0.85 to 0.849
  • Added UI layout improvements with grid-based header and "how it works"
    sections
  • Added calibration demo visualization with animated dot showing 9-point
    calibration pattern
  • Added camera permission modal for handling permission denial scenarios
  • Hid overlay calibration button with inline style
+71/-23 
velocityConfig.js
Enhanced velocity configuration with latency validation   

src/views/GameTest/utils/velocityConfig.js

  • Changed screen dimensions from window.screen to
    window.innerWidth/innerHeight for better accuracy
  • Added latency validation thresholds for pro-saccade and anti-saccade
    trials with express/normal/delayed classifications
  • Added amplitude and duration validation constants for saccade
    detection
  • Implemented calculatePerTrialThreshold function for per-trial adaptive
    threshold calculation with fixation velocity filtering
  • Updated adaptive threshold multiplier from 3 to 2.5 and increased
    minimum fixation samples from 10 to 20
+61/-13 
video.js
Camera stream initialization with permission handling       

src/views/Calibration/utils/modules/video.js

  • Added JSDoc documentation for cameraLoop and startDistanceCheck
    functions
  • Enhanced video stream request with specific resolution (1280x720) and
    frame rate (60fps min 30fps) parameters
  • Added camera permission modal display on permission denial
  • Added fallback alert for camera access denial
  • Added check to hide overlay calibration button when starting distance
    check
  • Added JSDoc for stopDistanceCheck function
+30/-1   
calibration.js
Calibration process synchronization and documentation       

src/views/Calibration/utils/calibration.js

  • Added calibrationRunning flag to prevent multiple simultaneous
    calibration sessions
  • Enhanced initCalibration with guard logic to prevent duplicate
    calibration starts
  • Added cleanup to reset calibration flag on module cleanup
  • Added JSDoc documentation for functions and flag
+30/-1   
faceModel.js
MediaPipe FaceLandmarker initialization improvements         

src/views/Calibration/utils/modules/faceModel.js

  • Updated MediaPipe WASM URL from specific version (0.10.3) to @latest
    for automatic updates
  • Added JSDoc documentation for faceLandmarker global and
    initFaceLandmarker function
  • Added confidence thresholds for face detection, presence, and tracking
    (all set to 0.5)
+14/-2   
distance.js
Distance validation threshold and documentation                   

src/views/Calibration/utils/modules/distance.js

  • Updated CLOSE distance threshold from 0.25 to 0.30
  • Added JSDoc documentation for distanceOK flag, computeEyeDistance, and
    handleDistanceState functions
+19/-1   
Calibration.css
Calibration UI styling enhancements                                           

src/views/Calibration/Calibration.css

  • Added grid layout styles for "how it works" section with two-column
    layout
  • Added demo screen visualization with animated calibration dot showing
    9-point pattern
  • Added camera permission modal styling with warning icon and centered
    panel
  • Added responsive media queries for mobile devices
  • Removed max-width constraint on video-box element
  • Added header grid layout for calibration introduction with image
    support
+185/-1 
Results.css
Results view styling improvements                                               

src/views/Results/Results.css

  • Added padding to stat-footer element
  • Added interpretation card styling with content, summary, and list
    styles
  • Added disclaimer text styling with reduced font size and italic
    formatting
  • Added reference text styling for citations
+42/-0   
Miscellaneous
1 files
accuracy.js
Archive original accuracy calculation implementation         

src/views/GameTest/utils/accuracy.js

  • Commented out entire original accuracy calculation implementation (61
    lines)
  • Preserved research-grade algorithm documentation for future reference
  • File now serves as placeholder for new accuracy calculation module
+312/-60
Documentation
2 files
domRefs.js
Add documentation and camera permission modal reference   

src/views/Calibration/utils/modules/domRefs.js

  • Added JSDoc documentation for refs object and initDomRefs() function
  • Added reference to camera permission modal element (permissionModal)
+10/-0   
index.js
Instructions view documentation                                                   

src/views/Instructions/index.js

  • Added JSDoc documentation block describing the Instructions view
    component and its purpose
+6/-0     
Bug fix
3 files
detectSaccade.js
Relaxed saccade detection validation constraints                 

src/views/GameTest/utils/detectSaccade.js

  • Modified time delta validation to allow up to 2x the maximum delta
    (relaxed constraint)
  • Changed binocular data validation to require at least one eye instead
    of both eyes
  • Updated disparity check to return isValid: true with reason flag
    instead of isValid: false for excessive disparity
  • Improved calibration data validation with detailed debug information
+29/-19 
app.js
GameTest route restructuring for fullscreen support           

src/app.js

  • Moved gameTest route outside of the main layout route to render
    without the layout wrapper
  • Changed route nesting structure to allow GameTest to render in
    fullscreen without header/footer
+1/-1     
GameTest.css
GameTest fullscreen and dot positioning adjustments           

src/views/GameTest/GameTest.css

  • Changed min-height from calc(100vh - 60px) to 100vh for fullscreen
    coverage
  • Updated left-dot position from 10% to 20%
  • Updated right-dot position from 10% to 20%
+3/-3     
Configuration changes
3 files
setupTests.js
Jest test environment configuration                                           

src/setupTests.js

  • Created Jest test setup file with global mocks for window.matchMedia
    and ResizeObserver
  • Added console error suppression for React deprecation warnings during
    tests
  • Imports @testing-library/jest-dom for extended matchers
+41/-0   
test.yml
GitHub Actions CI/CD test workflow with quality gates       

.github/workflows/test.yml

  • Added comprehensive GitHub Actions workflow for automated testing on
    pull requests to main, master, and develop branches
  • Configured matrix testing across Node.js versions 18.x and 20.x
  • Implemented test execution with coverage reporting and quality gate
    enforcement (90% pass rate minimum)
  • Added Firebase environment variables configuration and coverage
    artifact upload with 7-day retention
+112/-0 
.env.test
Test environment variables configuration file                       

.env.test

  • Created test environment configuration file with placeholder Firebase
    credentials
  • Includes all required Firebase environment variables for testing
    purposes
  • Provides template for local testing setup with dummy values
+10/-0   
Dependencies
1 files
package.json
Testing dependencies and Jest configuration setup               

package.json

  • Added test:ci script for continuous integration testing with coverage
    and no watch mode
  • Added testing library dependencies (@testing-library/react,
    @testing-library/jest-dom, @testing-library/user-event)
  • Configured Jest test matching pattern to look for tests in
    src/__tests__/**/*.test.js
  • Added coverage collection configuration excluding index.js, test
    files, and mock files
+18/-1   
Additional files
1 files
velocity.js +0/-92   

quangptt0910 and others added 30 commits January 4, 2026 20:56
Improved aesthetically the calibration screen
- Add Jest/React Testing Library setup
- Add tests for:
  - Redux auth slice (login, logout, state transitions)
  - Redux store configuration
  - Firebase authentication (sign in, sign up, sign out)
  - Firestore operations (doc, setDoc, getDoc)
  - Firebase configuration validation
  - Button component
  - Input component
- Add Firebase mocks for testing
- Add GitHub Actions workflow to run tests on PRs
- Workflow blocks merge if tests don't pass 90% threshold
- Add test:ci script for CI environments

Total: 83 tests across 7 test suites
…culation

- Changed npm ci to npm install to avoid package-lock sync issues
- Fixed bash regex parsing (removed -P flag not available on Ubuntu)
- Simplified workflow to single test job with quality gate check
- Use awk instead of bc for arithmetic operations
- Fixed quality gate job to properly check needs.test.result
- Import Button and Input directly from their folders instead of barrel export
- Barrel export (components/index.js) triggers Firebase init via Layout/Navbar
- All 83 tests now pass
Added docstrings to Calibration screen, and deleted redundant imports
@nerikebosch nerikebosch merged commit 8dc15b9 into main Jan 17, 2026
3 checks passed
@qodo-code-review
Copy link
Copy Markdown

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🔴
Sensitive data exposure

Description: New diagnostic logging and data export paths expose highly sensitive
biometric/health-adjacent data (raw/normalized iris positions, calibrated gaze
coordinates, inferred saccade events/velocity, and trial context such as trial,
dotPosition, targetX, targetY) via console.log/console.warn and CSV export, which can leak
user data to shared devices, remote debugging/telemetry tooling, or screenshots/session
recordings.
iris-facemesh.js [231-351]

Referred Code
// 🔍 DIAGNOSTIC - Log first 3 frames
if (this.trackingData.length < 3) {
    console.log(`🎮Frame ${this.trackingData.length + 1}:`, {
        timestamp,
        leftIris,
        rightIris,
        totalLandmarks: landmarks.length
    });
}

// Apply calibration if available
let calibratedLeft = null;
let calibratedRight = null;
let calibratedAvg = null;

if (this.calibrationModel) {
    calibratedLeft = this.predictGaze(leftIris, 'left');
    calibratedRight = this.predictGaze(rightIris, 'right');

    // Average the two eyes
    if (calibratedLeft && calibratedRight) {


 ... (clipped 100 lines)
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Unhandled edge cases: getRelativeIrisPos() can throw on invalid eyeSide and can divide by zero when eyeWidthSq
is 0, causing runtime failures instead of graceful degradation.

Referred Code
getRelativeIrisPos(landmarks, eyeSide) {
    const indices = EYE_INDICES[eyeSide];
    const pInner = landmarks[indices.inner];
    const pOuter = landmarks[indices.outer];
    const pIris = landmarks[indices.iris];

    if (!pInner || !pOuter || !pIris) return null;

    // 1. Calculate Vector Basis (Eye Width line)
    const vecEye = { x: pOuter.x - pInner.x, y: pOuter.y - pInner.y };
    const vecIris = { x: pIris.x - pInner.x, y: pIris.y - pInner.y };

    // 2. Eye Width (Magnitude squared for projection)
    const eyeWidthSq = vecEye.x * vecEye.x + vecEye.y * vecEye.y;
    const eyeWidth = Math.sqrt(eyeWidthSq);

    // 3. Project Iris onto horizontal Eye Axis (Scalar Projection)
    // Formula: (Iris • Eye) / |Eye|^2
    // This gives a normalized X value: 0.0 (Inner) -> 1.0 (Outer)
    let normX = (vecIris.x * vecEye.x + vecIris.y * vecEye.y) / eyeWidthSq;



 ... (clipped 9 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Sensitive debug logging: New console.log() statements emit detailed biometric/behavioral tracking data (iris
positions/landmarks, calibration metrics) in unstructured logs, which can expose sensitive
health-related signals.

Referred Code
    console.log(`📍 Point ${idx} (target: ${screenX.toFixed(2)}, ${screenY.toFixed(2)}):`, {
        dotPixels: { x: screenX * window.innerWidth, y: screenY * window.innerHeight },
        targetNormalized: { x: screenX, y: screenY },

        // 🔍 RAW LANDMARKS (before flip)
        raw_468_frameLeft: leftRaw,
        raw_473_frameRight: rightRaw,

        // After processing
        irisLeft: left,
        irisRight: right,

        videoSize: { width: refs.video.videoWidth, height: refs.video.videoHeight },
        totalLandmarks: lm.length
    });
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Unsafe data handling: New calculations can produce invalid values due to missing/incorrect validation (e.g.,
hypometricRate divides by gains.length when gains is empty, and selector
selectCalibrationMetrics is used like data rather than being invoked with state).

Referred Code
const accuracyResults = calculateAccuracy(
    recordingData,
    dotAppearanceTime,
    saccadeInfo,
    {
        calibrationAccuracy: selectCalibrationMetrics?.accuracy?.left || 0.90, //fallback value
        trackerFPS: 30,             // webcam frame rate
        roiRadius: null,
        fixationDuration: 300,
        saccadicGainWindow: 100,
        minLatency: minLatency,
        fixationStabilityThreshold: 0.70
    }
);

//  Data Quality
const totalFramesAnalyzed = validFrameCount + invalidFrameCount;
const dataQuality = totalFramesAnalyzed > 0
    ? validFrameCount / totalFramesAnalyzed
    : 0;



 ... (clipped 124 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit scope: The diff adds analytics/clinical interpretation and Firebase reads but does not show
whether any critical actions (auth/data access) are auditable with
userId/timestamp/outcome logs, requiring verification outside the visible hunks.

Referred Code
// Fetch saccade metrics history from Firebase Firestore
useEffect(() => {
  const fetchMetrics = async () => {
    if (!user?.uid) return;

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status:
Non-descriptive locals: New code introduces terse identifiers (e.g., r, lm, p, tx, ty) in multiple places that may
reduce readability, though they may be acceptable as short-lived locals and should be
reviewed in full-file context.

Referred Code
const r = faceLandmarker.detectForVideo(refs.video, performance.now());
if (r?.faceLandmarks?.length) {
    const lm = r.faceLandmarks[0];
    // const right = computeIrisCenter(lm, RIGHT_IRIS_CENTER);
    // const left = computeIrisCenter(lm, LEFT_IRIS_CENTER);

    // Use local coordinates (0.0 - 1.0 relative to eye corners)
    // No need for manual "1 - x" flipping here; the corners define the direction.
    const rightRaw = getRelativeIrisPos(lm, 'right');
    const leftRaw = getRelativeIrisPos(lm, 'left');

    // NOTE: Even with local coords, we ensure the object structure is clean
    const right = rightRaw ? {
        x: 1 - rightRaw.x, // FLIP X to match screen direction
        y: rightRaw.y
    } : null;

    const left = leftRaw ? {
        x: 1 - leftRaw.x, // FLIP X to match screen direction
        y: leftRaw.y
    } : null;


 ... (clipped 3 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Handle regression failures during cross-validation

In findOptimalLambda, handle ridgeRegression failures by setting the error to
Infinity and breaking the loop to prevent selecting an unstable lambda.

src/views/Calibration/utils/modules/mathUtils.js [192-197]

 // Train model
 const beta = ridgeRegression(trainA, trainB, lambda);
-if (!beta) continue;
+if (!beta) {
+    totalError = Infinity;
+    break; // Exit the fold loop for this lambda
+}
 
 // Test error
 for (let i = 0; i < testA.length; i++) {
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion identifies a critical bug in the cross-validation logic where a failing lambda value could be incorrectly chosen as optimal, leading to a poor calibration model.

High
Prevent crash when one eye is undetected

Prevent a runtime error by adding a null check before calculating avgIris. If
one eye's data is missing, use the available eye's data for the average.

src/views/GameTest/utils/iris-facemesh.js [291-294]

-avgIris: {
+avgIris: (leftIris && rightIris) ? {
     x: (leftIris.x + rightIris.x) / 2,
     y: (leftIris.y + rightIris.y) / 2,
-},
+} : (leftIris || rightIris),
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: This suggestion correctly identifies a potential TypeError that would crash the application if landmarks for one eye are not detected. The proposed fix is robust and prevents the crash, making it a critical improvement for the application's stability.

Medium
Prevent CSV export from crashing

Prevent the exportCSV function from crashing by using optional chaining (?.)
when accessing properties of point.leftIris, point.rightIris, and point.avgIris.
This handles cases where eye data might be null.

src/views/GameTest/utils/iris-facemesh.js [453-467]

 this.trackingData.forEach(point => {
 
     csv += `${point.startTime || point.timestamp},`;
-    csv += `${point.leftIris.x},${point.leftIris.y},`;
-    csv += `${point.rightIris.x},${point.rightIris.y},`;
-    csv += `${point.avgIris.x},${point.avgIris.y},`;
+    csv += `${point.leftIris?.x || ''},${point.leftIris?.y || ''},`;
+    csv += `${point.rightIris?.x || ''},${point.rightIris?.y || ''},`;
+    csv += `${point.avgIris?.x || ''},${point.avgIris?.y || ''},`;
     csv += `${point.calibrated.left?.x || ''},${point.calibrated.left?.y || ''},`;
     csv += `${point.calibrated.right?.x || ''},${point.calibrated.right?.y || ''},`;
     csv += `${point.calibrated.avg?.x || ''},${point.calibrated.avg?.y || ''},`;
     csv += `${point.isSaccade || false},`;
     csv += `${point.velocity || 0},`;
     csv += `${point.trial || ''},`;
     csv += `${point.dotPosition || ''},`;
     csv += `${point.targetX || ''},${point.targetY || ''}\n`;
 });

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 8

__

Why: This suggestion correctly identifies a potential TypeError that would crash the CSV export functionality if eye data is missing for any frame. The proposed fix using optional chaining is idiomatic and effectively prevents the crash, ensuring the export feature is reliable.

Medium
Handle monocular data during saccade detection

In validateBinocularData, when only one eye's velocity is available, return it
as the average velocity to prevent NaN calculations downstream.

src/views/GameTest/utils/detectSaccade.js [66-74]

 // Validity check: At least one eye must be tracked (Relaxed from requiring both)
 if (leftVelocity === null && rightVelocity === null) {
     return {
         leftVelocity,
         rightVelocity,
         isValid: false,
         reason: 'no_data'
     };
 }
 
+// If one eye is missing, use the other as the average
+if (leftVelocity === null || rightVelocity === null) {
+    return {
+        leftVelocity,
+        rightVelocity,
+        isValid: true,
+        avgVelocity: leftVelocity ?? rightVelocity,
+        reason: 'monocular_data'
+    };
+}
+
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion fixes a bug where monocular data causes a NaN velocity calculation, by correctly propagating the single available eye's velocity.

Medium
Correct return property typo

In the return object of displayPredictionModel, correct the typo sucess to
success.

src/views/Calibration/utils/modules/display.js [145-151]

 return {
-    sucess: {left: leftRes.success, right: rightRes.success },
+    success: {left: leftRes.success, right: rightRes.success },
     rmse: {left: leftRes.rmse, right: rightRes.rmse },
     accuracy: { left: leftRes.accuracy, right: rightRes.accuracy },
     method: useRidge ? 'ridge' : 'ols'
 };
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion corrects a typo in a returned object key, which would likely cause a runtime error or incorrect behavior in the consuming code.

Medium
Correctly filter invalid coordinate values

In the per-eye movement analysis, replace .filter(Boolean) with an explicit
check for null or undefined to avoid incorrectly filtering out valid 0
coordinates.

src/views/Calibration/utils/modules/display.js [71-85]

 // Left eye analysis
-const leftIrisX = gazeData.map(d => d.iris_left?.x).filter(Boolean);
+const leftIrisX = gazeData.map(d => d.iris_left?.x).filter(v => v !== null && v !== undefined);
 const leftMinX = Math.min(...leftIrisX);
 const leftMaxX = Math.max(...leftIrisX);
 ...
 // Right eye analysis
-const rightIrisX = gazeData.map(d => d.iris_right?.x).filter(Boolean);
+const rightIrisX = gazeData.map(d => d.iris_right?.x).filter(v => v !== null && v !== undefined);
 const rightMinX = Math.min(...rightIrisX);
 const rightMaxX = Math.max(...rightIrisX);

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a bug where valid coordinates of 0 are filtered out, which affects the accuracy of debugging logs.

Low
Validate modal element reference

Before assigning the camera permission modal to refs.permissionModal, check if
the element exists to prevent null references and log a warning if it's not
found.

src/views/Calibration/utils/modules/domRefs.js [19]

-refs.permissionModal = document.getElementById("camera-permission-modal");
+{
+    const modal = document.getElementById("camera-permission-modal");
+    if (!modal) {
+        console.warn('DOM element "camera-permission-modal" not found.');
+    }
+    refs.permissionModal = modal;
+}
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion improves code robustness by adding a null check for a DOM element, which helps prevent potential runtime errors and aids in debugging.

Low
General
Pin WASM URL version

Replace the @latest tag in the MediaPipe WASM URL with a specific, pinned
version (e.g., 0.10.3) to prevent unexpected breaking changes from future
releases.

src/views/Calibration/utils/modules/faceModel.js [19-21]

 const resolver = await FilesetResolver.forVisionTasks(
-    "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm" // CHANGED to @latest
+    "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm"
 );
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: This suggestion correctly identifies that using @latest for a critical dependency is risky and can lead to unexpected runtime failures, proposing a change that ensures application stability.

Medium
Clamp normalized iris values

Clamp the calculated normX and normY values to the [0, 1] range in the
getRelativeIrisPos function. This will prevent potential errors from extreme
head poses that could cause out-of-bounds coordinates.

src/views/GameTest/utils/iris-facemesh.js [73-81]

 let normX = (vecIris.x * vecEye.x + vecIris.y * vecEye.y) / eyeWidthSq;
+normX = Math.max(0, Math.min(1, normX));
 ...
 let normY = 0.5 + (crossProduct / eyeWidth) * 4.0;
+normY = Math.max(0, Math.min(1, normY));

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: This is a good defensive programming practice that increases the robustness of the iris position calculation. By clamping the values, it prevents potential out-of-bounds errors in downstream logic that consumes these coordinates, such as gaze prediction.

Medium
Use JSON output for robust testing

Refactor the test script in the CI workflow to use Jest's JSON output and jq for
parsing test results, making it more robust and less prone to breaking from text
output changes.

.github/workflows/test.yml [32-76]

 - name: Run tests with coverage
   id: run-tests
   run: |
-    set +e
-    npm run test:ci 2>&1 | tee test-output.txt
-    TEST_EXIT_CODE=$?
-    set -e
+    npm run test:ci -- --json --outputFile=test-results.json || true
     
-    # Extract test results - look for "Tests: X passed, Y total" pattern
-    if grep -q "Tests:" test-output.txt; then
-      PASSED_TESTS=$(grep "Tests:" test-output.txt | grep -oE '[0-9]+ passed' | grep -oE '[0-9]+' | tail -1 || echo "0")
-      TOTAL_TESTS=$(grep "Tests:" test-output.txt | grep -oE '[0-9]+ total' | grep -oE '[0-9]+' | tail -1 || echo "0")
-    else
-      PASSED_TESTS="0"
-      TOTAL_TESTS="0"
+    if [ ! -f test-results.json ]; then
+      echo "::error::test-results.json not found. Tests may have crashed."
+      exit 1
     fi
-    
+
+    PASSED_TESTS=$(jq '.numPassedTests' test-results.json)
+    TOTAL_TESTS=$(jq '.numTotalTests' test-results.json)
+    TEST_STATUS=$(jq -r '.testResults[0].status' test-results.json)
+
     echo "Total Tests: $TOTAL_TESTS"
     echo "Passed: $PASSED_TESTS"
-    echo "test_exit_code=$TEST_EXIT_CODE" >> $GITHUB_OUTPUT
     echo "passed=$PASSED_TESTS" >> $GITHUB_OUTPUT
     echo "total=$TOTAL_TESTS" >> $GITHUB_OUTPUT
-    
-    if [ "$TOTAL_TESTS" -gt "0" ] && [ "$PASSED_TESTS" -gt "0" ]; then
+
+    if [ "$TOTAL_TESTS" -gt "0" ]; then
       PASS_RATE=$(awk "BEGIN {printf \"%.2f\", ($PASSED_TESTS / $TOTAL_TESTS) * 100}")
       echo "Pass Rate: $PASS_RATE%"
       echo "pass_rate=$PASS_RATE" >> $GITHUB_OUTPUT
       
-      # Check if pass rate is >= 90%
       PASS_CHECK=$(awk "BEGIN {print ($PASS_RATE >= 90) ? 1 : 0}")
       if [ "$PASS_CHECK" -eq "1" ]; then
         echo "✅ Quality gate passed! Pass rate: $PASS_RATE%"
       else
         echo "❌ Quality gate failed! Pass rate: $PASS_RATE% (required: 90%)"
         exit 1
       fi
+    elif [ "$TEST_STATUS" == "passed" ]; then
+      echo "✅ All tests passed!"
     else
-      # If we can't determine test count, use exit code
-      if [ $TEST_EXIT_CODE -eq 0 ]; then
-        echo "✅ All tests passed!"
-      else
-        echo "❌ Tests failed!"
-        exit 1
-      fi
+      echo "❌ Tests failed!"
+      exit 1
     fi
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion significantly improves the CI workflow's robustness by replacing a brittle text-parsing script with a standard and reliable JSON-based approach.

Medium
Add init error handling

Add a try/catch block within the initFaceLandmarker function to handle and log
potential errors during model loading and initialization, preventing silent
failures.

src/views/Calibration/utils/modules/faceModel.js [17-35]

 export async function initFaceLandmarker() {
-    const resolver = await FilesetResolver.forVisionTasks( /* ... */ );
-    faceLandmarker = await FaceLandmarker.createFromOptions(resolver, { /* options */ });
+    try {
+        const resolver = await FilesetResolver.forVisionTasks( /* ... */ );
+        faceLandmarker = await FaceLandmarker.createFromOptions(resolver, { /* options */ });
+    } catch (error) {
+        console.error("Failed to initialize FaceLandmarker:", error);
+        throw error;
+    }
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out missing error handling for a critical, failure-prone initialization process, improving the application's robustness and debuggability.

Medium
Use config static threshold

Replace the hardcoded fallback threshold of 30 with the
STATIC_THRESHOLD_DEG_PER_SEC constant from the velocity configuration file.

src/views/GameTest/index.js [270-276]

 // ...
 // Record when fixation ends
 const fixationEndTime = irisTracker.current.getRelativeTime();
 
-let trialThreshold = 30;
+import { VelocityConfig } from "./utils/velocityConfig";
+let trialThreshold = VelocityConfig.SCREEN.STATIC_THRESHOLD_DEG_PER_SEC;
 
 if (irisTracker.current) {
   // ...
 }
 // ...

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 5

__

Why: The suggestion correctly points out a hardcoded value that should be sourced from the configuration file, improving maintainability and consistency.

Low
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants