feat(ms-ai-architect): G3 gull-intern-konsistens-lint + G4 build-instruks-policy — §8 gap-lukk [skip-docs]

This commit is contained in:
Kjell Tore Guttormsen 2026-06-30 09:55:15 +02:00
commit 9b147b470f
6 changed files with 256 additions and 5 deletions

View file

@ -98,7 +98,12 @@ Status-nøkkel: 🔴 ikke startet · 🟡 pågår · 🟢 lukket.
|---|---|---|---|---|---|
| **G1** | Judgen er ikke herdet mot de 8 dokumenterte feilmodusene (`source_silent`-maskerer-fravær, legacy-rad-match, ramme-skifte-tall-overlever, nedre-grense-understatement, eksakt-streng-pedanteri, taksonomi-nyanse, kapabilitet-bom) | Judge-FN/FP påvist i Spor 2b (8 mål, se `ref-kb-gold-reconciliation-2026-06.md`) | **Spor 2a** — judge-prompt-v3, MÅLT single vs v3/ensemble på herdet gull; adopter kun ved målt forbedring (ad-hoc-patch overfitter + bytter P/R) | 🔴 | Spor 1 korpus-pass (judgen brukes i ~2700 fetches) |
| **G2** | Herdet judge er ikke wired inn i Port 2 (born-verified create-guard) + Port 3 (kadens) — uten innplugging binder ikke hardningen mekanisk | Re-introdusert drift ved nye/regenererte filer + kadens-bom | Del av Spor 2a→3: bytt ut v2 med v3 i `transform.mjs`-judge-passet + kadens-runneren | 🔴 (avh. G1) | Spor 1 |
| **G3** | Ingen deterministisk gull-intern-konsistens-vakt (`verdict=correct` mens egen `notes` sier «uverifisert/illustrativ») | Gull-labeling-feil av FP1-klassen (selvmotsigende annotasjon) | Liten TDD-lint over `gold-correctness-set.json` (+ kjøres på fremtidige gull-bygg) | 🔴 | Spor 1 (nytt gull bygges) / §7 friskt utvalg |
| **G4** | Nedre-grense-policyen lever kun i prosa (denne dok + reconciliation-logg) — ikke kodet i judge-prompt ELLER `build-gold-set`-instruks | Re-introdusert nedre-grense-ambivalens i fremtidige gull-bygg + judge-kjøringer | Kod policyen inn i judge-prompt-v3 (G1) + build-gold-set-instruks | 🔴 | Spor 1 / §7 friskt utvalg |
| **G3** | Ingen deterministisk gull-intern-konsistens-vakt (`verdict=correct` mens egen `notes` sier «uverifisert/illustrativ») | Gull-labeling-feil av FP1-klassen (selvmotsigende annotasjon) | Liten TDD-lint over `gold-correctness-set.json` (+ kjøres på fremtidige gull-bygg) | 🟢 **lukket 2026-06-30** | Spor 1 (nytt gull bygges) / §7 friskt utvalg |
| **G4** | Nedre-grense-policyen lever kun i prosa (denne dok + reconciliation-logg) — ikke kodet i judge-prompt ELLER `build-gold-set`-instruks | Re-introdusert nedre-grense-ambivalens i fremtidige gull-bygg + judge-kjøringer | Kod policyen inn i judge-prompt-v3 (G1) + build-gold-set-instruks | 🟡 **build-instruks ✅ (2026-06-30); judge-prompt-v3-del i G1** | Spor 1 / §7 friskt utvalg |
**Ikke mekanisme-gap, men sporet backlog (innhold, ikke loop):** reference-`.md`-fil-fiksene fra Spor 2b (FP1 11000+/40+, FP2 «kun», FP6 Preview/Norway-East, FN2FN6 utdaterte tall) er **Spor 0/1**-innholdsarbeid — pekt per-claim i `notes`, ikke gjentakelses-mekanisme. Føres i Spor 0-manifest / Spor 1-korpus-pass, ikke her.
### Lukke-logg
- **G3 🟢 lukket (2026-06-30).** Deterministisk lint `lib/gold-consistency.mjs` + CLI `lint-gold-consistency.mjs` + TDD `tests/kb-eval/test-gold-consistency.test.mjs` (4 tester); wiret som hard gate på `build-gold-set.mjs --write` (dry-run forhåndsviser ikke-fatalt). De 3 nåværende shippet-gull-treffene resolvert med `consistency_waiver` (én — `reserved-capacity-planning#5` — live kilde-bekreftet FØR waiver, verifiseringsplikt). **Bevist mot FP1:** rebuild fra batch-returns flagger `azure-ai-foundry.md#2` (verdict=correct, note «11000+/40+ uverifisert») — nøyaktig claimen Spor 2b fant via dyr live re-fetch. Linten fanger klassen gratis ved bygg.
- **G4 🟡 build-instruks ✅ (2026-06-30).** Nedre-grense-policyen + konsistens-policyen kodet inn i `build-gold-set.mjs` `_meta.lower_bound_policy` / `_meta.consistency_policy` (instruks subagenter følger ved fremtidig gull-bygg). Resterende halvdel — policyen inn i `judge-claim-prompt-v3.md` — lukkes i G1 når v3 forfattes.

View file

@ -20,6 +20,7 @@ import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { parseLastUpdated, fileLastmodChanged } from './lib/base-rate.mjs';
import { lintGoldConsistency } from './lib/gold-consistency.mjs';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.resolve(__dirname, '..', '..');
@ -86,12 +87,39 @@ const goldSet = {
raw_returns: 'fase0-returns/batch-*.json',
note_evidence_quote:
'Per-claim evidence_quote omitted here to bound size; full verbatim quotes live in the session transcript. notes + evidence_url capture each verdict basis.',
// G4 (programdok §8 / §3-kjennelse 2026-06-30): nedre-grense-policy for
// subagenter som bygger fremtidig gull. En nedre-grense-påstand («100+»,
// «200k+») teller som FEIL (outdated/wrong) hvis den GROVT understater
// (>~2x, beslutnings-endrende) den sanne verdien; en STRAM nedre grense (sann
// verdi i samme størrelsesorden) blir stående correct. Anvendt på FN2 (Spor 2b).
lower_bound_policy:
'Lower-bound claims (e.g. "100+", "200k+"): verdict=outdated/wrong if the bound grossly understates (>~2x, decision-changing) the true value; a tight bound (true value within the same order of magnitude) stays correct.',
// G3 (programdok §8): gull-intern-konsistens. Et verdict=correct-claim hvis
// egen `notes` innrømmer at verdien ikke er bekreftet mot kilden («uverifisert
// / illustrativ / ikke i kilden») MÅ enten relabel-es ELLER bære et
// `consistency_waiver` med begrunnelse. Håndhevet av lint-gold-consistency.mjs.
consistency_policy:
'verdict=correct claims whose notes admit the value is unverified/illustrative/not-in-source must be relabeled OR carry a consistency_waiver. Enforced by lint-gold-consistency.mjs.',
claim_count: claims.length,
},
claims,
};
// G3 (programdok §8): gull fødes konsistent. Hard gate kun på --write — et
// nybygget gull med uwaived selvmotsigende correct-claims (verdict=correct mens
// noten innrømmer ikke-bekreftet: «uverifisert/illustrativ/ikke i kilden») nektes
// SKREVET; relabel eller waiver først. Dry-run forhåndsviser (advarer, blokkerer
// ikke). Escape-hatch --allow-inconsistent (samme idiom som
// run-judge-bakeoff --allow-incomplete) for bevisst override.
const consistency = lintGoldConsistency(goldSet);
if (process.argv.includes('--write')) {
if (!consistency.ok && !process.argv.includes('--allow-inconsistent')) {
console.error(`error: ${consistency.flagged.length} uwaived selvmotsigende correct-claim(s) — gull nektes skrevet (G3):`);
for (const f of consistency.flagged) console.error(` - ${f.id} [${f.markers.join(', ')}]: ${f.notes}`);
console.error('Resolver hver (relabel ELLER consistency_waiver), eller --allow-inconsistent for å overstyre.');
process.exit(2);
}
const out = path.join(DATA, 'gold-correctness-set.json');
fs.writeFileSync(out, JSON.stringify(goldSet, null, 2) + '\n');
console.log(`wrote ${out} (${claims.length} claims)`);
@ -101,5 +129,11 @@ if (process.argv.includes('--write')) {
const filesUnknown = Object.entries(fileMeta).filter(([, m]) => m.lastmod_changed === null).length;
console.log(`claims: ${claims.length} | files: ${Object.keys(fileMeta).length}`);
console.log(`file lastmod_changed: true=${filesWithChange} false=${filesNoChange} unknown(null date)=${filesUnknown}`);
if (consistency.ok) {
console.log('G3 gull-konsistens: OK (0 uwaived selvmotsigende correct-claims)');
} else {
console.log(`G3 gull-konsistens: ⚠ ${consistency.flagged.length} uwaived selvmotsigende correct-claim(s) — --write vil nektes:`);
for (const f of consistency.flagged) console.log(` - ${f.id} [${f.markers.join(', ')}]`);
}
console.log('(dry run — pass --write to persist gold-correctness-set.json)');
}

View file

@ -3451,7 +3451,8 @@
"evidence_url": "https://learn.microsoft.com/azure/reliability/reliability-ai-search",
"lastmod_changed": false,
"file_last_updated": "2026-02-01",
"notes": "AI Search single-region; manuell multi-region matcher MS-veiledning. RTO 15 min illustrativ."
"notes": "AI Search single-region; manuell multi-region matcher MS-veiledning. RTO 15 min illustrativ.",
"consistency_waiver": "G3: 'RTO 15 min illustrativ' er en note-aside om et tidstall utenfor den vurderte claim-en (claim = 'ingen built-in cross-region', grunnet mot reliability-ai-search). Kapabiliteten korrekt; ikke FP1."
},
{
"id": "ms-ai-infrastructure/bcdr/service-level-documentation-dr.md#5",
@ -3477,7 +3478,8 @@
"evidence_url": "https://learn.microsoft.com/azure/cosmos-db/continuous-backup-restore-introduction",
"lastmod_changed": false,
"file_last_updated": "2026-02-01",
"notes": "Multi-write reell active-active; ~0-tall illustrative men kapabiliteten korrekt."
"notes": "Multi-write reell active-active; ~0-tall illustrative men kapabiliteten korrekt.",
"consistency_waiver": "G3/FP5 (Spor 2b reconciled): multi-region-write active-active grunnet (cosmos-db/distribute-data-globally); '~0'-RTO/RPO-tall illustrative, ikke kilde-siterte. Kapabilitet korrekt — behold correct."
},
{
"id": "ms-ai-infrastructure/bcdr/service-level-documentation-dr.md#7",
@ -4296,7 +4298,8 @@
"evidence_url": "https://learn.microsoft.com/azure/cost-management-billing/reservations/azure-openai",
"lastmod_changed": false,
"file_last_updated": "2026-06-01",
"notes": "Cross-model-sharing + per-time matching bekreftet. 'mai 2025' ikke i kilden."
"notes": "Cross-model-sharing + per-time matching bekreftet. 'mai 2025' ikke i kilden.",
"consistency_waiver": "G3: kjerne-kapabilitet (cross-model PTU-deling + per-minutt pro-rata matching) bekreftet live mot Foundry PTU-reservasjons-siden 2026-06-30; 'mai 2025'-ikrafttredelsesdato IKKE i kilden (ikke-materiell, ikke beslutnings-endrende). Behold correct; fjern/merk datoen i .md = Spor 0/1-fil-fiks."
},
{
"id": "ms-ai-security/cost-optimization/reserved-capacity-planning.md#6",

View file

@ -0,0 +1,62 @@
// lib/gold-consistency.mjs — G3 (programdok §8): deterministisk gull-intern-
// konsistens-vakt. Fanger FP1-klassen (Spor 2b): et claim med verdict=correct
// hvis egen `notes` innrømmer at den påståtte verdien ikke er bekreftet mot
// kilden («uverifisert / illustrativ / ikke i kilden»). Verdikten sier «matcher
// kilden»; noten sier det motsatte — en selvmotsigende annotasjon.
//
// Tripwire-design: brede markører for recall, presisjon via en eksplisitt
// `consistency_waiver`-escape-hatch (menneske-i-loop §4c). Linten klassifiserer
// ikke — den surfacer kandidater et menneske enten relabel-er eller waiver-er
// med begrunnelse. Ren funksjon, ingen I/O; testet i tests/kb-eval/.
// Markører som — i en note festet til et verdict=correct-claim — innrømmer at
// den påståtte verdien IKKE er bekreftet mot den siterte kilden. Holdt brede med
// vilje (recall); falske positive absorberes av waiver-hatchen, ikke av en
// perfekt regex. Hver er en delstreng matchet case-insensitivt.
export const CONTRADICTION_MARKERS = [
'uverifisert',
'ikke verifiser', // ikke verifisert / ikke verifiserbar
'kan ikke verifiser',
'illustrativ', // illustrativt / illustrative
'ikke i kilden',
'ikke nevnt i kild',
'kilden oppgir ikke',
'ikke bekreftet',
'ubekreftet',
'source_silent',
'plassholder',
'placeholder',
'eksempel-tall',
'eksempeltall',
];
// Verdikter som hevder samsvar med dagens kilde. Kun disse kan motsi en
// «ikke bekreftet»-note: outdated/wrong/unsourced anerkjenner allerede ikke-match.
const ASSERTS_SOURCE_MATCH = new Set(['correct']);
export function findContradictionMarkers(notes) {
if (!notes || typeof notes !== 'string') return [];
const lc = notes.toLowerCase();
return CONTRADICTION_MARKERS.filter((m) => lc.includes(m));
}
function hasWaiver(claim) {
return typeof claim.consistency_waiver === 'string' && claim.consistency_waiver.trim().length > 0;
}
// Returnerer { ok, flagged: [{ id, verdict, notes, markers }] }.
// Et claim flagges når: verdikten hevder kilde-samsvar, noten bærer en
// motsigelses-markør, og det ikke finnes et ikke-tomt consistency_waiver.
export function lintGoldConsistency(goldSet) {
const claims = (goldSet && goldSet.claims) || [];
const flagged = [];
for (const c of claims) {
if (!ASSERTS_SOURCE_MATCH.has(c.verdict)) continue;
if (hasWaiver(c)) continue;
const markers = findContradictionMarkers(c.notes);
if (markers.length) {
flagged.push({ id: c.id, verdict: c.verdict, notes: c.notes, markers });
}
}
return { ok: flagged.length === 0, flagged };
}

View file

@ -0,0 +1,47 @@
#!/usr/bin/env node
// lint-gold-consistency.mjs — G3 (programdok §8) CLI: kjør gull-intern-
// konsistens-vakten over gold-correctness-set.json. Tynn wiring; all logikk i
// testet lib/gold-consistency.mjs (samme form som run-judge-bakeoff.mjs).
//
// Flagger verdict=correct-claims hvis egen `notes` innrømmer at verdien ikke er
// bekreftet mot kilden («uverifisert / illustrativ / ikke i kilden») og mangler
// et `consistency_waiver`. Exit 1 hvis noen uwaived → hard gate for gull-bygg.
//
// Usage:
// node scripts/kb-eval/lint-gold-consistency.mjs [--gold <path>] [--json]
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { lintGoldConsistency } from './lib/gold-consistency.mjs';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const DATA = path.join(__dirname, 'data');
function flag(name) {
const i = process.argv.indexOf(name);
return i >= 0 ? process.argv[i + 1] : undefined;
}
const goldPath = flag('--gold') || path.join(DATA, 'gold-correctness-set.json');
if (!fs.existsSync(goldPath)) {
console.error(`error: ${goldPath} not found`);
process.exit(2);
}
const gold = JSON.parse(fs.readFileSync(goldPath, 'utf8'));
const r = lintGoldConsistency(gold);
if (process.argv.includes('--json')) {
console.log(JSON.stringify(r, null, 2));
} else if (r.ok) {
console.log(`gull-konsistens OK — 0 uwaived selvmotsigende correct-claims (${(gold.claims || []).length} claims)`);
} else {
console.error(`gull-konsistens FEIL — ${r.flagged.length} uwaived selvmotsigende correct-claim(s):`);
for (const f of r.flagged) {
console.error(` - ${f.id} [${f.markers.join(', ')}]`);
console.error(` notes: ${f.notes}`);
}
console.error('\nResolver hver: relabel verdikten ELLER legg til et consistency_waiver med begrunnelse (menneske-i-loop §4c).');
}
process.exit(r.ok ? 0 : 1);

View file

@ -0,0 +1,100 @@
// tests/kb-eval/test-gold-consistency.test.mjs
// G3 (programdok §8 mekanisme-gap-register) — deterministisk gull-intern-konsistens-vakt.
//
// Feilklassen (FP1, Spor 2b): et gull-claim bærer verdict=correct mens dens egen
// `notes` innrømmer at den påståtte verdien IKKE er bekreftet mot kilden
// («uverifisert / illustrativ / ikke i kilden»). Det er en selvmotsigende
// annotasjon — verdikten sier «matcher kilden i dag», noten sier «gjorde det ikke».
// Reconciliation fant FP1 dyrt (live re-fetch). En deterministisk lint fanger
// klassen gratis ved hvert gull-bygg.
//
// Designet er en TRIPWIRE, ikke en auto-klassifiserer: brede markører (recall),
// presisjon via en eksplisitt `consistency_waiver`-escape-hatch (menneske-i-loop
// §4c — relabel ELLER waiver-med-begrunnelse, aldri auto-fiks). Et waiver er den
// varige menneske-bekreftelses-loggen.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import {
lintGoldConsistency,
findContradictionMarkers,
} from '../../scripts/kb-eval/lib/gold-consistency.mjs';
const __dirname = dirname(fileURLToPath(import.meta.url));
const PLUGIN_ROOT = join(__dirname, '..', '..');
// --- (1) marker-deteksjon ------------------------------------------------------
test('findContradictionMarkers detects unverified/illustrative admissions', () => {
assert.ok(findContradictionMarkers('RTO 15 min illustrativ.').length > 0);
assert.ok(findContradictionMarkers("'mai 2025' ikke i kilden.").length > 0);
assert.ok(findContradictionMarkers('Tallet er uverifisert mot kilden.').length > 0);
assert.ok(findContradictionMarkers('kan ikke verifisere mot kilden').length > 0);
// clean note → no markers
assert.equal(findContradictionMarkers('GA-dato og kontekstvindu matcher modell-siden eksakt.').length, 0);
assert.equal(findContradictionMarkers('').length, 0);
assert.equal(findContradictionMarkers(undefined).length, 0);
});
// --- (2) lint over en konstruert gull-fixture ----------------------------------
const fixture = {
claims: [
// FP1-klasse: correct, men noten innrømmer verdien ikke er i kilden, ingen waiver → FLAGGET
{ id: 'a#1', verdict: 'correct', notes: "'11000+ modeller' ikke i kilden; '40+ regioner' finnes ikke." },
// correct + illustrativ-innrømmelse, ingen waiver → FLAGGET
{ id: 'a#2', verdict: 'correct', notes: 'RTO 15 min illustrativ.' },
// correct + selvmotsigende note MEN waiver til stede → IKKE flagget
{ id: 'a#3', verdict: 'correct', notes: '~0-tall illustrative men kapabiliteten korrekt.', consistency_waiver: 'FP5: kapabilitet grunnet, tall illustrativt.' },
// correct + ren note → IKKE flagget
{ id: 'a#4', verdict: 'correct', notes: 'Matcher modell-siden eksakt.' },
// verdict=wrong med samme markør → IKKE flagget (verdikten er allerede uenig med kilden)
{ id: 'a#5', verdict: 'wrong', notes: 'tallet er ikke i kilden.' },
// verdict=outdated → IKKE flagget (anerkjenner allerede ikke-match)
{ id: 'a#6', verdict: 'outdated', notes: 'verdien er ikke i kilden lenger.' },
// verdict=unsourced → IKKE flagget (ærlig merket)
{ id: 'a#7', verdict: 'unsourced', notes: 'kan ikke verifisere; pris JS-rendret.' },
// tom waiver (whitespace) teller ikke som waiver → FLAGGET
{ id: 'a#8', verdict: 'correct', notes: 'uverifisert.', consistency_waiver: ' ' },
],
};
test('lintGoldConsistency flags only un-waived contradictory correct-claims', () => {
const r = lintGoldConsistency(fixture);
const flaggedIds = r.flagged.map((f) => f.id).sort();
assert.deepEqual(flaggedIds, ['a#1', 'a#2', 'a#8']);
assert.equal(r.ok, false);
});
test('lintGoldConsistency returns ok:true on a fully-waived/clean set', () => {
const clean = {
claims: [
{ id: 'b#1', verdict: 'correct', notes: 'matcher kilden eksakt.' },
{ id: 'b#2', verdict: 'correct', notes: 'illustrativt tall.', consistency_waiver: 'kapabilitet grunnet.' },
{ id: 'b#3', verdict: 'wrong', notes: 'ikke i kilden.' },
],
};
const r = lintGoldConsistency(clean);
assert.equal(r.ok, true);
assert.equal(r.flagged.length, 0);
});
// --- (3) live-gull-vakt: den shippede fasiten har INGEN uwaived motsigelse ------
// Dette kobler suiten til gold-correctness-set.json — invarianten «kjøres på
// fremtidige gull-bygg». RØD til de 3 nåværende treffene er waivet/adjudisert.
test('shipped gold-correctness-set.json is internally consistent (no un-waived contradictions)', () => {
const gold = JSON.parse(
readFileSync(join(PLUGIN_ROOT, 'scripts/kb-eval/data/gold-correctness-set.json'), 'utf8'),
);
const r = lintGoldConsistency(gold);
assert.equal(
r.ok,
true,
`gull har ${r.flagged.length} uwaived selvmotsigende correct-claim(s): ` +
r.flagged.map((f) => `${f.id} [${f.markers.join(',')}]`).join('; '),
);
});