feat(ms-ai-architect): RX-REG — én maskinlesbar AI Act-frist-kilde + synk-test (B2-B5, R3-5, M10) [skip-docs]
Rotårsak-mekanisme: scripts/kb-update/data/ai-act-deadlines.json er nå eneste kilde for AI Act-frister; CLAUDE.md-tabellen, assessor-malen og begge hooks synk-testes mot den (tests/kb-update/test-ai-act-deadlines-sync.test.mjs, 9 tester, TDD rød→grønn). Suite 815/815. - B2: «Kommisjonen kan fremskynde»/«ytre grense» fjernet (trigger droppet i endelig Omnibus-tekst) - B3: status oppdatert i alle 3 lag — formelt vedtatt (EP 2026-06-16, Rådet 2026-06-29), trer i kraft ved OJ-publisering (ikke publisert per 2026-07-15, verifisert mot EUR-Lex 32024R1689) - B4: Art. 50-raden «Gjeldende» → «Fra 2026-08-02» - B5: stop-hooken feilmerket 2026-08-02 som «GPAI-frist» — begge hooks leser nå kilden, 0 hardkodede frist-literals - R3-5: 2026-12-02-raden (Art. 50(2)) inn i assessor-malen - M10: Nkom navngitt som koordinerende markedstilsynsmyndighet + nasjonalt kontaktpunkt (kilde: nkom.no/ki/regulering/hvem-handhever) - pending_oj-markører i kilden for RX-REG² (nudifiserings-forbud, Art. 111) - .gitignore: whitelist for den kuraterte frist-kilden
This commit is contained in:
parent
4794de0b79
commit
a8ae1fd276
8 changed files with 195 additions and 27 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -23,10 +23,12 @@ node_modules/
|
|||
.work/
|
||||
org/
|
||||
# Generated KB-update artifacts (registry, reports) are ignored, but the
|
||||
# hand-authored taxonomy (lag 0) and the decision ledger (lag 2) are tracked.
|
||||
# hand-authored taxonomy (lag 0), the decision ledger (lag 2) and the curated
|
||||
# AI Act deadline source (RX-REG, sync-tested consumer contract) are tracked.
|
||||
scripts/kb-update/data/*
|
||||
!scripts/kb-update/data/domain-taxonomy.json
|
||||
!scripts/kb-update/data/decisions.json
|
||||
!scripts/kb-update/data/ai-act-deadlines.json
|
||||
# Generated skill-lifecycle detection report (Spor B / B1) — regenerated on demand,
|
||||
# like the kb-update reports above. The detector script + curated inputs are tracked.
|
||||
scripts/kb-eval/data/skill-lifecycle-report.json
|
||||
|
|
|
|||
12
CLAUDE.md
12
CLAUDE.md
|
|
@ -108,18 +108,20 @@ Agenter leser navngitte kjernefiler, ikke hele kataloger. «3 kjernefiler» er n
|
|||
|
||||
## Viktige frister (EU AI Act)
|
||||
|
||||
> **NB — Digital Omnibus (provisorisk):** EU-rådet og Parlamentet ble 7. mai 2026 enige om å utsette høyrisiko-fristene (Digital Omnibus). Endringene trer i kraft først ved formell vedtakelse + publisering i Official Journal (ventet før 2026-08-02), så datoene under er **foreløpige**. Des. 2027 er en **ytre grense** — Kommisjonen kan fremskynde til 6 mnd etter at standarder/spesifikasjoner/veiledning er på plass. Kjør `/architect:classify` for systemspesifikk vurdering.
|
||||
> **NB — Digital Omnibus (vedtatt, avventer OJ):** Digital Omnibus utsetter høyrisiko-fristene i AI Act. Endringen er **formelt vedtatt** (Europaparlamentet 16. juni, Rådet 29. juni 2026) og trer i kraft tredje dag etter publisering i Official Journal — senest 2026-07-30 for anvendelse før 2026-08-02. Datoene under følger vedtatt tekst og bekreftes mot OJ ved publisering. Kjør `/architect:classify` for systemspesifikk vurdering.
|
||||
|
||||
| Frist | Krav | Status |
|
||||
|-------|------|--------|
|
||||
| 2025-02-02 | Forbudte AI-praksiser (Art. 5) | Gjeldende |
|
||||
| 2025-08-02 | GPAI-krav + governance/sanksjoner (Art. 99) | Gjeldende |
|
||||
| 2026-08-02 | Transparens (Art. 50): merking av syntetisk innhold gjelder | Gjeldende |
|
||||
| 2026-08-02 | Transparens (Art. 50): merking av syntetisk innhold | Fra 2026-08-02 |
|
||||
| 2026-12-02 | Art. 50(2): frist for maskinlesbar merking i eksisterende generative systemer | Overgang (Omnibus) |
|
||||
| 2027-12-02 | Annex III høyrisiko (frittstående) — utsatt fra 2026-08-02 | Provisorisk (Omnibus) |
|
||||
| 2028-08-02 | Annex I høyrisiko (innebygd i regulerte produkter) | Provisorisk (Omnibus) |
|
||||
| 2027-12-02 | Annex III høyrisiko (frittstående) — utsatt fra 2026-08-02 | Vedtatt (Omnibus, avventer OJ) |
|
||||
| 2028-08-02 | Annex I høyrisiko (innebygd i regulerte produkter) | Vedtatt (Omnibus, avventer OJ) |
|
||||
|
||||
**Tilsynsmyndigheter:** Datatilsynet (personvern), nasjonal AI-tilsynsmyndighet (under etablering), sektortilsyn.
|
||||
> Maskinlesbar kilde: `scripts/kb-update/data/ai-act-deadlines.json` — synk-testet mot denne tabellen, assessor-malen og hookene (`tests/kb-update/test-ai-act-deadlines-sync.test.mjs`). Oppdater kilden først.
|
||||
|
||||
**Tilsynsmyndigheter:** Nkom (koordinerende markedstilsynsmyndighet og nasjonalt kontaktpunkt for AI-forordningen), Datatilsynet (personvern), sektortilsyn kan utpekes i tillegg.
|
||||
|
||||
## Relaterte plugins (fremtidig)
|
||||
|
||||
|
|
|
|||
|
|
@ -142,8 +142,9 @@ Anbefal oppfølgingsaktiviteter:
|
|||
| 2025-02-02 | Forbudte AI-praksiser (Art. 5) | [Gjelder/Gjelder ikke] |
|
||||
| 2025-08-02 | GPAI-krav + governance/sanksjoner (Art. 99) | [Gjelder/Gjelder ikke] |
|
||||
| 2026-08-02 | Transparens (Art. 50, syntetisk innhold) | [Gjelder/Gjelder ikke] |
|
||||
| 2027-12-02 | Annex III høyrisiko — provisorisk (utsatt fra 2026-08-02 via Omnibus, avventer OJ) | [Gjelder/Gjelder ikke] |
|
||||
| 2028-08-02 | Annex I høyrisiko innebygd (provisorisk) | [Gjelder/Gjelder ikke] |
|
||||
| 2026-12-02 | Art. 50(2): maskinlesbar merking i eksisterende generative systemer | [Gjelder/Gjelder ikke] |
|
||||
| 2027-12-02 | Annex III høyrisiko — utsatt fra 2026-08-02 (Omnibus vedtatt, avventer OJ) | [Gjelder/Gjelder ikke] |
|
||||
| 2028-08-02 | Annex I høyrisiko innebygd (Omnibus vedtatt, avventer OJ) | [Gjelder/Gjelder ikke] |
|
||||
|
||||
### Referanser
|
||||
- [Liste over KB-filer og MCP-kilder brukt]
|
||||
|
|
@ -176,8 +177,8 @@ Bruk `microsoft_docs_search` for:
|
|||
## Norwegian Public Sector Context
|
||||
|
||||
- Alle vurderinger gjøres i norsk kontekst (EØS-implementering)
|
||||
- Datatilsynet er sannsynlig tilsynsmyndighet (personverndimensjon)
|
||||
- Nasjonal AI-tilsynsmyndighet er under etablering
|
||||
- Nkom er koordinerende markedstilsynsmyndighet og nasjonalt kontaktpunkt for AI-forordningen i Norge
|
||||
- Datatilsynet er tilsynsmyndighet for personverndimensjonen; sektortilsyn kan utpekes i tillegg
|
||||
- Forvaltningsloven gjelder i tillegg til AI Act for vedtakssystemer
|
||||
- Offentlig sektor er nesten alltid deployer, sjelden provider
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import {
|
|||
FREE_CONTEXT_FILE,
|
||||
buildOrgSummary,
|
||||
} from '../../scripts/kb-update/lib/user-data.mjs';
|
||||
import { loadAiActDeadlines } from '../../scripts/kb-update/lib/ai-act-deadlines.mjs';
|
||||
|
||||
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT || join(process.cwd());
|
||||
const cwd = process.cwd();
|
||||
|
|
@ -93,20 +94,12 @@ if (shouldRunDetection(scheduleConfig, lastPollDaysAgo).run) {
|
|||
}
|
||||
}
|
||||
|
||||
// --- 3. Check EU AI Act deadlines ---
|
||||
const AI_ACT_DEADLINES = [
|
||||
// NB: Digital Omnibus (prov. enighet 2026-05-07) utsatte høyrisiko; datoer foreløpige til OJ-publisering.
|
||||
{ date: new Date('2025-02-02'), label: 'Forbudte AI-praksiser (Art. 5)' },
|
||||
{ date: new Date('2025-08-02'), label: 'GPAI-krav + governance/sanksjoner (Art. 99)' },
|
||||
{ date: new Date('2026-08-02'), label: 'Transparens Art. 50 (syntetisk innhold)' },
|
||||
{ date: new Date('2026-12-02'), label: 'Art. 50(2) merking — frist for eksisterende generative systemer (Omnibus)' },
|
||||
{ date: new Date('2027-12-02'), label: 'Annex III høyrisiko (provisorisk, Omnibus — utsatt fra 2026-08-02)' },
|
||||
{ date: new Date('2028-08-02'), label: 'Annex I høyrisiko innebygd (provisorisk, Omnibus)' },
|
||||
];
|
||||
// --- 3. Check EU AI Act deadlines (single source: scripts/kb-update/data/ai-act-deadlines.json) ---
|
||||
const aiActSource = loadAiActDeadlines();
|
||||
|
||||
let nearestDeadline = null;
|
||||
for (const dl of AI_ACT_DEADLINES) {
|
||||
const daysLeft = Math.ceil((dl.date.getTime() - now) / DAY_MS);
|
||||
for (const dl of aiActSource ? aiActSource.deadlines : []) {
|
||||
const daysLeft = Math.ceil((new Date(dl.date).getTime() - now) / DAY_MS);
|
||||
if (daysLeft > 0 && daysLeft <= 180) {
|
||||
if (!nearestDeadline || daysLeft < nearestDeadline.daysLeft) {
|
||||
nearestDeadline = { ...dl, daysLeft };
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import { readdirSync, statSync, existsSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { loadAiActDeadlines } from '../../scripts/kb-update/lib/ai-act-deadlines.mjs';
|
||||
|
||||
const cwd = process.cwd();
|
||||
const workDir = join(cwd, '.work');
|
||||
|
|
@ -60,12 +61,18 @@ const suggestions = [
|
|||
'/architect:summary — lag beslutningsnotat',
|
||||
];
|
||||
|
||||
// Add AI Act suggestion if deadline is within 180 days
|
||||
// Add AI Act suggestion if the nearest deadline (from the shared source) is within 180 days
|
||||
const DAY_MS = 24 * 60 * 60 * 1000;
|
||||
const gpaiDeadline = new Date('2026-08-02');
|
||||
const daysToGpai = Math.ceil((gpaiDeadline.getTime() - now) / DAY_MS);
|
||||
if (daysToGpai > 0 && daysToGpai <= 180) {
|
||||
suggestions.push(`/architect:classify — EU AI Act-klassifisering (${daysToGpai}d til GPAI-frist)`);
|
||||
const aiActSource = loadAiActDeadlines();
|
||||
let nearestDeadline = null;
|
||||
for (const dl of aiActSource ? aiActSource.deadlines : []) {
|
||||
const daysLeft = Math.ceil((new Date(dl.date).getTime() - now) / DAY_MS);
|
||||
if (daysLeft > 0 && daysLeft <= 180 && (!nearestDeadline || daysLeft < nearestDeadline.daysLeft)) {
|
||||
nearestDeadline = { ...dl, daysLeft };
|
||||
}
|
||||
}
|
||||
if (nearestDeadline) {
|
||||
suggestions.push(`/architect:classify — EU AI Act-klassifisering (${nearestDeadline.daysLeft}d til ${nearestDeadline.label})`);
|
||||
}
|
||||
|
||||
const sessionList = recentSessions.join(', ');
|
||||
|
|
|
|||
36
scripts/kb-update/data/ai-act-deadlines.json
Normal file
36
scripts/kb-update/data/ai-act-deadlines.json
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"_comment": "Single source of truth for EU AI Act deadlines. Consumers: CLAUDE.md «Viktige frister»-tabellen, agents/ai-act-assessor.md frist-malen, hooks/scripts/session-start-context.mjs, hooks/scripts/stop-assessment-reminder.mjs. Sync enforced by tests/kb-update/test-ai-act-deadlines-sync.test.mjs — update THIS file first, then the markdown consumers, and keep the suite green.",
|
||||
"verified": "2026-07-15",
|
||||
"sources": [
|
||||
"https://www.consilium.europa.eu/en/press/press-releases/2026/06/29/artificial-intelligence-council-gives-final-green-light-to-simplify-and-streamline-rules/",
|
||||
"https://www.europarl.europa.eu/legislative-train/package-digital-package/file-digital-omnibus-on-ai",
|
||||
"https://eur-lex.europa.eu/legal-content/EN/ALL/?uri=CELEX:32024R1689",
|
||||
"https://nkom.no/ki/regulering/hvem-handhever"
|
||||
],
|
||||
"omnibus": {
|
||||
"status": "vedtatt_avventer_oj",
|
||||
"ep_plenary": "2026-06-16",
|
||||
"council_final": "2026-06-29",
|
||||
"oj_published": null,
|
||||
"oj_expected_by": "2026-07-30",
|
||||
"note": "Digital Omnibus er formelt vedtatt (Europaparlamentet 16. juni, Rådet 29. juni 2026) og trer i kraft tredje dag etter publisering i Official Journal — senest 2026-07-30 for anvendelse før 2026-08-02. Per verified-datoen er den IKKE OJ-publisert (EUR-Lex 32024R1689 viser ingen 2026-endringsakt). Datoene under følger vedtatt tekst; RX-REG² flipper status til i_kraft med CELEX-referanse ved OJ-publisering."
|
||||
},
|
||||
"deadlines": [
|
||||
{ "date": "2025-02-02", "label": "Forbudte AI-praksiser (Art. 5)", "status": "Gjeldende" },
|
||||
{ "date": "2025-08-02", "label": "GPAI-krav + governance/sanksjoner (Art. 99)", "status": "Gjeldende" },
|
||||
{ "date": "2026-08-02", "label": "Transparens (Art. 50): merking av syntetisk innhold", "status": "Fra 2026-08-02" },
|
||||
{ "date": "2026-12-02", "label": "Art. 50(2): frist for maskinlesbar merking i eksisterende generative systemer", "status": "Overgang (Omnibus)" },
|
||||
{ "date": "2027-12-02", "label": "Annex III høyrisiko (frittstående) — utsatt fra 2026-08-02", "status": "Vedtatt (Omnibus, avventer OJ)" },
|
||||
{ "date": "2028-08-02", "label": "Annex I høyrisiko (innebygd i regulerte produkter)", "status": "Vedtatt (Omnibus, avventer OJ)" }
|
||||
],
|
||||
"pending_oj": [
|
||||
"Nudifiserings-/CSAM-forbudet (nytt Art. 5-forbud i Omnibus; tekniske sikringstiltak innen 2026-12-02): artikkelplassering + anvendelsesdato verifiseres mot OJ-tekst i RX-REG²",
|
||||
"Art. 111-legacy-radene verifiseres mot OJ-tekst i RX-REG²",
|
||||
"Ved OJ-publisering: omnibus.status → i_kraft, oj_published + CELEX-referanse inn, «avventer OJ»-statusene flippes (RX-REG²)"
|
||||
],
|
||||
"authorities": {
|
||||
"coordinating": "Nkom — koordinerende markedstilsynsmyndighet og nasjonalt kontaktpunkt for AI-forordningen i Norge",
|
||||
"privacy": "Datatilsynet — personverndimensjonen",
|
||||
"sector": "Sektortilsyn kan utpekes i tillegg"
|
||||
}
|
||||
}
|
||||
18
scripts/kb-update/lib/ai-act-deadlines.mjs
Normal file
18
scripts/kb-update/lib/ai-act-deadlines.mjs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// ai-act-deadlines.mjs
|
||||
// Accessor for the machine-readable EU AI Act deadline source (RX-REG).
|
||||
// The JSON is resolved relative to THIS module, so it works both in dev mode
|
||||
// (cwd = plugin root) and installed mode (any cwd), without CLAUDE_PLUGIN_ROOT.
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
export const DATA_URL = new URL('../data/ai-act-deadlines.json', import.meta.url);
|
||||
|
||||
// Returns the parsed source, or null when unreadable — hook consumers are
|
||||
// advisory-never-blocking and silently skip the deadline signal on null.
|
||||
export function loadAiActDeadlines() {
|
||||
try {
|
||||
return JSON.parse(readFileSync(DATA_URL, 'utf8'));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
109
tests/kb-update/test-ai-act-deadlines-sync.test.mjs
Normal file
109
tests/kb-update/test-ai-act-deadlines-sync.test.mjs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
// tests/kb-update/test-ai-act-deadlines-sync.test.mjs
|
||||
// TDD for RX-REG (review 2026-07-09, B2/B3/B4/B5 + R3-5/M10): the EU AI Act
|
||||
// deadlines get ONE machine-readable source — scripts/kb-update/data/ai-act-deadlines.json
|
||||
// — and every consumer is sync-tested against it:
|
||||
// - CLAUDE.md «Viktige frister»-tabellen (date + label + status verbatim)
|
||||
// - agents/ai-act-assessor.md frist-malen (identical DATE SET; labels are
|
||||
// template-compact by design — R3-5: the 2026-12-02 row was missing)
|
||||
// - hooks/scripts/{session-start-context,stop-assessment-reminder}.mjs must READ
|
||||
// the source instead of carrying hardcoded date literals (B5: the stop hook
|
||||
// labelled 2026-08-02 «GPAI-frist» — wrong article; GPAI was 2025-08-02)
|
||||
// Refuted-claim guard: the final Omnibus text (EP 2026-06-16, Council 2026-06-29)
|
||||
// dropped the acceleration trigger, so «kan fremskynde»/«ytre grense» must not
|
||||
// appear; Nkom is the designated coordinating authority, so «under etablering»
|
||||
// must be gone (source: nkom.no/ki/regulering/hvem-handhever).
|
||||
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { loadAiActDeadlines, DATA_URL } from '../../scripts/kb-update/lib/ai-act-deadlines.mjs';
|
||||
|
||||
const pluginRoot = new URL('../../', import.meta.url);
|
||||
const read = (rel) => readFileSync(new URL(rel, pluginRoot), 'utf8');
|
||||
|
||||
const source = loadAiActDeadlines();
|
||||
|
||||
// --- 1. The source itself ---
|
||||
|
||||
test('deadline source loads with omnibus adoption-status + deadline entries', () => {
|
||||
assert.ok(source, 'ai-act-deadlines.json must exist and parse');
|
||||
assert.ok(source.omnibus, 'source must carry an omnibus adoption block');
|
||||
assert.equal(typeof source.omnibus.status, 'string', 'omnibus.status (vedtaks-status) required');
|
||||
assert.ok(Array.isArray(source.deadlines) && source.deadlines.length >= 6, 'at least the 6 known deadlines');
|
||||
for (const dl of source.deadlines) {
|
||||
assert.match(dl.date, /^\d{4}-\d{2}-\d{2}$/, `ISO date, got: ${dl.date}`);
|
||||
assert.ok(dl.label && dl.status, `label + status required for ${dl.date}`);
|
||||
}
|
||||
const dates = source.deadlines.map((d) => d.date);
|
||||
assert.deepEqual(dates, [...dates].sort(), 'deadlines sorted ascending');
|
||||
assert.equal(new Set(dates).size, dates.length, 'no duplicate dates');
|
||||
});
|
||||
|
||||
test('source carries no refuted claims and no stale authority phrasing', () => {
|
||||
const raw = readFileSync(DATA_URL, 'utf8');
|
||||
assert.ok(!/fremskynde|ytre grense|under etablering/i.test(raw),
|
||||
'refuted Omnibus-acceleration claim / stale Nkom phrasing must not re-enter the source');
|
||||
});
|
||||
|
||||
test('status wording never claims «Gjeldende» for a future date (rot-guard)', () => {
|
||||
const today = new Date().toISOString().slice(0, 10);
|
||||
for (const dl of source.deadlines) {
|
||||
if (/^Gjeldende/i.test(dl.status)) {
|
||||
assert.ok(dl.date <= today, `${dl.date} marked «${dl.status}» before it applies`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// --- 2. Markdown consumers ---
|
||||
|
||||
// Rows whose FIRST cell is an ISO date; other tables (#-keyed) never match.
|
||||
function parseDeadlineTable(md) {
|
||||
const rows = [];
|
||||
for (const line of md.split('\n')) {
|
||||
const m = line.match(/^\|\s*(\d{4}-\d{2}-\d{2})\s*\|\s*(.+?)\s*\|\s*(.+?)\s*\|\s*$/);
|
||||
if (m) rows.push({ date: m[1], label: m[2], status: m[3] });
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
test('CLAUDE.md frist-tabell matches the source verbatim (date + label + status)', () => {
|
||||
const rows = parseDeadlineTable(read('CLAUDE.md'));
|
||||
assert.deepEqual(
|
||||
rows.map((r) => [r.date, r.label, r.status]),
|
||||
source.deadlines.map((d) => [d.date, d.label, d.status]),
|
||||
);
|
||||
});
|
||||
|
||||
test('CLAUDE.md drops refuted claims and names Nkom', () => {
|
||||
const md = read('CLAUDE.md');
|
||||
assert.ok(!/fremskynde|ytre grense|under etablering/.test(md));
|
||||
assert.ok(md.includes('Nkom'), 'M10: Nkom (koordinerende tilsynsmyndighet) must be named');
|
||||
});
|
||||
|
||||
test('ai-act-assessor frist-mal covers exactly the source dates (R3-5: 2026-12-02)', () => {
|
||||
const rows = parseDeadlineTable(read('agents/ai-act-assessor.md'));
|
||||
assert.deepEqual(
|
||||
rows.map((r) => r.date).sort(),
|
||||
source.deadlines.map((d) => d.date).sort(),
|
||||
);
|
||||
});
|
||||
|
||||
test('ai-act-assessor names Nkom and drops «under etablering»', () => {
|
||||
const md = read('agents/ai-act-assessor.md');
|
||||
assert.ok(md.includes('Nkom'));
|
||||
assert.ok(!/under etablering/.test(md));
|
||||
});
|
||||
|
||||
// --- 3. Hook consumers read the source, no drift-prone literals ---
|
||||
|
||||
for (const hook of [
|
||||
'hooks/scripts/session-start-context.mjs',
|
||||
'hooks/scripts/stop-assessment-reminder.mjs',
|
||||
]) {
|
||||
test(`${hook} reads deadlines from the shared source`, () => {
|
||||
const src = read(hook);
|
||||
assert.ok(src.includes('ai-act-deadlines'), 'must import the shared loader');
|
||||
assert.ok(!/new Date\('20\d{2}-\d{2}-\d{2}'\)/.test(src), 'no hardcoded deadline literals');
|
||||
assert.ok(!src.includes('GPAI'), 'B5: no GPAI-labelled deadline left in hook code');
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue