SOURCE / PINNED RELEASE
Made of little things.
Body Journal
- Release
- e8049f8da4e2…
- Author-recorded commit
- 61c04bf0e8aa…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-6c4554844c7
Archive hash verified: 4369d778da046a8b…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import { parseReport } from '../src/ai-contract.ts';
const text = maxLength => ({ type: 'string', minLength: 1, maxLength });
const array = (items, maxItems, minItems = 0) => ({ type: 'array', items, minItems, maxItems });
const list = (max, min = 0) => array(text(1600), max, min);
const record = properties => ({ type: 'object', properties, required: Object.keys(properties), additionalProperties: false });
// Provider-side grammar constraints complement the app's semantic validation.
export const REPORT_SCHEMA = record({
version: { type: 'integer', enum: [2] }, summary: text(4000), history: text(4000),
evidence: record({ reported: list(12), visual: list(12), missing: list(12) }),
assessments: array(record({ concernId: { type: 'integer', minimum: 1 }, assessment: text(2000) }), 50, 1),
urgency: record({ level: { type: 'string', enum: ['unclear', 'routine', 'soon', 'urgent', 'emergency'] }, reason: text(2000) }),
possibilities: array(record({ name: text(200), rationale: text(1600), against: text(1600), uncertainty: text(1600) }), 6),
evaluation: array(record({ item: text(300), rationale: text(1600) }), 8),
nextSteps: list(8, 1), questions: list(10), clinician: record({ type: text(200), reason: text(1600) }),
safetyNet: list(6, 1), plainLanguage: record({ gist: text(3000), nextSteps: list(6, 1), seekHelp: list(6, 1) }),
limitations: list(6, 1),
});
export function reportSchema(hasPatientPhotos) {
const schema = structuredClone(REPORT_SCHEMA);
if (!hasPatientPhotos) schema.properties.evidence.properties.visual.maxItems = 0;
return schema;
}
// Narrow source-absence grammar, not a classifier for medical claims. Unknown
// wording fails closed. In particular, a "no photos" prefix alone is insufficient.
export function isNoPhotoDisclaimer(value) {
const parts = value.trim().replace(/\.$/, '').split(';').map(part => part.trim());
const absent = /^no patient[- ](?:photos?|photographs?|images?)(?: were| was| are| is| have been| has been)? (?:attached|provided|supplied|sent|available|reviewed)(?: (?:or|and) (?:attached|provided|supplied|sent|available|reviewed))*$/i;
if (!absent.test(parts[0])) return false;
if (parts.length === 1) return true;
if (parts.length !== 2) return false;
const bodyMap = /^only (?:schematic )?body-map annotations(?: \(([^()]*)\))? were supplied, which indicate patient-marked location, not examination findings$/i.exec(parts[1]);
if (!bodyMap) return false;
const annotation = /^(?:(?:(?:central|left|right|upper|lower|front|back|head|neck|chest|abdomen|pelvis|arm|hand|finger|leg|knee|foot)[ -]){1,6}mark|(?:skin|muscle|muscles|skeleton|organs|mouth) layer|(?:standing|sitting|lying|walking|jogging|custom) pose)$/i;
return !bodyMap[1] || bodyMap[1].split(',').every(label => annotation.test(label.trim()));
}
function scan(text) {
const stack = [], candidates = [];
let previous = '', previousAt = -1;
for (let i = 0; i < text.length; i++) {
const c = text[i];
if (/\s/.test(c)) continue;
if (c === '"') {
const start = i++;
while (i < text.length && text[i] !== '"') { if (text[i] === '\\') i++; i++; }
if (i >= text.length) return null;
let after = i + 1; while (/\s/.test(text[after] || '') && after < text.length) after++;
if (text[after] === ':') {
let key; try { key = JSON.parse(text.slice(start, i + 1)); } catch { return null; }
const parent = stack.at(-1);
if (parent?.type !== '{' || parent.keys.has(key)) return null;
parent.keys.add(key);
// Only close an immediate child object before a known root-level field.
if (stack.length === 2 && previous === ',' && Object.hasOwn(REPORT_SCHEMA.properties, key)) candidates.push({ at: previousAt, key });
}
} else if (c === '{' || c === '[') stack.push({ type: c, keys: new Set() });
else if (c === '}' || c === ']') {
if (stack.pop()?.type !== (c === '}' ? '{' : '[')) return null;
}
previous = c; previousAt = i;
}
return { stack, candidates };
}
function unchanged(value, validated) {
if (value === validated) return true;
if (!value || !validated || typeof value !== 'object' || typeof validated !== 'object' || Array.isArray(value) !== Array.isArray(validated)) return false;
const keys = Object.keys(value);
return keys.length === Object.keys(validated).length && keys.every(key => Object.hasOwn(validated, key) && unchanged(value[key], validated[key]));
}
export function parseReportOutput(content) {
try { return { value: JSON.parse(content) }; }
catch (syntaxError) {
const scanned = scan(content);
// A missing final root brace can mean truncation. Never append data or repair
// strings, values, duplicate keys, multiple delimiters or ambiguous structures.
if (!scanned || scanned.stack.length !== 1 || scanned.stack[0].type !== '{' || scanned.candidates.length > 50) throw syntaxError;
const matches = [];
for (const candidate of scanned.candidates) {
const repaired = content.slice(0, candidate.at) + '}' + content.slice(candidate.at);
const checked = scan(repaired);
if (!checked || checked.stack.length) continue;
try {
const value = JSON.parse(repaired), report = parseReport(value, true);
if (unchanged(value, report)) matches.push({ value, formatRecovery: `Inserted one missing closing brace before "${candidate.key}". All report fields validated; no text or values were changed.` });
} catch { /* This insertion does not produce a complete valid report. */ }
}
if (matches.length === 1) return matches[0];
throw syntaxError;
}
}
