Skip to content

51 scoring for robins#208

Merged
InfinityBowman merged 10 commits into
mainfrom
51-reconcile-for-robins
Jan 3, 2026
Merged

51 scoring for robins#208
InfinityBowman merged 10 commits into
mainfrom
51-reconcile-for-robins

Conversation

@InfinityBowman
Copy link
Copy Markdown
Owner

@InfinityBowman InfinityBowman commented Jan 3, 2026

Summary by CodeRabbit

  • New Features

    • Added ROBINS-I intelligent auto-scoring engine that calculates risk judgements based on domain answers.
    • Introduced Auto/Manual mode toggle, allowing users to switch between calculated and manually-set scores.
    • Added Scoring Summary component displaying overall assessment results and domain completion status.
    • Enhanced text field editors with improved content handling across assessment sections.
  • Tests

    • Added comprehensive test suite for ROBINS-I scoring logic.

✏️ Tip: You can customize this high-level summary in your review settings.

@InfinityBowman InfinityBowman linked an issue Jan 3, 2026 that may be closed by this pull request
@InfinityBowman InfinityBowman changed the title 51 reconcile for robins 51 scoring for robins Jan 3, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 3, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This PR implements a comprehensive ROBINS-I auto-scoring engine, refactors checklist operations into modular type-specific handlers, replaces inline text inputs with collaborative NoteEditor components across sections, and introduces auto/manual scoring mode switching for domain and overall judgements in the checklist UI.

Changes

Cohort / File(s) Summary
Configuration & Mock Routes
.vscode/settings.json, packages/web/src/Routes.jsx, packages/web/src/components/mock/MockIndex.jsx, packages/web/src/components/mock/RobinsReconcileSectionBQuestionMock.jsx
Fixed JSON syntax error; added two public mock routes and corresponding visual-only components for ROBINS-I Section B reconciliation mock.
ROBINS-I Scoring Engine
packages/web/src/components/checklist/ROBINSIChecklist/scoring/robins-scoring.js, packages/web/src/components/checklist/ROBINSIChecklist/scoring/decision-tables/table*.md (9 files), packages/web/src/components/checklist/ROBINSIChecklist/__tests__/robins-scoring.test.js, packages/web/src/components/checklist/ROBINSIChecklist/checklist.js
Implemented deterministic table-driven scoring engine with domain-specific logic (D1A–D6), decision tables for each domain, and comprehensive test suite; integrated scoreAllDomains and getEffectiveDomainJudgement into checklist state.
Checklist Operations Refactoring
packages/web/src/primitives/useProject/checklists.js (removed), packages/web/src/primitives/useProject/checklists/index.js, packages/web/src/primitives/useProject/checklists/common.js, packages/web/src/primitives/useProject/checklists/handlers/base.js, packages/web/src/primitives/useProject/checklists/handlers/amstar2.js, packages/web/src/primitives/useProject/checklists/handlers/robins-i.js
Deleted monolithic checklists module; introduced modular handler architecture with type-specific handlers (AMSTAR2, ROBINS-I) extending a base ChecklistHandler, common operations utility, and coordinating index module; exposed getRobinsText for field-level text retrieval. Requires attention: Complete API reorganization of checklist operations.
Prop Threading & Integration
packages/web/src/components/checklist/ChecklistWithPdf.jsx, packages/web/src/components/checklist/ChecklistYjsWrapper.jsx, packages/web/src/components/checklist/GenericChecklist.jsx, packages/web/src/primitives/useProject/index.js
Threaded getRobinsText prop from useProject hook through ChecklistWithPdf → GenericChecklist → ROBINSIChecklist for field-level free-text access; exposed getRobinsText in public useProject API.
Auto/Manual Mode UI
packages/web/src/components/checklist/ROBINSIChecklist/DomainSection.jsx, packages/web/src/components/checklist/ROBINSIChecklist/OverallSection.jsx, packages/web/src/components/checklist/ROBINSIChecklist/DomainJudgement.jsx
Introduced auto-first scoring with computed autoScore/effectiveJudgement; added isManualMode and isOverridden reactive flags; implemented mode toggle (Auto/Manual) and revert-to-calculated option; refactored button rendering to support auto-mode styling. Requires attention: Significant state management and UI refactoring affecting core scoring display.
Text Input Replacement
packages/web/src/components/checklist/ROBINSIChecklist/PlanningSection.jsx, packages/web/src/components/checklist/ROBINSIChecklist/SectionA.jsx, packages/web/src/components/checklist/ROBINSIChecklist/SectionB.jsx, packages/web/src/components/checklist/ROBINSIChecklist/SectionC.jsx, packages/web/src/components/checklist/ROBINSIChecklist/SectionD.jsx, packages/web/src/components/checklist/ROBINSIChecklist/SignallingQuestion.jsx
Replaced inline textarea/input elements with NoteEditor components; introduced yText() helpers and getRobinsText prop usage to fetch Y.Text for collaborative editing; removed local state update handlers.
Summary & Navigation
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx, packages/web/src/components/checklist/ROBINSIChecklist/ROBINSIChecklist.jsx
Added new ScoringSummary component displaying overall badge, domain chips with per-domain judgements, and Resources modal; integrated into ROBINSIChecklist with sticky header and handleDomainClick callback for in-page navigation; added scroll-margin styling to domain sections.
Data Sync & Migration
packages/web/src/primitives/useProject/sync.js, packages/workers/migrations/meta/0000_snapshot.json, packages/workers/migrations/meta/_journal.json, packages/workers/scripts/generate-openapi.mjs
Enhanced sync logic to convert Y.Text to plain strings during extraction; applied JSON formatting changes to migration files and OpenAPI script (no functional changes).
Tests
packages/web/src/primitives/__tests__/useProject.test.js
Added test case verifying judgementSource preservation as "manual" when updating overall ROBINS-I checklist section.

Sequence Diagrams

sequenceDiagram
    autonumber
    actor User
    participant ROBINSIChecklist
    participant DomainSection
    participant ScoringEngine as Scoring Engine<br/>(robins-scoring.js)
    participant State as Checklist State
    
    User->>DomainSection: Updates domain question answer
    DomainSection->>ScoringEngine: scoreRobinsDomain(domain, answers)
    ScoringEngine-->>DomainSection: {judgement, ruleId, isComplete}
    DomainSection->>State: Store auto score + update domainState
    DomainSection->>DomainSection: Compute effectiveJudgement<br/>(auto or manual override)
    
    alt In Auto Mode
        DomainSection->>DomainSection: Display "Calculated" judgement
        Note over DomainSection: Judgement source: 'auto'
    else User Switches to Manual
        User->>DomainSection: Click "Manual" toggle
        DomainSection->>State: judgementSource = 'manual'<br/>preserve current/auto judgement
        DomainSection->>DomainSection: Display manual edit option
    end
    
    alt Manual Override Changed
        User->>DomainSection: Update manual judgement
        DomainSection->>State: Update judgement + judgementSource
        DomainSection->>DomainSection: Show "Revert to calculated" button
    end
    
    DomainSection-->>ROBINSIChecklist: Render with mode indicator
    ROBINSIChecklist->>ScoringEngine: scoreAllDomains(checklistState)
    ScoringEngine-->>ROBINSIChecklist: {domain results, overall, isComplete}
Loading
sequenceDiagram
    autonumber
    actor User
    participant ChecklistYjsWrapper
    participant useProject as useProject Hook
    participant ChecklistOps as Checklist Operations<br/>(handlers)
    participant ROBINSIHandler
    participant YDoc as Yjs Document
    
    ChecklistYjsWrapper->>useProject: getRobinsText(studyId, checklistId,<br/>sectionKey, fieldKey, questionKey)
    useProject->>ChecklistOps: checklistOps.getRobinsText(...args)
    ChecklistOps->>ROBINSIHandler: Handler.getTextGetter(getYDoc)
    ROBINSIHandler->>ROBINSIHandler: Return navigation function for<br/>reviews → study → checklist
    ROBINSIHandler-->>ChecklistOps: textGetter function
    ChecklistOps->>YDoc: Navigate to field path<br/>Create Y.Text if missing
    YDoc-->>ChecklistOps: Y.Text instance
    ChecklistOps-->>useProject: Y.Text reference
    useProject-->>ChecklistYjsWrapper: Y.Text for NoteEditor
    
    ChecklistYjsWrapper->>ChecklistYjsWrapper: Pass Y.Text to child components<br/>(PlanningSection, SectionA, etc.)
    User->>ChecklistYjsWrapper: Edit text in NoteEditor
    Note over YDoc: Yjs syncs edits<br/>collaboratively across<br/>connected clients
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Rationale: The PR spans 30+ files with significant heterogeneous changes: (1) new deterministic scoring engine with 9 decision tables requiring validation against ROBINS-I specifications; (2) complete refactoring of checklist operations with new modular handler architecture affecting critical data-access paths; (3) substantial UI state management additions (auto/manual modes, derived computed values) in 3 core components; (4) repetitive text-input replacements across 6 sections but with distinct integration points; (5) new ScoringSummary component with modal and navigation logic. The scoring engine and handler refactoring demand careful code review for correctness and API compatibility; DomainSection and OverallSection changes require verification of state transitions and manual override logic.

Possibly related PRs

  • Robins i #50: Directly overlaps on ROBINS-I scoring engine paths (scoreRobinsDomain, getRobinsText, checklist handlers, scoring UI) with code-level modifications to the same modules.
  • 81 todo tab multiple pdf support #83: Modifies packages/web/src/primitives/useProject/checklists.js (main PR deletes/replaces this module), creating a direct conflict/overlap requiring coordination.
  • improve ux for robins and add missing sections #66: Overlapping changes to ROBINS-I checklist UI components (PlanningSection, SectionA–D, DomainJudgement, OverallSection, ROBINSIChecklist) affecting the same rendering and state logic.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 74.65% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The PR title '51 scoring for robins' refers to issue #51 and mentions 'scoring' and 'robins', which aligns with the core objective of implementing ROBINS-I smart scoring. However, the title is vague and abbreviated, lacking clarity about what 'scoring' entails or the scope of changes. Consider a more descriptive title such as 'Add ROBINS-I smart scoring engine with auto/manual mode switching' to better convey the main change and its significance.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Jan 3, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
corates a702dbb Commit Preview URL Jan 03 2026, 05:23 AM

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/web/src/components/checklist/ROBINSIChecklist/DomainSection.jsx (1)

198-206: Subsection questions lack collaborative comment editing props; verify if intentional.

Subsection questions (Domain 3, lines 198-206) don't receive domainKey, questionKey, and getRobinsText props, unlike non-subsection questions (lines 181-183). These props are optional and only affect Y.Text-synced collaborative comment editing via NoteEditor. When these props are absent, commentYText() returns null, and NoteEditor gracefully falls back to local-only comments without real-time sync.

Functionally, subsection questions work correctly, but they lose collaborative comment editing. If comment collaboration should be consistent across all questions, pass the missing props with appropriate keys. If subsections intentionally exclude collaborative features, add a comment explaining why.

🧹 Nitpick comments (9)
packages/web/src/primitives/useProject/checklists/common.js (2)

19-37: Consider updating study's updatedAt for consistency.

The deleteChecklist function updates studyYMap.set('updatedAt', Date.now()) (line 56), but updateChecklist only updates the checklist's own updatedAt (line 36). For consistency, consider updating the study's updatedAt when a checklist is modified, so that study-level change tracking reflects checklist updates.

Proposed change
   if (updates.title !== undefined) checklistYMap.set('title', updates.title);
   if (updates.assignedTo !== undefined) checklistYMap.set('assignedTo', updates.assignedTo);
   if (updates.status !== undefined) checklistYMap.set('status', updates.status);
   checklistYMap.set('updatedAt', Date.now());
+  studyYMap.set('updatedAt', Date.now());

65-80: Ensure consistent null return for missing answers.

Line 79 returns checklistYMap.get('answers'), which will return undefined if the 'answers' key doesn't exist, but the JSDoc states it returns Y.Map|null. For consistency with the rest of the function's null-checking pattern, consider explicitly returning null when answers are missing.

Proposed change
   const checklistYMap = checklistsMap.get(checklistId);
   if (!checklistYMap) return null;

-  return checklistYMap.get('answers');
+  const answersMap = checklistYMap.get('answers');
+  return answersMap || null;
packages/web/src/components/checklist/ROBINSIChecklist/DomainJudgement.jsx (1)

48-53: Consider extracting getShortLabel to a shared utility.

Both DomainJudgement and JudgementBadge define identical getShortLabel functions. While this works fine, extracting it to a shared utility (e.g., in checklist-map.js or a separate utils file) would eliminate duplication and ensure consistency if the label shortening logic needs to change in the future.

Also applies to: 140-145

packages/web/src/components/checklist/ROBINSIChecklist/ROBINSIChecklist.jsx (1)

96-105: ScoringSummary sticky positioning.

The sticky positioning with z-40 and inline top: '8px' provides a floating summary header. Consider using a CSS variable or Tailwind class for the top offset to maintain consistency with the scroll-margin-top calculation in domain sections.

packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx (1)

150-164: Domain chips with accessibility title.

The domain chips include a descriptive title attribute showing the full domain name and status. Consider adding aria-label for better screen reader support since the visible text is abbreviated (D1, D2, etc.).

Optional: Add aria-label for improved accessibility
               <button
                 type='button'
                 onClick={() => props.onDomainClick?.(domainKey)}
                 title={`${ROBINS_I_CHECKLIST[domainKey]?.name}: ${getDomainStatusText(domainKey)}`}
+                aria-label={`${ROBINS_I_CHECKLIST[domainKey]?.name}: ${getDomainStatusText(domainKey)}`}
                 class={`inline-flex items-center gap-1 rounded border px-2 py-0.5 text-xs font-medium transition-colors hover:opacity-80 ${getDomainChipColor(domainKey)}`}
               >
packages/web/src/components/checklist/ROBINSIChecklist/OverallSection.jsx (1)

165-199: Mode toggle UI with duplicate revert action.

The "Revert to calculated" link (lines 168-176) and the "Auto" button (lines 178-187) both call handleRevertToAuto. Consider removing the redundant link since the Auto button provides the same functionality with clearer UX.

Optional: Remove redundant revert link

The Auto/Manual toggle buttons already provide the ability to switch modes. The additional "Revert to calculated" link may be redundant:

           {/* Mode toggle */}
           <div class='flex items-center gap-2'>
-            <Show when={isManualMode() && isOverridden()}>
-              <button
-                type='button'
-                onClick={handleRevertToAuto}
-                disabled={props.disabled}
-                class='text-xs text-blue-600 hover:text-blue-800 hover:underline disabled:opacity-50'
-              >
-                Revert to calculated
-              </button>
-            </Show>
             <div class='flex rounded-md border border-gray-200 bg-white text-xs'>
packages/web/src/primitives/useProject/checklists/index.js (1)

20-22: Unused projectId parameter.

The projectId parameter is declared but never used within the function body. If it's intended for future use, consider prefixing it with an underscore (_projectId) like _isSynced to indicate intentional non-use. Otherwise, remove it.

packages/web/src/components/checklist/ROBINSIChecklist/scoring/robins-scoring.js (1)

376-379: Unused variable _q10 in Domain 4 scoring.

The variable _q10 (d4_10) is extracted from answers but is not used in the current scoring logic. The underscore prefix indicates awareness, but consider adding a comment explaining this is reserved for future table expansion, or remove it if not needed.

packages/web/src/components/checklist/ROBINSIChecklist/DomainSection.jsx (1)

247-278: Auto/Manual toggle buttons have redundant click handler.

The "Auto" button (lines 248-262) calls handleRevertToAuto() on click, which is the same action as the "Revert to calculated" link above (lines 235-246). This is intentional UX (clicking "Auto" when in manual mode reverts to auto), but consider extracting the common styling logic to reduce duplication.

Consider extracting button styling
const modeButtonClass = (isActive, disabled) => `
  px-2.5 py-1 transition-colors
  ${isActive ? 'bg-blue-100 text-blue-800' : 'text-gray-600 hover:bg-gray-50'}
  ${disabled ? 'cursor-not-allowed opacity-50' : ''}
`;

Comment on lines +1 to +10
| Rule | Q1.1 Appropriate analysis | Q1.2 All confounders controlled | Q1.3 Confounders measured validly | Q1.4 Post‑intervention vars controlled | Q1.5 Uncontrolled confounding | Risk of Bias |
| ---- | ------------------------- | ------------------------------- | --------------------------------- | -------------------------------------- | ----------------------------- | ----------------------------- |
| 1 | Y/PY | Y/PY | Y/PY | — | N/PN | **Low** |
| 2 | Y/PY | Y/PY | Y/PY | — | Y/PY | **Moderate** |
| 3 | Y/PY | WN | Y/PY/WN | — | N/PN | **Low (except uncontrolled)** |
| 4 | Y/PY | WN | Y/PY/WN | — | Y/PY | **Moderate** |
| 5 | Y/PY | SN/NI | — | — | — | **Serious** |
| 6 | N/PN/NI | — | — | Y/PY | — | **Critical** |
| 7 | N/PN/NI | — | — | N/PN/NI | Y/PY | **Critical** |
| 8 | N/PN/NI | — | — | N/PN/NI | N/PN | **Serious** |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Replace unicode em-dashes with ASCII hyphens.

The table uses unicode em-dash characters (—) for cells indicating "not applicable," which violates the coding guideline prohibiting unicode symbols. Use regular ASCII hyphens or plain text instead.

🔎 Proposed fix

Replace all unicode em-dashes (—) with regular hyphens (-) or dashes (--):

  | Rule | Q1.1 Appropriate analysis | Q1.2 All confounders controlled | Q1.3 Confounders measured validly | Q1.4 Post‑intervention vars controlled | Q1.5 Uncontrolled confounding | Risk of Bias                  |
  | ---- | ------------------------- | ------------------------------- | --------------------------------- | -------------------------------------- | ----------------------------- | ----------------------------- |
- | 3    | Y/PY                      | WN                              | Y/PY/WN                           | —                                      | N/PN                          | **Low (except uncontrolled)** |
+ | 3    | Y/PY                      | WN                              | Y/PY/WN                           | -                                      | N/PN                          | **Low (except uncontrolled)** |
- | 5    | Y/PY                      | SN/NI                           | —                                 | —                                      | —                             | **Serious**                   |
+ | 5    | Y/PY                      | SN/NI                           | -                                 | -                                      | -                             | **Serious**                   |

[As per coding guidelines: "Do NOT use unicode symbols - unicode symbols are forbidden anywhere in the codebase"]

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
packages/web/src/components/checklist/ROBINSIChecklist/scoring/decision-tables/table
(1).md around lines 1 to 10, the table uses unicode em-dashes (—) to indicate
"not applicable"; replace every em-dash character with an ASCII hyphen (-) (or
plain text like "N/A" if preferred by project style) so no unicode symbols
remain, ensuring the replacements preserve table alignment and spacing.

Comment on lines +1 to +9
| Rule | Q2.1 Distinguishable at start | Q2.2 Outcomes distinguishable | Q2.3 Appropriate analysis | Q2.4 Outcome‑dependent classification | Q2.5 Further errors | Risk of Bias |
| ---- | ----------------------------- | ----------------------------- | ------------------------- | ------------------------------------- | ------------------- | ------------ |
| 1 | Y/PY | — | — | N/PN | N/PN | **Low** |
| 2 | Y/PY | — | — | N/PN | Y/PY/NI | **Moderate** |
| 3 | Y/PY | — | — | WY/NI | N/PN | **Moderate** |
| 4 | Y/PY | — | — | SY | — | **Serious** |
| 5 | N/PN/NI | Y/PY | — | N/PN | N/PN | **Low** |
| 6 | N/PN/NI | N/PN/NI | Y/PY | WY/NI | Y/PY/NI | **Serious** |
| 7 | N/PN/NI | N/PN/NI | N/PN | SY/WY/NI | — | **Critical** |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Replace unicode em-dashes with ASCII hyphens.

The table uses unicode em-dash characters (—) for cells indicating "not applicable," which violates the coding guideline prohibiting unicode symbols. Use regular ASCII hyphens or plain text instead.

🔎 Proposed fix

Replace all unicode em-dashes (—) with regular hyphens (-):

  | Rule | Q2.1 Distinguishable at start | Q2.2 Outcomes distinguishable | Q2.3 Appropriate analysis | Q2.4 Outcome‑dependent classification | Q2.5 Further errors | Risk of Bias |
  | ---- | ----------------------------- | ----------------------------- | ------------------------- | ------------------------------------- | ------------------- | ------------ |
- | 1    | Y/PY                          | —                             | —                         | N/PN                                  | N/PN                | **Low**      |
+ | 1    | Y/PY                          | -                             | -                         | N/PN                                  | N/PN                | **Low**      |
- | 2    | Y/PY                          | —                             | —                         | N/PN                                  | Y/PY/NI             | **Moderate** |
+ | 2    | Y/PY                          | -                             | -                         | N/PN                                  | Y/PY/NI             | **Moderate** |
- | 3    | Y/PY                          | —                             | —                         | WY/NI                                 | N/PN                | **Moderate** |
+ | 3    | Y/PY                          | -                             | -                         | WY/NI                                 | N/PN                | **Moderate** |
- | 4    | Y/PY                          | —                             | —                         | SY                                    | —                   | **Serious**  |
+ | 4    | Y/PY                          | -                             | -                         | SY                                    | -                   | **Serious**  |

[As per coding guidelines: "Do NOT use unicode symbols - unicode symbols are forbidden anywhere in the codebase"]

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
packages/web/src/components/checklist/ROBINSIChecklist/scoring/decision-tables/table
(2).md around lines 1 to 9, the table uses unicode em-dashes (—) to indicate
"not applicable"; replace every unicode em-dash with a plain ASCII hyphen (-) so
cells show "-" instead of "—", and save the file ensuring no other unicode dash
characters remain.

Comment on lines +1 to +10
| Rule | Complete data (4.1–4.3) | Method | Missingness handled | Evidence not biased | Risk |
| ---- | ----------------------- | ------------- | ---------------------- | ------------------- | ------------ |
| 1 | All Y/PY | — | — | — | **Low** |
| 2 | Any N/PN/NI | Complete‑case | Not outcome‑related | — | **Low** |
| 3 | Any N/PN/NI | Complete‑case | Explained by model | Y/PY | **Moderate** |
| 4 | Any N/PN/NI | Complete‑case | Explained by model | N/PN | **Serious** |
| 5 | Any N/PN/NI | Imputation | MAR/MCAR + appropriate | — | **Low** |
| 6 | Any N/PN/NI | Imputation | Weak/unclear | Y/PY | **Moderate** |
| 7 | Any N/PN/NI | Imputation | Weak/unclear | N/PN | **Serious** |
| 8 | Any N/PN/NI | Poor/none | Strong concern | N/PN | **Critical** |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Replace unicode dashes with ASCII hyphens throughout the table.

The table uses unicode characters: em-dashes (—) for "not applicable" cells and en-dashes in terms like "Complete‑case" and "outcome‑related." These violate the coding guideline prohibiting unicode symbols. Replace with regular ASCII hyphens.

🔎 Proposed fix

Replace unicode em-dashes and en-dashes with ASCII hyphens:

  | Rule | Complete data (4.1–4.3) | Method        | Missingness handled    | Evidence not biased | Risk         |
  | ---- | ----------------------- | ------------- | ---------------------- | ------------------- | ------------ |
- | 1    | All Y/PY                | —             | —                      | —                   | **Low**      |
+ | 1    | All Y/PY                | -             | -                      | -                   | **Low**      |
- | 2    | Any N/PN/NI             | Complete‑case | Not outcome‑related    | —                   | **Low**      |
+ | 2    | Any N/PN/NI             | Complete-case | Not outcome-related    | -                   | **Low**      |
- | 3    | Any N/PN/NI             | Complete‑case | Explained by model     | Y/PY                | **Moderate** |
+ | 3    | Any N/PN/NI             | Complete-case | Explained by model     | Y/PY                | **Moderate** |
- | 4    | Any N/PN/NI             | Complete‑case | Explained by model     | N/PN                | **Serious**  |
+ | 4    | Any N/PN/NI             | Complete-case | Explained by model     | N/PN                | **Serious**  |

[As per coding guidelines: "Do NOT use unicode symbols - unicode symbols are forbidden anywhere in the codebase"]

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
packages/web/src/components/checklist/ROBINSIChecklist/scoring/decision-tables/table
(6).md around lines 1 to 10, replace all unicode dash characters (em-dash U+2014
"—", en-dash U+2013 "–", and non‑breaking hyphen U+2011 "‑") used in the table
with the ASCII hyphen-minus character '-' so that cells like "—" become "-" and
terms like "Complete‑case" and "outcome‑related" use "Complete-case" and
"outcome-related"; update every occurrence in the file and save.

Comment on lines +79 to +90
{responseOptions.map(option => (
<div
class={`inline-flex items-center justify-center rounded-lg border-2 px-4 py-2 text-sm font-medium transition-all ${
reviewer1Answer === option ?
'border-blue-400 bg-blue-50 text-blue-800'
: 'border-gray-200 bg-white text-gray-700'
}`}
>
<span class='mr-1'>{option}</span>
<span class='text-xs opacity-70'>({RESPONSE_LABELS[option]})</span>
</div>
))}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use SolidJS For component instead of Array.map().

The component uses Array.map() to render response options in three places. Per the coding guidelines, SolidJS applications should use the For component for rendering lists instead of Array.map().

Example refactor for Reviewer 1 panel
+import { createSignal, For } from 'solid-js';
...
-              {responseOptions.map(option => (
+              <For each={responseOptions}>
+                {option => (
                  <div
                    class={`inline-flex items-center justify-center rounded-lg border-2 px-4 py-2 text-sm font-medium transition-all ${
                      reviewer1Answer === option ?
                        'border-blue-400 bg-blue-50 text-blue-800'
                      : 'border-gray-200 bg-white text-gray-700'
                    }`}
                  >
                    <span class='mr-1'>{option}</span>
                    <span class='text-xs opacity-70'>({RESPONSE_LABELS[option]})</span>
                  </div>
-              ))}
+                )}
+              </For>

Apply the same pattern to the other two panels (Reviewer 2 and Final).

As per coding guidelines: "Use Solid's For component for rendering lists instead of Array.map()"

Also applies to: 110-121, 141-160

🤖 Prompt for AI Agents
In packages/web/src/components/mock/RobinsReconcileSectionBQuestionMock.jsx
around lines 79-90 (and similarly at 110-121 and 141-160), the JSX uses
Array.map() to render responseOptions; replace each Array.map usage with
SolidJS's For component (import For from 'solid-js' or 'solid-js/web' as
appropriate), move the mapped markup into the For child function, and ensure
each item is rendered using the item and index provided by For (no manual key
prop needed). Apply the same For-based refactor to the Reviewer 2 and Final
panels at the other line ranges so all list rendering follows the SolidJS
guideline.

Comment on lines +238 to +246
Object.entries(data.answers).forEach(([qKey, qValue]) => {
let questionYMap = answersNestedYMap.get(qKey);
if (!questionYMap || !(questionYMap instanceof Y.Map)) {
questionYMap = new Y.Map();
answersNestedYMap.set(qKey, questionYMap);
}
if (qValue.answer !== undefined) questionYMap.set('answer', qValue.answer);
if (qValue.comment !== undefined) questionYMap.set('comment', qValue.comment);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Comment field stored as string instead of Y.Text in updateAnswer.

In updateAnswer for domain questions (line 245), qValue.comment is set directly as a string. However, in createAnswersYMap (line 68), comments are initialized as Y.Text. This inconsistency could cause issues when collaborative edits occur on comments.

Suggested fix: Handle comment as Y.Text in updateAnswer
         Object.entries(data.answers).forEach(([qKey, qValue]) => {
           let questionYMap = answersNestedYMap.get(qKey);
           if (!questionYMap || !(questionYMap instanceof Y.Map)) {
             questionYMap = new Y.Map();
             answersNestedYMap.set(qKey, questionYMap);
           }
           if (qValue.answer !== undefined) questionYMap.set('answer', qValue.answer);
-          if (qValue.comment !== undefined) questionYMap.set('comment', qValue.comment);
+          if (qValue.comment !== undefined) {
+            const commentText = questionYMap.get('comment');
+            if (commentText instanceof Y.Text) {
+              // Update existing Y.Text content
+              commentText.delete(0, commentText.length);
+              commentText.insert(0, qValue.comment);
+            } else {
+              // Create new Y.Text if missing
+              const newComment = new Y.Text();
+              newComment.insert(0, qValue.comment);
+              questionYMap.set('comment', newComment);
+            }
+          }
         });

The same pattern should be applied to sectionB comment handling at lines 257-258.

🤖 Prompt for AI Agents
packages/web/src/primitives/useProject/checklists/handlers/robins-i.js around
lines 238-246 (and similarly adjust sectionB at lines ~257-258): updateAnswer is
storing comment as a plain string while createAnswersYMap initializes comments
as Y.Text; change the logic so you always store a Y.Text for comment: if the map
already contains a Y.Text, replace its contents with the new string (not
overwrite the entry with a string); if it does not, create a new Y.Text, set its
contents to the comment string, and put that Y.Text into the Y.Map. Apply the
same pattern for the sectionB comment handling at the noted lines.

@InfinityBowman InfinityBowman merged commit 8a7531d into main Jan 3, 2026
2 checks passed
@InfinityBowman InfinityBowman deleted the 51-reconcile-for-robins branch January 3, 2026 14:32
This was referenced Jan 7, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Apr 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Automatic Scoring for ROBINS

2 participants