Skip to content

fix(relation-discovery): improve evidence retries#104

Merged
Moskize91 merged 6 commits into
mainfrom
codex/matching-text-progress
Jul 7, 2026
Merged

fix(relation-discovery): improve evidence retries#104
Moskize91 merged 6 commits into
mainfrom
codex/matching-text-progress

Conversation

@Moskize91

Copy link
Copy Markdown
Contributor

Summary

  • tighten evidence quote guidance so relation evidence uses short source-line locators instead of proof excerpts
  • add retry feedback for quote boundary failures and same-mention self-links
  • require relation endpoints to be explicitly tagged mentions, skipping relations that need untagged endpoints
  • show relation-discovery progress by windows only, avoiding the stale records 0/N counter

Testing

  • pnpm lint:fix
  • pnpm typecheck
  • pnpm vitest run test/evidence-selection/selection-resolver.test.ts --passWithNoTests
  • pnpm vitest run test/wikilink/relation-discovery.test.ts --passWithNoTests
  • pnpm vitest run test/facade/build-queue.test.ts test/cli/queue.test.ts --passWithNoTests

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This PR adds "char"/"chars" progress handling across the queue, build-facade, and knowledge-graph flow, and introduces an optional force flag for phase snapshots. It also streams wikispine match output through incremental NDJSON parsing while forwarding progress callbacks. Separately, it tightens evidence-selection quote rules and failure hints, and updates relation-discovery validation and prompt rules for tagged mentions.

Sequence Diagram(s)

sequenceDiagram
  participant Build as generateChapterKnowledgeGraphArtifact
  participant Match as matchWikispineSentenceCandidates
  participant Parser as createWikispineNdjsonParser
  participant WikiSpine as WikiSpine process/API
  participant Reporter as BuildJobProgressReporter

  Build->>Reporter: updatePhase(matching, total=text.length, unit=char)
  Build->>Match: matchWikispineSentenceCandidates(onProgress)
  Match->>WikiSpine: send sentence text/range
  WikiSpine-->>Parser: stream NDJSON output
  Parser->>Parser: push(chunk), parse line
  Parser-->>Match: onMatch(coveredRangeEnd)
  Match-->>Build: onProgress(coveredRangeEnd)
  Build->>Reporter: updatePhase(coveredRangeEnd, unit=char, force?)
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title follows the required format and accurately reflects the relation-discovery retry and evidence guidance changes.
Description check ✅ Passed The description is clearly related to the changeset and summarizes the main fixes and tests.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch codex/matching-text-progress

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

@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

🧹 Nitpick comments (1)
src/wikilink/relation-discovery.ts (1)

386-409: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor redundancy between adjacent prompt bullets.

Line 393 ("Every relation must connect two mention IDs from the <mention id="..." qid="..."> tags") and the new line 394 ("A relation is valid only when both endpoints are explicitly tagged mentions...") convey largely the same constraint. Not incorrect, just slightly repetitive for the LLM prompt.

🤖 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 `@src/wikilink/relation-discovery.ts` around lines 386 - 409, The relation
prompt in formatRelationSystemPrompt is slightly redundant because the “Every
relation must connect two mention IDs” bullet and the “both endpoints are
explicitly tagged mentions” bullet repeat the same rule. Merge or remove one of
these adjacent bullets in relation-discovery.ts so the prompt stays concise
while preserving the mention-ID constraint.
🤖 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 `@src/facade/knowledge-graph-build.ts`:
- Around line 141-157: The onProgress callback in
matchWikispineSentenceCandidates currently swallows updatePhase() cancellation
failures via .catch(() => undefined), which prevents BuildJobStoppedError from
stopping the work promptly. Remove the suppression so the promise rejection from
options.progressTracker?.updatePhase() can bubble out of the callback, allowing
knowledge-graph build to abort immediately when stopped.

In `@src/wikimatch/wikispine.ts`:
- Around line 184-190: The wikispine progress callback is swallowing rejected
promises because `void options.onProgress?.(...)` ignores failures, which can
lead to unhandled rejections. Update the `createWikispineNdjsonParser` `onMatch`
handler in `wikispine.ts` to either await/propagate `options.onProgress` or
explicitly attach a catch handler that logs or handles errors, and make the same
adjustment anywhere else the fetch path uses the same `onProgress` pattern. Keep
the fix localized around `onMatch` and the `options.onProgress` call sites.

---

Nitpick comments:
In `@src/wikilink/relation-discovery.ts`:
- Around line 386-409: The relation prompt in formatRelationSystemPrompt is
slightly redundant because the “Every relation must connect two mention IDs”
bullet and the “both endpoints are explicitly tagged mentions” bullet repeat the
same rule. Merge or remove one of these adjacent bullets in
relation-discovery.ts so the prompt stays concise while preserving the
mention-ID constraint.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c1fff9db-03d5-47ee-ba4c-6a80340a2493

📥 Commits

Reviewing files that changed from the base of the PR and between b610b06 and 420129d.

📒 Files selected for processing (11)
  • src/cli/queue.ts
  • src/evidence-selection/prompt.ts
  • src/evidence-selection/selection-resolver.ts
  • src/facade/build-queue.ts
  • src/facade/knowledge-graph-build.ts
  • src/wikilink/relation-discovery.ts
  • src/wikimatch/wikispine.ts
  • test/cli/queue.test.ts
  • test/evidence-selection/selection-resolver.test.ts
  • test/facade/build-queue.test.ts
  • test/wikimatch/wikispine.test.ts

Comment thread src/facade/knowledge-graph-build.ts
Comment thread src/wikimatch/wikispine.ts
@Moskize91 Moskize91 changed the title Fix relation discovery evidence retries fix(relation-discovery): improve evidence retries Jul 7, 2026
@Moskize91 Moskize91 merged commit bb9c5f6 into main Jul 7, 2026
2 of 3 checks passed
@Moskize91 Moskize91 deleted the codex/matching-text-progress branch July 7, 2026 08:41

@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.

🧹 Nitpick comments (2)
test/wikimatch/wikispine.test.ts (1)

167-193: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Temp directory not cleaned up.

mkdtemp creates a temp dir but it's never removed after the test, leaking fake-wikispine.mjs files across test runs.

♻️ Optional cleanup
   it("rejects CLI matches when progress reporting fails", async () => {
     const tempDir = await mkdtemp(join(tmpdir(), "wikispine-test-"));
     const commandPath = join(tempDir, "fake-wikispine.mjs");
+    onTestFinished(() => rm(tempDir, { recursive: true, force: true }));
🤖 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/wikimatch/wikispine.test.ts` around lines 167 - 193, The wikispine test
creates a temporary directory with mkdtemp in the
matchWikispineSentenceCandidates case but never removes it, leaving
fake-wikispine.mjs behind between runs. Add cleanup in the test using the
tempDir variable so the temporary directory is deleted after the assertion
completes, ideally by wrapping the test body in a try/finally and removing the
directory in the finally block.
src/wikimatch/wikispine.ts (1)

328-344: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Release the reader when the stream loop aborts early.

When progress.throwIfFailed() throws (an onProgress callback rejected), the function exits with the ReadableStreamDefaultReader still locked and the response body unconsumed, leaking the underlying connection/socket. Cancel the reader on any early exit.

♻️ Proposed fix to cancel the reader on early exit
   const reader = response.body.getReader();
   const decoder = new TextDecoder();

-  while (true) {
-    const { done, value } = await reader.read();
-    if (done) {
-      break;
-    }
-    parser.push(decoder.decode(value, { stream: true }));
-    progress.throwIfFailed();
-  }
-
-  parser.push(decoder.decode());
+  try {
+    while (true) {
+      const { done, value } = await reader.read();
+      if (done) {
+        break;
+      }
+      parser.push(decoder.decode(value, { stream: true }));
+      progress.throwIfFailed();
+    }
+    parser.push(decoder.decode());
+  } catch (error) {
+    await reader.cancel().catch(() => {});
+    throw error;
+  }
   const matches = parser.finish();
   await progress.wait();
   return matches;
🤖 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 `@src/wikimatch/wikispine.ts` around lines 328 - 344, The stream loop in
wikispine’s reader handling can exit early when progress.throwIfFailed() throws,
leaving the ReadableStreamDefaultReader locked and the response body unconsumed.
Update the logic around response.body.getReader(), the read loop, and
parser.finish() so the reader is cancelled/released on any early exit path,
especially when onProgress fails, while preserving the normal decode/push/finish
flow.
🤖 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.

Nitpick comments:
In `@src/wikimatch/wikispine.ts`:
- Around line 328-344: The stream loop in wikispine’s reader handling can exit
early when progress.throwIfFailed() throws, leaving the
ReadableStreamDefaultReader locked and the response body unconsumed. Update the
logic around response.body.getReader(), the read loop, and parser.finish() so
the reader is cancelled/released on any early exit path, especially when
onProgress fails, while preserving the normal decode/push/finish flow.

In `@test/wikimatch/wikispine.test.ts`:
- Around line 167-193: The wikispine test creates a temporary directory with
mkdtemp in the matchWikispineSentenceCandidates case but never removes it,
leaving fake-wikispine.mjs behind between runs. Add cleanup in the test using
the tempDir variable so the temporary directory is deleted after the assertion
completes, ideally by wrapping the test body in a try/finally and removing the
directory in the finally block.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 835c8eff-311f-4a82-9652-9e615cfe29aa

📥 Commits

Reviewing files that changed from the base of the PR and between 420129d and f61d8d8.

📒 Files selected for processing (3)
  • src/facade/knowledge-graph-build.ts
  • src/wikimatch/wikispine.ts
  • test/wikimatch/wikispine.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/facade/knowledge-graph-build.ts

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.

1 participant