Step 3/17 av Playground v3-leveransen.
Eksport:
- buildEnvelope(): { appId, schemaVersion, exportedAt, shared, projects,
activeProjectId, activeSurface, preferences } — JSON.parse(JSON.stringify(...))
for å strippe Proxy-wrappere
- exportState(): Blob + URL.createObjectURL + programmatisk <a download>-klikk
+ revokeObjectURL etter 0ms timeout. File System Access API krever HTTPS
(secure context) og er ikke tilgjengelig på file:// — derfor Blob-pattern.
- Filnavn-format: ms-ai-architect-playground-<ISO-stamp>.json
Import:
- importState(File): file.text() -> JSON.parse -> envelope-validering (appId
+ schemaVersion required) -> migrateState() -> persistence.save() -> in-place
state-update (Proxy-binding må bevares — kan ikke bytte raw-referansen)
-> manuell 'change'-event-dispatch så subscribers re-rendrer
- file.text() er Promise<string> som fungerer på file:// uten secure context
MIGRATIONS-pipeline:
- Eager: alle migrasjoner kjøres sekvensielt fra fil-versjon til SCHEMA_VERSION
ved import (ikke lazy ved access)
- Nøkkel-format: 'N->M' (fortløpende). Aldri hopp over et steg.
- Kaster eksplisitt feil ved manglende migrasjons-funksjon eller ved
funksjon som ikke setter schemaVersion korrekt — silent corruption
unngås (brief Risk High).
Eksponerte globals: __buildEnvelope, __exportState, __importState, __MIGRATIONS.
Verify-assert: JSON.parse(JSON.stringify(window.__buildEnvelope())).schemaVersion === 1
Plan: .claude/projects/2026-05-03-playground-v3-architecture/plan.md (Step 3)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Step 2/17 av Playground v3-leveransen.
State-skjelett:
- StateBus extends EventTarget (sharedBus + projectBus)
- Dyp Proxy med set/deleteProperty-traps som batcher dispatchEvent via
queueMicrotask (N synkrone mutasjoner -> én change-event per tick)
- Path tracking: subscribers får detail.paths for å filtrere relevante grener
- INITIAL_STATE med shared.{organization,technology,security,architecture,
business} + projects[] + activeProjectId/Surface + preferences.theme
Persistens:
- IDB primær: én DB ('ms-ai-architect-playground-v1') med 3 stores
(shared, projects, meta). Promise-wrapper rundt indexedDB.open.
- Synkrone migrasjoner i onupgradeneeded med oldVersion-guards (callback-stil
cursor — async cursor-iterasjon er forbudt per w3c/IndexedDB#282)
- db.onversionchange = () => db.close() defensivt på alle koblinger
- localStorage-fallback ved IDB-feil (Safari private mode, kvote): rå JSON
i STATE_KEY, warn ved >4.5 MB nær 5 MiB cap
- Throttled writer: debounce 300 ms etter siste mutasjon
Bootstrap:
- Auto-kjørt på slutten av <body> (DOM allerede parsed)
- window.__store + window.__persistence eksponert for Verify-asserts
Verify-asserts (i nettleser-konsoll på file://-åpnet HTML):
typeof window.__store !== 'undefined' && window.__store.state.schemaVersion === 1
Plan: .claude/projects/2026-05-03-playground-v3-architecture/plan.md (Step 2)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Step 1/17 av Playground v3-leveransen (Session 1, Wave 1).
- Single-file HTML med klassisk inline-script (file://-kompatibel per WHATWG
html#8121: external type=module-scripts feiler på file:// i Chrome+Firefox)
- 7 vendored CSS-link-tags i korrekt rekkefølge: fonts, tokens, base, components,
components-tier2, components-tier3, components-tier3-supplement
- 4 placeholder-overflater (#surface-onboarding, #surface-home, #surface-catalog,
#surface-project) — fylles ut i Steps 5-7
- IIFE med STATE_KEY ('ms-ai-architect-state-v1') og SCHEMA_VERSION (1) konstanter
- Eksponerer __STATE_KEY og __SCHEMA_VERSION på window for Verify-asserts
- v2-fila beholdes parallelt frem til Step 17 (sletting)
Plan: .claude/projects/2026-05-03-playground-v3-architecture/plan.md
Brief: .claude/projects/2026-05-03-playground-v3-architecture/brief.md
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Establish a single governance document at marketplace root and copy
it into each of the 9 plugins so every plugin folder remains 100%
self-contained. Replace the inconsistent provocative blurb across
all READMEs with a uniform fork-and-own paragraph that links to
the local GOVERNANCE.md.
[skip-docs]
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Renames playground/azure-ai-playground.html to
playground/ms-ai-architect-playground.html (history preserved via git mv).
Old name was too narrow — plugin covers the full Microsoft AI stack
(Foundry, Copilot Studio, M365 Copilot, Power Platform, Agent Framework).
Replaces the inline <style> block with seven <link> tags pointing at the
vendored design-system under playground/vendor/playground-design-system/:
fonts.css, tokens.css, base.css, components.css, components-tier2.css,
components-tier3.css, components-tier3-supplement.css.
A small inline shim maps legacy playground tokens (--bg, --surface,
--accent, --gradient1) onto design-system tokens (--color-bg,
--color-surface, --color-primary-500, etc.), keeping all existing
playground-specific class CSS (.hero, .wizard-card, .scenario-card,
.item-card, ...) working without rewrites. <html data-theme="dark">
preserves v2's dark visual identity; light-mode toggle is deferred.
DOM, JS logic, scenario data, and command pipelines are unchanged.
Also includes .gitleaks.toml at repo root (path allowlist for vendored
MANIFEST.json files — SHA-256 file hashes are not secrets) which was
missed in the previous commit due to global git ignore.
Docs updated:
- README.md (root): notes the vendoring sync script + ms-ai-architect
Playground subsection
- plugins/ms-ai-architect/README.md: new Playground section with sync
workflow and standalone guarantee
- plugins/ms-ai-architect/CLAUDE.md: Playground section updated with
vendored design-system details + new filename
Initial sync of shared/playground-design-system/ into
plugins/ms-ai-architect/playground/vendor/playground-design-system/
via scripts/sync-design-system.mjs.
Source commit: f1fecf39b8
Files: 25 (7 CSS + 11 fonts/licenses + 3 schemas + README + MANIFEST)
Vendored copy keeps the plugin standalone — playground will load CSS
from ./vendor/ regardless of where the plugin is installed.
Also adds .gitleaks.toml at repo root with a path allowlist for
vendored MANIFEST.json files (SHA-256 file hashes are not secrets).
Docs updated together with the playground HTML refactor that actually
consumes the vendored CSS (next commit). This commit is internal-only.
Phase 2 bulk replace produced a few factually wrong attributions where
real publicly known sector documents/datasets/personas were incorrectly
re-attributed to the fictional generic entity. Genericize those
references instead.
- ros-sector-checklists.md: V440 håndbok citation -> "sektorvise
faglige håndbøker"; tilsynsmyndighet list -> generic phrasing
- master-data-management-ai.md: NVDB row -> generic "sektor-/fagregistre"
- ai-center-of-excellence-setup.md: NVDB integration line -> generic
"sektorvise nasjonale registre"
- multimodal-prompt-engineering.md: system_message persona -> generic
"fagingeniør i norsk offentleg sektor"
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tiny helper command for ad-hoc multi-session flows that don't run through
/ultraexecute-local. Writes .session-state.local.json so /ultracontinue
can resume in a fresh chat. Required args (next-brief-path, next-label) —
no inline prompt, headless-safe. Validates via session-state-validator
and prints the same 3-line narration that /ultracontinue Phase 3 uses
(SC-8 cross-project consistency).
Step 9 of /ultracontinue v3.3.0. README/CLAUDE updates land in Step 11.
Extends the PreCompact hook with a sibling block that refreshes
.session-state.local.json's updated_at when status is in_progress or
partial. Per-project: runs after the existing progress.json mutation,
inside the same loop iteration.
Design:
- Only refreshes existing state files; creation is the writer's job
(ultraexecute Phase 8 / 2.55 / 4 + future helper command).
- Monotonic guard: only updated_at is touched. project, status,
next_session_brief_path, next_session_label remain owned by the writer.
- Skips status in {completed, failed, stopped} — the latter two are
operator-action-required and silently bumping updated_at would mask
alert state.
- Always exit 0; never blocks compaction.
[skip-docs] rationale: README + CLAUDE.md updates land in Step 11.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three insertions in commands/ultraexecute-local.md so every session-end
path produces or refreshes .session-state.local.json (Handover 7):
- Phase 2.55 (Check 1, line ~376): write status=stopped on dirty-tree
pre-flight stop before parallel session-spawn
- Phase 4 (line ~773): write status=stopped when entry condition fails
- Phase 8 (line ~1151): canonical convergence — every completed/failed/
stopped/partial run refreshes the state file using atomicWriteJson +
validator verification
Phase 2.3 (validate exit) and Phase 5 (dry-run) intentionally skip the
write — neither path is resumable. Validator errors warn but never block
the run; progress.json remains authoritative.
[skip-docs] rationale: README + CLAUDE.md updates land in Step 11.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Reads .claude/projects/<project>/.session-state.local.json (Handover 7),
narrates a 3-line summary, and immediately begins executing the next
session — no interactive confirmation, headless-safe.
Phases:
- 0: --help (self-documenting per brief NFR)
- 1: resolve project dir (auto-discover via node -e enumeration)
- 2: validate via session-state-validator
- 3: narrate (project / next_session_label / brief path)
- 4: read brief and begin
- 5: stats
[skip-docs] rationale: README + CLAUDE.md updates land in Step 11 (Session
2b) per plan structure. Step 8 (docs:) updates HANDOVER-CONTRACTS.md and
the doc-consistency test pin in the same session.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Plain-language UX humanizer release. Default output of all 18 commands
now leads with prose; technical IDs surface at end-of-line as references
rather than headlines. Scanner internals are unchanged; humanization is
a pure output-time transform applied at the rendering layer.
Highlights:
- New scanner-lib modules: humanizer.mjs, humanizer-data.mjs (TRANSLATIONS
for 13 scanner prefixes)
- New --raw flag threaded through every CLI for byte-stable v5.0.0
verbatim output (--json unchanged from v5.0.0, also byte-stable)
- 5 user-impact categories, 5 action-language phrases, 3 relevance contexts
- Self-audit terminal output also humanized; --json path unchanged
- 21 command and agent templates updated for humanized rendering with
--raw passthrough
- 635 → 792 tests (+157) including SC-3 forbidden-words lint, SC-4
scenario read-test, SC-5/6/7 backwards-compat snapshots
Migration:
- Existing --json automation: zero changes required (envelope is
byte-stable with v5.0.0; humanizer fields are bypassed)
- stderr-scraping tooling: review default mode (now uses prose); pass
--raw for v5.0.0 verbatim
- No scanner-internal changes (IDs, severity ladders, scoring weights,
area scorecards all unchanged)
Verification:
- 792/792 tests pass
- self-audit configGrade A (97), pluginGrade A (100), readmeCheck passed
- README badge: tests-635+ → tests-792+
- Plugin README: add "What's New in v5.1.0" section with humanizer overview,
before/after example, plain-language vocabulary table, --raw flag docs.
Bump version badge 5.0.0 → 5.1.0. Add Version History row.
- Plugin CLAUDE.md: add humanizer.mjs + humanizer-data.mjs to Scanner Lib
table. Add "Plain-Language Output (v5.1.0)" section documenting output
modes, vocabularies, and Wave 5 lessons. Bump test count 635 → 792 across
52 test files.
- Marketplace root README: bump config-audit entry 5.0.0 → 5.1.0, update
one-line description to mention plain-language UX, add bullet for the
v5.1.0 humanizer, bump test count 635+ → 792+.
Test-normalizer hardening (consequence of growing CLAUDE.md):
walkClaudeMdCascade walks upward from the marketplace-medium fixture into
this plugin's own CLAUDE.md, so any docs edit ripples into
`scanners[*].activeConfig.claudeMdEstimatedTokens`. The v5.0.0 byte-stability
contract is about scanner internals being unchanged, not ancestor input
content being frozen. Normalizers in json-backcompat, raw-backcompat,
posture-humanizer, scan-orchestrator-humanizer, and snapshot-default-output
now strip claudeMdEstimatedTokens to <ANCESTOR_DERIVED>. The
default-output snapshot for scan-orchestrator was re-seeded via
UPDATE_SNAPSHOT=1 (intent: Wave 6 docs additions; humanizer prose
unchanged).
Verify:
- grep -E "5\.1\.0|v5\.1\.0" README.md CLAUDE.md ../../README.md | wc -l = 12
- node --test 'tests/**/*.test.mjs' = 792/792 pass
- self-audit configGrade A (97), pluginGrade A (100), readmeCheck.passed true
- Bump README test-count badge: 635 → 792 (matches filesystem after Wave 0–5)
- Wire formatSelfAudit() through humanizeEnvelope + humanizeFindings so the
terminal-output path renders humanized finding titles. The --json path is
unchanged — only the prose terminal render is humanized.
- readmeCheck.passed now returns true; configGrade A (97), pluginGrade A (100)
Three changes in one commit:
1. NEW lib/util/atomic-write.mjs — exports atomicWriteJson(path, obj),
the canonical tmp+rename pattern. Reused by pre-compact-flush.mjs and
(in subsequent steps) by the new session-state writer.
2. NEW tests/lib/atomic-write.test.mjs — 4 unit tests covering
round-trip, no-orphan-tmp, overwrite-atomic, pretty-print formatting.
3. REFACTOR hooks/scripts/pre-compact-flush.mjs — replace the inline
atomicWrite() with the imported atomicWriteJson(). Also fixes a
pre-existing syntax error (leading whitespace + stray --resume token
outside the comment block) that silently broke the hook from v3.1.0
onward — PreCompact runtime is fail-open and swallowed the error.
File reformatted with standard zero-indent JS.
163 → 167 tests, 0 fail.
Step 2 of /ultracontinue v3.3.0 (project 2026-05-01-ultracontinue).
Brief assumed *.local.* covered .session-state.local.json — only *.local.md
existed. Adding *.local.json before any state file can be created.
Step 1 of /ultracontinue v3.3.0 (project 2026-05-01-ultracontinue).
Wave 5 Step 16 — final wave step. Threads humanizer-aware rendering
rules through the three agent prompts that produce user-facing output,
and adds a shape test that locks the structure.
- agents/analyzer-agent.md: documents the humanizer envelope shape
(userImpactCategory, userActionLanguage, relevanceContext) in the
Input section; new "Humanizer-aware rendering rules" subsection
instructs the agent to: render humanized title/description/
recommendation verbatim, group findings by userImpactCategory, lead
each line with userActionLanguage, surface relevanceContext when
not affects-everyone, and skip jargon-translation subroutines.
--raw fallback documented (v5.0.0 verbatim severity prefiks).
- agents/planner-agent.md: documents the same vocabulary; instructs
the planner to consume humanized fields from the analysis report,
preserve titles verbatim, and order actions by both dependencies
AND userActionLanguage urgency. Translation duties explicitly
removed from the plan.
- agents/feature-gap-agent.md: replaces the inline t1/t2/t3/t4
tier-to-prose section ladder with userActionLanguage-driven
groupings ("Fix soon" → High Impact, "Fix when convenient" →
Worth Considering, "Optional cleanup"/"FYI" → Explore When Ready);
instructs skipping findings whose relevanceContext is
test-fixture-no-impact; --raw fallback documented.
tests/agents/agent-prompt-shape.test.mjs (new, +6 tests, 786 → 792):
- structural: humanized field reference + frontmatter preserved
- per-agent anchors: analyzer groups by userImpactCategory; planner
orders by userActionLanguage; feature-gap references
test-fixture-no-impact
- global: no "explain what {jargon} means" / "translate jargon" /
"jargon-translation duty" prose anywhere
Self-audit: Grade A unchanged (config 97/100, plugin 100/100).
Wave 5 Step 15. Threads --raw plumbing through all seven action
command templates and adds a shape test covering structural plumbing
plus help.md's plain-language vocabulary.
- commands/fix.md: --raw flag parsed; fix-plan rendering groups by
userActionLanguage; humanized title/description/recommendation are
rendered verbatim from the cross-referenced scan envelope.
- commands/rollback.md: terminology pass — "manifest" → "list of
changes" in user-facing copy; the file name manifest.yaml is kept
as the machine contract; --raw threaded through.
- commands/plan.md: --raw forwarded to the planner-agent's prompt;
agent now instructed to group actions by userImpactCategory and
lead with userActionLanguage; bash block added for flag parsing.
- commands/implement.md: --raw forwarded to the implementer-agent's
prompt; progress-log lines now reference the humanized titles
already present in the action plan.
- commands/cleanup.md: --raw accepted as no-op (cleanup is
file-management only, no findings prose); bash block added.
- commands/help.md: full plain-language pass — "PreToolUse" and
"frontmatter" jargon removed from user-facing copy; new
vocabulary table surfaces the humanized userImpactCategory and
userActionLanguage labels ("Configuration mistake", "Conflict",
"Wasted tokens", "Missed opportunity", "Dead config" / "Fix this
now", "Fix soon", "Fix when convenient", "Optional cleanup",
"FYI"); --raw documented as global pass-through flag.
- commands/interview.md: --raw accepted as no-op; "unused hooks"
question phrased as "unused automation that runs at specific
events" in user-facing copy.
tests/commands/action-commands-shape.test.mjs (new, +6 tests, 780 → 786):
- structural: bash block + Read tool + --raw/$ARGUMENTS plumbing
across all 7 files
- help.md vocabulary: ≥3 userImpactCategory labels and ≥3
userActionLanguage phrases present
- help.md jargon: no bare "PreToolUse" or "frontmatter" in copy
Wave 5 Step 14. Threads the humanizer vocabulary through the remaining
six audit/analysis command templates and adds a shape test that locks
the structure plus a pair of anchor must-contains.
- commands/drift.md: --raw pass-through; new/resolved/changed-finding
rendering instructions reference userActionLanguage and
relevanceContext rather than raw severity.
- commands/plugin-health.md: --raw pass-through; finding rendering
groups by userImpactCategory and leads with userActionLanguage.
- commands/config-audit.md (router): replaces the 25-line A/B/C/D/F
prose ladder with a humanized stderr-scorecard reference + three
userActionLanguage-grouped "What you can do next" branches; --raw
threaded through both scan-orchestrator and posture invocations.
- commands/discover.md: --raw pass-through; finding-summary rendering
groups by userImpactCategory.
- commands/analyze.md: --raw pass-through; analyzer-agent prompt now
instructs grouping by userImpactCategory and leading with
userActionLanguage; humanized title/description/recommendation
strings rendered verbatim, no paraphrasing.
- commands/status.md: phase-label humanization table — current_phase
machine field name preserved, user-facing labels translated
("Looking at your config files", "Working out what to recommend",
"Asking what you'd like to focus on", "Putting together your action
plan", "Making the changes", "Double-checking everything worked");
--raw preserves verbatim machine field values.
tests/commands/group-b-shape.test.mjs (new, +8 tests, 772 → 780):
- structural: bash block + Read tool + --raw/$ARGUMENTS plumbing
across all 6 files
- findings-renderers: humanized field reference + no grade-prose
- anchor must-contains per plan: config-audit.md ⊇
userImpactCategory|userActionLanguage; drift.md ⊇ --raw|humanized
- status.md: current_phase preserved + ≥3 humanized phase labels
Wave 5 Step 13. Threads the humanizer vocabulary through five audit/
analysis command templates and adds a shape test that locks the
structure in place.
- commands/posture.md, tokens.md, feature-gap.md (findings-renderers):
reference userImpactCategory/userActionLanguage/relevanceContext;
remove hardcoded A/B/C/D/F-to-prose tables (humanizer owns the
grade-context vocabulary now via the stderr scorecard headline).
- commands/manifest.md, whats-active.md (inventory CLIs): add --raw
pass-through for CLI-surface consistency. --raw is a no-op in these
CLIs, but the flag is threaded through so users get uniform behaviour.
- All five files: --raw flag parsed from $ARGUMENTS and passed verbatim
to the underlying scanner CLI when present.
tests/commands/group-a-shape.test.mjs (new, +5 tests, 767 → 772):
- structural: every file has a bash invocation block, Read tool
reference, and --raw/$ARGUMENTS plumbing
- findings-renderers only: at least one humanized field referenced;
no hardcoded "[grade] grade is..." prose tables
Step 12 of v5.1.0 humanizer Wave 4. Adds tests/snapshot-default-output
.test.mjs and seeds three snapshots in tests/snapshots/default-output/
that capture humanized default-mode output for representative CLIs.
Coverage:
- scan-orchestrator: stdout JSON envelope (humanized findings); time
fields normalized.
- token-hotspots-cli: stdout JSON envelope (humanized payload.findings);
duration_ms normalized.
- posture: stderr humanized scorecard; (Xms) durations normalized.
Snapshot envelope is uniform on disk: { kind: 'json', payload: ... }
for JSON streams and { kind: 'text', payload: '...' } for stderr text.
This keeps the snapshot files self-describing and easy to read.
Re-seeding requires UPDATE_SNAPSHOT=1 — drift fails the test by design,
so any humanizer prose change is intentional and re-approved.
Tests: 764 to 767 (+3 SC-5 cases). Full suite passes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Step 11 of v5.1.0 humanizer Wave 4. Adds tests/raw-backcompat.test.mjs
mirroring the SC-6 contract for the --raw flag — the explicit "v5.0.0
verbatim" escape hatch.
- 4 fixture-deterministic CLIs (scan-orchestrator, posture,
token-hotspots-cli, fix-cli) get strict byte-equal against
tests/snapshots/v5.0.0/<cli>.json with time fields normalized.
- drift-cli is checked under the same contract guarded by
ensureDriftBaseline.
- 3 environment-aware CLIs (plugin-health, manifest, whats-active) are
checked for mode-equivalence (--raw equals --json).
- Posture additionally asserts its --raw stderr scorecard reproduces
tests/snapshots/v5.0.0-stderr/posture.txt verbatim, modulo (Xms)
duration markers normalized to (0ms).
- Cross-cutting suite asserts --raw findings carry no humanizer fields
on any CLI.
Tests: 751 to 764 (+13 SC-7 cases). Full suite passes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Step 10 of v5.1.0 humanizer Wave 4. Adds tests/json-backcompat.test.mjs
asserting that --json output of every CLI remains backwards-compatible
with the v5.0.0 contract.
Coverage strategy mirrors Wave 3 cli-humanizer test discovery:
- 4 fixture-deterministic CLIs (scan-orchestrator, posture,
token-hotspots-cli, fix-cli) get strict byte-equal byte-equal --json
vs frozen tests/snapshots/v5.0.0/ snapshot, with time-varying fields
(timestamp, target path, duration_ms, generatedAt, durationMs)
normalized.
- drift-cli is checked with the same byte-equal contract guarded by an
ensureDriftBaseline precondition; the test silently skips when the
baseline cannot be created.
- 3 environment-aware CLIs (plugin-health-scanner, manifest,
whats-active) read live config-cascade state, so frozen snapshots
drift as the marketplace evolves. They are verified by mode-
equivalence (--json equals --raw) instead — the same approach
established in Wave 3 cli-humanizer.test.mjs.
A cross-cutting suite asserts --json output of the 4 deterministic
CLIs never carries humanizer fields (userImpactCategory,
userActionLanguage, relevanceContext) on any finding, walking both
top-level findings arrays and scanners[].findings paths.
Tests: 739 to 751 (+12 SC-6 cases). Full suite passes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Step 9 of v5.1.0 humanizer Wave 4. Adds tests/scenario-read-test.mjs
runner, tests/scenario-read-test.test.mjs wrapper, and 5 scenario
fixtures in tests/scenarios/ that feed deterministic raw findings
through humanizeFinding and assert the humanized
title/description/recommendation match brief-owner-approved regex
patterns encoding the ground-truth what/why/whatNext answers.
Corpus selection (per brief criteria):
- 01-tok-cascade.json - TOK/CPS category (token efficiency)
- 02-cps-volatile.json - TOK/CPS category (cache prefix stability)
- 03-cnf-conflict.json - CNF category (conflicts)
- 04-gap-no-claude-md.json - GAP category (feature gap)
- 05-set-invalid-json.json - SET category, AND its v5.0.0 title +
description carry tier1 'invalid' (the brief criterion 'one finding
whose v5.0.0 description uses a forbidden word').
Runner mechanics:
- Loads scenarios matching ^\\d{2}-[a-z0-9-]+\\.json$ in sorted order.
- Calls humanizeFinding(scannerInput) and matches each humanized field
against its declared pattern (case-insensitive regex).
- Verifies humanizer-added structural fields (userImpactCategory,
userActionLanguage, relevanceContext) are non-empty strings.
- Per session decision (1a) acceptance is deterministic regex matching
without a runtime human approval gate.
Wrapper adds 3 tests: scenario-match (binds runner to node --test),
category-coverage (TOK/CPS, CNF, GAP, SET all present), and
tier1-presence (at least one v5.0.0 title or description contains a
tier1 forbidden word).
Tests: 736 to 739 (+3 SC-4 tests). Full suite passes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>