Skip to content

fix(merge-tracker): require company match for number-based dedup#913

Open
darkpandawarrior wants to merge 1 commit into
santifer:mainfrom
darkpandawarrior:fix/merge-dedup-number-collision
Open

fix(merge-tracker): require company match for number-based dedup#913
darkpandawarrior wants to merge 1 commit into
santifer:mainfrom
darkpandawarrior:fix/merge-dedup-number-collision

Conversation

@darkpandawarrior

@darkpandawarrior darkpandawarrior commented Jun 10, 2026

Copy link
Copy Markdown

Fixes #912

Problem

merge-tracker.mjs's first two duplicate checks — report-number match and entry-number match — had no company guard. TSV numbers carry the report sequence while the tracker # column is its own row sequence, so a TSV numbered 001 colliding with tracker row #1 (a completely different company) was treated as a duplicate, and the update-in-place path rewrote that row's company, role, report link, and notes. A first batch merge with TSVs 001–003 against a tracker holding manually-added rows #1#3 corrupts all three.

Fix

  • A report-number or entry-number match counts as a duplicate only when the normalized company also matches (the company+role fuzzy fallback is unchanged).
  • A colliding TSV falls through to the new-entry path and is appended with the next free number.
  • Added a CAREER_OPS_ADDITIONS env override for the additions dir, mirroring the existing CAREER_OPS_TRACKER test hook, so the merge flow can be tested end-to-end against fixtures.

Tests

New section in test-all.mjs (4 checks, all fixture-based, no personal data):

  1. Number collision leaves the existing row byte-identical.
  2. The colliding TSV is appended as a new row with the next free number.
  3. A legit same-company, same-report-number re-eval with a higher score still updates in place (no duplicate row).
  4. The unrelated row stays intact through that second merge.

node test-all.mjs --quick: 156 passed, 0 failed (7 pre-existing warnings about README.ua.md in the personal-data scan, unrelated).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Deduplication now requires normalized company equality before treating entries as duplicates, preventing incorrect merges across different companies.
    • When report-number collisions occur between unrelated companies, existing rows are preserved and new entries are appended using the next available number.
  • New Features

    • Tracker additions directory can be configured via an environment variable.
  • Tests

    • Added regression tests covering deduplication and collision-safety scenarios.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 645c9c3f-2ec0-4294-9646-fd469de6ab13

📥 Commits

Reviewing files that changed from the base of the PR and between f900d5a and 93d94ed.

📒 Files selected for processing (2)
  • merge-tracker.mjs
  • test-all.mjs

📝 Walkthrough

Walkthrough

merge-tracker.mjs now requires normalized-company equality for report-number and entry-number matches; cross-company number collisions append as new entries with the next free tracker number. CAREER_OPS_ADDITIONS can override the additions directory. A regression test validates collision safety and same-company updates.

Changes

Number collision safety in merge-tracker

Layer / File(s) Summary
Dedup logic refactor and environment override
merge-tracker.mjs
Top-of-file doc updated; duplicate detection refactored to compute normCompany and sameCompany, require sameCompany for report-number and entry-number exact matches before company+role fuzzy matching; clarified new-entry append behavior; added CAREER_OPS_ADDITIONS env override for additions directory.
Regression test for number collision safety
test-all.mjs
New test creates a temp tracker with an OldCo #1 row, applies a NewCo TSV claiming report number 1 and asserts OldCo remains unchanged while NewCo is appended with the next free number; re-runs with a higher-scoring NewCo TSV and asserts the appended NewCo row is updated in place while OldCo remains intact.

Sequence Diagram(s)

sequenceDiagram
  participant AdditionTSV as Addition TSV
  participant MergeTracker as merge-tracker.mjs
  participant TrackerCSV as Tracker CSV

  AdditionTSV->>MergeTracker: addition with reportNum, company, role, score
  MergeTracker->>TrackerCSV: check reportNum + normalized company
  alt reportNum match & same company
    MergeTracker->>TrackerCSV: update matching tracker row
  else
    MergeTracker->>TrackerCSV: check entryNum + same company
    alt entryNum match & same company
      MergeTracker->>TrackerCSV: update matching tracker row
    else
      MergeTracker->>TrackerCSV: perform fuzzy company+role match
      alt fuzzy match found
        MergeTracker->>TrackerCSV: update matching tracker row
      else
        MergeTracker->>TrackerCSV: append as new row with next free number
      end
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

  • #924: Similar over-merging/fuzzy-dedup behavior; this PR's company-guarded exact-match changes address the same collision-overwrite concern.

Possibly related PRs

  • santifer/career-ops#867: Updates merge-tracker.mjs duplicate-detection to require normalized company match for num/entry-number dedup, treating collisions across companies as numbering drift and appending with next free number.
  • santifer/career-ops#820: Related changes around tracker-additions directory usage and additions TSV pipeline.
  • santifer/career-ops#793: Related dedup and fuzzy-match adjustments that interact with collision handling.

Suggested labels

🔴 core-architecture

Suggested reviewers

  • amrskr4-arch
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(merge-tracker): require company match for number-based dedup' accurately summarizes the core change: adding a company match requirement to number-based deduplication logic.
Linked Issues check ✅ Passed Changes comprehensively address all objectives from issue #912: company-guarded report-number and entry-number checks, proper new-entry numbering for collisions, and regression tests validating both collision handling and legitimate same-company updates.
Out of Scope Changes check ✅ Passed All changes are within scope: merge-tracker.mjs fixes the dedup logic with company guards, test-all.mjs adds regression tests for the fix, and the CAREER_OPS_ADDITIONS env override is a necessary test infrastructure change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@lligirlburg-wq

lligirlburg-wq commented Jun 10, 2026 via email

Copy link
Copy Markdown

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@lligirlburg-wq It looks like your reply forwarded the original notification email without adding any new content. If you have a question, request, or feedback about the PR review, feel free to share it here and I'll be happy to help!

If you'd like me to trigger a fresh review of the current changes, just let me know.

@coderabbitai coderabbitai Bot left a 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.

Caution

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

⚠️ Outside diff range comments (1)
merge-tracker.mjs (1)

389-416: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Batch dedup state is stale after first mutation (can duplicate or overwrite with stale score).

existingApps is used for duplicate detection, but it isn’t updated after add/update operations in the same run. A later TSV in the same batch can miss a just-added row (duplicate append) or compare against stale duplicate.score (incorrect re-eval decision).

Proposed fix
@@
       if (lineIdx >= 0) {
         const updatedLine = `| ${duplicate.num} | ${addition.date} | ${addition.company} | ${addition.role} | ${addition.score} | ${duplicate.status} | ${duplicate.pdf} | ${addition.report} | Re-eval ${addition.date} (${oldScore}→${newScore}). ${addition.notes} |`;
         appLines[lineIdx] = updatedLine;
+        // Keep in-memory dedup index in sync for later files in this same batch.
+        duplicate.raw = updatedLine;
+        duplicate.date = addition.date;
+        duplicate.company = addition.company;
+        duplicate.role = addition.role;
+        duplicate.score = addition.score;
+        duplicate.report = addition.report;
         updated++;
       }
@@
     const newLine = `| ${entryNum} | ${addition.date} | ${addition.company} | ${addition.role} | ${addition.score} | ${addition.status} | ${addition.pdf} | ${addition.report} | ${addition.notes} |`;
     newLines.push(newLine);
+    // Keep in-memory dedup index in sync for later files in this same batch.
+    existingApps.push({
+      num: entryNum,
+      date: addition.date,
+      company: addition.company,
+      role: addition.role,
+      score: addition.score,
+      status: addition.status,
+      pdf: addition.pdf,
+      report: addition.report,
+      notes: addition.notes || '',
+      raw: newLine,
+    });
     added++;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@merge-tracker.mjs` around lines 389 - 416, The batch dedup state isn't
updated after mutating rows so later additions in the same run use stale data;
after you modify an existing row (inside the if (duplicate) branch where you set
appLines[lineIdx] and increment updated) update the in-memory index/state (the
same structure used to find duplicate) so duplicate.score (and any lookup by
company/role) reflects the new score/date/report/notes; likewise after pushing
newLine and incrementing added update that state (and maxNum if changed) so
subsequent additions in this batch see the newly added entry instead of reusing
the number or making wrong comparisons.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@merge-tracker.mjs`:
- Around line 389-416: The batch dedup state isn't updated after mutating rows
so later additions in the same run use stale data; after you modify an existing
row (inside the if (duplicate) branch where you set appLines[lineIdx] and
increment updated) update the in-memory index/state (the same structure used to
find duplicate) so duplicate.score (and any lookup by company/role) reflects the
new score/date/report/notes; likewise after pushing newLine and incrementing
added update that state (and maxNum if changed) so subsequent additions in this
batch see the newly added entry instead of reusing the number or making wrong
comparisons.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c23ad328-3a5f-44aa-ba62-19ac5ac123c4

📥 Commits

Reviewing files that changed from the base of the PR and between e2272dc and b21178b.

📒 Files selected for processing (2)
  • merge-tracker.mjs
  • test-all.mjs

@santifer

Copy link
Copy Markdown
Owner

Nice work, @darkpandawarrior — and to be clear up front: the bug you found is real and still live on main. I reproduced it: #867 guarded the entry-number match, but the report-number match is still unguarded, so a TSV whose report number collides with an unrelated company's row link overwrites that row (company/role/notes destroyed). Your diagnosis of the two independent sequences (TSV = report sequence, tracker # = row sequence) is exactly right. Direction is solid — two things to adjust before merge:

  1. Rebase onto current main. Your branch predates fix(merge-tracker): require company match on exact entry-number dedup #867 (entry-number company guard) and fix(merge-tracker): use token-union ratio in roleFuzzyMatch to stop cross-role dedup #793 (roleFuzzyMatch + the CAREER_OPS_ADDITIONS env override, which main already has) — both conflict with your diff in merge-tracker.mjs and test-all.mjs. After rebasing, the remaining delta should be just the report-number company guard + the new-entry numbering comment. Tip: in the entry-number block, your sameCompany() form is semantically identical to what fix(merge-tracker): require company match on exact entry-number dedup #867 landed — keep one, don't end up with a shadowed duplicate normCompany.

  2. Make the tests pin your fix. As written, all 4 new tests pass on main without your change: the fixture rows use for Report, so the report-number path never matches, and the entry-number case is already covered by fix(merge-tracker): require company match on exact entry-number dedup #867. Give the existing row a real report link (e.g. [1](reports/001-oldco-2026-01-09.md)) so the colliding TSV exercises the report-number path — that's the test that fails on main today and passes with your guard.

Happy to merge once these are in — it closes a real data-loss hole that has now bitten three times (#634, #867/#912, this).

@darkpandawarrior darkpandawarrior force-pushed the fix/merge-dedup-number-collision branch from b21178b to 8fbfe9f Compare June 11, 2026 06:17
@darkpandawarrior

Copy link
Copy Markdown
Author

Both points addressed in the rebased branch (now a single commit, 8fbfe9f, on top of ae6beec):

Rebase: The delta is now just the report-number company guard + the new-entry numbering comment. I hoisted a single normCompany/sameCompany above the three duplicate checks and removed the two block-local normCompany declarations that #867/#793 introduced — same semantics, no shadowing, and all three checks now share one guard.

Tests pin the fix: The fixture row #1 now carries a real report link ([1](../reports/001-oldco-2026-01-09.md)) and a real score (4.1/5), with the colliding TSV at 4.7/5 so the update-in-place branch fires through the unguarded report-number path. Verified both directions against a worktree of current main:

Also kept a positive control: a same-company, same-report-number re-eval with a higher score still updates in place through the now-guarded report-number path (no duplicate row).

node test-all.mjs --quick: 178 passed, 0 failed.

🤖 Generated with Claude Code

@darkpandawarrior darkpandawarrior force-pushed the fix/merge-dedup-number-collision branch from 8fbfe9f to f900d5a Compare June 11, 2026 06:26
The report-number duplicate check matched on the bare number, but TSV
numbers carry the report sequence while the tracker # column is its own
row sequence (santifer#867), so a TSV whose report number collides with the
report number on an unrelated company's row was treated as a duplicate
— and the update-in-place path overwrote that row's company, role,
report link, and notes.

Guard the report-number match with the same normalized-company check
that santifer#867 added for the entry-number match, hoisting a single
normCompany/sameCompany shared by all three duplicate checks. Colliding
TSVs fall through to the new-entry path and are appended with the next
free number.

Adds a regression section to test-all.mjs: the collision scenario
corrupts row santifer#1 on current main (verified) and leaves it byte-identical
with the guard, plus a positive control proving same-company re-evals
still update in place through the guarded path.

Fixes santifer#912

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test-all.mjs`:
- Around line 1859-1863: The test currently only checks the single line found by
batchRunner.split('\n').find(l => l.includes('claude_args=(')) so it misses
flags that appear on subsequent lines of a multiline claude_args=( ...)
construction; change the check to locate the line index for the line containing
'claude_args=(' (use batchRunner.split('\n') to get an array), then collect and
join subsequent lines until the closing ')' is found (or until end), and search
that joined multiline block for '--strict-mcp-config' so the assertion on
claudeArgsLine/batchRunner becomes resilient to multiline argument formatting.
- Around line 1401-1450: The test lacks an explicit invariant that the existing
row `#2` (OtherCo) remains byte-identical across both merges; capture the original
row `#2` string (e.g. readFileSync(tracker) and extract the line containing
'OtherCo' into a const like originalRow2) before performing the merges, then
after each run(NODE, ['merge-tracker.mjs'], { env: mergeEnv }) compare the
current file's row for OtherCo to originalRow2 and call pass(...) or fail(...)
accordingly so the test asserts that the unrelated row remains unchanged; locate
the setup using oldcoRow, tracker, additionsDir and the two run(...) points to
insert these checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 645c9c3f-2ec0-4294-9646-fd469de6ab13

📥 Commits

Reviewing files that changed from the base of the PR and between f900d5a and 93d94ed.

📒 Files selected for processing (2)
  • merge-tracker.mjs
  • test-all.mjs

@coderabbitai coderabbitai Bot left a 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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test-all.mjs`:
- Around line 1859-1863: The test currently only checks the single line found by
batchRunner.split('\n').find(l => l.includes('claude_args=(')) so it misses
flags that appear on subsequent lines of a multiline claude_args=( ...)
construction; change the check to locate the line index for the line containing
'claude_args=(' (use batchRunner.split('\n') to get an array), then collect and
join subsequent lines until the closing ')' is found (or until end), and search
that joined multiline block for '--strict-mcp-config' so the assertion on
claudeArgsLine/batchRunner becomes resilient to multiline argument formatting.
- Around line 1401-1450: The test lacks an explicit invariant that the existing
row `#2` (OtherCo) remains byte-identical across both merges; capture the original
row `#2` string (e.g. readFileSync(tracker) and extract the line containing
'OtherCo' into a const like originalRow2) before performing the merges, then
after each run(NODE, ['merge-tracker.mjs'], { env: mergeEnv }) compare the
current file's row for OtherCo to originalRow2 and call pass(...) or fail(...)
accordingly so the test asserts that the unrelated row remains unchanged; locate
the setup using oldcoRow, tracker, additionsDir and the two run(...) points to
insert these checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 645c9c3f-2ec0-4294-9646-fd469de6ab13

📥 Commits

Reviewing files that changed from the base of the PR and between f900d5a and 93d94ed.

📒 Files selected for processing (2)
  • merge-tracker.mjs
  • test-all.mjs
🛑 Comments failed to post (2)
test-all.mjs (2)

1401-1450: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add an explicit invariant check for the preexisting row #2 across both merges.

This regression currently proves row #1 stability, append-on-collision, and same-company in-place update, but it does not pin that the unrelated row | 2 | ... OtherCo ... | remains byte-identical. That leaves a hole in the intended #912 coverage.

Suggested patch
-    writeFileSync(tracker,
+    const othercoRow = '| 2 | 2026-01-01 | OtherCo | Widget Engineer | N/A | Applied | ❌ | — | row two |';
+    writeFileSync(tracker,
       '# Applications Tracker\n\n' +
       '| # | Date | Company | Role | Score | Status | PDF | Report | Notes |\n' +
       '|---|------|---------|------|-------|--------|-----|--------|-------|\n' +
       oldcoRow + '\n' +
-      '| 2 | 2026-01-01 | OtherCo | Widget Engineer | N/A | Applied | ❌ | — | row two |\n');
+      othercoRow + '\n');

@@
     if (after.includes(oldcoRow)) {
       pass('report-number collision: existing row `#1` (OldCo) left byte-identical');
     } else {
       fail('report-number collision OVERWROTE row `#1` (`#912` regression — bare number match must not dedup)');
     }
+    if (after.includes(othercoRow)) {
+      pass('unrelated row `#2` remains byte-identical after first merge');
+    } else {
+      fail('row `#2` changed during first merge');
+    }

@@
     if (after2.includes(oldcoRow)) {
       pass('row `#1` still intact after the same-company re-eval merge');
     } else {
       fail('row `#1` was modified by the same-company re-eval merge');
     }
+    if (after2.includes(othercoRow)) {
+      pass('unrelated row `#2` remains byte-identical after second merge');
+    } else {
+      fail('row `#2` changed during second merge');
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    const oldcoRow = '| 1 | 2026-01-09 | OldCo | Senior Widget Engineer | 4.1/5 | Interview | ❌ | [1](../reports/001-oldco-2026-01-09.md) | precious row-one notes |';
    const othercoRow = '| 2 | 2026-01-01 | OtherCo | Widget Engineer | N/A | Applied | ❌ | — | row two |';
    writeFileSync(tracker,
      '# Applications Tracker\n\n' +
      '| # | Date | Company | Role | Score | Status | PDF | Report | Notes |\n' +
      '|---|------|---------|------|-------|--------|-----|--------|-------|\n' +
      oldcoRow + '\n' +
      othercoRow + '\n');
    for (const n of ['001-oldco-2026-01-09', '001-newco-2026-01-10', '001-newco-2026-01-11']) {
      writeFileSync(join(collTmp, 'reports', `${n}.md`), '# fixture\n');
    }

    // Colliding TSV: report number 1 (= row `#1`'s report number), DIFFERENT company,
    // higher score than row `#1` so the update-in-place branch would fire if matched.
    writeFileSync(join(additionsDir, '001-newco.tsv'),
      '1\t2026-01-10\tNewCo\tPlatform Reliability Lead\tEvaluated\t4.7/5\t❌\t[1](reports/001-newco-2026-01-10.md)\tfresh eval\n');

    run(NODE, ['merge-tracker.mjs'], { env: mergeEnv });
    const after = readFileSync(tracker, 'utf-8');

    if (after.includes(oldcoRow)) {
      pass('report-number collision: existing row `#1` (OldCo) left byte-identical');
    } else {
      fail('report-number collision OVERWROTE row `#1` (`#912` regression — bare number match must not dedup)');
    }
    if (after.includes(othercoRow)) {
      pass('unrelated row `#2` remains byte-identical after first merge');
    } else {
      fail('row `#2` changed during first merge');
    }

    const newcoRows = after.split('\n').filter(l => l.includes('NewCo'));
    if (newcoRows.length === 1 && /^\| 3 \| 2026-01-10 \| NewCo \| Platform Reliability Lead \|/.test(newcoRows[0])) {
      pass('colliding TSV appended as a new row with the next free number (`#3`)');
    } else {
      fail(`colliding TSV not appended as `#3`: ${JSON.stringify(newcoRows)}`);
    }

    // Positive control: SAME company + same report number with a higher score
    // must still UPDATE in place via the (now company-guarded) report-number path.
    writeFileSync(join(additionsDir, '001-newco.tsv'),
      '1\t2026-01-11\tNewCo\tPlatform Reliability Lead\tEvaluated\t4.9/5\t❌\t[1](reports/001-newco-2026-01-11.md)\tre-evaluated\n');

    run(NODE, ['merge-tracker.mjs'], { env: mergeEnv });
    const after2 = readFileSync(tracker, 'utf-8');
    const newcoRows2 = after2.split('\n').filter(l => l.includes('NewCo'));
    if (newcoRows2.length === 1 && newcoRows2[0].startsWith('| 3 |') && newcoRows2[0].includes('4.9/5')) {
      pass('same-company report-number match still updates in place (no duplicate row)');
    } else {
      fail(`same-company re-eval did not update `#3` in place: ${JSON.stringify(newcoRows2)}`);
    }
    if (after2.includes(oldcoRow)) {
      pass('row `#1` still intact after the same-company re-eval merge');
    } else {
      fail('row `#1` was modified by the same-company re-eval merge');
    }
    if (after2.includes(othercoRow)) {
      pass('unrelated row `#2` remains byte-identical after second merge');
    } else {
      fail('row `#2` changed during second merge');
    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-all.mjs` around lines 1401 - 1450, The test lacks an explicit invariant
that the existing row `#2` (OtherCo) remains byte-identical across both merges;
capture the original row `#2` string (e.g. readFileSync(tracker) and extract the
line containing 'OtherCo' into a const like originalRow2) before performing the
merges, then after each run(NODE, ['merge-tracker.mjs'], { env: mergeEnv })
compare the current file's row for OtherCo to originalRow2 and call pass(...) or
fail(...) accordingly so the test asserts that the unrelated row remains
unchanged; locate the setup using oldcoRow, tracker, additionsDir and the two
run(...) points to insert these checks.

1859-1863: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Make the MCP isolation assertion resilient to multiline argument construction.

The current check inspects only the single line containing claude_args=(. If --strict-mcp-config is appended on another line, this test can fail spuriously.

Suggested patch
-  const claudeArgsLine = batchRunner
-    .split('\n')
-    .find(l => l.includes('claude_args=('));
-  if (claudeArgsLine && claudeArgsLine.includes('--strict-mcp-config')) {
+  const hasStrictMcp =
+    /claude_args=\([\s\S]*?--strict-mcp-config/.test(batchRunner) ||
+    /claude[^\n]*--strict-mcp-config/.test(batchRunner);
+  if (hasStrictMcp) {
     pass('batch workers spawn with --strict-mcp-config (no inherited MCP)');
   } else {
     fail('batch-runner.sh worker spawn missing --strict-mcp-config (issue `#506` regression)');
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-all.mjs` around lines 1859 - 1863, The test currently only checks the
single line found by batchRunner.split('\n').find(l =>
l.includes('claude_args=(')) so it misses flags that appear on subsequent lines
of a multiline claude_args=( ...) construction; change the check to locate the
line index for the line containing 'claude_args=(' (use batchRunner.split('\n')
to get an array), then collect and join subsequent lines until the closing ')'
is found (or until end), and search that joined multiline block for
'--strict-mcp-config' so the assertion on claudeArgsLine/batchRunner becomes
resilient to multiline argument formatting.

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.

merge-tracker: bare number collision overwrites an unrelated company's tracker row

3 participants