From ffe5eb2130e83b3f6a9299713656e7cdf21f0f93 Mon Sep 17 00:00:00 2001 From: Seowoo Han Date: Wed, 20 May 2026 19:56:04 +0900 Subject: [PATCH] Add domain review template selector --- domain-review-template-selector/README.md | 20 ++ .../acceptance-notes.md | 30 +++ domain-review-template-selector/demo.js | 36 ++++ domain-review-template-selector/demo.mp4 | Bin 0 -> 44743 bytes domain-review-template-selector/demo.svg | 26 +++ domain-review-template-selector/index.js | 176 ++++++++++++++++++ .../requirements-map.md | 13 ++ domain-review-template-selector/test.js | 98 ++++++++++ 8 files changed, 399 insertions(+) create mode 100644 domain-review-template-selector/README.md create mode 100644 domain-review-template-selector/acceptance-notes.md create mode 100644 domain-review-template-selector/demo.js create mode 100644 domain-review-template-selector/demo.mp4 create mode 100644 domain-review-template-selector/demo.svg create mode 100644 domain-review-template-selector/index.js create mode 100644 domain-review-template-selector/requirements-map.md create mode 100644 domain-review-template-selector/test.js diff --git a/domain-review-template-selector/README.md b/domain-review-template-selector/README.md new file mode 100644 index 0000000..827ffe2 --- /dev/null +++ b/domain-review-template-selector/README.md @@ -0,0 +1,20 @@ +# Domain Review Template Selector + +This module covers the adaptive peer-review template slice of SCIBASE issue #16. + +It classifies a manuscript's scientific domain from title, keywords, methods, and artifact metadata, then selects a domain-specific review template for the AI research assistant. The output combines domain review sections with claim/evidence alignment, reproducibility readiness, reviewer expertise, blockers, warnings, and a deterministic audit digest. + +## What It Does + +- Selects clinical, machine-learning, wet-lab biology, materials/chemistry, computational, or general-science review templates. +- Uses domain-specific review sections instead of a one-size-fits-all peer-review checklist. +- Checks manuscript, data, code, evidence anchors, environment, run command, and expected output readiness. +- Blocks review packets with unanchored or missing-evidence claims. +- Emits reviewer questions, expertise routing, warnings, blockers, and an audit digest. + +## Run + +```bash +node domain-review-template-selector/test.js +node domain-review-template-selector/demo.js +``` diff --git a/domain-review-template-selector/acceptance-notes.md b/domain-review-template-selector/acceptance-notes.md new file mode 100644 index 0000000..7f34213 --- /dev/null +++ b/domain-review-template-selector/acceptance-notes.md @@ -0,0 +1,30 @@ +# Acceptance Notes + +## Review Scenarios + +1. Clinical manuscript + - Clinical terms select a clinical peer-review template. + - Patient eligibility, endpoint validity, safety reporting, and ethics/consent sections are included. + +2. Machine-learning manuscript + - Benchmark, model, training, and ablation terms select the machine-learning template. + - Data split integrity, baseline comparison, ablation strength, and leakage risk sections are included. + +3. Blocked wet-lab review packet + - A CRISPR manuscript with unanchored claims is blocked before review. + - Missing data, code, environment, run command, and output manifests are surfaced. + +4. Computational reproducibility review + - A computational manuscript with missing expected outputs is marked needs-review and routed to reproducibility expertise. + +## Validation + +```bash +node domain-review-template-selector/test.js +node domain-review-template-selector/demo.js +node --check domain-review-template-selector/index.js +node --check domain-review-template-selector/test.js +node --check domain-review-template-selector/demo.js +``` + +The included `demo.mp4` is a five-second visual walkthrough of domain classification, template selection, and review packet readiness. diff --git a/domain-review-template-selector/demo.js b/domain-review-template-selector/demo.js new file mode 100644 index 0000000..8d1b972 --- /dev/null +++ b/domain-review-template-selector/demo.js @@ -0,0 +1,36 @@ +"use strict" + +const { selectDomainReviewTemplate } = require("./index") + +const result = selectDomainReviewTemplate({ + manuscript: { + title: "Transformer baseline for satellite image segmentation", + keywords: ["model", "benchmark", "training", "ablation"], + methods: ["dataset split", "baseline comparison", "validation"], + artifacts: [ + { type: "manuscript", name: "paper.md" }, + { type: "data", name: "dataset-card.json" }, + { type: "code", name: "train.py" }, + ], + evidence: [{ id: "ev-split" }, { id: "ev-ablation" }], + claims: [ + { id: "claim-performance", evidenceIds: ["ev-split"] }, + { id: "claim-ablation", evidenceIds: ["ev-ablation"] }, + ], + reproducibility: { + environment: "Dockerfile", + runCommand: "python train.py --config baseline.yaml", + expectedOutputs: ["metrics.json", "ablation.csv"], + }, + }, +}) + +console.log("Domain Review Template Selector Demo") +console.log("====================================") +console.log(`status: ${result.status}`) +console.log(`domain: ${result.domain}`) +console.log(`template: ${result.templateId}`) +console.log(`first section: ${result.prioritySections[0]}`) +console.log(`review question count: ${result.reviewQuestions.length}`) +console.log(`expertise: ${result.recommendedReviewerExpertise.join(", ")}`) +console.log(`digest: ${result.auditDigest.slice(0, 16)}...`) diff --git a/domain-review-template-selector/demo.mp4 b/domain-review-template-selector/demo.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..7110b41044140ace36e366a622ea47e7458f8fa2 GIT binary patch literal 44743 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%0DaT0Htrr0a!}(MQ5b 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 + Domain Review Template Selector + A visual summary showing manuscript domain classification, template selection, evidence checks, and review packet routing. + + + Domain Review Template Selector + Adaptive peer-review templates for AI research assistant packets. + + + Classify + keywords + methods + + + + Template + domain-specific sections + + + + Check + evidence + reproducibility + + Output + template id, review questions, blockers, warnings, reviewer expertise, audit digest + Clinical, ML, wet-lab biology, materials/chemistry, computational, and general science. + diff --git a/domain-review-template-selector/index.js b/domain-review-template-selector/index.js new file mode 100644 index 0000000..fce7527 --- /dev/null +++ b/domain-review-template-selector/index.js @@ -0,0 +1,176 @@ +"use strict" + +const crypto = require("node:crypto") + +function stableStringify(value) { + if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]` + if (value && typeof value === "object") { + return `{${Object.keys(value) + .sort() + .map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`) + .join(",")}}` + } + return JSON.stringify(value) +} + +function digest(value) { + return crypto.createHash("sha256").update(stableStringify(value)).digest("hex") +} + +const DOMAIN_RULES = [ + { + domain: "clinical", + terms: ["clinical", "trial", "patient", "cohort", "consort", "irb", "endpoint", "randomized"], + sections: ["patient eligibility", "endpoint validity", "safety reporting", "ethics and consent"], + }, + { + domain: "machine-learning", + terms: ["model", "benchmark", "dataset", "training", "validation", "baseline", "ablation", "auc", "accuracy"], + sections: ["data split integrity", "baseline comparison", "ablation strength", "leakage risk"], + }, + { + domain: "wet-lab-biology", + terms: ["assay", "cell", "gene", "protein", "western", "qpcr", "crispr", "replicate", "antibody"], + sections: ["biological replicates", "reagent validation", "protocol controls", "raw measurement evidence"], + }, + { + domain: "materials-chemistry", + terms: ["synthesis", "catalyst", "polymer", "crystal", "spectra", "xrd", "sem", "nmr", "yield"], + sections: ["synthesis reproducibility", "characterization evidence", "purity controls", "yield accounting"], + }, + { + domain: "computational", + terms: ["simulation", "notebook", "pipeline", "code", "parameter", "runtime", "dependency", "container"], + sections: ["runtime reproducibility", "parameter coverage", "artifact availability", "determinism checks"], + }, +] + +function tokenize(input) { + return String(input || "") + .toLowerCase() + .split(/[^a-z0-9+.-]+/) + .filter(Boolean) +} + +function classifyDomain(manuscript) { + const tokens = tokenize( + [ + manuscript.title, + manuscript.abstract, + ...(manuscript.keywords || []), + ...(manuscript.methods || []), + ...(manuscript.artifacts || []).map((artifact) => `${artifact.type || ""} ${artifact.name || ""}`), + ].join(" "), + ) + const tokenSet = new Set(tokens) + + const scores = DOMAIN_RULES.map((rule) => { + const matchedTerms = rule.terms.filter((term) => tokenSet.has(term)) + return { + domain: rule.domain, + score: matchedTerms.length, + matchedTerms, + sections: rule.sections, + } + }).sort((a, b) => b.score - a.score || a.domain.localeCompare(b.domain)) + + const winner = scores[0] + return winner.score > 0 + ? winner + : { + domain: "general-science", + score: 0, + matchedTerms: [], + sections: ["claim clarity", "methods adequacy", "evidence alignment", "reproducibility readiness"], + } +} + +function evaluateEvidence(manuscript) { + const artifacts = manuscript.artifacts || [] + const evidenceIds = new Set((manuscript.evidence || []).map((item) => item.id)) + const claims = manuscript.claims || [] + const warnings = [] + const blockers = [] + + for (const required of ["manuscript", "data", "code"]) { + if (!artifacts.some((artifact) => artifact.type === required)) { + warnings.push(`missing ${required} artifact`) + } + } + + for (const claim of claims) { + const claimEvidence = claim.evidenceIds || [] + if (claimEvidence.length === 0) { + blockers.push(`claim ${claim.id} has no evidence anchors`) + } else { + const missing = claimEvidence.filter((id) => !evidenceIds.has(id)) + if (missing.length > 0) blockers.push(`claim ${claim.id} references missing evidence: ${missing.join(", ")}`) + } + } + + if (!manuscript.reproducibility?.environment) warnings.push("missing reproducibility environment") + if (!manuscript.reproducibility?.runCommand) warnings.push("missing reproducibility run command") + if (!manuscript.reproducibility?.expectedOutputs?.length) warnings.push("missing expected output manifest") + + return { blockers, warnings } +} + +function buildReviewQuestions(domainResult, manuscript, evidenceResult) { + const questions = domainResult.sections.map((section) => ({ + section, + prompt: `Assess ${section} for ${manuscript.title || "the manuscript"} using cited evidence and reproducibility artifacts.`, + })) + + questions.push({ + section: "claim-evidence alignment", + prompt: "List every central claim and confirm whether the cited artifacts directly support it.", + }) + questions.push({ + section: "reproducibility check", + prompt: "Verify the data, code, environment, run command, and expected outputs are sufficient for rerun.", + }) + + if (evidenceResult.blockers.length > 0) { + questions.unshift({ + section: "release blocker", + prompt: "Resolve unanchored or missing-evidence claims before sending this manuscript to review.", + }) + } + + return questions +} + +function selectDomainReviewTemplate(input) { + const manuscript = input.manuscript || {} + const domain = classifyDomain(manuscript) + const evidence = evaluateEvidence(manuscript) + const questions = buildReviewQuestions(domain, manuscript, evidence) + const reviewerPacket = { + templateId: `${domain.domain}-peer-review`, + domain: domain.domain, + matchedTerms: domain.matchedTerms, + status: evidence.blockers.length > 0 ? "blocked" : evidence.warnings.length > 0 ? "needs-review" : "ready", + prioritySections: domain.sections, + blockers: evidence.blockers, + warnings: evidence.warnings, + reviewQuestions: questions, + recommendedReviewerExpertise: [ + domain.domain, + evidence.warnings.some((warning) => + ["reproducibility", "environment", "run command", "expected output"].some((term) => warning.includes(term)), + ) + ? "reproducibility" + : null, + evidence.blockers.length > 0 ? "evidence-audit" : null, + ].filter(Boolean), + } + + return { + ...reviewerPacket, + auditDigest: digest(reviewerPacket), + } +} + +module.exports = { + selectDomainReviewTemplate, +} diff --git a/domain-review-template-selector/requirements-map.md b/domain-review-template-selector/requirements-map.md new file mode 100644 index 0000000..e513403 --- /dev/null +++ b/domain-review-template-selector/requirements-map.md @@ -0,0 +1,13 @@ +# Requirements Map + +| Issue #16 requirement | Coverage in this module | +| --- | --- | +| Auto peer review reports | Builds reviewer-ready questions and sections for a manuscript before public release. | +| Adaptive templates per domain | Selects clinical, machine-learning, wet-lab biology, materials/chemistry, computational, or general-science templates. | +| Claims vs evidence alignment | Blocks unanchored claims and claims that reference missing evidence. | +| Reproducibility checker | Checks data/code artifacts, environment, run command, and expected output manifest readiness. | +| Equip researchers with editorial-quality feedback | Produces domain-specific review questions, blockers, warnings, and reviewer expertise routing. | + +## Non-Overlap Note + +This submission is distinct from broad assistant suites, evidence traces, protocol traces, statistics review, research-gap planners, rebuttal packs, ethics/data availability checks, citation-context reconciliation, reporting-guideline compliance, benchmark leakage audits, figure/table consistency checks, and analysis-variable provenance assistants. It focuses specifically on adaptive domain review template selection and review packet routing. diff --git a/domain-review-template-selector/test.js b/domain-review-template-selector/test.js new file mode 100644 index 0000000..8a5c730 --- /dev/null +++ b/domain-review-template-selector/test.js @@ -0,0 +1,98 @@ +"use strict" + +const assert = require("node:assert/strict") +const { selectDomainReviewTemplate } = require("./index") + +{ + const result = selectDomainReviewTemplate({ + manuscript: { + title: "Randomized clinical trial of a sepsis biomarker", + keywords: ["clinical", "trial", "patient"], + artifacts: [ + { type: "manuscript", name: "paper.md" }, + { type: "data", name: "cohort.csv" }, + { type: "code", name: "analysis.py" }, + ], + evidence: [{ id: "ev-primary-endpoint" }], + claims: [{ id: "claim-survival", evidenceIds: ["ev-primary-endpoint"] }], + reproducibility: { + environment: "conda-lock.yml", + runCommand: "python analysis.py", + expectedOutputs: ["tables/primary.csv"], + }, + }, + }) + + assert.equal(result.domain, "clinical") + assert.equal(result.status, "ready") + assert.ok(result.prioritySections.includes("patient eligibility")) + assert.match(result.auditDigest, /^[0-9a-f]{64}$/) +} + +{ + const result = selectDomainReviewTemplate({ + manuscript: { + title: "Transformer baseline for satellite image segmentation", + keywords: ["model", "benchmark", "training", "ablation"], + artifacts: [ + { type: "manuscript", name: "paper.md" }, + { type: "data", name: "dataset-card.json" }, + { type: "code", name: "train.py" }, + ], + evidence: [{ id: "ev-split" }], + claims: [{ id: "claim-sota", evidenceIds: ["ev-split"] }], + reproducibility: { + environment: "Dockerfile", + runCommand: "python train.py --config baseline.yaml", + expectedOutputs: ["metrics.json"], + }, + }, + }) + + assert.equal(result.domain, "machine-learning") + assert.equal(result.status, "ready") + assert.ok(result.prioritySections.includes("leakage risk")) +} + +{ + const result = selectDomainReviewTemplate({ + manuscript: { + title: "CRISPR screen identifies stress response genes", + keywords: ["crispr", "cell", "gene", "replicate"], + artifacts: [{ type: "manuscript", name: "paper.md" }], + evidence: [{ id: "ev-figure-1" }], + claims: [{ id: "claim-gene-hit", evidenceIds: [] }], + reproducibility: {}, + }, + }) + + assert.equal(result.domain, "wet-lab-biology") + assert.equal(result.status, "blocked") + assert.ok(result.blockers.includes("claim claim-gene-hit has no evidence anchors")) + assert.ok(result.warnings.includes("missing data artifact")) + assert.equal(result.reviewQuestions[0].section, "release blocker") +} + +{ + const result = selectDomainReviewTemplate({ + manuscript: { + title: "A reusable simulation workflow", + keywords: ["simulation", "notebook", "dependency"], + artifacts: [ + { type: "manuscript", name: "paper.md" }, + { type: "data", name: "input.json" }, + { type: "code", name: "notebook.ipynb" }, + ], + evidence: [], + claims: [], + reproducibility: { environment: "Dockerfile", runCommand: "jupyter nbconvert --execute notebook.ipynb" }, + }, + }) + + assert.equal(result.domain, "computational") + assert.equal(result.status, "needs-review") + assert.ok(result.warnings.includes("missing expected output manifest")) + assert.ok(result.recommendedReviewerExpertise.includes("reproducibility")) +} + +console.log("domain-review-template-selector tests passed")