refactor(ms-ai-architect): R14 — persona ut av plugin-flaten, og de seks stedene som produserte den

Nøytral arkitekt-ramme (ratifisert 15.09) i SKILL.md-ene, 23 kommandoer, 70 redaksjonelle
forekomster i ref-korpuset, README/CLAUDE.md/NOTICE og A11Y-rapportens proveniens-linje.
Hver av de 70 avgjort i kontekst: dialog fikk ny taler, proveniens ny opphavspåstand.

Ordren navnga fem produsent-steder; den live sjette manglet. `PROMPT_TEMPLATE` settes i
generate-skills.sh:27 og leses ALDRI — prompten er en heredoc i samme script. Å rette bare
prompt-template.md ville latt generatoren re-minte personaen ved neste KB-kjøring.

Ny G4-klausul i check-cosmo-gate.mjs: persona i leveranseflaten = 0, derivasjonsregisteret
pinnet per fil PÅ TALL (et filnavn-unntak er blindt for hva fila senere inneholder).
Registeret utvidet med README.md 3 — versjonstabellens rader er historikk, ikke leveranse.
Den ene genitiv-formede produktlinja adjudiseres på cosmos-db-URL-en i samme rad; regelen
er målt lukket (8 tvetydige linjer totalt, 33 URL-linjer, 2 persona-klassifiserte, begge
produkt) og hvitvasker ikke bar `Cosmo`. classifyCosmo urørt — baselinene hviler på den.
R3 godtar nå R14-utført (0) men ingenting imellom: et halvveis sveip felles fortsatt.

Bevis: gate PASSED + NETTET VALIDERT BEGGE VEIER · 1137/1137 · validate-plugin 250/0/0 ·
begge --dry-drivere 0 · Layer B 45/45 OK (kjent-positiv feller, exit 1).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-15 23:15:27 +02:00
commit ced0c5f46d
80 changed files with 400 additions and 152 deletions

View file

@ -325,3 +325,62 @@ test('a neutralized document has no dead anchors', () => {
assert.deepEqual(findDeadAnchors(content), []);
assert.match(content, /^- \[Quick Reference Card\]\(#quick-reference-card\)$/m);
});
// ================================== R14: the delivery-surface clause ======================
//
// G4 persona occurrences in the DELIVERY SURFACE = 0.
//
// Delivery surface = tracked `*.md`, minus the reference corpus (G1/G3 already own it) and
// minus the derivation register — CHANGELOG rows, docs records and the measurement document
// itself, all TRUE statements about the past that CLAUDE.md forbids rewriting.
//
// The register is pinned on PER-FILE OCCURRENCE COUNTS, never on filenames. Measured: inject
// one new persona line into an exempt file and the count moves, so a number-pinned exemption
// FELLS it while a filename-pinned one is blind to it. That is the difference between an
// exemption and a hole.
//
// The one adjudicated product line: `docs/ref-kb-gold-reconciliation-2026-06.md:93` reads
// "Cosmos multi-region writes (active-active)", which the R13 Norwegian-genitive rule scores
// as persona because the enumerated PRODUCT_FOLLOWERS list was built over a corpus with no
// English product prose. The verdict was settled by the `/azure/cosmos-db/` URL in the same
// table row, so G4 applies THAT discriminator rather than exempting the file. Measured over
// all tracked `*.md`: 8 `Cosmos <lowercase>` lines exist in total and 33 lines carry a
// cosmos-db URL — of those, 2 classify as persona and BOTH are genuinely the product, so the
// rule is closed, not open-ended. The classifier itself is untouched: G1/G3/R1/R3 baselines
// rest on it.
import { personaInDeliveryContent, DERIVATION_REGISTER } from '../../scripts/kb-update/lib/cosmo-persona.mjs';
test('G4 known-negative — an Azure Cosmos DB product line carries no delivery persona', () => {
assert.equal(personaInDeliveryContent('| Azure Cosmos DB | 8000 NOK |\n'), 0);
assert.equal(personaInDeliveryContent('Bruk `CosmosClient` mot cosmos_ru-kvoten.\n'), 0);
// The adjudicated line: genitive-shaped, but the row's own URL settles it as product.
assert.equal(
personaInDeliveryContent(
'| Cosmos multi-region writes (active-active) | learn.microsoft.com/azure/cosmos-db/distribute-data-globally |\n',
),
0,
);
});
test('G4 known-positive — persona in the delivery surface is seen, in every form it takes', () => {
// Prose, the form 62 of the 62 measured occurrences actually took.
assert.equal(personaInDeliveryContent('Du er Cosmo Skyberg i en anskaffelsesrolle.\n'), 1);
// Norwegian genitive — the case the letter-s heuristic gets wrong in BOTH directions.
assert.equal(personaInDeliveryContent('Legg til Cosmos helhetsvurdering:\n'), 1);
// A heading, and a persona line that ALSO carries a cosmos-db URL: the URL rule must not
// become a laundering channel for a genuine persona mention.
assert.equal(personaInDeliveryContent('# Cosmo Skyberg - Microsoft AI Solution Architect\n'), 1);
assert.equal(
personaInDeliveryContent('Cosmo anbefaler learn.microsoft.com/azure/cosmos-db/ som kilde.\n'),
1,
);
});
test('G4 register is pinned on counts, so a new persona line in an exempt file still fells it', () => {
// The exemption must be a number, not a filename. A filename-pinned exemption is blind to
// what the file later comes to contain; this asserts the blindness is absent.
assert.ok(DERIVATION_REGISTER['CHANGELOG.md'] > 0, 'CHANGELOG is registered with a count');
for (const [file, count] of Object.entries(DERIVATION_REGISTER)) {
assert.equal(typeof count, 'number', `${file} is pinned on a count, not a filename`);
}
});