memento-mori-jester 0.1.78 → 0.1.79
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/CHANGELOG.md +6 -0
- package/README.md +2 -0
- package/ROADMAP.md +2 -1
- package/docs/PRODUCTION_READINESS.md +3 -0
- package/docs/RELEASE.md +1 -0
- package/docs/RELEASE_NOTES_v0.1.79.md +47 -0
- package/package.json +3 -2
- package/scripts/check-production-readiness.mjs +4 -0
- package/scripts/check-promo-freshness.mjs +201 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to Memento Mori Jester are tracked here.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.1.79
|
|
8
|
+
|
|
9
|
+
- Added `npm run promo:check` to verify the current repo-local promo video, stills, docs, and fixture evidence numbers stay aligned.
|
|
10
|
+
- Wired promo freshness validation into `npm test` and the production-readiness guard.
|
|
11
|
+
- Updated release, readiness, roadmap, and promo docs with the new maintainer check.
|
|
12
|
+
|
|
7
13
|
## 0.1.78
|
|
8
14
|
|
|
9
15
|
- Added a refreshed HyperFrames X demo render under `promo/x-demo-v0.1.78` with current version and fixture-evidence numbers.
|
package/README.md
CHANGED
|
@@ -503,6 +503,7 @@ Use the false-positive template for noisy cautions or blocks. Include `jester su
|
|
|
503
503
|
Maintainers can use [docs/MAINTAINER_TRIAGE.md](docs/MAINTAINER_TRIAGE.md) to turn useful false-positive reports into redacted fixtures.
|
|
504
504
|
Run `npm run fixtures:check` before merging fixture changes; it catches duplicate IDs, missing rule metadata, weak descriptions, unsafe-looking content, and duplicate content.
|
|
505
505
|
Run `npm run fixtures:report` to see fixture coverage by rule, rule family, preset slice, kind, verdict, quiet-pass boundaries, feasible pass-case gaps, and curation-next guidance before choosing the next fixture. Use `npm run fixtures:report -- --markdown` when you want a paste-ready summary for release notes or GitHub issues.
|
|
506
|
+
Run `npm run promo:check` after editing promo assets; it checks the current demo video, stills, docs, and fixture evidence numbers stay in sync.
|
|
506
507
|
|
|
507
508
|
For vulnerabilities, private code exposure, or credential-handling concerns, follow [SECURITY.md](SECURITY.md) instead of opening a public issue with sensitive details.
|
|
508
509
|
|
|
@@ -512,6 +513,7 @@ Release checklist:
|
|
|
512
513
|
|
|
513
514
|
```powershell
|
|
514
515
|
npm.cmd test
|
|
516
|
+
npm.cmd run promo:check
|
|
515
517
|
npm.cmd run production:check
|
|
516
518
|
npm.cmd run pack:dry
|
|
517
519
|
git tag -a v0.1.x -m "Memento Mori Jester v0.1.x"
|
package/ROADMAP.md
CHANGED
|
@@ -6,6 +6,7 @@ Memento Mori Jester is usable today as a CLI, MCP server, GitHub Action, and git
|
|
|
6
6
|
|
|
7
7
|
## Recently Shipped
|
|
8
8
|
|
|
9
|
+
- Promo freshness check in v0.1.79, verifying the current demo video, share-kit stills, docs, and fixture evidence numbers before public posting.
|
|
9
10
|
- Fresh demo render in v0.1.78, updating the repo-local X video and share-kit stills to current version and fixture totals.
|
|
10
11
|
- Promo/share kit in v0.1.77, adding X post copy, a short demo script, a posting checklist, and still images from the existing demo video.
|
|
11
12
|
- Real-world preset quiet-pass curation in v0.1.76, adding eight safe examples across python, security, web, and AI workflows while keeping fixture coverage gaps clean.
|
|
@@ -69,7 +70,7 @@ Memento Mori Jester is usable today as a CLI, MCP server, GitHub Action, and git
|
|
|
69
70
|
|
|
70
71
|
- Collect real-world reports for the next lowest-count preset slices now highlighted by `fixtures:report`.
|
|
71
72
|
- Add more framework-specific false-positive examples from real reports so tuning guidance keeps getting sharper.
|
|
72
|
-
- Add a
|
|
73
|
+
- Add a lightweight social preview card or landing-page still for GitHub and X link previews.
|
|
73
74
|
|
|
74
75
|
## Quality And Safety
|
|
75
76
|
|
|
@@ -9,6 +9,7 @@ This checklist defines what "production grade" means for Memento Mori Jester rig
|
|
|
9
9
|
- GitHub Releases and npm publishing are automated from annotated `v*` tags through GitHub Actions trusted publishing.
|
|
10
10
|
- CI runs tests and a package dry run on every push to `main` and pull request.
|
|
11
11
|
- The local playground, GitHub Action, MCP setup snippets, preset examples, fixtures, and release notes ship in the npm package.
|
|
12
|
+
- Repo-local promo assets stay outside the npm package, but `npm run promo:check` keeps the current demo video, stills, docs, and fixture evidence numbers aligned.
|
|
12
13
|
|
|
13
14
|
## npm Package
|
|
14
15
|
|
|
@@ -54,6 +55,7 @@ This checklist defines what "production grade" means for Memento Mori Jester rig
|
|
|
54
55
|
- `docs/MAINTAINER_TRIAGE.md` explains how to turn useful false-positive reports into fixture coverage before changing rule logic.
|
|
55
56
|
- `npm run fixtures:check` validates fixture IDs, metadata, unsafe-looking content, duplicate content, and explicit expected/absent rule intent.
|
|
56
57
|
- `npm run fixtures:report` shows fixture coverage by rule, rule family, preset slice, kind, verdict, quiet-pass rule boundaries, and feasible pass-case gaps so maintainers can pick the next fixture target; `npm run fixtures:report -- --markdown` produces a paste-ready maintainer snapshot.
|
|
58
|
+
- `npm run promo:check` verifies current repo-local promo assets against the current fixture evidence before maintainers post or refresh the demo.
|
|
57
59
|
- npm publish has a manual workflow fallback, but the normal release path is tag-driven trusted publishing.
|
|
58
60
|
|
|
59
61
|
## Static Guard
|
|
@@ -69,6 +71,7 @@ This checklist defines what "production grade" means for Memento Mori Jester rig
|
|
|
69
71
|
- maintainer triage docs exist and link noisy-rule reports back to fixture coverage.
|
|
70
72
|
- fixture authoring checks are wired into `npm test`.
|
|
71
73
|
- fixture coverage reports are wired into `npm test`.
|
|
74
|
+
- promo freshness checks are wired into `npm test`.
|
|
72
75
|
|
|
73
76
|
`npm test` runs this check after the TypeScript build and unit tests.
|
|
74
77
|
|
package/docs/RELEASE.md
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Memento Mori Jester v0.1.79
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
This release adds a repo-local promo freshness check so maintainers can verify the current demo video, stills, docs, and fixture evidence numbers before posting or refreshing public assets.
|
|
6
|
+
|
|
7
|
+
## What Changed
|
|
8
|
+
|
|
9
|
+
- Added `scripts/check-promo-freshness.mjs`.
|
|
10
|
+
- Added `npm run promo:check`.
|
|
11
|
+
- Wired `promo:check` into `npm test`.
|
|
12
|
+
- Updated production-readiness checks so the promo freshness guard cannot silently disappear.
|
|
13
|
+
- Updated README, release docs, production-readiness docs, promo docs, roadmap, changelog, and release notes.
|
|
14
|
+
|
|
15
|
+
## Public Interface
|
|
16
|
+
|
|
17
|
+
- No CLI command changes.
|
|
18
|
+
- No MCP tool changes.
|
|
19
|
+
- No config schema changes.
|
|
20
|
+
- No review rule, scoring, or verdict behavior changes.
|
|
21
|
+
- No GitHub Action behavior changes.
|
|
22
|
+
- `promo/` remains outside the npm package `files` list.
|
|
23
|
+
|
|
24
|
+
## Release Validation
|
|
25
|
+
|
|
26
|
+
```powershell
|
|
27
|
+
npm.cmd test
|
|
28
|
+
npm.cmd run demo:svg:check
|
|
29
|
+
npm.cmd run promo:check
|
|
30
|
+
npm.cmd run pack:dry
|
|
31
|
+
git diff --check
|
|
32
|
+
git diff | node .\dist\cli.js diff --fail-on block --subject "v0.1.79 promo freshness check"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For a future same-version promo refresh, maintainers can run:
|
|
36
|
+
|
|
37
|
+
```powershell
|
|
38
|
+
npm.cmd run promo:check -- --require-package-version
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
This release does not require that strict mode because the current public demo snapshot remains `x-demo-v0.1.78`.
|
|
42
|
+
|
|
43
|
+
Expected:
|
|
44
|
+
|
|
45
|
+
- default `promo:check` passes for the current published demo snapshot,
|
|
46
|
+
- `--require-package-version` is available for intentional same-version promo refreshes,
|
|
47
|
+
- GitHub Release and npm Publish complete from the `v0.1.79` tag.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memento-mori-jester",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.79",
|
|
4
4
|
"description": "A local court-jester sidecar for AI coding agents: review plans, commands, diffs, and final claims before they get too pleased with themselves.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -40,12 +40,13 @@
|
|
|
40
40
|
"build": "tsc -p tsconfig.json",
|
|
41
41
|
"start": "node dist/server.js",
|
|
42
42
|
"start:mcp": "node dist/server.js",
|
|
43
|
-
"test": "npm run build && node scripts/run-tests.mjs && npm run fixtures:check && npm run fixtures:report && npm run production:check",
|
|
43
|
+
"test": "npm run build && node scripts/run-tests.mjs && npm run fixtures:check && npm run fixtures:report && npm run promo:check && npm run production:check",
|
|
44
44
|
"doctor": "node dist/cli.js doctor",
|
|
45
45
|
"demo:svg": "node scripts/render-demo-svg.mjs",
|
|
46
46
|
"demo:svg:check": "node scripts/render-demo-svg.mjs --check",
|
|
47
47
|
"fixtures:check": "node scripts/check-fixtures.mjs",
|
|
48
48
|
"fixtures:report": "node scripts/report-fixtures.mjs",
|
|
49
|
+
"promo:check": "node scripts/check-promo-freshness.mjs",
|
|
49
50
|
"production:check": "node scripts/check-production-readiness.mjs",
|
|
50
51
|
"pack:dry": "npm pack --dry-run",
|
|
51
52
|
"prepare": "npm run build",
|
|
@@ -64,6 +64,7 @@ for (const path of [
|
|
|
64
64
|
"docs/MAINTAINER_TRIAGE.md",
|
|
65
65
|
`docs/RELEASE_NOTES_${tag}.md`,
|
|
66
66
|
"action.yml",
|
|
67
|
+
"scripts/check-promo-freshness.mjs",
|
|
67
68
|
"scripts/check-fixtures.mjs",
|
|
68
69
|
"scripts/report-fixtures.mjs",
|
|
69
70
|
".github/ISSUE_TEMPLATE/bug_report.yml",
|
|
@@ -132,8 +133,11 @@ requireText("scripts/report-fixtures.mjs", /--markdown/, "Markdown fixture repor
|
|
|
132
133
|
forbidText("scripts/report-fixtures.mjs", /src\/config\.ts|src\/types\.ts/, "source-only fixture report dependencies");
|
|
133
134
|
requireText("package.json", /"fixtures:check": "node scripts\/check-fixtures\.mjs"/, "fixture authoring check script");
|
|
134
135
|
requireText("package.json", /"fixtures:report": "node scripts\/report-fixtures\.mjs"/, "fixture coverage report script");
|
|
136
|
+
requireText("package.json", /"promo:check": "node scripts\/check-promo-freshness\.mjs"/, "promo freshness check script");
|
|
135
137
|
requireText("package.json", /npm run fixtures:check/, "fixture authoring check in npm test");
|
|
136
138
|
requireText("package.json", /npm run fixtures:report/, "fixture coverage report in npm test");
|
|
139
|
+
requireText("package.json", /npm run promo:check/, "promo freshness check in npm test");
|
|
140
|
+
requireText("scripts/check-promo-freshness.mjs", /--require-package-version/, "optional strict package-version promo check");
|
|
137
141
|
requireText("SECURITY.md", /doctor --json/, "doctor JSON redaction guidance");
|
|
138
142
|
requireText("SECURITY.md", /security\/advisories\/new/, "private vulnerability report link");
|
|
139
143
|
requireText(".github/ISSUE_TEMPLATE/bug_report.yml", /doctor --json/, "doctor JSON support prompt");
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
|
|
6
|
+
const root = process.cwd();
|
|
7
|
+
const failures = [];
|
|
8
|
+
const args = new Set(process.argv.slice(2));
|
|
9
|
+
const requirePackageVersion = args.has("--require-package-version");
|
|
10
|
+
|
|
11
|
+
for (const arg of args) {
|
|
12
|
+
if (arg !== "--require-package-version") {
|
|
13
|
+
failures.push(`Unknown option: ${arg}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function read(path) {
|
|
18
|
+
return readFileSync(join(root, path), "utf8");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function readJson(path) {
|
|
22
|
+
return JSON.parse(read(path));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function escapeRegExp(value) {
|
|
26
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function requireFile(path, description, minBytes = 1) {
|
|
30
|
+
const fullPath = join(root, path);
|
|
31
|
+
if (!existsSync(fullPath)) {
|
|
32
|
+
failures.push(`${description} is missing: ${path}`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const size = statSync(fullPath).size;
|
|
36
|
+
if (size < minBytes) {
|
|
37
|
+
failures.push(`${description} looks too small: ${path} (${size} bytes).`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function requireText(path, pattern, description) {
|
|
42
|
+
const content = read(path);
|
|
43
|
+
if (!pattern.test(content)) {
|
|
44
|
+
failures.push(`${path} should include ${description}.`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function failJson(path, error) {
|
|
49
|
+
failures.push(`${path} could not be parsed: ${error instanceof Error ? error.message : String(error)}.`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function loadRiskyDomainEvidence() {
|
|
53
|
+
const cliPath = join(root, "dist", "cli.js");
|
|
54
|
+
if (!existsSync(cliPath)) {
|
|
55
|
+
failures.push("dist/cli.js is missing; run `npm run build` before `npm run promo:check`.");
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const result = spawnSync(
|
|
60
|
+
process.execPath,
|
|
61
|
+
[cliPath, "tune", "risky-domain", "--json", "--no-config"],
|
|
62
|
+
{ cwd: root, encoding: "utf8" }
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (result.status !== 0) {
|
|
66
|
+
failures.push(`Could not load risky-domain fixture evidence: ${result.stderr || result.stdout}`.trim());
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(result.stdout);
|
|
72
|
+
return parsed.fixtureEvidence ?? null;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
failures.push(`Could not parse risky-domain fixture evidence JSON: ${error instanceof Error ? error.message : String(error)}.`);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let packageJson;
|
|
80
|
+
try {
|
|
81
|
+
packageJson = readJson("package.json");
|
|
82
|
+
} catch (error) {
|
|
83
|
+
failJson("package.json", error);
|
|
84
|
+
packageJson = {};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let fixtures;
|
|
88
|
+
try {
|
|
89
|
+
fixtures = readJson("examples/fixtures/preset-review-cases.json");
|
|
90
|
+
} catch (error) {
|
|
91
|
+
failJson("examples/fixtures/preset-review-cases.json", error);
|
|
92
|
+
fixtures = [];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const promoReadmePath = "promo/README.md";
|
|
96
|
+
const promoReadme = read(promoReadmePath);
|
|
97
|
+
const currentVideo = promoReadme.match(/Final vertical demo video:\s*\[([^\]]+)\]\(([^)]+)\)/);
|
|
98
|
+
|
|
99
|
+
if (!currentVideo) {
|
|
100
|
+
failures.push(`${promoReadmePath} should link the final vertical demo video.`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const linkedLabel = currentVideo?.[1] ?? "";
|
|
104
|
+
const linkedTarget = currentVideo?.[2] ?? "";
|
|
105
|
+
if (linkedLabel && linkedTarget && linkedLabel !== linkedTarget) {
|
|
106
|
+
failures.push(`${promoReadmePath} video link label and target should match.`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const videoMatch = linkedTarget.match(/^x-demo-v(\d+\.\d+\.\d+)\/renders\/memento-mori-jester-x-demo-v\1\.mp4$/);
|
|
110
|
+
if (!videoMatch) {
|
|
111
|
+
failures.push(`${promoReadmePath} video should point at x-demo-vX.Y.Z/renders/memento-mori-jester-x-demo-vX.Y.Z.mp4.`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const promoVersion = videoMatch?.[1] ?? "unknown";
|
|
115
|
+
const demoId = `x-demo-v${promoVersion}`;
|
|
116
|
+
const demoDir = `promo/${demoId}`;
|
|
117
|
+
const demoVideoPath = linkedTarget ? `promo/${linkedTarget}` : "";
|
|
118
|
+
const fixtureTotal = Array.isArray(fixtures) ? fixtures.length : 0;
|
|
119
|
+
const riskyEvidence = loadRiskyDomainEvidence();
|
|
120
|
+
|
|
121
|
+
if (requirePackageVersion && packageJson.version !== promoVersion) {
|
|
122
|
+
failures.push(`Current promo version v${promoVersion} should match package.json ${packageJson.version} when --require-package-version is used.`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (promoVersion !== "unknown") {
|
|
126
|
+
requireFile(`${demoDir}/index.html`, "current promo demo HTML");
|
|
127
|
+
requireFile(`${demoDir}/README.md`, "current promo demo README");
|
|
128
|
+
requireFile(`${demoDir}/package.json`, "current promo demo package.json");
|
|
129
|
+
requireFile(`${demoDir}/package-lock.json`, "current promo demo package-lock.json");
|
|
130
|
+
requireFile(`${demoDir}/meta.json`, "current promo demo metadata");
|
|
131
|
+
requireFile(demoVideoPath, "current promo demo video", 100_000);
|
|
132
|
+
|
|
133
|
+
for (const still of ["01-opener.jpg", "02-command-block.jpg", "03-tuning-evidence.jpg", "04-try-it.jpg"]) {
|
|
134
|
+
requireFile(`promo/share-kit/stills/${still}`, `share-kit still ${still}`, 50_000);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const demoPackage = readJson(`${demoDir}/package.json`);
|
|
139
|
+
if (demoPackage.name !== demoId) {
|
|
140
|
+
failures.push(`${demoDir}/package.json name should be ${demoId}.`);
|
|
141
|
+
}
|
|
142
|
+
} catch (error) {
|
|
143
|
+
failJson(`${demoDir}/package.json`, error);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
const demoLock = readJson(`${demoDir}/package-lock.json`);
|
|
148
|
+
if (demoLock.name !== demoId || demoLock.packages?.[""]?.name !== demoId) {
|
|
149
|
+
failures.push(`${demoDir}/package-lock.json root name should be ${demoId}.`);
|
|
150
|
+
}
|
|
151
|
+
} catch (error) {
|
|
152
|
+
failJson(`${demoDir}/package-lock.json`, error);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
const demoMeta = readJson(`${demoDir}/meta.json`);
|
|
157
|
+
if (demoMeta.id !== demoId || demoMeta.name !== demoId) {
|
|
158
|
+
failures.push(`${demoDir}/meta.json id and name should be ${demoId}.`);
|
|
159
|
+
}
|
|
160
|
+
} catch (error) {
|
|
161
|
+
failJson(`${demoDir}/meta.json`, error);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const escapedVersion = escapeRegExp(promoVersion);
|
|
165
|
+
requireText(`${demoDir}/README.md`, new RegExp(`# Memento Mori Jester X Demo v${escapedVersion}`), `demo title v${promoVersion}`);
|
|
166
|
+
requireText(`${demoDir}/README.md`, new RegExp(`renders/memento-mori-jester-x-demo-v${escapedVersion}\\.mp4`), "current render path");
|
|
167
|
+
requireText(`${demoDir}/index.html`, new RegExp(`<span>v${escapedVersion}</span>`), `visible version v${promoVersion}`);
|
|
168
|
+
requireText(`${demoDir}/index.html`, new RegExp(`PASS package-version: ${escapedVersion}`), `doctor package version ${promoVersion}`);
|
|
169
|
+
requireText(`${demoDir}/index.html`, new RegExp(`<strong>${fixtureTotal}</strong>\\s*<span>fixtures checked</span>`), `${fixtureTotal} fixture count`);
|
|
170
|
+
requireText("promo/share-kit/README.md", new RegExp(escapeRegExp(`../${linkedTarget}`)), "current promo video path");
|
|
171
|
+
|
|
172
|
+
if (riskyEvidence) {
|
|
173
|
+
requireText(
|
|
174
|
+
`${demoDir}/index.html`,
|
|
175
|
+
new RegExp(`<strong>${riskyEvidence.matchCount}</strong>\\s*<span>risky-domain matches</span>`),
|
|
176
|
+
`${riskyEvidence.matchCount} risky-domain match count`
|
|
177
|
+
);
|
|
178
|
+
requireText(
|
|
179
|
+
`${demoDir}/index.html`,
|
|
180
|
+
new RegExp(`<strong>${riskyEvidence.quietPassCount}</strong>\\s*<span>quiet-pass examples</span>`),
|
|
181
|
+
`${riskyEvidence.quietPassCount} quiet-pass count`
|
|
182
|
+
);
|
|
183
|
+
requireText("docs/DEMO.md", new RegExp(`Total fixtures checked: ${riskyEvidence.totalFixtures}`), "current tune fixture total");
|
|
184
|
+
requireText("docs/DEMO.md", new RegExp(`Matching fixtures: ${riskyEvidence.matchCount}`), "current tune match count");
|
|
185
|
+
requireText("docs/DEMO.md", new RegExp(`Quiet-pass fixtures: ${riskyEvidence.quietPassCount}`), "current tune quiet-pass count");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (failures.length > 0) {
|
|
190
|
+
process.stderr.write("Promo freshness check failed:\n");
|
|
191
|
+
for (const failure of failures) {
|
|
192
|
+
process.stderr.write(`- ${failure}\n`);
|
|
193
|
+
}
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
process.stdout.write(
|
|
198
|
+
`Promo freshness check passed for ${demoId}: ${fixtureTotal} fixtures, ` +
|
|
199
|
+
`${riskyEvidence?.matchCount ?? "unknown"} risky-domain matches, ` +
|
|
200
|
+
`${riskyEvidence?.quietPassCount ?? "unknown"} quiet-pass examples.\n`
|
|
201
|
+
);
|