@dzhechkov/harness-core 0.8.11 → 0.8.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dz-manifest.json +399 -139
- package/LICENSE +13 -0
- package/README.md +420 -6
- package/dist/agents-policy.d.ts +15 -1
- package/dist/agents-policy.d.ts.map +1 -1
- package/dist/agents-policy.js +27 -1
- package/dist/agents-policy.js.map +1 -1
- package/dist/amendment-trace.d.ts +72 -0
- package/dist/amendment-trace.d.ts.map +1 -1
- package/dist/amendment-trace.js +385 -17
- package/dist/amendment-trace.js.map +1 -1
- package/dist/backlog-public.d.ts +153 -0
- package/dist/backlog-public.d.ts.map +1 -0
- package/dist/backlog-public.js +415 -0
- package/dist/backlog-public.js.map +1 -0
- package/dist/backlog-transitions.d.ts +48 -0
- package/dist/backlog-transitions.d.ts.map +1 -0
- package/dist/backlog-transitions.js +64 -0
- package/dist/backlog-transitions.js.map +1 -0
- package/dist/backlog.d.ts.map +1 -1
- package/dist/backlog.js +13 -0
- package/dist/backlog.js.map +1 -1
- package/dist/claim-check.d.ts.map +1 -1
- package/dist/claim-check.js +24 -2
- package/dist/claim-check.js.map +1 -1
- package/dist/claude-hooks-assets.d.ts +93 -0
- package/dist/claude-hooks-assets.d.ts.map +1 -0
- package/dist/claude-hooks-assets.js +208 -0
- package/dist/claude-hooks-assets.js.map +1 -0
- package/dist/clean-room-smoke.d.ts +83 -0
- package/dist/clean-room-smoke.d.ts.map +1 -0
- package/dist/clean-room-smoke.js +138 -0
- package/dist/clean-room-smoke.js.map +1 -0
- package/dist/cmd-usage.d.ts.map +1 -1
- package/dist/cmd-usage.js +36 -6
- package/dist/cmd-usage.js.map +1 -1
- package/dist/codex-hooks-assets.d.ts +25 -7
- package/dist/codex-hooks-assets.d.ts.map +1 -1
- package/dist/codex-hooks-assets.js +138 -30
- package/dist/codex-hooks-assets.js.map +1 -1
- package/dist/codex-hooks.d.ts +21 -1
- package/dist/codex-hooks.d.ts.map +1 -1
- package/dist/codex-hooks.js +21 -1
- package/dist/codex-hooks.js.map +1 -1
- package/dist/course-staleness.d.ts +19 -0
- package/dist/course-staleness.d.ts.map +1 -0
- package/dist/course-staleness.js +95 -0
- package/dist/course-staleness.js.map +1 -0
- package/dist/destructive-guard-hook.d.ts +40 -0
- package/dist/destructive-guard-hook.d.ts.map +1 -0
- package/dist/destructive-guard-hook.js +109 -0
- package/dist/destructive-guard-hook.js.map +1 -0
- package/dist/destructive-guard.d.ts +27 -0
- package/dist/destructive-guard.d.ts.map +1 -0
- package/dist/destructive-guard.js +2808 -0
- package/dist/destructive-guard.js.map +1 -0
- package/dist/discrimination-gate.d.ts +28 -3
- package/dist/discrimination-gate.d.ts.map +1 -1
- package/dist/discrimination-gate.js +76 -16
- package/dist/discrimination-gate.js.map +1 -1
- package/dist/feature-adr-routing.d.ts +95 -1
- package/dist/feature-adr-routing.d.ts.map +1 -1
- package/dist/feature-adr-routing.js +193 -27
- package/dist/feature-adr-routing.js.map +1 -1
- package/dist/guard.d.ts +90 -0
- package/dist/guard.d.ts.map +1 -1
- package/dist/guard.js +271 -0
- package/dist/guard.js.map +1 -1
- package/dist/harness-core-location.d.ts +18 -0
- package/dist/harness-core-location.d.ts.map +1 -0
- package/dist/harness-core-location.js +42 -0
- package/dist/harness-core-location.js.map +1 -0
- package/dist/index.d.ts +24 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -3
- package/dist/index.js.map +1 -1
- package/dist/lead-shift-gate.d.ts +95 -0
- package/dist/lead-shift-gate.d.ts.map +1 -0
- package/dist/lead-shift-gate.js +100 -0
- package/dist/lead-shift-gate.js.map +1 -0
- package/dist/ledger-backfill.d.ts +11 -1
- package/dist/ledger-backfill.d.ts.map +1 -1
- package/dist/ledger-backfill.js +19 -0
- package/dist/ledger-backfill.js.map +1 -1
- package/dist/loop-blobs.generated.d.ts +1 -1
- package/dist/loop-blobs.generated.d.ts.map +1 -1
- package/dist/loop-blobs.generated.js +12 -3
- package/dist/loop-blobs.generated.js.map +1 -1
- package/dist/loop-lint.d.ts.map +1 -1
- package/dist/loop-lint.js +56 -7
- package/dist/loop-lint.js.map +1 -1
- package/dist/loop-plan-graph.d.ts +1 -3
- package/dist/loop-plan-graph.d.ts.map +1 -1
- package/dist/loop-plan-graph.js +70 -1
- package/dist/loop-plan-graph.js.map +1 -1
- package/dist/loop-trace.d.ts.map +1 -1
- package/dist/loop-trace.js +16 -2
- package/dist/loop-trace.js.map +1 -1
- package/dist/managed-hooks.d.ts +5 -6
- package/dist/managed-hooks.d.ts.map +1 -1
- package/dist/managed-hooks.js +2 -2
- package/dist/managed-hooks.js.map +1 -1
- package/dist/model-recommender.d.ts.map +1 -1
- package/dist/model-recommender.js +14 -3
- package/dist/model-recommender.js.map +1 -1
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +82 -0
- package/dist/operations.js.map +1 -1
- package/dist/patterns.d.ts +23 -0
- package/dist/patterns.d.ts.map +1 -1
- package/dist/patterns.js +10 -0
- package/dist/patterns.js.map +1 -1
- package/dist/publish.d.ts +11 -0
- package/dist/publish.d.ts.map +1 -1
- package/dist/publish.js +16 -2
- package/dist/publish.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +3 -2
- package/dist/registry.js.map +1 -1
- package/dist/score.d.ts.map +1 -1
- package/dist/score.js +15 -4
- package/dist/score.js.map +1 -1
- package/dist/session-retro.d.ts +121 -2
- package/dist/session-retro.d.ts.map +1 -1
- package/dist/session-retro.js +454 -11
- package/dist/session-retro.js.map +1 -1
- package/dist/setup.d.ts +28 -0
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +223 -6
- package/dist/setup.js.map +1 -1
- package/dist/sign.d.ts.map +1 -1
- package/dist/sign.js +18 -1
- package/dist/sign.js.map +1 -1
- package/dist/skills-verify.d.ts +34 -1
- package/dist/skills-verify.d.ts.map +1 -1
- package/dist/skills-verify.js +82 -0
- package/dist/skills-verify.js.map +1 -1
- package/dist/stage-line.d.ts +68 -0
- package/dist/stage-line.d.ts.map +1 -0
- package/dist/stage-line.js +129 -0
- package/dist/stage-line.js.map +1 -0
- package/dist/statusline.d.ts +99 -0
- package/dist/statusline.d.ts.map +1 -1
- package/dist/statusline.js +310 -44
- package/dist/statusline.js.map +1 -1
- package/dist/store-counts.d.ts +26 -0
- package/dist/store-counts.d.ts.map +1 -0
- package/dist/store-counts.js +125 -0
- package/dist/store-counts.js.map +1 -0
- package/dist/store-guard.d.ts +106 -0
- package/dist/store-guard.d.ts.map +1 -0
- package/dist/store-guard.js +294 -0
- package/dist/store-guard.js.map +1 -0
- package/dist/swarm-brief.d.ts +95 -0
- package/dist/swarm-brief.d.ts.map +1 -0
- package/dist/swarm-brief.js +660 -0
- package/dist/swarm-brief.js.map +1 -0
- package/dist/trace-bundle.d.ts +8 -0
- package/dist/trace-bundle.d.ts.map +1 -1
- package/dist/trace-bundle.js +11 -0
- package/dist/trace-bundle.js.map +1 -1
- package/package.json +12 -11
- package/sbom.json +804 -154
- package/src/agents-policy.ts +46 -2
- package/src/amendment-trace.ts +441 -19
- package/src/backlog-public.ts +503 -0
- package/src/backlog-transitions.ts +77 -0
- package/src/backlog.ts +12 -0
- package/src/claim-check.ts +25 -2
- package/src/claude-hooks-assets.ts +227 -0
- package/src/clean-room-smoke.ts +195 -0
- package/src/cmd-usage.ts +29 -5
- package/src/codex-hooks-assets.ts +140 -30
- package/src/codex-hooks.ts +21 -1
- package/src/course-staleness.ts +125 -0
- package/src/destructive-guard-hook.ts +151 -0
- package/src/destructive-guard.ts +3027 -0
- package/src/discrimination-gate.ts +98 -19
- package/src/feature-adr-routing.ts +220 -22
- package/src/guard.ts +318 -0
- package/src/harness-core-location.ts +44 -0
- package/src/index.ts +111 -3
- package/src/lead-shift-gate.ts +145 -0
- package/src/ledger-backfill.ts +20 -1
- package/src/loop-blobs.generated.ts +12 -3
- package/src/loop-lint.ts +52 -7
- package/src/loop-plan-graph.ts +66 -1
- package/src/loop-trace.ts +13 -1
- package/src/managed-hooks.ts +5 -6
- package/src/model-recommender.ts +14 -3
- package/src/operations.ts +75 -0
- package/src/patterns.ts +33 -0
- package/src/publish.ts +27 -2
- package/src/registry.ts +3 -2
- package/src/score.ts +16 -4
- package/src/session-retro.ts +466 -11
- package/src/setup.ts +246 -9
- package/src/sign.ts +18 -1
- package/src/skills-verify.ts +99 -1
- package/src/stage-line.ts +151 -0
- package/src/statusline.ts +396 -47
- package/src/store-counts.ts +154 -0
- package/src/store-guard.ts +388 -0
- package/src/swarm-brief.ts +661 -0
- package/src/trace-bundle.ts +10 -0
package/src/operations.ts
CHANGED
|
@@ -169,6 +169,26 @@ export interface InitReport {
|
|
|
169
169
|
// Platform enrichment — optional extras beyond SKILL.md
|
|
170
170
|
// ---------------------------------------------------------------------------
|
|
171
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Размер RVF-файла, при котором в нём заведомо НЕТ ни одной записи.
|
|
174
|
+
*
|
|
175
|
+
* ИЗМЕРЕНО 2026-09-04 прямым прогоном на `@ruvector/rvf-node` 0.1.8 (linux-x64): пустое хранилище —
|
|
176
|
+
* РОВНО 162 байта при любой размерности; первая запись доводит файл до 615 байт при размерности 8,
|
|
177
|
+
* 839 при 64, 2119 при 384 и 6727 при 1536. Порог 200 — небольшой запас над измеренным пустым
|
|
178
|
+
* размером: он покрывает возможный чуть больший заголовок и втрое ниже самого маленького
|
|
179
|
+
* наблюдавшегося хранилища С записью.
|
|
180
|
+
*
|
|
181
|
+
* ПОПРАВКА К ПЕРВОЙ РЕДАКЦИИ (ревью 2026-09-04). Здесь стояло «первая запись добавляет ~1550 байт»
|
|
182
|
+
* и «порог — середина измеренного зазора». Оба утверждения неверны: 1550 нигде не измерялось, а
|
|
183
|
+
* серединой зазора [162, 2119] было бы 1140, не 200. Строгое на вид обоснование опиралось на
|
|
184
|
+
* арифметическую ошибку в собственных числах документа.
|
|
185
|
+
*
|
|
186
|
+
* Оговорка «при меньшей размерности запись могла бы уместиться в зазор» тоже СНЯТА как
|
|
187
|
+
* неизмеренная: замер по четырём размерностям показывает обратное — даже при размерности 8
|
|
188
|
+
* хранилище с записью втрое больше порога.
|
|
189
|
+
*/
|
|
190
|
+
const RVF_HEADER_ONLY_MAX_BYTES = 200;
|
|
191
|
+
|
|
172
192
|
/**
|
|
173
193
|
* Where each target's skill tree is rooted. These MUST agree with the
|
|
174
194
|
* `skillsRoot` each adapter actually emits to — so we import the adapters'
|
|
@@ -1187,6 +1207,61 @@ export async function runDoctor(options: { projectRoot: string }): Promise<Docto
|
|
|
1187
1207
|
detail: 'orphan .dz/memory.rvf placeholder from an old setup (nothing reads it) — delete it; the real store is .dz/agentdb.db',
|
|
1188
1208
|
});
|
|
1189
1209
|
}
|
|
1210
|
+
// 8y. ПУСТОЕ ВЕКТОРНОЕ ХРАНИЛИЩЕ МОЛЧИТ, А НЕ ЖАЛУЕТСЯ (решение владельца 2026-09-04).
|
|
1211
|
+
//
|
|
1212
|
+
// Пустой RVF-файл не даёт ошибки: поиск по нему возвращает пустой список, и всё выглядит
|
|
1213
|
+
// работающим. ИЗМЕРЕНО 2026-09-04: `.agentic-qe/patterns.rvf` — 162 байта (записей не помещается)
|
|
1214
|
+
// при 288 паттернах и 275 векторах, целых в `.agentic-qe/memory.db` рядом. Подробности,
|
|
1215
|
+
// измерения и названные пределы — features/doctor-empty-vector-store/01_requirements.md.
|
|
1216
|
+
//
|
|
1217
|
+
// ПОЧЕМУ ПО РАЗМЕРУ, А НЕ ПО ЧИСЛУ ВЕКТОРОВ. Единственная причина — не потревожить наблюдение:
|
|
1218
|
+
// идёт семидневный замер «читает ли этот файл хоть кто-нибудь», а открытие сдвигает время
|
|
1219
|
+
// последнего чтения. Прежняя редакция называла второй причиной файловый замок — ЭТО ОПРОВЕРГНУТО
|
|
1220
|
+
// ревью экспериментально: `openReadonly` под живым замком открывает хранилище, не создаёт `.lock`
|
|
1221
|
+
// и не меняет ни размер, ни mtime. Ложное обоснование убрано, верное оставлено.
|
|
1222
|
+
//
|
|
1223
|
+
// ЧТО ДОКАЗЫВАЕТ РАЗМЕР: ровно «записей тут поместиться не может». НЕ доказывает, что файл —
|
|
1224
|
+
// валидный заголовок формата: пустой, обрезанный или посторонний файл с тем же расширением
|
|
1225
|
+
// попадёт в ту же ветку, поэтому текст находки говорит про размер и следствие.
|
|
1226
|
+
//
|
|
1227
|
+
// ОБЛАСТЬ — ТРИ ИЗВЕСТНЫХ КАТАЛОГА ХРАНИЛИЩ, без рекурсии. `.dz/memory` добавлен по находке
|
|
1228
|
+
// ревью: собственное RVF-хранилище dz лежит именно там (vector-tier.ts), и без него ветка `.dz`
|
|
1229
|
+
// покрывала только legacy-заглушку, то есть была декоративной. Рекурсия по дереву не делается:
|
|
1230
|
+
// она нашла бы десятки копий в `.claude/worktrees/agent-*/`, и отчёт утонул бы в шуме.
|
|
1231
|
+
for (const dir of ['.agentic-qe', '.dz', '.dz/memory']) {
|
|
1232
|
+
let names: string[] = [];
|
|
1233
|
+
try {
|
|
1234
|
+
names = readdirSync(join(root, dir)).filter((n) => n.endsWith('.rvf'));
|
|
1235
|
+
} catch { continue; } // каталога нет — проверять нечего, и это не находка
|
|
1236
|
+
for (const name of names) {
|
|
1237
|
+
// `.dz/memory.rvf` уже разобран проверкой выше как legacy-сирота с советом «удалить».
|
|
1238
|
+
// Вторая находка на тот же файл советовала бы искать держателя у файла, который никто не
|
|
1239
|
+
// читает — два совета об одном объекте, и один из них бессмысленный (находка ревью).
|
|
1240
|
+
if (dir === '.dz' && name === 'memory.rvf') continue;
|
|
1241
|
+
let size: number;
|
|
1242
|
+
try {
|
|
1243
|
+
const st = statSync(join(root, dir, name));
|
|
1244
|
+
// Каталог с таким именем — не хранилище; `isFile` дешевле и честнее, чем гадать по размеру.
|
|
1245
|
+
if (!st.isFile()) continue;
|
|
1246
|
+
size = st.size;
|
|
1247
|
+
} catch { continue; } // нечитаемый или исчезнувший файл — не находка: мы про него ничего не установили
|
|
1248
|
+
if (size > RVF_HEADER_ONLY_MAX_BYTES) continue;
|
|
1249
|
+
// СООБЩЕНИЕ, А НЕ ПРОВАЛ. Проверка не умеет отличить испорченное хранилище от только что
|
|
1250
|
+
// созданного, в которое ещё ничего не писали, — а это здоровое состояние первого дня. Ронять
|
|
1251
|
+
// код возврата на здоровом состоянии значит приучить читателя к красному; соседняя проверка
|
|
1252
|
+
// целостности в этой же функции решает ту же дилемму так же и говорит об этом вслух.
|
|
1253
|
+
checks.push({
|
|
1254
|
+
name: 'vector store',
|
|
1255
|
+
ok: true,
|
|
1256
|
+
detail: `${dir}/${name} — ${size} bytes: too small to hold a single record, so a search `
|
|
1257
|
+
+ 'over it returns an empty answer instead of an error, and nothing looks broken. '
|
|
1258
|
+
+ 'Size alone does not say WHY: an empty store, a truncated file, or not a store at all. '
|
|
1259
|
+
+ 'If this project HAS learned patterns, the store is behind — compare with the SQLite '
|
|
1260
|
+
+ 'store beside it before deciding.',
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1190
1265
|
const legacyMcp = join(root, '.claude', 'mcp.json');
|
|
1191
1266
|
if (existsSync(legacyMcp) && readFileSync(legacyMcp, 'utf-8').includes('agentdb')) {
|
|
1192
1267
|
checks.push({
|
package/src/patterns.ts
CHANGED
|
@@ -60,6 +60,29 @@ export interface PatternRecord {
|
|
|
60
60
|
readonly lessonPairId?: string;
|
|
61
61
|
/** Read-model companion; derived from the linked class row, never persisted on this row. */
|
|
62
62
|
readonly classForm?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Address of this record IN THE STORE IT CAME FROM — `MemoryRecord.id`, carried so that
|
|
65
|
+
* `dz recall --forget` / `--promote` can be driven from `dz recall --all --json`, which their own
|
|
66
|
+
* help text already tells the reader to use. Deriving it instead is the trap `cmdRecallForget`
|
|
67
|
+
* already warns about: MEASURED on this store, `patternRecordId(recordToPattern(r))` reproduces
|
|
68
|
+
* the id for 535 of 537 records and hands a plausible WRONG address for the other two (a
|
|
69
|
+
* `dream:`-written row and one on an older scheme) — and a wrong id makes `--forget` report
|
|
70
|
+
* success while deleting nothing. So the id travels rather than being recomputed.
|
|
71
|
+
*
|
|
72
|
+
* VALID ONLY IN THE ISSUING STORE. `dz teach --from-json` must never adopt it: an id names a
|
|
73
|
+
* DIFFERENT record on the receiving machine, so an adopted id would point `--forget` at the wrong
|
|
74
|
+
* lesson. The importer builds its candidate from named fields (never a spread), and a test pins
|
|
75
|
+
* that — the property is what keeps the portable export safe to accept from anyone.
|
|
76
|
+
*/
|
|
77
|
+
readonly dzId?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Quarantine marker (feature lesson-quarantine): the lesson is a HYPOTHESIS, not knowledge.
|
|
80
|
+
* Present ONLY when true — absence means promoted, matching `readQuarantineState`'s AM-1
|
|
81
|
+
* fail-safe, so a missing field is never read as a claim about the record. Carried because
|
|
82
|
+
* `--promote` addresses exactly the quarantined rows and had no way to name them from an export.
|
|
83
|
+
* Like `dzId`, it is a fact about the ISSUING store and is not adopted on import.
|
|
84
|
+
*/
|
|
85
|
+
readonly quarantined?: boolean;
|
|
63
86
|
}
|
|
64
87
|
|
|
65
88
|
/** A session lifecycle event as written by the session hooks to `.dz/sessions.jsonl`. */
|
|
@@ -498,6 +521,15 @@ export function recordToPattern(r: MemoryRecord): PatternRecord {
|
|
|
498
521
|
&& typeof lessonPairId === 'string' && lessonPairId !== ''
|
|
499
522
|
? { lessonForm, lessonPairId }
|
|
500
523
|
: {};
|
|
524
|
+
// The id and the quarantine marker travel with the row. Both are facts about THIS store, and
|
|
525
|
+
// both were previously dropped here — the single place the whole `--all --json` export is built
|
|
526
|
+
// (`loadStorePatternsSync` = `loadStoreRecordsSync().map(recordToPattern)`), which is why
|
|
527
|
+
// `--forget`'s own "find them with `dz recall --all --json`" hint pointed at a file that could
|
|
528
|
+
// not answer. `quarantined` is emitted only when true, so absence keeps meaning "promoted".
|
|
529
|
+
const addressing: { dzId?: string; quarantined?: boolean } = {
|
|
530
|
+
...(typeof r.id === 'string' && r.id !== '' ? { dzId: r.id } : {}),
|
|
531
|
+
...(readQuarantineState(r).quarantined ? { quarantined: true } : {}),
|
|
532
|
+
};
|
|
501
533
|
return {
|
|
502
534
|
pattern: r.text,
|
|
503
535
|
type: PATTERN_TYPES.has(r.outcome) ? (r.outcome as PatternRecord['type']) : 'lesson-learned',
|
|
@@ -506,6 +538,7 @@ export function recordToPattern(r: MemoryRecord): PatternRecord {
|
|
|
506
538
|
ts: r.timestamp,
|
|
507
539
|
source: r.metadata?.['source'] ?? 'dz-teach',
|
|
508
540
|
...pair,
|
|
541
|
+
...addressing,
|
|
509
542
|
};
|
|
510
543
|
}
|
|
511
544
|
|
package/src/publish.ts
CHANGED
|
@@ -27,6 +27,17 @@ export interface PublishResult {
|
|
|
27
27
|
* unmodified `publishPackages` call is byte-compatible with pre-gate behavior.
|
|
28
28
|
*/
|
|
29
29
|
readonly claimCheck?: { readonly findings: number; readonly high: number } | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* DRY-RUN ONLY, and the reason it exists is a measured incident. A dry run short-circuits
|
|
32
|
+
* BEFORE build, sign and pack (see the `opts.dryRun` branch below), so the package's own
|
|
33
|
+
* `prepublishOnly` gate never executes. On 2026-09-02 a clean dry run was read as evidence that
|
|
34
|
+
* publication would succeed; the real gate was RED — a stale signature baseline plus six
|
|
35
|
+
* `__pycache__/*.pyc` files already signed into the manifest. A preview that names only what it
|
|
36
|
+
* DID check reads as a pass for everything it skipped, which is the same failure class as a gate
|
|
37
|
+
* that infers success from silence. So a dry-run result carries the list of gates it did NOT run,
|
|
38
|
+
* and the CLI prints it. Absent on a real publish, where every gate actually ran.
|
|
39
|
+
*/
|
|
40
|
+
readonly notVerified?: readonly string[] | undefined;
|
|
30
41
|
}
|
|
31
42
|
|
|
32
43
|
/** Full publish report. */
|
|
@@ -630,8 +641,22 @@ export function publishPackages(
|
|
|
630
641
|
}
|
|
631
642
|
|
|
632
643
|
if (opts.dryRun) {
|
|
633
|
-
|
|
634
|
-
|
|
644
|
+
// NOT a statement that the package would publish cleanly — only that the gates checked ABOVE
|
|
645
|
+
// this line passed. Everything below it (build, re-sign, pack, the package's own
|
|
646
|
+
// `prepublishOnly`, the registry itself) is untouched by a dry run and is named as such.
|
|
647
|
+
const NOT_VERIFIED_BY_DRY_RUN = Object.freeze([
|
|
648
|
+
'prepublishOnly пакета (его собственный гейт публикации)',
|
|
649
|
+
'сборка dist из исходников',
|
|
650
|
+
'пере-подпись манифеста после бампа',
|
|
651
|
+
'содержимое тарбола (npm pack)',
|
|
652
|
+
'ответ реестра npm',
|
|
653
|
+
]);
|
|
654
|
+
results.push({
|
|
655
|
+
name: pkg.name, oldVersion, newVersion, status: 'skipped',
|
|
656
|
+
claimCheck: claimCheckSummary,
|
|
657
|
+
notVerified: NOT_VERIFIED_BY_DRY_RUN,
|
|
658
|
+
});
|
|
659
|
+
landedInBatch.add(pkg.name);
|
|
635
660
|
continue;
|
|
636
661
|
}
|
|
637
662
|
|
package/src/registry.ts
CHANGED
|
@@ -363,8 +363,9 @@ function categoryFromPack(pack: string): string {
|
|
|
363
363
|
// digitizer outputs like `skills-12factor` (The Twelve-Factor App). Future digitized public packs
|
|
364
364
|
// (e.g. AOSA) should be added here or carry a `book`/digitized marker.
|
|
365
365
|
if (pack.includes('book') || pack.includes('12factor')) return 'knowledge';
|
|
366
|
-
//
|
|
367
|
-
|
|
366
|
+
// Learning and demo-site manufacturing: tutorial packs teach; the demo publisher records a
|
|
367
|
+
// product journey and emits a Pages-ready explanatory site.
|
|
368
|
+
if (pack.includes('tutorial') || pack.includes('demo-publisher')) return 'learning';
|
|
368
369
|
// Packs that carry skills without the `skills-` prefix, catalogued since 2026-09-01. Each needs a
|
|
369
370
|
// category or it lands in `other`, and a test rightly forbids that bucket: an uncategorised skill
|
|
370
371
|
// cannot be filtered for, which is half of being findable.
|
package/src/score.ts
CHANGED
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
* PURE: the CLI reads the artifact files; this module only classifies.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
+
import { amendmentIdsIn } from './amendment-trace.js';
|
|
24
|
+
|
|
23
25
|
export type DisciplineVerdict = 'pass' | 'partial' | 'absent';
|
|
24
26
|
|
|
25
27
|
export interface DisciplineScore {
|
|
@@ -524,11 +526,21 @@ export function scoreRun(slug: string, artifacts: RunArtifacts): RunScorecard {
|
|
|
524
526
|
// 7. Amendment confirmation — only when amendments EXIST; their absence is not a failure.
|
|
525
527
|
// Born in the PLAN/ideation: a stray "AM-7" in QE prose (e.g. another feature's test name)
|
|
526
528
|
// must not conjure the discipline (caught by the very first dogfood run).
|
|
527
|
-
|
|
529
|
+
// ONE reader of the `AM-*` token, shared with the row grammar and pinned against K2's by
|
|
530
|
+
// test/amendment-grammar-agreement.test.ts. It used to be a THIRD private contract here —
|
|
531
|
+
// `/AM-\d+/g`, which does not match `AM-CP-1` at all (MEASURED 2026-09-06:
|
|
532
|
+
// `'AM-CP-1'.match(/AM-\d+/g)` → `null`), so a plan whose amendments were all challenge-panel
|
|
533
|
+
// rows scored `plannedAm = []` and this whole discipline was skipped silently — no `absent`, no
|
|
534
|
+
// `partial`, just a smaller denominator. A check that silently checks nothing is the class the
|
|
535
|
+
// amendment gate exists to remove, and it had reappeared in the scorer.
|
|
536
|
+
const plannedAm = amendmentIdsIn(planText).sort();
|
|
528
537
|
if (plannedAm.length > 0) {
|
|
529
|
-
// One stray AM-9 in QE must not satisfy AM-1..AM-2 (Codex QE #3): coverage is id-by-id
|
|
530
|
-
|
|
531
|
-
|
|
538
|
+
// One stray AM-9 in QE must not satisfy AM-1..AM-2 (Codex QE #3): coverage is id-by-id — and
|
|
539
|
+
// `includes` was not id-by-id: a planned `AM-1` read as covered by a report mentioning only
|
|
540
|
+
// `AM-10` (MEASURED — `'AM-10'.includes('AM-1')` → `true`). A substring is not an id.
|
|
541
|
+
const mentionedInQe = new Set(amendmentIdsIn(qeText));
|
|
542
|
+
const covered = plannedAm.filter((id) => mentionedInQe.has(id));
|
|
543
|
+
const missing = plannedAm.filter((id) => !mentionedInQe.has(id));
|
|
532
544
|
add(
|
|
533
545
|
'amendment-confirmation',
|
|
534
546
|
'amendments carried into QE with confirmation',
|