refactor(ms-ai-architect): R13b — nøytraliser de mekaniske persona-forekomstene utenfor headinger, etter at ordrens egen korrigerte bøttegrense ble målt usann

Ordren ba meg behandle sitt eget premiss som et premiss: «PM-ens 87/45 er korrigert
til 85/47 ved maaling ... Behandle ogsaa 85/47 som et premiss og re-maal det foer du
bygger.» Re-målt over de 389 ref-filene holder 85/47 heller ikke — og feilen ligger i
KLASSIFIKATOREN, ikke i tellingen. Summen 132 står; fordelingen er 62/70.

TRE FUNN, alle pinnet i test:

1. FJORTEN bold-etiketter er DIALOG-ATTRIBUSJONER, ikke etiketter. Dialog-bøtta
   matchet bare kursivformen `*Cosmo:*`. Fetformen står foran sitert tale —
   `**Naar kunden sier:** "..."` / `**Cosmo svarer:** "..."` — så å slette den
   etterlater replikken uten taler. Redaksjonelt, ikke mekanisk.
2. TI tabellceller er PROVENIENSPÅSTANDER i kildekvalitets-kolonnen. Celleposisjon
   deler de 26 tabellforekomstene i tre klasser, ikke én: 12 radetiketter (kolonne 0),
   4 kolonneoverskrifter, 10 proveniensverdier (`Moenstre er Cosmo-design`,
   `Raadgivende innhold basert paa Cosmo-persona`). Å skrive om en av dem er å avgi en
   ny påstand om hvor innholdet kommer fra, og den siste har ikke noe slettemål i det
   hele tatt. Seks av ordrens ni sammensetninger ligger helt inne i denne klassen —
   ordrens egen advarsel traff, målingen lokaliserte den.
3. Lekkasje ANDRE veien, +1 mekanisk: `- **For arkitekten (Cosmo):** ...` i
   reasoning-models-o1-o3-optimization.md:549 er nøyaktig målklassen, men et
   linjestart-forankret nett ser den ikke bak `- ` og bokførte den som prosa.

Operatøren ratifiserte 2026-09-15 alt. A: kjør de 62, hold dialog og proveniens for
R14. Begge tilbakeholdte klasser henger på #R14-persona-ramme som aldri er besvart;
de 62 gjør ikke det, fordi R13 ALT har kjørt `For Cosmo` -> `For arkitekten` over 401
headinger — dette gjør bare etiketter og tabellrader konsistente med en beslutning
som allerede er utført.

UTFØRT: 62 forekomster i 50 filer (ordren sa 47) — 46 etiketter i 16 ratifiserte
varianter, 16 celler i 4. Diffen er 62 fjernet = 62 lagt til, ren in-place-erstatning;
hver endret linje klassifisert, ANNET = 0. Ingen måltekst innfører et ord kilden ikke
hadde, utover R13s sanksjonerte `arkitekten` (samme invariant-test, gjenbrukt).

GATEN, DEKOMPONERT I TRE KLAUSULER, hver validert BEGGE veier før den ble konsumert:
  R1 REFERENT      mekaniske sites 62 -> 0, produkt 451 uendret.
                   Kjent-pos: `**For Cosmo:**` OG `| Cosmos raad |` (genitiven er den
                   et bold-only nett mister) feller begge. Kjent-neg:
                   `**Cosmos DB-anbefaling:**` — ser ut som persona, er produkt —
                   og `| Azure Cosmos DB |` passerer urørt.
  R2 REKKEVIDDE    0 umålte varianter, 0 utenfor rekkevidde. Kjent-pos: en ukjent
                   etikettform rapporteres som umålt OG transformen KASTER, den
                   hopper ikke stille over. Kjent-neg: dialog + proveniens bokføres
                   utenfor scope og er byte-identiske.
  R3 HVA SOM STÅR  16 redaksjonelle etiketter + 10 celler uendret, heading/TOC
                   fortsatt 0 (R13 ikke regradert), prosa 132 -> 70. Kjent-pos: et
                   fjernet tegn i `Cosmos DB` feller produkt-differansen. Kjent-neg:
                   alle kun-produkt-filer byte-identiske gjennom transformen.

Gaten ble kjørt FØR transformen og felte R1 (exit 1) — et nullresultat som aldri er
tvunget til det andre svaret er ingen måling. R13b har egen baseline-fil;
cosmo-gate-baseline.json er et referansepunkt-artefakt (personaHeadings 401) og er
IKKE re-emittert. Ny .gitignore-negasjon (6 entries), aldri `git add -f`.

Målt underveis: 0 av de 62 målinjene ligger i en kodeblokk, så fence-agnostisk
transform er trygg her — samme konklusjon R13 nådde for headinger. Nøyaktig 1 linje
bærer begge klasser; dens `Cosmo-persona` står igjen, som den skal.

Suite 1134/1134 (1120 + 14 nye), validate-plugin 250/0/0, transform idempotent,
R13-driveren fortsatt no-op. RX-OPS1 adversarial-scan kjørt MANUELT på de 56 stagede
filene (OK, exit 0) — `core.hooksPath` skygger repoets pre-commit, fiksen eies av
`.claude`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-15 21:09:00 +02:00
commit 1c9af82daa
56 changed files with 793 additions and 63 deletions

View file

@ -322,3 +322,200 @@ export function neutralizeContent(content, { relPath = '' } = {}) {
return { content: out.join('\n'), changes };
}
// ===========================================================================================
// R13b — the MECHANICAL persona sites OUTSIDE headings: bold labels and table cells.
//
// THE SPLIT IS A MEASUREMENT, NOT THE ORDER'S PREMISE. The dispatching order carried
// "MEKANISK 85 / REDAKSJONELT 47" — itself a correction of an earlier "87/45" — and asked for
// it to be re-measured before anything was built. Re-measured over the 389 reference files, it
// is wrong again, and wrong in the CLASSIFIER rather than the count:
//
// 1. FOURTEEN bold labels are DIALOGUE SPEAKER ATTRIBUTIONS. The dialogue bucket only ever
// matched the italic `*Cosmo:*`; the bold form introduces quoted speech —
// `**Naar kunden sier:** "..."` / `**Cosmo svarer:** "..."` — so deleting it leaves the
// quote with no speaker. That is editorial work, not a scripted rewrite.
// 2. TEN table cells are PROVENANCE CLAIMS in the source-quality column. Cell position splits
// the 26 table occurrences into three classes, not one: 12 row labels (column 0),
// 4 column headers, 10 provenance values such as `Moenstre er Cosmo-design` and
// `Raadgivende innhold basert paa Cosmo-persona`. Rewriting one asserts something new
// about where the content came from, and the last of them has no deletion target at all.
// Six of the order's nine compound forms live entirely inside this class.
// 3. Leaking the other way, +1 mechanical: `- **For arkitekten (Cosmo):** ...` in
// reasoning-models-o1-o3-optimization.md:549 is exactly the target class, but a
// line-start-anchored net cannot see it behind the `- ` marker and books it as prose.
//
// MEASURED: MEKANISK 62 (46 labels + 16 cells) / REDAKSJONELT 70; sum 132 unchanged.
// Operator-ratified 2026-09-15, alternative A: execute the 62, hold dialogue and provenance
// for R14. Both held-back classes depend on the never-answered #R14-persona-ramme (neutral
// frame / new named persona / none); the 62 do not, because R13 has ALREADY executed
// `For Cosmo` -> `For arkitekten` across 401 headings, so this only brings labels and table
// rows into line with a decision that has already run.
//
// KEYED ON EXACT TEXT, like HEADING_MAP, and for the same reason: every rewrite is then a
// table entry a human ratified, and an unmeasured variant THROWS instead of being guessed at.
// Exact keying is also what keeps the two table classes apart without any row-role heuristic —
// the header cell is `Cosmo-anbefaling`, the provenance cell is
// `Cosmo-anbefaling basert paa verified data`, and they simply are different keys.
/**
* The ratified bold-label rewrites: 16 variants, 46 occurrences. Keys are the text INSIDE the
* `**...**` span, colon included where the source has it inside the bold.
* No target introduces a word its source did not carry, except R13's sanctioned `arkitekten`.
*/
export const LABEL_MAP = {
// --- the bulk: the three forms that converge on R13's ratified heading vocabulary ---
'For Cosmo:': 'For arkitekten:',
'For Cosmo Skyberg:': 'For arkitekten:',
'For arkitekten (Cosmo):': 'For arkitekten:',
// --- compound nouns: the persona is the first element, so the head stands alone ---
'Cosmo-anbefaling:': 'Anbefaling:',
"Cosmo's anbefaling:": 'Anbefaling:',
'Cosmo Skybergs anbefaling:': 'Anbefaling:',
'Cosmo-svar:': 'Svar:',
'Cosmo-spørsmål:': 'Spørsmål:',
'Cosmo-checkpoint:': 'Checkpoint:',
"Cosmo's one-liner:": 'One-liner:',
"Cosmo's rule of thumb:": 'Rule of thumb:',
// --- parenthetical or prepositional: the name drops out and the label survives intact ---
'Owner (Cosmo):': 'Owner:',
'Note til Cosmo:': 'Note:',
'Oppsummering for Cosmo': 'Oppsummering',
'Oppsummering for Cosmo:': 'Oppsummering:',
// --- addressed TO the architect, so the role takes the name's place ---
'Til Cosmo:': 'Til arkitekten:',
};
/**
* Bold labels that carry persona but are OUT of R13b's scope: speaker attributions in front of
* quoted speech. Enumerated rather than pattern-matched, so that a variant in NEITHER table is
* a hole in the net and throws, instead of being silently skipped. 6 variants, 14 occurrences.
*/
export const EDITORIAL_LABELS = new Set([
'Cosmo:', // 5 — `**Cosmo:** "Jeg forstaar at dere er klare for produksjon..."`
'Cosmo svarer:', // 4 — paired with `**Naar kunden sier:**`
'Cosmo forklarer:', // 2 — same dialogue frame
'Cosmo spør:', // 1 — same dialogue frame
'Mitt svar (Cosmo):', // 1 — first person, inside a scripted exchange
'Cosmo Skyberg tipset:', // 1 — past-tense attribution of advice to a person
// The two the ORDER already booked as editorial, and the reason its predecessor undercounted
// provenance: both are whole sentences that merely happen to be bold, and the first also
// points at `/architect`, an R14 delivery surface. Listed here so the net has no hole.
'For spørsmål om NLU-konfigurasjon, kontakt Cosmo Skyberg via `/architect`.',
'Sist oppdatert av Cosmo Skyberg, Microsoft AI Solution Architect',
]);
/** The ratified table-cell rewrites: 4 variants, 16 occurrences (12 row labels, 4 headers). */
export const TABLE_CELL_MAP = {
'For arkitekten (Cosmo)': 'For arkitekten',
'**For arkitekten (Cosmo)**': '**For arkitekten**',
'Cosmo-anbefaling': 'Anbefaling',
'Cosmos råd': 'Råd',
};
/** Provenance cells held back for R14's editorial pass. 10 occurrences, measured. */
export const EDITORIAL_CELLS = new Set([
'Cosmo-syntese av verified sources',
'Cosmo-anbefaling basert på verified data',
'Cosmo-anbefalinger basert på best practices',
"Cosmo's domain expertise + maturity model",
"Cosmo's domain knowledge + norsk lovverk",
"Cosmo's expertise + best practices fra docs",
'Rådgivende innhold basert på Cosmo-persona',
'Mønstre er Cosmo-design, PowerShell-kode er Verified',
'Tabeller og anbefalinger basert på Cosmo-erfaring + Microsoft docs',
'GDPR/AI Act-mapping er Cosmo-tolkninger (ikke Microsoft-spesifikk)',
]);
/** A bold label at the start of a line, optionally behind a list marker. */
const LABEL_RE = /^(\s*(?:[-*+]\s+)?)\*\*([^*\n]+)\*\*/;
/** A markdown table row. */
const TABLE_RE = /^\s*\|/;
/**
* Where do this document's non-heading persona occurrences sit, and is each one in a ratified
* table? Counts only the SITES R13b acts on bold labels and table cells; prose, dialogue
* outside bold labels and provenance lines are R14's and are not counted here.
*
* `unmapped` is the fail-safe: a persona label or cell in neither the mechanical nor the
* editorial table is an unmeasured variant, and the driver refuses to run rather than guess.
*
* @param {string} content
* @returns {{label: {mechanical: number, editorial: number},
* table: {mechanical: number, editorial: number}, unmapped: string[]}}
*/
export function classifyPersonaSites(content) {
const label = { mechanical: 0, editorial: 0 };
const table = { mechanical: 0, editorial: 0 };
const unmapped = [];
for (const line of String(content ?? '').split('\n')) {
if (/^#{1,6}\s+/.test(line)) continue;
if (TABLE_RE.test(line)) {
const segs = line.split('|');
for (let i = 1; i < segs.length - 1; i++) {
const cell = segs[i].trim();
if (!hasPersona(cell)) continue;
if (TABLE_CELL_MAP[cell] !== undefined) table.mechanical++;
else if (EDITORIAL_CELLS.has(cell)) table.editorial++;
else unmapped.push(`cell: ${JSON.stringify(cell)}`);
}
continue;
}
const m = LABEL_RE.exec(line);
if (!m || !hasPersona(m[2])) continue;
if (LABEL_MAP[m[2]] !== undefined) label.mechanical++;
else if (EDITORIAL_LABELS.has(m[2])) label.editorial++;
else unmapped.push(`label: ${JSON.stringify(m[2])}`);
}
return { label, table, unmapped };
}
/**
* Neutralise the ratified bold labels and table cells. Pure: returns new content, writes
* nothing. Surgical only the label span or the single matching cell is rewritten, so the
* rest of the line, including any persona R14 still owns, stays byte-identical. Splitting and
* rejoining a row on `|` is lossless, so cell padding survives untouched.
*
* Throws never writes a guess on a persona label or cell in neither ratified table.
* Idempotent: a neutral target matches no key.
*
* @param {string} content
* @param {{relPath?: string}} [opts]
* @returns {{content: string, changes: Array<{kind: string, line: number, from: string, to: string}>}}
*/
export function neutralizeLabels(content, { relPath = '' } = {}) {
const where = (i) => `${relPath || '<ukjent fil>'}:${i + 1}`;
const changes = [];
const out = String(content ?? '').split('\n').map((line, i) => {
if (/^#{1,6}\s+/.test(line)) return line;
if (TABLE_RE.test(line)) {
const segs = line.split('|');
let touched = false;
for (let c = 1; c < segs.length - 1; c++) {
const cell = segs[c].trim();
if (!hasPersona(cell)) continue;
const to = TABLE_CELL_MAP[cell];
if (to === undefined) {
if (EDITORIAL_CELLS.has(cell)) continue;
throw new Error(`ukjent persona-tabellcelle i ${where(i)}: ${JSON.stringify(cell)}`);
}
segs[c] = segs[c].replace(cell, to);
changes.push({ kind: 'cell', line: i + 1, from: cell, to });
touched = true;
}
return touched ? segs.join('|') : line;
}
const m = LABEL_RE.exec(line);
if (!m || !hasPersona(m[2])) return line;
const to = LABEL_MAP[m[2]];
if (to === undefined) {
if (EDITORIAL_LABELS.has(m[2])) return line;
throw new Error(`ukjent persona-etikett i ${where(i)}: ${JSON.stringify(m[2])}`);
}
changes.push({ kind: 'label', line: i + 1, from: m[2], to });
return `${m[1]}**${to}**${line.slice(m[0].length)}`;
});
return { content: out.join('\n'), changes };
}