Skip to content

Commit 07d1985

Browse files
Bernhard Götzendorferclaude
andcommitted
feat(orchestrator): #385 #393 #390 #391 #394 #387 #392 — /test live-coverage + housekeeping cluster
- #385 (partial): /test --target aiat-pmo-module live-run; mechanism end-to-end proven (bootstrap + Playwright spawn + reporter artifacts), 1 fail + 31 skip classified. Coverage-proof partial — rubric-v1 artifact-shape gap filed as #396. Proof at docs/test-runs/proof-aiat-pmo-module-2026-05-14.md - #393: relocate scripts/lib/test-runner/profile-{registry,schema}.mjs → scripts/lib/shared/profiles/ (closes ARCH-PD-MED-3 cross-layer import). 30 tests preserved + import-depth fix - #390: profiles-path path-traversal validation in scripts/lib/config/test.mjs (isPathInside) - #391: rubric path-traversal validation in scripts/lib/shared/profiles/schema.mjs (default value still validates) - #394 (partial): peekaboo-driver SKILL.md soul wording parity (LOW-1) + Phase 3 AUQ multi-permission template iterating over $MISSING (LOW-3) + glass-modifiers status:stub field + rubric-v1.md Check 4 note (LOW-5). LOW-4 V2 deferred - #387 (partial): project-instruction-file line 9 + README.md inventory updated (31→32 skills, 11→12 commands). Baseline-dir deferred (external repo absent) - #392: .claude/rules/testing.md § "Shared-Hardware Runner Contention" subsection — Mac runner CPU-starvation pattern, mitigations, pipeline #3940 evidence anchor W1 mid-wave hotfixes (deviations logged in STATE.md): - runner.mjs reporter syntax: replaced Jest/Vitest html:<path> form with canonical --reporter html,json + PLAYWRIGHT_HTML_OUTPUT_DIR / PLAYWRIGHT_JSON_OUTPUT_FILE / PLAYWRIGHT_HTML_OPEN=never env vars per playwright.dev/docs/test-reporters - nested-package target resolution: pass tests/e2e directly when target has its own package.json W4 Q-polish folded inline: - ARCH-Q3-MED-1: canary SCAN_ROOTS +scripts/lib/shared/profiles/ in both check-{playwright-mcp,peekaboo-driver}-canary.mjs (validate-plugin 34→36) - ARCH-Q3-MED-2: playwright-driver/SKILL.md reporter doc-drift fix (removed all html:<path> references) - GAP-Q4-2: +5 timeout_ms boundary tests (0, -1, 120000.5, 3_600_001, 3_600_000 ceiling) closing SEC-PD-LOW-3 regression gap Quality: 4944p/12s → 4966p/12s (+22 net tests; Q1 +17 + Q-polish +5). validate-plugin 34→36, typecheck 67/67, lint 0, doc-consistency 0 findings. Closes #385 #393 #390 #391 #394 #387 #392. Filed follow-ups: #395 (runner reporter regression-test gap) · #396 (runner artifact-shape vs rubric-v1) · #397 (SEC-Q2 LOW cluster) · #398 (runner runDir traversal MED) · #399 (runner AbortController test MED) · #400 (ARCH-MED-3 shared/ rename MED) · #401 (LOW cluster polish). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 253a4ab commit 07d1985

18 files changed

Lines changed: 448 additions & 28 deletions

File tree

.claude/rules/testing.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,32 @@ globs:
9595
- Coverage regex: `/All files[^|]*\|[^|]*\s+([\d\.]+)/` extracts percentage for MR badges.
9696
- Failed tests block merge. No exceptions.
9797

98+
### Shared-Hardware Runner Contention (Mac shell executors)
99+
100+
Shell-executor runners that share a host with an active Claude Code session can be CPU-starved when concurrent Claude processes climb past ~10. Symptom: vitest tests that pass locally in <2min hit `testTimeout` (default `10_000`) on the runner. **This is an operator/concurrency issue, not a test or code regression.** Do not treat it as a flaky-test problem and do not widen timeouts globally to paper over it.
101+
102+
- **Cautionary tale:** Pipeline #3940 (2026-05-14 deep-1) failed with 7 `testTimeout` fails after 34m total (test job 18.7min, gitleaks 7m58s) on the GitLab Mac runner. Same commit, same tests passed locally in <2min (4897p/11s). Local re-run of the 7 failing tests: 90/90 green. Resource probe at session-start showed 14 Claude processes — well above the `concurrent-sessions-warn=5` threshold.
103+
- **Diagnostic signal:** if local `npm test` is green and CI fails only with `testTimeout` (not assertion failures), check the host's Claude-process count before re-running:
104+
```bash
105+
pgrep -fc 'claude' # count of active Claude processes on this host
106+
```
107+
A count ≥10 against a shared shell-executor runner is the smoking gun.
108+
109+
**Mitigations, in order of effort:**
110+
111+
1. **Avoid concurrent sessions during CI runs (primary).** Do not start a new Claude Code session in this repo while a CI pipeline is in flight on the same host. The session-start resource-probe banner (threshold `concurrent-sessions-warn=5`) is the active signal — treat it as load-shedding guidance, not a passive note.
112+
2. **Raise the per-test vitest timeout only when contention is expected:**
113+
```ts
114+
// vitest.config.ts — ceiling for a contended Mac runner
115+
export default defineConfig({ test: { testTimeout: 30_000 } });
116+
```
117+
Trade-off: real hangs take longer to surface. Do not push past `30_000` as a default.
118+
3. **Offload heavy CI to a dedicated runner** when the pattern becomes recurring — the resource probe is the trigger, not a single failed pipeline.
119+
120+
What this is **NOT**: a test-quality bug. Do not retry, mark `.skip`, or widen timeout values on quiet runners to "stabilise" — that masks real perf regressions where they should be loudest.
121+
122+
Cross-reference: learning id `mac-gitlab-runner-cpu-starvation-under-concurrent-claude-load` in `.orchestrator/metrics/learnings.jsonl` (confidence 0.9). `/evolve` rotates the rule if the signal stops applying.
123+
98124
## E2E Best Practices
99125
- Use data-testid attributes for stable selectors.
100126
- Avoid `page.waitForTimeout()` — use `page.waitForSelector()` or `expect().toBeVisible()`.

CLAUDE.md

Lines changed: 6 additions & 4 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ Active Cursor hooks: 2 events (`afterFileEdit`, `beforeShellExecution`) routed t
227227

228228
## Components
229229

230-
- **31 Skills**: bootstrap, session-start, session-plan, wave-executor, session-end, claude-md-drift-check, ecosystem-health, gitlab-ops, quality-gates, discovery, plan, evolve, vault-sync, vault-mirror, daily, docs-orchestrator, skill-creator, mcp-builder, hook-development, architecture, domain-model, ubiquitous-language, autopilot, mode-selector, repo-audit, convergence-monitoring, using-orchestrator, frontmatter-guard, test-runner, playwright-driver, peekaboo-driver (session-start sub-files: `phase-2-5-docs-planning.md`, `phase-4-5-resource-health.md`, `phase-7-5-mode-selector.md`, `phase-8-5-express-path.md`)
231-
- **11 Commands**: `/session`, `/go`, `/close`, `/discovery`, `/plan`, `/evolve`, `/bootstrap`, `/harness-audit`, `/autopilot`, `/repo-audit`, `/test`
230+
- **32 Skills**: bootstrap, session-start, session-plan, wave-executor, session-end, claude-md-drift-check, ecosystem-health, gitlab-ops, quality-gates, discovery, plan, evolve, vault-sync, vault-mirror, daily, docs-orchestrator, skill-creator, mcp-builder, hook-development, architecture, domain-model, ubiquitous-language, autopilot, mode-selector, repo-audit, convergence-monitoring, using-orchestrator, frontmatter-guard, test-runner, playwright-driver, peekaboo-driver (session-start sub-files: `phase-2-5-docs-planning.md`, `phase-4-5-resource-health.md`, `phase-7-5-mode-selector.md`, `phase-8-5-express-path.md`)
231+
- **12 Commands**: `/session`, `/go`, `/close`, `/discovery`, `/plan`, `/evolve`, `/bootstrap`, `/harness-audit`, `/autopilot`, `/repo-audit`, `/test`
232232
- **11 Agents**: code-implementer, test-writer, ui-developer, db-specialist, security-reviewer, session-reviewer, docs-writer, architect-reviewer, qa-strategist, analyst, ux-evaluator
233233
- **10 hook event matchers / 10 handlers**: SessionStart (banner + init), PreToolUse/Edit\|Write (scope enforcement), PreToolUse/Bash (destructive-command guard + enforce-commands), PostToolUse (edit validation), Stop (session events), SubagentStop (telemetry), PostToolUseFailure (corrective context), PostToolBatch (wave signal), SubagentStart (telemetry), CwdChanged (cwd-change record). Plus the Clank Event Bus integration in `hooks/_lib/events.mjs`.
234234
- **Output Styles**: 3 (session-report, wave-summary, finding-report) for consistent reporting

docs/test-runs/.gitkeep

Whitespace-only changes.
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# /test --target aiat-pmo-module — Value-Proof Report
2+
3+
> **Issue:** [#385](https://gitlab.gotzendorfer.at/infrastructure/session-orchestrator/-/issues/385) — end2end-proof: /test --target aiat-pmo-module (web-gate)
4+
> **Session:** main-2026-05-14-deep-3 W1 (coord-direct)
5+
> **Status:** Mechanism + live-execution proven. Coverage-proof partial — rubric-v1 artifact gap surfaced for follow-up.
6+
7+
## Run Metadata
8+
9+
| Field | Value |
10+
|---|---|
11+
| Target | `/Users/bernhardg./Projects/intern/aiat-pmo-module/tests/e2e` |
12+
| Profile | `web-gate` (`.orchestrator/policy/test-profiles.json`) |
13+
| Driver | `scripts/lib/playwright-driver/runner.mjs` (Playwright 1.x via global npx) |
14+
| Run-ID | `aiat-pmo-2026-05-14-170021-v3` |
15+
| Run-Dir | `.orchestrator/metrics/test-runs/aiat-pmo-2026-05-14-170021-v3/` |
16+
| Started | 2026-05-14T15:00:22.316Z |
17+
| Duration | 547 ms (test execution); ~30 s wall-clock incl. spawn + reporter |
18+
| Exit code | 1 (Playwright: ≥1 unexpected failure) — runner.mjs maps to exit 1 per spec |
19+
| Orchestrator session | `main-2026-05-14-deep-3` |
20+
| Plugin version | v3.5.0 |
21+
22+
## Stack Setup
23+
24+
Pre-existing (3 h uptime at session start):
25+
26+
```bash
27+
docker compose -f ~/Projects/intern/aiat-pmo-module/dev/docker-compose.yml ps
28+
# aiat-pmo-daemon, aiat-pmo-ws, aiat-pmo-espo, aiat-pmo-db (healthy)
29+
```
30+
31+
Bootstrap (coord-direct W1, ~30 s):
32+
33+
```bash
34+
cd ~/Projects/intern/aiat-pmo-module/tests/e2e && npm install # 4 packages
35+
npx playwright install chromium # 92.4 MiB → ~/Library/Caches/ms-playwright/chromium_headless_shell-1223
36+
```
37+
38+
Health: `curl http://localhost:8090` → 200 OK (EspoCRM responding).
39+
40+
Env: `tests/e2e/.env` not used; tests read `process.env.ESPOCRM_URL` (defaults to `http://localhost:8090`). No `TEST_INITIATIVE_ID` env var set → most tests conditionally skipped.
41+
42+
## Test Execution Summary
43+
44+
| Metric | Value |
45+
|---|---|
46+
| Expected (passed) | 0 |
47+
| Unexpected (failed) | 1 |
48+
| Flaky | 0 |
49+
| Skipped | 31 |
50+
| Total declared | 32 |
51+
52+
The single failure is `initiative-list.spec.ts:27 — GET /api/v1/Initiative returns 200 with total and list`. The test asserts `expect(response.status()).toBe(200)` but the server returns 401 because no API key / session token was provided in the test environment. The 31 skipped tests all carry conditional `test.skip(!ENV_VAR, '...')` guards; this one is missing that guard, so it executes and fails immediately. **This is a minor finding in `aiat-pmo-module` (missing skip-guard) — not a /test bug.**
53+
54+
Skip distribution (31 across 14 spec files):
55+
56+
| File | Skipped |
57+
|---|---|
58+
| `api/restricted-role-403.spec.ts` | 6 |
59+
| `api/acl-team-isolation.spec.ts` | 3 |
60+
| `api/auth-token.spec.ts` | 3 |
61+
| `api/cluster-routing.spec.ts` | 3 |
62+
| `api/create-via-api-key.spec.ts` | 3 |
63+
| `api/stale-filter.spec.ts` | 3 |
64+
| `initiative-auth.spec.ts` | 2 |
65+
| `api/score-live.spec.ts` | 2 |
66+
| Remaining 6 spec files | 1 each |
67+
68+
## Artifacts Captured
69+
70+
```
71+
.orchestrator/metrics/test-runs/aiat-pmo-2026-05-14-170021-v3/
72+
├── console.log 17 279 B combined stdout+stderr from npx
73+
├── exit_code 1 B Playwright exit code (1)
74+
├── report/index.html Playwright HTML reporter output
75+
├── results.json 27 154 B Playwright JSON reporter
76+
└── test-results/ per-test artifacts
77+
├── .last-run.json
78+
└── <test-name-chromium>/ 32 sub-dirs
79+
└── trace.zip Playwright trace (`--trace on`)
80+
```
81+
82+
## ux-evaluator Status — Coverage Gap
83+
84+
ux-evaluator agent **not dispatched** this run. Rationale: the rubric-v1 specifies 4 checks each requiring artifact shapes the current playwright-driver runner does not produce:
85+
86+
| rubric-v1 check | Required artifact | Produced this run? |
87+
|---|---|---|
88+
| 1. onboarding-step-count ≤ 7 | AX-tree snapshots (`ax-snapshots/*.yaml` or similar) | ❌ no — peekaboo-style concept, not implemented for web in v1 |
89+
| 2. axe-violations critical/serious | `axe-*.json` from @axe-core/playwright | ❌ no — soft-skipped (axe-core not in tests/e2e deps) |
90+
| 3. console-errors visible-to-user | `console.ndjson` structured | ❌ no — only flat `console.log` (combined stdout) |
91+
| 4. Apple-Liquid-Glass conformance | macOS-only (peekaboo) | n/a — web target |
92+
93+
The agent would have nothing actionable to classify. Two follow-up issues were filed to close this gap (see Findings & Follow-ups below).
94+
95+
## Findings & Follow-ups (filed this session)
96+
97+
| # | Severity | Description | Disposition |
98+
|---|---|---|---|
99+
| RUNNER-1 | MED | `runner.mjs:174-180` used Jest/Vitest `--reporter html:<path>,json:<path>` syntax; Playwright canonical is `--reporter=html,json` + `PLAYWRIGHT_HTML_OUTPUT_DIR` / `PLAYWRIGHT_JSON_OUTPUT_FILE` / `PLAYWRIGHT_HTML_OPEN` env vars. | **Fixed inline this session** (coord-direct W1 hotfix; deviation logged in STATE.md). Filed retro issue for the regression-test gap (mechanism-proof dry-run didn't catch this — only live spawn does). |
100+
| RUNNER-2 | MED | `runner.mjs` does not write rubric-v1 expected artifacts: no `ax-snapshots/`, no `console.ndjson`, no `screenshots/` namespace. Only Playwright-native artifacts. Skips axe-core unconditionally if `@axe-core/playwright` isn't in target's package.json. | **New issue filed** — V2 capture-extension to bridge runner.mjs ↔ rubric-v1. Until then, /test on web targets is mechanism-proven but coverage-proof partial. |
101+
| TARGET-RESOLUTION | LOW | Runner uses `--target <repo-root>` but tests/e2e is a nested package (own playwright.config.ts + node_modules). First retry failed with "two different versions of @playwright/test" because npx fell back to global. Resolved by passing `--target tests/e2e` directly. Profile registry should grow a `tests-dir` field or runner.mjs should walk for the closest `playwright.config.*`. | **Documented here**; deferred to a future profile-schema enhancement. |
102+
| AIAT-PMO-INIT-LIST | LOW | `aiat-pmo-module tests/e2e/tests/initiative-list.spec.ts:27` lacks the `test.skip(!AUTH_ENV, …)` guard the other 13 spec files use; fails 401 in any env without auth. | **Cross-repo finding** — not filed here. Will surface to aiat-pmo-module backlog. |
103+
104+
## Re-Run Dedupe Verification
105+
106+
Not exercised this session. The first live run (`aiat-pmo-2026-05-14-165941-retry`, target=repo-root) errored at the spawn level before reporter output. The second run (`aiat-pmo-2026-05-14-170021-v3`, target=tests/e2e) is the first artifact-producing run. A re-run dedupe pass requires reconcile triage, which is gated on the ux-evaluator artifact-shape fix (RUNNER-2 above).
107+
108+
## Conclusion
109+
110+
The /test command's end-to-end pipeline is **mechanically proven** against a real live target: bootstrap → driver spawn → Playwright execution → HTML/JSON reporter → exit-code mapping all work as specified. The reporter-syntax bug (RUNNER-1) blocked the value-proof at first attempt; it was fixed inline using canonical Playwright documentation (https://playwright.dev/docs/test-reporters) sourced via ref-mcp + WebFetch, then re-verified in the same session.
111+
112+
The **coverage-proof is partial**: the runner's artifact shape does not yet match rubric-v1's expectations (RUNNER-2), so the ux-evaluator agent cannot perform its 4-check classification. This is a V2-substrate gap, not a mechanism failure. /test on web targets is usable today for "did Playwright tests pass" answers; value-proof for the agentic UX-rubric flow needs RUNNER-2.
113+
114+
Real findings in the target repo (1 missing skip-guard) demonstrate the pipeline produces actionable, repo-relevant signal even in this stub state.
115+
116+
**Recommendation:** Close #385 with status "mechanism + minimal-coverage proof PARTIAL". File RUNNER-2 as the gating issue for full rubric-v1 coverage on the next /test --target aiat-pmo-module pass.

scripts/lib/config/test.mjs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
* as part of the /test epic (#378) Track B wiring.
77
*/
88

9+
import path from 'node:path';
10+
import { isPathInside } from '../path-utils.mjs';
11+
912
/**
1013
* Parse the top-level `test:` YAML block from markdown content.
1114
* Returns defaults when the block is absent.
@@ -71,7 +74,15 @@ export function _parseTest(content) {
7174
if (v) tcDefaultProfile = v;
7275
break;
7376
case 'profiles-path':
74-
if (v) tcProfilesPath = v;
77+
if (v) {
78+
// SEC-IR-LOW-2: reject path-traversal in profiles-path (CWE-23)
79+
const projectRoot = process.cwd();
80+
const resolved = path.resolve(projectRoot, v);
81+
if (isPathInside(resolved, projectRoot)) {
82+
tcProfilesPath = v;
83+
}
84+
// Silent skip on traversal — matches the lenient pattern used by other case branches
85+
}
7586
break;
7687
case 'mode':
7788
if (validModes.has(v.toLowerCase())) tcMode = v.toLowerCase();

scripts/lib/playwright-driver/runner.mjs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import realFs from 'node:fs';
2929
import os from 'node:os';
3030
import path from 'node:path';
3131
import { parseArgs } from 'node:util';
32-
import { getProfile, loadProfiles, validateProfile } from '../test-runner/profile-registry.mjs';
32+
import { getProfile, loadProfiles, validateProfile } from '../shared/profiles/registry.mjs';
3333

3434
// ---------------------------------------------------------------------------
3535
// Path resolution helper
@@ -117,7 +117,10 @@ export default async function run(opts = {}) {
117117
process.exit(2);
118118
}
119119

120-
// SEC-PD-MED-2: reject runDir values that would break the --reporter "html:...,json:..." comma+colon split
120+
// SEC-PD-MED-2: reject runDir values containing commas or colons as defensive
121+
// path-sanitization (original rationale: reporter comma+colon split is now obsolete
122+
// after the 2026-05-14 deep-3 reporter fix — paths flow via env vars, not CLI string).
123+
// Kept as belt-and-braces against pathological run-dirs; revisit alongside #390 path-traversal.
121124
if (/[,:]/.test(runDir)) {
122125
console.error('runner: --run-dir must not contain commas or colons');
123126
process.exit(2);
@@ -171,11 +174,15 @@ export default async function run(opts = {}) {
171174
// Build Playwright args
172175
// -------------------------------------------------------------------------
173176

177+
// Playwright reporter syntax: comma-separated reporter NAMES, paths via env vars.
178+
// Canonical: https://playwright.dev/docs/test-reporters#html-reporter (PLAYWRIGHT_HTML_OUTPUT_DIR)
179+
// and #json-reporter (PLAYWRIGHT_JSON_OUTPUT_FILE). The previous `html:<path>` form
180+
// was Jest/Vitest syntax — Playwright rejected it as `Cannot find module 'html:<path>'`.
174181
const playwrightArgs = [
175182
'playwright',
176183
'test',
177184
'--output', path.join(runDir, 'test-results'),
178-
'--reporter', `html:${path.join(runDir, 'report')},json:${path.join(runDir, 'results.json')}`,
185+
'--reporter', 'html,json',
179186
'--trace', 'on',
180187
];
181188

@@ -212,6 +219,12 @@ export default async function run(opts = {}) {
212219
cwd: targetPath,
213220
signal: controller.signal,
214221
stdio: ['ignore', 'pipe', 'pipe'],
222+
env: {
223+
...process.env,
224+
PLAYWRIGHT_HTML_OUTPUT_DIR: path.join(runDir, 'report'),
225+
PLAYWRIGHT_JSON_OUTPUT_FILE: path.join(runDir, 'results.json'),
226+
PLAYWRIGHT_HTML_OPEN: 'never',
227+
},
215228
});
216229

217230
proc.stdout.pipe(logStream, { end: false });

scripts/lib/test-runner/profile-registry.mjs renamed to scripts/lib/shared/profiles/registry.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* test-runner/profile-registry.mjs — Pure loader for test profile registry.
2+
* shared/profiles/registry.mjs — Pure loader for test profile registry.
33
*
44
* Reads `.orchestrator/policy/test-profiles.json`, validates each entry
55
* against profileRegistrySchema, and exposes pure helper accessors.
@@ -16,7 +16,7 @@
1616
*/
1717

1818
import fsPromises from 'node:fs/promises';
19-
import { profileEntrySchema, profileRegistrySchema } from './profile-schema.mjs';
19+
import { profileEntrySchema, profileRegistrySchema } from './schema.mjs';
2020

2121
// ---------------------------------------------------------------------------
2222
// Default path

scripts/lib/test-runner/profile-schema.mjs renamed to scripts/lib/shared/profiles/schema.mjs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* test-runner/profile-schema.mjs — Validation schemas for test profile entries.
2+
* shared/profiles/schema.mjs — Validation schemas for test profile entries.
33
*
44
* Zod was not available in this project's node_modules at implementation time
55
* (issue #383 part 3), so validation is implemented as a hand-rolled validator
@@ -13,6 +13,8 @@
1313
* `{ success: true, data }` or `{ success: false, error: ZodLike }`.
1414
*/
1515

16+
import { isPathInside } from '../../path-utils.mjs';
17+
1618
// ---------------------------------------------------------------------------
1719
// Validation helpers
1820
// ---------------------------------------------------------------------------
@@ -92,6 +94,11 @@ function parseProfileEntry(value) {
9294
if (typeof rubric !== 'string') {
9395
return { success: false, error: makeError('rubric must be a string') };
9496
}
97+
// SEC-IR-LOW-3: rubric must stay within project root
98+
const projectRoot = process.cwd();
99+
if (!isPathInside(rubric, projectRoot)) {
100+
return { success: false, error: makeError('rubric path escapes project root') };
101+
}
95102

96103
// checks (optional array of strings)
97104
if (v.checks !== undefined) {

scripts/lib/validate/check-peekaboo-driver-canary.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ const DOCUMENTATION_MARKERS = [
7777
const SCAN_ROOTS = [
7878
'skills/peekaboo-driver',
7979
'scripts/lib/test-runner',
80+
'scripts/lib/shared/profiles',
8081
];
8182

8283
const SCAN_EXTENSIONS = ['.md', '.mjs', '.js', '.ts'];

0 commit comments

Comments
 (0)