feat(voyage): S18 — framing-hardening (min-version gate + memory status + pre-2.2 doc + flagship hedge)
Closes devils-advocate audit #4–#6 (MAJOR×MED). Four additive, non-breaking changes to the v5.5 framing-alignment machinery: 1. --min-brief-version <ver> gate (audit #4). Opt-in version floor on /trekplan + /trekresearch, forwarded to brief-validator as --min-version. New opts.minBriefVersion warns BRIEF_VERSION_BELOW_MINIMUM (never blocks) when a brief declares a version below the floor; trekreview exempt; absent opt = no check. CLI shim parses --min-version and skips its value token in filePath detection. 2. memory_alignment.status field (audit #5). brief-reviewer now emits status: verified | n_a | contradictions so a score-5 N/A (no memory) is distinguishable from a score-5 verified-aligned brief — the score≥4 gate passes in both, status reveals whether the wrong-premise defense ran. 3. Document pre-2.2 = zero framing enforcement (audit #4). HANDOVER-CONTRACTS §Handover 1 now states the producer-elective hole + two remedies. Also fixes a stale "current is 2.1" line (current is 2.2). 4. Soften flagship overselling (audit #6). CLAUDE.md Context-Engineering principle now hedges that main-context relief is asserted-by-design, not measured (T1 PoC found Δ≈0); README carried no false claim to fix. TDD: 8 new tests written failing-first (5 validator, 1 trekbrief status pin, 2 doc-consistency cross-file pins). Suite 691→699 (697 pass / 2 skip / 0 fail). No flagship prose-pin added (deliberate, per S19 anti-bloat). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
This commit is contained in:
parent
eb5a7324a4
commit
987e847ea1
11 changed files with 145 additions and 13 deletions
|
|
@ -155,6 +155,32 @@ export function validateBriefContent(text, opts = {}) {
|
|||
}
|
||||
}
|
||||
|
||||
// S18 — opt-in version floor. When the caller passes minBriefVersion (commands
|
||||
// forward --min-brief-version), WARN (never block) if the brief declares a
|
||||
// version below it: framing enforcement only fires at ≥ 2.2, so an older brief
|
||||
// sidesteps the framing-alignment defense silently. Absent opt → no check.
|
||||
// trekreview briefs have no framing and are exempt.
|
||||
if (opts.minBriefVersion && fm.type !== 'trekreview') {
|
||||
const mm = String(opts.minBriefVersion).match(/^(\d+)\.(\d+)$/);
|
||||
if (mm) {
|
||||
const minMajor = Number(mm[1]);
|
||||
const minMinor = Number(mm[2]);
|
||||
const bm = fm.brief_version === undefined
|
||||
? null
|
||||
: String(fm.brief_version).match(/^(\d+)\.(\d+)$/);
|
||||
const below = bm
|
||||
? (Number(bm[1]) < minMajor || (Number(bm[1]) === minMajor && Number(bm[2]) < minMinor))
|
||||
: true; // absent or unparseable version is below any floor
|
||||
if (below) {
|
||||
warnings.push(issue(
|
||||
'BRIEF_VERSION_BELOW_MINIMUM',
|
||||
`brief_version ${fm.brief_version ?? '(absent)'} is below the requested minimum ${opts.minBriefVersion} — framing enforcement (≥ 2.2) is bypassed`,
|
||||
'Re-run /trekbrief to produce a brief_version 2.2 brief, or drop --min-brief-version to accept the older brief as-is.',
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fm.type !== undefined && !BRIEF_TYPE_VALUES.includes(fm.type)) {
|
||||
errors.push(issue(
|
||||
'BRIEF_WRONG_TYPE',
|
||||
|
|
@ -223,12 +249,15 @@ export function validateBrief(filePath, opts = {}) {
|
|||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
const args = process.argv.slice(2);
|
||||
const strict = !args.includes('--soft');
|
||||
const filePath = args.find(a => !a.startsWith('--'));
|
||||
const minIdx = args.indexOf('--min-version');
|
||||
const minBriefVersion = minIdx >= 0 ? args[minIdx + 1] : undefined;
|
||||
// filePath is the first positional, skipping the --min-version value token.
|
||||
const filePath = args.find((a, i) => !a.startsWith('--') && i !== minIdx + 1);
|
||||
if (!filePath) {
|
||||
process.stderr.write('Usage: brief-validator.mjs [--soft] <brief.md>\n');
|
||||
process.stderr.write('Usage: brief-validator.mjs [--soft] [--min-version <x.y>] <brief.md>\n');
|
||||
process.exit(2);
|
||||
}
|
||||
const r = validateBrief(filePath, { strict });
|
||||
const r = validateBrief(filePath, { strict, minBriefVersion });
|
||||
if (args.includes('--json')) {
|
||||
process.stdout.write(JSON.stringify({ valid: r.valid, errors: r.errors, warnings: r.warnings }, null, 2) + '\n');
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue