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:
parent
06713ed7b8
commit
1c9af82daa
56 changed files with 793 additions and 63 deletions
|
|
@ -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 };
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue