Skip to content

feat(import): return per-source resolution metadata - #40

Closed
minhthanhdang wants to merge 1 commit into
mainfrom
minh/rm-17863-per-source-resolution-metadata
Closed

feat(import): return per-source resolution metadata#40
minhthanhdang wants to merge 1 commit into
mainfrom
minh/rm-17863-per-source-resolution-metadata

Conversation

@minhthanhdang

@minhthanhdang minhthanhdang commented Aug 11, 2026

Copy link
Copy Markdown
Contributor
🚥 Resolves RM-17863

🎨 UI is awaiting confirmation from Ryan.
🔗 Part of a 3-PR chain: ai-cli-runner#109, readme#20253

🧰 What's changing

importDocs() for website-URL imports now returns a sources array — one entry per source URL — recording how the CLI resolved it: the requested URL, any redirect, the adopted docs-route base, the final URL, and which discovery route produced the skeleton (llms / mintlify / archbee / scrape / sitemap / none, plus a scrapeDiscarded flag when the coverage gate threw the scrape away).

🧬 Why

The import runner needs this signal to decide whether a submitted URL actually resolved to a documentation site. Strong routes (llms.txt, Mintlify, Archbee) are docs sites by construction; weak routes (scrape/sitemap) trigger an AI docs-site check downstream that can surface a soft "this might not be a docs site" warning (slug non_docs_site) on the import progress screen. The import itself is never blocked.

Pure metadata bolt-on — no behavior change to discovery, staging, or zipping.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

URL imports now collect per-source resolution metadata. The metadata includes the requested, redirected, docs-base, and final URLs, the discovery route, and optional scrape-discard status. URL import results expose this data through the sources field for test-preview, empty-staging, and packaged results. Each source retains its original requested URL before URL rebasing.


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.

@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 `@src/commands/import.js`:
- Around line 823-830: Update the discard tracking around the resolution
assembly and orphan-triage flow so a general scrape-discarded boolean is set for
both coverage-gate and thin-scrape re-clustering paths. Keep the existing
coverage-specific flag for warning suppression if needed, and use the general
boolean in the `organized.resolution` construction to emit `scrapeDiscarded` for
either discard path.
- Around line 823-828: Update the route assignment in the organized.resolution
metadata to reflect the final organizer selected around the scraped/llms
handling: prefer scraped when it produced the final tree, and use llms only when
the scrape result was absent or discarded, while preserving the existing
Mintlify, Archbee, sitemap, and none labels. Add regression coverage for llms
combined with Mintlify, Archbee, and generic scrape discovery.
🪄 Autofix

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 Plus

Run ID: 4f5704da-8a93-46f4-b288-aa111c127073

📥 Commits

Reviewing files that changed from the base of the PR and between 0b01be7 and 90777a3.

📒 Files selected for processing (1)
  • src/commands/import.js
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • readmeio/ai (manual)
  • readmeio/gitto (manual)
  • readmeio/markdown (manual)
  • readmeio/readme (manual)

Comment thread src/commands/import.js
Comment on lines +823 to +828
organized.resolution = {
requestedUrl,
redirectedUrl: redirected ? redirected.toString() : null,
docsBaseUrl: docsBase ? docsBase.url.toString() : null,
finalUrl: sourceUrl.toString(),
route: llms ? 'llms' : mintlifyNav ? 'mintlify' : archbeeNav ? 'archbee' : scraped ? 'scrape' : sitemapUrl ? 'sitemap' : 'none',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Make route match the final selected organizer.

Lines 722-728 use scraped when it is available. This includes Mintlify, Archbee, and generic scrape results. Line 828 checks llms first, so the metadata reports llms even when the final organized tree came from scraped.

Compute route from the final branch. Use llms only when the scrape result was discarded or absent.

Proposed route selection
-    route: llms ? 'llms' : mintlifyNav ? 'mintlify' : archbeeNav ? 'archbee' : scraped ? 'scrape' : sitemapUrl ? 'sitemap' : 'none',
+    route: scraped
+      ? mintlifyNav
+        ? 'mintlify'
+        : archbeeNav
+          ? 'archbee'
+          : 'scrape'
+      : llms
+        ? 'llms'
+        : sitemapUrl
+          ? 'sitemap'
+          : 'none',

Add regression tests for llms combined with Mintlify, Archbee, and generic scrape discovery.

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

Suggested change
organized.resolution = {
requestedUrl,
redirectedUrl: redirected ? redirected.toString() : null,
docsBaseUrl: docsBase ? docsBase.url.toString() : null,
finalUrl: sourceUrl.toString(),
route: llms ? 'llms' : mintlifyNav ? 'mintlify' : archbeeNav ? 'archbee' : scraped ? 'scrape' : sitemapUrl ? 'sitemap' : 'none',
organized.resolution = {
requestedUrl,
redirectedUrl: redirected ? redirected.toString() : null,
docsBaseUrl: docsBase ? docsBase.url.toString() : null,
finalUrl: sourceUrl.toString(),
route: scraped
? mintlifyNav
? 'mintlify'
: archbeeNav
? 'archbee'
: 'scrape'
: llms
? 'llms'
: sitemapUrl
? 'sitemap'
: 'none',
🤖 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/commands/import.js` around lines 823 - 828, Update the route assignment
in the organized.resolution metadata to reflect the final organizer selected
around the scraped/llms handling: prefer scraped when it produced the final
tree, and use llms only when the scrape result was absent or discarded, while
preserving the existing Mintlify, Archbee, sitemap, and none labels. Add
regression coverage for llms combined with Mintlify, Archbee, and generic scrape
discovery.

Comment thread src/commands/import.js
Comment on lines +823 to +830
organized.resolution = {
requestedUrl,
redirectedUrl: redirected ? redirected.toString() : null,
docsBaseUrl: docsBase ? docsBase.url.toString() : null,
finalUrl: sourceUrl.toString(),
route: llms ? 'llms' : mintlifyNav ? 'mintlify' : archbeeNav ? 'archbee' : scraped ? 'scrape' : sitemapUrl ? 'sitemap' : 'none',
...(scrapeDiscardedForCoverage ? { scrapeDiscarded: true } : {}),
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Record the orphan-triage discard in scrapeDiscarded.

When orphan triage re-clusters a thin scrape, Lines 609-620 log that the scrape was discarded. The flag used here is set only by the coverage gate at Lines 553-559. The returned metadata therefore omits scrapeDiscarded for this discard path.

Track a general discard boolean for both paths. Keep the coverage-specific boolean if it is still needed for warning suppression.

Proposed discard tracking
   let scrapeDiscardedForCoverage = false
+  let scrapeDiscarded = false
...
       scraped = null
       scrapeDiscardedForCoverage = true
+      scrapeDiscarded = true
...
         if (reclustered) {
+          scrapeDiscarded = true
...
-    ...(scrapeDiscardedForCoverage ? { scrapeDiscarded: true } : {}),
+    ...(scrapeDiscarded ? { scrapeDiscarded: 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 `@src/commands/import.js` around lines 823 - 830, Update the discard tracking
around the resolution assembly and orphan-triage flow so a general
scrape-discarded boolean is set for both coverage-gate and thin-scrape
re-clustering paths. Keep the existing coverage-specific flag for warning
suppression if needed, and use the general boolean in the `organized.resolution`
construction to emit `scrapeDiscarded` for either discard path.

@minhthanhdang

Copy link
Copy Markdown
Contributor Author

Closing — direction changed for RM-17863: the non-docs-site check now runs on the marketing homepage before the redirect (quick classify endpoint on the launcher + warning with Continue Anyway on the form), replacing the in-pipeline warning. New PRs incoming.

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