Grounded-summary workflow example
This deterministic example contains a synthetic source, a JSON Schema, five cases, and a validator.
Run:
node validate.mjsExpected:
ACCEPT valid-date
ACCEPT valid-owner
REJECT missing-quote
REJECT unsupported-number
REJECT not-reviewed
PASS 5 cases: 2 accepted, 3 rejectedVerified on 2026-10-27 with Node v26.8.1.
The validator checks required structure, exact source substrings, and a human-review flag. It does not prove completeness, truth outside the supplied source, fairness, or writing quality.
Included source files
- README.md MARKDOWN
- validate.mjs JAVASCRIPT
- cases.json JSON
- schema.json JSON
- source.txt TEXT
validate.mjs
Download this fileimport { readFile } from 'node:fs/promises';
const source = await readFile(new URL('./source.txt', import.meta.url), 'utf8');
const cases = JSON.parse(await readFile(new URL('./cases.json', import.meta.url), 'utf8'));
export function validate(candidate) {
if (!candidate || typeof candidate.summary !== 'string' || !candidate.summary.trim()) return false;
if (typeof candidate.quote !== 'string' || !candidate.quote || !source.includes(candidate.quote)) return false;
if (!Array.isArray(candidate.claims) || candidate.claims.some(claim => typeof claim !== 'string' || !source.includes(claim))) return false;
return candidate.reviewed === true;
}
let accepted = 0;
let rejected = 0;
for (const item of cases) {
const actual = validate(item.candidate);
if (actual !== item.expected) throw new Error(item.name + ': expected ' + item.expected + ', got ' + actual);
actual ? accepted++ : rejected++;
console.log((actual ? 'ACCEPT ' : 'REJECT ') + item.name);
}
console.log('PASS ' + cases.length + ' cases: ' + accepted + ' accepted, ' + rejected + ' rejected');cases.json
Download this file[
{"name":"valid-date","candidate":{"summary":"Alder closes on 18 November.","quote":"Project Alder closes on 18 November.","claims":["18 November"],"reviewed":true},"expected":true},
{"name":"valid-owner","candidate":{"summary":"Team Blue owns final review.","quote":"Team Blue owns the final review.","claims":["Team Blue"],"reviewed":true},"expected":true},
{"name":"missing-quote","candidate":{"summary":"Alder closes in November.","quote":"","claims":["November"],"reviewed":true},"expected":false},
{"name":"unsupported-number","candidate":{"summary":"Alder closes on 12 November.","quote":"Project Alder closes on 18 November.","claims":["12 November"],"reviewed":true},"expected":false},
{"name":"not-reviewed","candidate":{"summary":"Alder requires approval.","quote":"The release note must be approved before publication.","claims":["approved before publication"],"reviewed":false},"expected":false}
]schema.json
Download this file{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["summary", "quote", "claims", "reviewed"],
"properties": {
"summary": { "type": "string", "minLength": 1 },
"quote": { "type": "string", "minLength": 1 },
"claims": { "type": "array", "items": { "type": "string", "minLength": 1 } },
"reviewed": { "const": true }
},
"additionalProperties": false
}source.txt
Download this fileProject Alder closes on 18 November. Team Blue owns the final review. The release note must be approved before publication.