Skip to content

263 add rob 2 reconcile#304

Merged
InfinityBowman merged 7 commits into
mainfrom
263-add-rob-2-reconcile
Jan 17, 2026
Merged

263 add rob 2 reconcile#304
InfinityBowman merged 7 commits into
mainfrom
263-add-rob-2-reconcile

Conversation

@InfinityBowman
Copy link
Copy Markdown
Owner

@InfinityBowman InfinityBowman commented Jan 17, 2026

Summary by CodeRabbit

  • New Features

    • Full ROB‑2 reconciliation workflow: domain‑grouped navbar, per‑item pages (preliminary, signalling, domain & overall directions), summary view with agreement stats, save/reset actions, and aim‑mismatch warning.
    • Checklist comparison utilities to detect aim mismatches and produce reconciliation summaries.
    • Split‑screen reconciliation with integrated read‑only PDF viewer and synchronized navigation.
  • Style

    • Simplified and unified panel/button styling across ROB‑2, ROBINS‑I and AMSTAR‑2 for consistent visuals.

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

@InfinityBowman InfinityBowman linked an issue Jan 17, 2026 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 17, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds a ROB‑2 checklist comparison engine and a complete reconciliation UI (multi‑page editor, navbar/progress utilities, PDF split view). Exposes comparison APIs in the shared package and implements per‑item pages, panels, navbar utilities, and summary/save/reset flows in the web app.

Changes

Cohort / File(s) Summary
Shared: Comparison Engine
packages/shared/src/checklists/rob2/compare.ts, packages/shared/src/checklists/rob2/index.ts
New compare module implementing types and functions (compareChecklists, hasAimMismatch, getReconciliationSummary, domain/preliminary helpers, re-exported ROB2Checklist) and re-exported from package index.
Web: Reconciliation Shell & Integration
packages/web/src/components/project/reconcile-tab/ReconciliationWrapper.jsx
Conditional routing to render ROB‑2 reconciliation UI (ROB2ReconciliationWithPdf) and added getRob2Text wiring.
Web: Core Reconciliation UI
packages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Reconciliation.jsx, .../ROB2ReconciliationWithPdf.jsx, .../index.js
New main reconciliation component, PDF split view wrapper, navbar store wiring, local navigation persistence, auto-fill/use‑this logic, save/reset flows, and barrel export for ROB‑2 UI.
Web: Navigation & Navbar Utilities
packages/web/src/components/project/reconcile-tab/rob2-reconcile/navbar-utils.js, .../ROB2Navbar.jsx, .../NavbarDomainPill.jsx
New navigation builder and grouping, progress/agreement evaluation, domain‑grouped accordion navbar and domain pill with expandable question pills, aim mismatch alert, summary/reset controls.
Web: Pages (Per‑item UIs)
packages/web/src/components/project/reconcile-tab/rob2-reconcile/pages/PreliminaryPage.jsx, SignallingQuestionPage.jsx, DomainDirectionPage.jsx, OverallDirectionPage.jsx
Four page components rendering three‑column Reviewer1/Reviewer2/Final views, computed judgements/directions, and "Use This" actions to copy reviewer values.
Web: Panels & Summary
packages/web/src/components/project/reconcile-tab/rob2-reconcile/panels/*, ROB2SummaryView.jsx
New panels: ROB2AnswerPanel, JudgementPanel, DirectionPanel; summary view showing grouped items, stats, agreement/disagreement, navigation and save flow.
Web: Styling/Refactors in Other Reconcile Flows
packages/web/src/components/project/reconcile-tab/amstar2-reconcile/AnswerPanel.jsx, packages/web/src/components/project/reconcile-tab/robins-i-reconcile/*
Minor visual/styling simplifications: removed final background in AMSTAR‑2 AnswerPanel and reduced panelType‑based styling complexity across ROBINS‑I navbar and panels.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as ROB2Reconciliation
    participant Compare as ComparisonEngine
    participant Store as NavStore/LocalStorage
    participant PDF as EmbedPdfViewer

    User->>UI: Load reconciliation (checklist1, checklist2, pdfData)
    UI->>Compare: compareChecklists(checklist1, checklist2)
    Compare-->>UI: ComparisonResult
    UI->>Store: init navItems, viewMode, currentPage
    UI-->>User: Render current page

    User->>UI: Edit final answer or "Use This"
    UI->>Store: update finalAnswers & persist
    UI->>Compare: recompute (scores/summary)
    UI-->>User: Update UI badges/predictions

    User->>UI: Toggle/select PDF
    UI->>PDF: load/select pdfData
    PDF-->>UI: render PDF panel

    User->>UI: Click Save
    UI->>UI: validate items
    UI-->>User: prompt & confirm
    UI->>User: call onSaveReconciled(reconciledChecklist)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • 263 add rob 2 reconcile #304: Appears to add the same ROB‑2 reconciliation UI and shared compare.ts changes; directly related and likely overlapping.
  • 262 add rob 2 #275: Introduces ROB‑2 schema, domain utilities, and types that this PR’s comparison engine and UI depend on.
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title '263 add rob 2 reconcile' uses a vague/abbreviated form that doesn't clearly convey the specific change; 'add rob 2 reconcile' lacks detail about what reconciliation feature is being added. Consider revising to a more descriptive title such as 'Add ROB-2 reconciliation UI components and comparison engine' to better communicate the scope and purpose of the changes.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 93.59% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 664d584 and d4a10a1.

📒 Files selected for processing (1)
  • packages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Reconciliation.jsx

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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 17, 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 terminated
View logs
corates d4a10a1 Commit Preview URL Jan 17 2026, 06:26 PM

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: 3

🤖 Fix all issues with AI agents
In `@packages/shared/src/checklists/rob2/compare.ts`:
- Around line 205-223: The current comparison logic in the loop (using
questionKeys, domain1, domain2, and building the comparison object with
isAgreement) treats two missing answers (both ans1 and ans2 null) as an
agreement; change the isAgreement calculation to only be true when both answers
are present and equal (e.g., isAgreement = ans1 != null && ans2 != null && ans1
=== ans2) so missing answers are not counted as agreements, and ensure
downstream pushes to agreements use that updated flag.

In
`@packages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Reconciliation.jsx`:
- Around line 119-133: Clamp the persisted current page index whenever nav items
change by adding a reactive effect that reads the stored/currentPage value,
computes a clamped index between 0 and totalPages()-1, and writes it back via
the currentPage setter; then resync the expanded domain to the new
navItems()[clampedIndex] (use navItems(), totalPages(), setCurrentPage and
setExpandedDomain inside a createEffect or equivalent reactive watcher). Ensure
the effect runs when navItems() or props.reconciledChecklist (if expanded domain
depends on it) change so currentNavItem() cannot become undefined after aim
changes or stale localStorage.

In
`@packages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2ReconciliationWithPdf.jsx`:
- Around line 59-87: headerContent is a static JSX value so
props.reviewer1Name/props.reviewer2Name and navbarStore.navItems are captured
once and won’t update; change headerContent into a reactive getter (e.g., const
headerContent = () => ( ... )) or inline the JSX inside the component return so
it reads reactive props and store values, and wherever headerContent is used
call headerContent() (or pass the function if SplitScreenLayout expects a
function); keep the same structure and component references (ROB2Navbar, Show,
navbarStore.navItems, props.reviewer1Name/props.reviewer2Name) so reactivity
works.
🧹 Nitpick comments (10)
packages/web/src/components/project/reconcile-tab/amstar2-reconcile/AnswerPanel.jsx (1)

193-202: Inconsistent radio button naming pattern between views.

The full view uses ${props.title}-${props.questionKey}-final for radio names (line 195), while the compact view uses a more robust pattern with panelId fallback: ${props.panelId || props.title || 'panel'}-... (line 91).

Consider using the same fallback pattern for consistency and to avoid potential undefined in the name if props.title is not provided.

Suggested fix
                              <input
                                type='radio'
-                               name={`${props.title}-${props.questionKey}-final`}
+                               name={`${props.panelId || props.title || 'panel'}-${props.questionKey}-final`}
                                checked={isChecked()}
                                disabled={props.readOnly}
packages/web/src/components/project/reconcile-tab/rob2-reconcile/panels/DirectionPanel.jsx (1)

31-93: Drop narrating section comments.

Comments like "Panel Header", "Direction Options", and "Selected Badge" restate the JSX structure; consider removing or replacing with intent-focused notes. As per coding guidelines, comments should explain why, not what.

packages/web/src/components/project/reconcile-tab/robins-i-reconcile/NavbarDomainPill.jsx (2)

83-87: Use Show instead of a ternary for the expand/collapse icon.

This is conditional rendering, so a Show keeps SolidJS patterns consistent and avoids ternary usage in JSX. As per coding guidelines, use Show for conditional rendering.

Proposed change
-          <Show when={props.sectionKey !== 'overall'}>
-            {props.isExpanded ?
-              <FiChevronDown class='h-3 w-3 opacity-60' />
-            : <FiChevronRight class='h-3 w-3 opacity-60' />}
-          </Show>
+          <Show when={props.sectionKey !== 'overall'}>
+            <Show
+              when={props.isExpanded}
+              fallback={<FiChevronRight class='h-3 w-3 opacity-60' />}
+            >
+              <FiChevronDown class='h-3 w-3 opacity-60' />
+            </Show>
+          </Show>

33-59: Avoid section comments that restate structure.

Comments like "Container style" and "Label button style" narrate what the code does; consider removing or rewriting to capture intent. As per coding guidelines, comments should explain why, not what.

packages/web/src/components/project/reconcile-tab/rob2-reconcile/pages/SignallingQuestionPage.jsx (1)

42-83: Remove narrating section comments.

The "Header", "Info text", and "Three-column comparison" comments restate the JSX structure; consider removing or converting to intent-focused notes. As per coding guidelines, comments should explain why, not what.

packages/web/src/components/project/reconcile-tab/rob2-reconcile/pages/DomainDirectionPage.jsx (1)

46-117: Keep section comments intent-focused.

Labels like "Header", "Auto-calculated Judgement Section", and "Direction Section" describe structure rather than intent; consider removing or rewriting. As per coding guidelines, comments should explain why, not what.

packages/web/src/components/project/reconcile-tab/rob2-reconcile/pages/PreliminaryPage.jsx (1)

243-262: Consider memoizing derived values for better performance.

The fieldDef, fieldLabel, getFieldType, and getOptions functions are re-evaluated on each access. While this works, consider using createMemo for fieldDef since it depends on props.fieldKey:

-  const fieldDef = () => PRELIMINARY_SECTION[props.fieldKey];
-  const fieldLabel = () => fieldDef()?.label || props.fieldKey;
+  const fieldDef = createMemo(() => PRELIMINARY_SECTION[props.fieldKey]);
+  const fieldLabel = createMemo(() => fieldDef()?.label || props.fieldKey);

This ensures the lookup only happens when props.fieldKey changes.

packages/web/src/components/project/reconcile-tab/rob2-reconcile/NavbarDomainPill.jsx (1)

172-180: Simplify the spacing class logic.

The current pillSpacingClass implementation has overlapping conditions that make it hard to reason about. Consider simplifying:

Suggested simplification
  const pillSpacingClass = () => {
-   let spacing = '';
-   if (props.isFirst) spacing += 'ml-0.5 ';
-   if (props.isLast) spacing += 'mr-0.5 ';
-   if (!props.isFirst && !props.isLast) spacing += 'mx-0.5 ';
-   if (props.isFirst && !props.isLast) spacing += 'mr-0.5 ';
-   if (!props.isFirst && props.isLast) spacing += 'ml-0.5 ';
-   return spacing;
+   if (props.isFirst && props.isLast) return 'mx-0.5';
+   if (props.isFirst) return 'ml-0.5 mr-0.5';
+   if (props.isLast) return 'ml-0.5 mr-0.5';
+   return 'mx-0.5';
  };
packages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2SummaryView.jsx (2)

67-88: Consider memoizing getDisplayValue for repeated access.

getDisplayValue is called inside a For loop for each item, and it accesses props.finalAnswers which could be a large object. Consider memoizing or caching the results if performance becomes an issue with many items.


189-202: Complex ternary chain for badge styling could be extracted.

The nested ternary for determining badge colors based on answer values is hard to read. Consider extracting to a helper function:

Suggested extraction
function getAnswerBadgeStyle(itemType, displayValue) {
  if (itemType !== NAV_ITEM_TYPES.DOMAIN_QUESTION) {
    return 'bg-blue-100 text-blue-700';
  }
  switch (displayValue) {
    case 'Y': return 'bg-green-100 text-green-700';
    case 'PY': return 'bg-lime-100 text-lime-700';
    case 'PN': return 'bg-amber-100 text-amber-700';
    case 'N': return 'bg-red-100 text-red-700';
    default: return 'bg-gray-100 text-gray-700';
  }
}

Comment thread packages/shared/src/checklists/rob2/compare.ts
Comment on lines +59 to +87
const headerContent = (
<>
{/* Back button */}
<button
onClick={() => props.onCancel?.()}
class='shrink-0 rounded-lg p-2 transition-colors hover:bg-gray-100'
title='Go back'
>
<FiArrowLeft class='h-5 w-5 text-gray-600' />
</button>

{/* Title */}
<div class='shrink-0'>
<h1 class='text-lg font-bold text-gray-900'>ROB-2 Reconciliation</h1>
<p class='text-xs text-gray-500'>
{props.reviewer1Name || 'Reviewer 1'} vs {props.reviewer2Name || 'Reviewer 2'}
</p>
</div>

<div class='h-8 w-px shrink-0 bg-gray-200' />

{/* Navbar - navigation pills */}
<Show when={navbarStore.navItems?.length > 0}>
<div class='flex min-w-0 flex-1 items-center overflow-x-auto'>
<ROB2Navbar store={navbarStore} />
</div>
</Show>
</>
);
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 | 🟠 Major

headerContent is defined as a static JSX block, not a reactive getter.

In SolidJS, JSX defined outside of a component's return statement or a reactive context captures values at definition time. This means props.reviewer1Name and props.reviewer2Name won't update reactively, and navbarStore.navItems changes won't trigger re-renders of the Show condition.

Consider wrapping this in a function or moving it inline:

Option 1: Use a getter function
-  const headerContent = (
+  const headerContent = () => (
     <>
       {/* ... */}
     </>
   );

Then use headerContent={headerContent()} or pass the function if SplitScreenLayout supports it.

🤖 Prompt for AI Agents
In
`@packages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2ReconciliationWithPdf.jsx`
around lines 59 - 87, headerContent is a static JSX value so
props.reviewer1Name/props.reviewer2Name and navbarStore.navItems are captured
once and won’t update; change headerContent into a reactive getter (e.g., const
headerContent = () => ( ... )) or inline the JSX inside the component return so
it reads reactive props and store values, and wherever headerContent is used
call headerContent() (or pass the function if SplitScreenLayout expects a
function); keep the same structure and component references (ROB2Navbar, Show,
navbarStore.navItems, props.reviewer1Name/props.reviewer2Name) so reactivity
works.

@InfinityBowman InfinityBowman merged commit dc1b85f into main Jan 17, 2026
1 of 2 checks passed
@InfinityBowman InfinityBowman deleted the 263-add-rob-2-reconcile branch January 17, 2026 18:05
@github-actions github-actions Bot restored the 263-add-rob-2-reconcile branch January 17, 2026 18:05
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: 1

🤖 Fix all issues with AI agents
In `@packages/shared/src/checklists/rob2/compare.ts`:
- Around line 232-266: The compare functions call scoreRob2Domain and
scoreAllDomains on partial data which may have undefined domains/answers; modify
the calls in compareDomain (where scoring1/scoring2 and judgement1/judgement2
are derived) and in compareOverall (where scoring1/scoring2 and
judgement1/judgement2 are derived) to first check inputs (e.g., domain?.answers
or checklist?.domains) and either short-circuit to null judgements or pass a
safe default structure expected by scoreRob2Domain/scoreAllDomains; ensure
judgement1/judgement2 are set to null when scoring is skipped and preserve
existing fields (direction1/direction2, judgementMatch, directionMatch) to
handle nulls safely.
🧹 Nitpick comments (1)
packages/shared/src/checklists/rob2/compare.ts (1)

333-350: Agreement stats exclude judgement matches.

judgementMatch is computed but not included in stats or getReconciliationSummary. If judgements are part of reconciliation scope, consider counting them; otherwise confirm that judgements are intentionally excluded to avoid confusion.

Possible adjustment
   for (const domainKey of activeDomains) {
     const domain = domains[domainKey];
     totalItems += domain.questions.agreements.length + domain.questions.disagreements.length;
     agreedItems += domain.questions.agreements.length;

+    // Count domain judgement as an item if reconciled
+    totalItems += 1;
+    if (domain.judgementMatch) agreedItems += 1;
+
     // Count direction as an item
     totalItems += 1;
     if (domain.directionMatch) agreedItems += 1;
   }

+  // Count overall judgement
+  totalItems += 1;
+  if (overall.judgementMatch) agreedItems += 1;
+
   // Count overall direction
   totalItems += 1;
   if (overall.directionMatch) agreedItems += 1;
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc65a06 and 664d584.

📒 Files selected for processing (1)
  • packages/shared/src/checklists/rob2/compare.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/yjs-sync.mdc)

**/*.{js,jsx,ts,tsx}: Use the useProject hook for managing Yjs connections with reference counting instead of creating Y.Doc instances directly
Never create Y.Doc instances directly; always use the connection registry managed by useProject
Access Y.Doc connection state via projectStore.getConnectionState(projectId) instead of checking connection state directly
Read Yjs-synced data from projectStore (using getStudies, getChecklist, etc.) rather than accessing Y.Doc maps/arrays directly
Use operation functions from useProject or projectActionsStore for writing data instead of directly modifying Y.Doc
Don't store Y.Doc references in component state; always retrieve the connection through useProject
Handle connection cleanup via onCleanup() in Solid.js components or equivalent cleanup patterns, calling disconnect() when the component unmounts

Files:

  • packages/shared/src/checklists/rob2/compare.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)

**/*.{js,ts,jsx,tsx}: Prefer modern ES6+ syntax and features
Comments should explain why something is being done, not what the code is doing
Reserve comments for explaining intent, context, workarounds, assumptions, edge cases, or limitations
Use TODO(agent): prefix for incomplete work or flagged items with brief description and relevant doc references

Files:

  • packages/shared/src/checklists/rob2/compare.ts
**/*

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Never use emojis or unicode symbols anywhere in code, comments, documentation, plan files, commit messages, or examples

Files:

  • packages/shared/src/checklists/rob2/compare.ts
packages/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

packages/**/*.{ts,tsx,js,jsx}: Prefer modern ES6+ syntax and features
Prefer config files over hardcoding values
Keep files small, focused, and modular - extract large files into sub-modules or separate utilities
Each file should handle one coherent responsibility
Comments should explain WHY something is being done or provide context, not repeat what the code is saying
Do NOT narrate what code is doing, don't duplicate function/variable names in comments, and don't leave stale comments that contradict the code
Use the Agent TODO convention // TODO(agent): Brief description for incomplete work, flagging items for future attention, known limitations, and documentation section references

Use TODO(agent) convention with brief description and relevant doc section references for incomplete work or flagged issues

Files:

  • packages/shared/src/checklists/rob2/compare.ts
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js,packages/web/src/AMSTAR2/checklist-compare.js} : Store final answers in the reconciled checklist itself, not in reconciliation progress metadata
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/AMSTAR2/checklist-compare.js} : Use compareChecklists utility from checklist-compare.js for comparing reviewer checklists
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/lib/checklist-domain.js,packages/web/src/AMSTAR2/checklist-compare.js} : Reconciliation structure should contain checklist1Id, checklist2Id, and reconciledChecklistId
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Checklist status transitions follow sequence: in_progress → completed (when all questions answered) → reconciled (after reconciliation complete)
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js} : Store reconciliation progress metadata (IDs and optional currentPage) in the study's Y.Map reconciliation property
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Use Y.Text objects for collaborative editing of question notes in reconciliation
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Maintain separate answer format implementations for each checklist type (AMSTAR2, ROBINS-I, Generic) to prevent data corruption
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js} : Multi-part answers (q9a, q9b, q11a, q11b) should be stored as objects with answer matrix and critical flag properties
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/ROBINS-I/** : Use scoreChecklist utility from `@/ROBINS-I/checklist.js` to determine risk of bias rating: 'Low' | 'Moderate' | 'Serious' | 'Critical'
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Use MultiPartQuestionPage component for multi-part questions (q9 and q11)
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/AMSTAR2/checklist-compare.js} : Use compareChecklists utility from checklist-compare.js for comparing reviewer checklists

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/lib/checklist-domain.js,packages/web/src/AMSTAR2/checklist-compare.js} : Reconciliation structure should contain checklist1Id, checklist2Id, and reconciledChecklistId

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js,packages/web/src/AMSTAR2/checklist-compare.js} : Store final answers in the reconciled checklist itself, not in reconciliation progress metadata

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js} : Multi-part answers (q9a, q9b, q11a, q11b) should be stored as objects with answer matrix and critical flag properties

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Use Y.Text objects for collaborative editing of question notes in reconciliation

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Maintain separate answer format implementations for each checklist type (AMSTAR2, ROBINS-I, Generic) to prevent data corruption

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/ROBINS-I/** : Use scoreChecklist utility from `@/ROBINS-I/checklist.js` to determine risk of bias rating: 'Low' | 'Moderate' | 'Serious' | 'Critical'

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Use multiPartAnswersEqual helper to compare multi-part answers between reviewers

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js,packages/web/src/primitives/useProject/checklists.js : Use checklist operations from useProject hook (createChecklist, updateChecklistAnswer, getChecklistData) instead of manually updating checklist structure

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js} : Store reconciliation progress metadata (IDs and optional currentPage) in the study's Y.Map reconciliation property

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Auto-fill final answer with reviewer1's answer when reviewers agree and no final answer exists

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/** : Handle multi-part AMSTAR2 questions correctly: q9 (parts a, b), q11 (parts a, b) require separate answer entries

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Use SingleQuestionPage component for standard single-part questions (q1-q8, q10, q12-q16)

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Use getChecklistStatus utility from `@/lib/checklist-domain.js` to determine current checklist status before performing operations

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/lib/checklist-domain.js : Register and retrieve checklists using checklist-registry: getChecklistType and getChecklistComponent functions

Applied to files:

  • packages/shared/src/checklists/rob2/compare.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Workers Builds: corates
🔇 Additional comments (2)
packages/shared/src/checklists/rob2/compare.ts (2)

150-165: [Your rewritten review comment text here]
[Exactly ONE classification tag]


316-329: Active domain selection ignores checklist2 aim and aim mismatches.

Using only checklist1's aim can omit domains that are active for checklist2 or when aims differ. This can hide disagreements and skew stats. Consider using the union of domains when aims differ.

Proposed fix
-  const isAdhering = checklist1.preliminary?.aim === 'ADHERING';
-  const activeDomains = getActiveDomainKeys(isAdhering);
+  const aim1 = checklist1.preliminary?.aim;
+  const aim2 = checklist2.preliminary?.aim;
+  const isAdhering1 = aim1 === 'ADHERING';
+  const isAdhering2 = aim2 === 'ADHERING';
+  const activeDomains =
+    aim1 && aim2 && aim1 === aim2
+      ? getActiveDomainKeys(isAdhering1)
+      : Array.from(
+          new Set([
+            ...getActiveDomainKeys(isAdhering1),
+            ...getActiveDomainKeys(isAdhering2),
+          ]),
+        );

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +232 to +266
// Get auto-calculated judgements
const scoring1 = scoreRob2Domain(domainKey, domain1?.answers);
const scoring2 = scoreRob2Domain(domainKey, domain2?.answers);

const judgement1 = scoring1.judgement;
const judgement2 = scoring2.judgement;

const direction1 = domain1?.direction ?? null;
const direction2 = domain2?.direction ?? null;

return {
questions: { agreements, disagreements },
judgement1,
judgement2,
judgementMatch: judgement1 === judgement2,
direction1,
direction2,
directionMatch: direction1 === direction2,
};
}

/**
* Compare overall judgement between two checklists
*/
function compareOverall(
checklist1: PartialROB2Checklist,
checklist2: PartialROB2Checklist,
): OverallComparison {
// Get auto-calculated overall judgements
// Cast to ChecklistState since the structures are compatible for scoring purposes
const scoring1 = scoreAllDomains(checklist1 as unknown as ChecklistState);
const scoring2 = scoreAllDomains(checklist2 as unknown as ChecklistState);

const judgement1 = scoring1.overall;
const judgement2 = scoring2.overall;
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 | 🟠 Major

Guard scoring calls when domains or answers are missing.

scoreRob2Domain and scoreAllDomains are called even when answers or entire domains may be undefined in partial checklists. If the scoring functions expect fully-populated structures, this can throw and break comparison on incomplete data. Consider short-circuiting to null judgements or passing safe defaults.

Proposed fix (example)
-  const scoring1 = scoreRob2Domain(domainKey, domain1?.answers);
-  const scoring2 = scoreRob2Domain(domainKey, domain2?.answers);
+  const scoring1 = domain1?.answers
+    ? scoreRob2Domain(domainKey, domain1.answers)
+    : { judgement: null };
+  const scoring2 = domain2?.answers
+    ? scoreRob2Domain(domainKey, domain2.answers)
+    : { judgement: null };
-  const scoring1 = scoreAllDomains(checklist1 as unknown as ChecklistState);
-  const scoring2 = scoreAllDomains(checklist2 as unknown as ChecklistState);
+  const scoring1 = scoreAllDomains(checklist1 as unknown as ChecklistState);
+  const scoring2 = scoreAllDomains(checklist2 as unknown as ChecklistState);
+  // If scoreAllDomains does not tolerate partial checklists, consider guarding with
+  // a presence check for required domains and returning null judgements instead.

To verify expected inputs for scoring, inspect the scoring implementation:

#!/bin/bash
rg -n "function scoreRob2Domain|function scoreAllDomains" packages/shared/src/checklists/rob2/scoring.ts
sed -n '1,220p' packages/shared/src/checklists/rob2/scoring.ts
🤖 Prompt for AI Agents
In `@packages/shared/src/checklists/rob2/compare.ts` around lines 232 - 266, The
compare functions call scoreRob2Domain and scoreAllDomains on partial data which
may have undefined domains/answers; modify the calls in compareDomain (where
scoring1/scoring2 and judgement1/judgement2 are derived) and in compareOverall
(where scoring1/scoring2 and judgement1/judgement2 are derived) to first check
inputs (e.g., domain?.answers or checklist?.domains) and either short-circuit to
null judgements or pass a safe default structure expected by
scoreRob2Domain/scoreAllDomains; ensure judgement1/judgement2 are set to null
when scoring is skipped and preserve existing fields (direction1/direction2,
judgementMatch, directionMatch) to handle nulls safely.

@InfinityBowman InfinityBowman deleted the 263-add-rob-2-reconcile branch March 29, 2026 03:08
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.

Add Rob-2 Reconcile

2 participants