Skip to content

feat: Auto-fetch full text for top-N documents per analysis run (--auto-full-text-top-n)#2044

Merged
pethers merged 11 commits intomainfrom
copilot/auto-fetch-full-text-documents
Apr 27, 2026
Merged

feat: Auto-fetch full text for top-N documents per analysis run (--auto-full-text-top-n)#2044
pethers merged 11 commits intomainfrom
copilot/auto-fetch-full-text-documents

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 27, 2026

  • Add --auto-full-text-top-n=N CLI flag to scripts/download-parliamentary-data.ts
  • Export fetchFullTextForTopN from scripts/parliamentary-data/data-downloader.ts
  • Extend serializeDataManifest to record full-text fetch outcomes
  • Wire flag into runPreArticleAnalysis (Step 2b)
  • Update analysis gate (05-analysis-gate.md) with Check 10 (full-text) and renumbered Check 11 (supplementary artifacts)
  • Update analysis/methodologies/ai-driven-analysis-guide.md (v6.7)
  • Resolve prior merge conflicts and review feedback
  • Merge latest origin/main with true merge commit ef34de7
  • Fix Vitest unit-test failure flagged in CI run 24992073946
  • Address review thread 4180780088:
    • Close missing fi in Check 10 bash snippet (05-analysis-gate.md)
    • Reuse already-enriched fullContent/fullText/text/html fields on RawDocument before issuing a duplicate MCP call
    • Normalize manifest filePath separators to POSIX (split(path.sep).join('/')) for byte-identical artifacts across OSes
  • Re-run targeted tests: npx vitest run tests/auto-full-text-top-n.test.ts tests/pir-status-contract.test.ts — 108 passed
  • Re-run npm run build:lib — passed
  • Reply to PR comment 4326877830

Copilot AI linked an issue Apr 27, 2026 that may be closed by this pull request
5 tasks
@github-actions github-actions Bot added the size-xs Extra small change (< 10 lines) label Apr 27, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🏷️ Automatic Labeling Summary

This PR has been automatically labeled based on the files changed and PR metadata.

Applied Labels: size-xs

Label Categories

  • 🗳️ Content: news, dashboard, visualization, intelligence
  • 💻 Technology: html-css, javascript, workflow, security
  • 📊 Data: cia-data, riksdag-data, data-pipeline, schema
  • 🌍 I18n: i18n, translation, rtl
  • 🔒 ISMS: isms, iso-27001, nist-csf, cis-controls
  • 🏗️ Infrastructure: ci-cd, deployment, performance, monitoring
  • 🔄 Quality: testing, accessibility, documentation, refactor
  • 🤖 AI: agent, skill, agentic-workflow

For more information, see .github/labeler.yml.

@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

@github-actions github-actions Bot added documentation Documentation updates testing Test coverage refactor Code refactoring size-l Large change (250-1000 lines) labels Apr 27, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

…sedAutoFullTextTopN, add comment)

Agent-Logs-Url: https://github.com/Hack23/riksdagsmonitor/sessions/c07332ca-b490-4915-9dd9-22c94ee49aea

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copilot AI changed the title [WIP] Add auto-fetch of full text for top-2 DIW-ranked documents feat: Auto-fetch full text for top-N documents per analysis run (--auto-full-text-top-n) Apr 27, 2026
Copilot AI requested a review from pethers April 27, 2026 01:03
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

@pethers pethers marked this pull request as ready for review April 27, 2026 08:06
Copilot AI review requested due to automatic review settings April 27, 2026 08:06
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an “auto full-text prefetch” step to the parliamentary data download pipeline so analysis runs can reliably access full text for the top-N documents (via --auto-full-text-top-n) and enforces this via an analysis-gate check.

Changes:

  • Add fetchFullTextForTopN() to fetch/persist full text for the first N documents and return structured outcomes.
  • Add --auto-full-text-top-n CLI parsing + manifest section ## Full-Text Fetch Outcomes.
  • Add Analysis Gate Check 10 enforcing “≥2 full texts available” (or a documented fallback), plus a new Vitest suite covering the feature.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/auto-full-text-top-n.test.ts New test coverage for CLI parsing and top-N full-text fetch/persist behavior.
scripts/parliamentary-data/data-downloader.ts Introduces fetchFullTextForTopN() and FullTextFetchOutcome type; writes full text artifacts under full-text/.
scripts/download-parliamentary-data.ts Adds CLI flag, runs auto-fetch step, and writes outcomes into data-download-manifest.md.
analysis/methodologies/ai-driven-analysis-guide.md Updates methodology guidance to recommend --auto-full-text-top-n 2 for L2/L3 runs.
.github/prompts/05-analysis-gate.md Adds new blocking gate check for top-2 full-text availability when outcomes table is present.

Comment on lines +19 to +21
import fs from 'node:fs';
import path from 'node:path';

Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

This module header says it is "side-effect-free with respect to the filesystem", but this file now imports fs/path and implements a function that writes to disk. Please update the module-level documentation (or move the filesystem-writing helper into a different module) so callers aren’t misled about side effects.

Copilot uses AI. Check for mistakes.
* "tried but only metadata returned".
*
* The function is intentionally *not* side-effect-free: it writes files to
* `outputDir/full-text/`. The caller is responsible for creating `outputDir`.
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

The docstring says the caller is responsible for creating outputDir, but the implementation calls fs.mkdirSync(fullTextDir, { recursive: true }), which will also create missing parent directories. Either adjust the wording to match the actual behavior or change the implementation to require a pre-existing outputDir.

Suggested change
* `outputDir/full-text/`. The caller is responsible for creating `outputDir`.
* `outputDir/full-text/` and creates that directory as needed, including any
* missing parent directories.

Copilot uses AI. Check for mistakes.
Comment on lines +599 to +600
].filter(Boolean).join('\n');
fs.writeFileSync(filePath, header + content, 'utf8');
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

header is built with .filter(Boolean), which removes the intentional blank lines and can cause the persisted file to lose Markdown structure. It also means header + content can join without a separating newline (e.g., ---<p>...), breaking the horizontal rule and readability. Preserve blank lines (don’t filter them out) and ensure there’s at least one \n between the header block and content when writing.

Suggested change
].filter(Boolean).join('\n');
fs.writeFileSync(filePath, header + content, 'utf8');
].join('\n');
const headerBlock = header.endsWith('\n') ? header : `${header}\n`;
fs.writeFileSync(filePath, headerBlock + content, 'utf8');

Copilot uses AI. Check for mistakes.
Comment on lines +601 to +605
outcome = {
dokId,
success: true,
chars: content.length,
filePath: path.relative(process.cwd(), filePath),
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

filePath is derived via path.relative(process.cwd(), filePath), which makes the manifest output dependent on the caller’s current working directory (and can vary between local runs/CI). Prefer a stable base such as outputDir or REPO_ROOT when computing the relative path so the persisted manifest points to the right location consistently.

Suggested change
outcome = {
dokId,
success: true,
chars: content.length,
filePath: path.relative(process.cwd(), filePath),
const manifestBaseDir = path.dirname(fullTextDir);
outcome = {
dokId,
success: true,
chars: content.length,
filePath: path.relative(manifestBaseDir, filePath),

Copilot uses AI. Check for mistakes.
Comment thread scripts/download-parliamentary-data.ts Outdated
Comment on lines +151 to +153
// --auto-full-text-top-n: Number of top documents to auto-fetch full text for.
// Defaults to 0 (disabled). Use 2 to guarantee the top-2 DIW-ranked documents
// have full text available for deep-analysis tiers (L2/L3).
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

The comment mentions "top-2 DIW-ranked documents", but this script doesn’t compute or apply any DIW ranking before passing allDocs into fetchFullTextForTopN (it uses the current array order after filtering). Please reword to avoid implying a ranking that isn’t present, or explicitly document what ordering determines the "top" documents here.

Suggested change
// --auto-full-text-top-n: Number of top documents to auto-fetch full text for.
// Defaults to 0 (disabled). Use 2 to guarantee the top-2 DIW-ranked documents
// have full text available for deep-analysis tiers (L2/L3).
// --auto-full-text-top-n: Number of documents to auto-fetch full text for.
// Defaults to 0 (disabled). When enabled, the script fetches full text for the
// first N documents in the current filtered array order for deep-analysis tiers (L2/L3).

Copilot uses AI. Check for mistakes.
@pethers
Copy link
Copy Markdown
Member

pethers commented Apr 27, 2026

@copilot resolve the merge conflicts in this pull request

…ble filePath, comment accuracy)

Agent-Logs-Url: https://github.com/Hack23/riksdagsmonitor/sessions/c2ed7611-af52-4af6-9563-cc59a848957f

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 27, 2026

@copilot resolve the merge conflicts in this pull request

Merge conflicts are resolved (commit 22044e3 already merged main). I also addressed all 5 automated review comments in commit 13c6e1d:

  • Module header — updated to clarify that most functions are side-effect-free; fetchFullTextForTopN is the documented exception
  • JSDoc outputDir — corrected to say the function creates outputDir/full-text/ including any missing parent directories
  • Header blank lines — replaced filter(Boolean) with an explicit conditional spread so \n\n---\n is preserved; added a test asserting this
  • filePath stability — now uses outputDir as the base for path.relative(...) instead of process.cwd(), making manifest entries consistent across environments; added a test asserting filePath === 'full-text/DOC99.md'
  • Misleading "DIW-ranked" comment — reworded to clarify ordering follows MCP fetch order, not any significance ranking

@pethers
Copy link
Copy Markdown
Member

pethers commented Apr 27, 2026

@copilot resolve the merge conflicts in this pull request

@github-actions github-actions Bot added skill Skill configuration size-xl Extra large change (> 1000 lines) labels Apr 27, 2026
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 27, 2026

@copilot resolve the merge conflicts in this pull request

Merge conflicts resolved in cb225a0. I merged latest origin/main and resolved conflicts in .github/prompts/05-analysis-gate.md and scripts/download-parliamentary-data.ts, preserving main’s Statskontoret/PIR checks and nullable enrichment default while keeping this PR’s persisted top-N full-text outcomes. Follow-up cleanup from validation is in 5579ce6.

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 27, 2026

@copilot resolve the merge conflicts in this pull request

Merge conflicts resolved in ef34de7. The branch now has a true merge commit with latest origin/main as a parent, while preserving this PR’s auto full-text behavior and main’s Statskontoret/PIR checks. Targeted Vitest coverage and npm run build:lib passed.

@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

@pethers
Copy link
Copy Markdown
Member

pethers commented Apr 27, 2026

@copilot analyse and improve and adress issues in TypeScript & JavaScript Testing / Unit Tests (Vitest) (pull_request)
TypeScript & JavaScript Testing / Unit Tests (Vitest) (pull_request)Failing after 2m

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 27, 2026

@copilot analyse and improve and adress issues in [TypeScript & JavaScript Testing / Unit Tests (Vitest) (pull_request)](https://github.com/Hack23/riksdagsmonitor/actions/runs/24992073...

Fixed in 5510696. The CI failure was tests/pir-status-contract.test.ts:853 asserting # Check 10 — supplementary artifacts, but this PR renumbered the gate so Check 10 is now "top-2 full-text availability" and supplementary artifacts moved to Check 11. Updated the assertion to expect both # Check 10 — top-2 full-text availability and # Check 11 — supplementary artifacts. Targeted run: npx vitest run tests/pir-status-contract.test.ts — 81/81 passing.

@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

scripts/download-parliamentary-data.ts:165

  • --auto-full-text-top-n currently accepts 1, but the updated analysis gate Check 10 requires at least 2 successful full-text rows whenever the outcomes table is present. With topN=1, the script will emit the table and the gate becomes impossible to satisfy without manually editing the manifest. Consider rejecting values between 1 and 1 (require 0 or ≥2), auto-bumping 1→2, or emitting an automatic <!-- full-text-fallback: ... --> annotation when topN < 2.
  // --auto-full-text-top-n: Override the per-type full-text enrichment limit and
  // persist full text outcomes for the first N documents in the current filtered
  // array order. Defaults to null when omitted so downloadAllDocuments uses
  // MAX_ENRICHMENT_PER_TYPE; explicit 0 disables per-type enrichment and
  // persisted full-text fetching. No DIW significance ranking is applied here.
  const autoFullTextTopNArg = get('--auto-full-text-top-n');
  let autoFullTextTopN: number | null = null;
  if (autoFullTextTopNArg !== null) {
    const parsed = Number(autoFullTextTopNArg);
    if (!Number.isInteger(parsed) || parsed < 0) {
      throw new Error(`Invalid --auto-full-text-top-n value: ${autoFullTextTopNArg}. Expected a non-negative integer.`);
    }
    autoFullTextTopN = parsed;
  }

[ "${FT_SUCCESS:-0}" -ge 2 ] \
|| { echo "❌ data-download-manifest.md: Full-Text Fetch Outcomes table present but fewer than 2 top documents have full_text_available=true (found ${FT_SUCCESS:-0}). Add <!-- full-text-fallback: <reason> --> to the manifest to bypass."; FAIL=1; }
fi
fi
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

The new Check 10 bash snippet opens an outer if [ -s "$ANALYSIS_DIR/data-download-manifest.md" ]; then but never closes it with a matching fi, so the example gate script is syntactically invalid if copied/run as-is. Add the missing fi before the final [ "$FAIL" -eq 0 ] || exit 1 line.

Suggested change
fi
fi
fi

Copilot uses AI. Check for mistakes.
Comment on lines +567 to +594
for (const { dokId } of candidates) {
let outcome: FullTextFetchOutcome;
try {
const details = await client.fetchDocumentDetails(dokId, true) as Record<string, unknown>;
const str = (v: unknown): string => (typeof v === 'string' ? v : '');
const sanitize = (v: unknown): string => {
const s = str(v).trim();
return isPersonProfileText(s) ? '' : s;
};

const rawText = str(details['text']).trim();
// fullText may contain MP profile/deceased-notice text — sanitize it.
// text and html fields are structural content from the Riksdag dump and
// do not contain person-profile text, so str().trim() is sufficient.
const rawFullText = sanitize(details['fullText']);
const rawHtml = str(details['html']).trim();

// Prefer MCP 'text' field (embedded HTML dump), fall back to fullText then html.
const content = rawText.length > FULL_TEXT_MIN_LENGTH
? rawText
: rawFullText.length > FULL_TEXT_MIN_LENGTH
? rawFullText
: rawHtml;

if (content.length > FULL_TEXT_MIN_LENGTH) {
const filenameSafeDokId = dokId.replace(/[^A-Za-z0-9_-]/g, '_');
const filePath = path.join(fullTextDir, `${filenameSafeDokId}.md`);
const snippet = sanitize(details['snippet']) || sanitize(details['summary']) || '';
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

fetchFullTextForTopN always calls client.fetchDocumentDetails(dokId, true) for each candidate, even though the caller (downloadAllDocuments) already enriches top documents via the same MCP call and stores fullContent/fullText on the existing RawDocument objects. Consider reusing already-enriched fields (and only calling MCP when missing/too short) to avoid duplicate network calls and reduce MCP load/rate-limit risk; note you already keep { dokId, doc } but currently don’t use doc.

Suggested change
for (const { dokId } of candidates) {
let outcome: FullTextFetchOutcome;
try {
const details = await client.fetchDocumentDetails(dokId, true) as Record<string, unknown>;
const str = (v: unknown): string => (typeof v === 'string' ? v : '');
const sanitize = (v: unknown): string => {
const s = str(v).trim();
return isPersonProfileText(s) ? '' : s;
};
const rawText = str(details['text']).trim();
// fullText may contain MP profile/deceased-notice text — sanitize it.
// text and html fields are structural content from the Riksdag dump and
// do not contain person-profile text, so str().trim() is sufficient.
const rawFullText = sanitize(details['fullText']);
const rawHtml = str(details['html']).trim();
// Prefer MCP 'text' field (embedded HTML dump), fall back to fullText then html.
const content = rawText.length > FULL_TEXT_MIN_LENGTH
? rawText
: rawFullText.length > FULL_TEXT_MIN_LENGTH
? rawFullText
: rawHtml;
if (content.length > FULL_TEXT_MIN_LENGTH) {
const filenameSafeDokId = dokId.replace(/[^A-Za-z0-9_-]/g, '_');
const filePath = path.join(fullTextDir, `${filenameSafeDokId}.md`);
const snippet = sanitize(details['snippet']) || sanitize(details['summary']) || '';
for (const { dokId, doc } of candidates) {
let outcome: FullTextFetchOutcome;
try {
const str = (v: unknown): string => (typeof v === 'string' ? v : '');
const sanitize = (v: unknown): string => {
const s = str(v).trim();
return isPersonProfileText(s) ? '' : s;
};
const selectContent = (source: Record<string, unknown>): string => {
const rawText = str(source['text']).trim();
const rawFullContent = sanitize(source['fullContent']);
// fullText may contain MP profile/deceased-notice text — sanitize it.
// text and html fields are structural content from the Riksdag dump and
// do not contain person-profile text, so str().trim() is sufficient.
const rawFullText = sanitize(source['fullText']);
const rawHtml = str(source['html']).trim();
// Prefer normalized/enriched content already present on the document,
// then fall back to the raw HTML dump fields.
return rawText.length > FULL_TEXT_MIN_LENGTH
? rawText
: rawFullContent.length > FULL_TEXT_MIN_LENGTH
? rawFullContent
: rawFullText.length > FULL_TEXT_MIN_LENGTH
? rawFullText
: rawHtml;
};
const docRecord = doc as Record<string, unknown>;
let details: Record<string, unknown> | null = null;
let content = selectContent(docRecord);
if (content.length <= FULL_TEXT_MIN_LENGTH) {
details = await client.fetchDocumentDetails(dokId, true) as Record<string, unknown>;
content = selectContent(details);
}
if (content.length > FULL_TEXT_MIN_LENGTH) {
const filenameSafeDokId = dokId.replace(/[^A-Za-z0-9_-]/g, '_');
const filePath = path.join(fullTextDir, `${filenameSafeDokId}.md`);
const snippet = sanitize(docRecord['snippet'])
|| sanitize(docRecord['summary'])
|| sanitize(details?.['snippet'])
|| sanitize(details?.['summary'])
|| '';

Copilot uses AI. Check for mistakes.
Comment on lines +608 to +612
outcome = {
dokId,
success: true,
chars: content.length,
filePath: path.relative(outputDir, filePath),
Copy link

Copilot AI Apr 27, 2026

Choose a reason for hiding this comment

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

filePath is recorded via path.relative(outputDir, filePath), which will emit backslashes on Windows and makes manifest output non-deterministic across OSes. Elsewhere in the repo, relative paths are normalized to POSIX separators (.split(path.sep).join('/')) for stable, byte-identical artifacts; consider doing the same here before storing filePath.

Suggested change
outcome = {
dokId,
success: true,
chars: content.length,
filePath: path.relative(outputDir, filePath),
// Normalize separators to POSIX form for byte-identical artifacts across OSes.
outcome = {
dokId,
success: true,
chars: content.length,
filePath: path.relative(outputDir, filePath).split(path.sep).join('/'),

Copilot uses AI. Check for mistakes.
@pethers
Copy link
Copy Markdown
Member

pethers commented Apr 27, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 27, 2026

@copilot apply changes based on the comments in this thread

Applied all three suggestions in 862da67:

  1. Missing fi — added the closing fi for the outer if [ -s "$ANALYSIS_DIR/data-download-manifest.md" ] so the Check 10 bash block is syntactically valid (verified with bash -n on the extracted block).
  2. Reuse enriched fieldsfetchFullTextForTopN now extracts text/fullContent/fullText/html from the existing RawDocument first via a shared selectContent() helper, and only calls client.fetchDocumentDetails(dokId, true) when the document doesn't already carry meaningful content. The doc field of each candidate is now actually used.
  3. POSIX path normalization — manifest filePath now goes through path.relative(outputDir, filePath).split(path.sep).join('/') for byte-identical artifacts across OSes.

Validation: npx vitest run tests/auto-full-text-top-n.test.ts tests/pir-status-contract.test.ts → 108/108 passing; npm run build:lib → clean.

@github-actions
Copy link
Copy Markdown
Contributor

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

@pethers pethers merged commit 453762b into main Apr 27, 2026
15 checks passed
@pethers pethers deleted the copilot/auto-fetch-full-text-documents branch April 27, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Documentation updates refactor Code refactoring size-l Large change (250-1000 lines) size-xl Extra large change (> 1000 lines) size-xs Extra small change (< 10 lines) skill Skill configuration testing Test coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Methodology] Auto-fetch full text for top-N DIW-ranked documents per analysis run

3 participants