๐Ÿ“Š Testing Dashboard & Enforcement System

โ€œYou read a scroll labeled TEST ENFORCEMENT SYSTEM. You feel a sense of discipline.โ€

Overview

This project implements mandatory test logging with a visual dashboard to track test quality over time and prevent regressions. Itโ€™s like the Rogue Monitor, but for your code quality.

The Oracle says: โ€œA test not logged is a bug waiting to happen. Choose your commits wisely, for they shall be measured.โ€

See also: docs/PARITY_TEST_MATRIX.md โ€” the canonical reference for what parity means operationally: test commands, session categories and counts, comparison channels, deterministic controls, and quality gates.

โœ… Official Test Run Paths

Use these as the canonical commands:

npm run test:unit      # unit tests
npm run test:e2e       # end-to-end browser tests
npm run test:session   # C-parity session tests

Session-parity coverage (C-grounded coverage signal):

npm run coverage:session-parity

Notes:

Aggregate commands:

npm test               # unit + session
npm run test:all       # unit + session + e2e

Session tests can include many logical subtypes (chargen, map, gameplay, special, interface, options), but they all run through one path: npm run test:session (test/comparison/sessions.test.js).

Runtime Guardrails

Fast feedback is required to catch hanging bugs early:

๐ŸŽฏ Two Approaches Available

You see here two scrolls:

a) Git Notes Approach โญ (blessed)

Authoritative data: Git notes attached to commits Dashboard data: Mirrored JSONL (one commit behind)

Advantages:

Documentation: docs/TESTING_GIT_NOTES.md

This scroll appears to be blessed. Would you like to read it? [yn]

b) Two-Commit Approach (uncursed, but dusty)

All data: In oracle/results.jsonl Workflow: Code commit + test log commit

Advantages:

Disadvantages:

Documentation: TESTING.md

This scroll looks old and worn. It might still work, but the blessed one is shinier.

๐Ÿš€ Quick Start (Git Notes)

The scroll reads: โ€œSpeak these incantations to summon the Testing Daemonโ€ฆโ€

1. Enable Git Hooks & Configure Auto-Push

# Engrave Elbereth... er, enable hooks
git config core.hooksPath .githooks

# Auto-push notes with commits (like a wand of teleportation for your data)
git config --add remote.origin.push '+refs/notes/test-results:refs/notes/test-results'

# setup.sh now configures merge.keepnewest automatically for:
#   _data/version.yml and js/version.js
# If needed manually:
# git config merge.keepnewest.name "keep higher version counter"
# git config merge.keepnewest.driver "bash scripts/git-merge-keepnewest.sh %O %A %B"

You feel your repository becoming more disciplined.

2. Make Changes & Commit

Use the magic helper scroll for easy workflow:

# Edit files (apply a blessed +1 fix to your code)
vim js/levels/themerms.js

# Commit with automatic testing (cast "test and log"!)
.githooks/commit-with-tests-notes.sh "Fix reservoir sampling" js/levels/themerms.js

# Push (ascend with the Amulet!)
git push

The voice of the Oracle echoes: โ€œYour tests have been logged. The dashboard shows 137 passing tests. This is a good thing.โ€

Thatโ€™s it! The scroll of commit-with-tests handles:

  1. โš—๏ธ Committing your code (mixing the potion)
  2. ๐Ÿ”ฌ Running tests and saving to git note (identifying the potion)
  3. ๐Ÿ“œ Syncing notes to results.jsonl (updating your conduct)
  4. ๐Ÿ’พ Committing the updated JSONL (engraving Elbereth)
  5. โœจ Ready to push! (ascending the stairs)

๐Ÿ“ˆ View Dashboard

The Oracleโ€™s Chamber (GitHub Pages):

https://davidbau.github.io/mazesofmenace/oracle/

A mysterious force prevents you from accessing this until you push to GitHub.

Local Divination:

open oracle/index.html

You gaze into the crystal ball and see the future of your test suiteโ€ฆ

๐ŸŽฏ Key Features

Test Enforcement

The Wizard of Yendor enforces these rules:

Violate these, and thou shalt not pass!

Dashboard

The Oracleโ€™s crystal ball reveals:

๐Ÿ“ Inventory

You are carrying:

oracle/
โ”œโ”€โ”€ index.html          # a) blessed scroll of Dashboard UI
โ”œโ”€โ”€ dashboard.js        # b) wand of Visualization (0:โˆž)
โ”œโ”€โ”€ dashboard.css       # c) cloak of Styling [+0]
โ”œโ”€โ”€ results.jsonl       # d) Book of Test History (mirrored from notes)
โ””โ”€โ”€ schema.json         # e) scroll labeled "LOG FORMAT"

.githooks/
โ”œโ”€โ”€ pre-push-notes      # f) magic trap (triggers on push)
โ”œโ”€โ”€ pre-commit          # g) squeaky board (sync notes โ†’ JSONL)
โ”œโ”€โ”€ test-and-log-to-note.sh       # h) wand of Testing
โ”œโ”€โ”€ sync-notes-to-jsonl.sh        # i) ring of Synchronization
โ”œโ”€โ”€ commit-with-tests-notes.sh    # j) blessed scroll of Easy Workflow
โ”œโ”€โ”€ pre-push            # k) dusty magic trap (legacy)
โ”œโ”€โ”€ test-and-log.sh     # l) old wand of Testing (uncharged)
โ”œโ”€โ”€ commit-with-tests.sh  # m) worn scroll (legacy)
โ””โ”€โ”€ README.md           # n) scroll of Hook Documentation

docs/
โ”œโ”€โ”€ TESTING_GIT_NOTES.md  # o) spellbook of Git Notes โญ
โ””โ”€โ”€ TESTING.md            # p) old spellbook (still readable)

.github/workflows/
โ””โ”€โ”€ test-enforcement.yml  # q) Scroll of GitHub Actions

Your pack weighs 0 zorkmids. You are not burdened (everything is in git!)

๐Ÿ”„ How Git Notes Workflow Works

The Oracle explains with a diagram:

graph LR
    A[๐Ÿ“ Edit Code] --> B[๐Ÿ’พ Commit Code]
    B --> C[๐Ÿงช Run Tests]
    C --> D[๐Ÿ“Œ Save to Git Note]
    D --> E[๐Ÿ”„ Sync Notes โ†’ JSONL]
    E --> F[๐Ÿ’ฟ Commit JSONL]
    F --> G[๐Ÿš€ Push Both]

The Chicken-and-Egg Problem (a.k.a. The Paradox of Temporal Causality)

Problem: โ€œHow can a commit name itself ere it exists? โ€˜Tis like trying to eat a cockatrice corpse before thou hast slain it!โ€

A commit canโ€™t contain its own hash in a file because the hash doesnโ€™t exist until after the commit is created.

Solution: Git notes! โ€œThe Wizards of old solved this with a clever trickโ€ฆโ€

โ€œA blessed solution indeed! The Wizard approves.โ€

Architecture (The Dungeon Layout)

         Level 1: Git Notes (Authoritative)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  refs/notes/test-results                       โ”‚
โ”‚  "The vaults where true knowledge is stored"   โ”‚
โ”‚                                                 โ”‚
โ”‚  commit abc123 โ†’ {results for abc123}          โ”‚
โ”‚  commit def456 โ†’ {results for def456}          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
             โ”‚ โ†“ sync-notes-to-jsonl.sh
             โ”‚   (A stairway down...)
         Level 2: JSONL Mirror
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  oracle/results.jsonl                       โ”‚
โ”‚  "A magical mirror reflecting level 1"         โ”‚
โ”‚                                                 โ”‚
โ”‚  One entry per commit, chronologically sorted  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
             โ”‚ โ†“ GitHub Pages
             โ”‚   (The astral plane...)
       The Oracle's Chamber
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  https://github.io/.../oracle/              โ”‚
โ”‚  "Where mortals come to seek wisdom"           โ”‚
โ”‚                                                 โ”‚
โ”‚  ๐Ÿ“Š Timeline, Charts, Scrubber                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ“ Test Log Format (The Scroll of Recording)

JSONL (newline-delimited JSON) - one entry per commit:

{"commit":"abc123","date":"2026-02-11T10:30:00Z","stats":{"total":631,"pass":137,"fail":494},"regression":false,...}

Each line is a complete message. Together they form the Book of Testing.

Benefits (or: Why JSONL is a blessed +2 format):

โš ๏ธ Handling Regressions

The Wizard is displeased. Your test count decreased! Choose thy path:

Path A: Fix the Regression (Lawful)

โ€œThe righteous path. Make things right.โ€

# Fix the issue (quaff a potion of restore ability)
vim js/file.js
git add js/file.js
git commit --amend --no-edit

# Re-run tests (pray at the altar)
.githooks/test-and-log-to-note.sh

The Wizard smiles upon you. +1 Wisdom.

Path B: Allow Regression (Neutral, Requires Justification)

โ€œSometimes the greater good requires temporary setbacks. But thou must explain thyself!โ€

# Run tests with override flag (eat a cursed scroll knowingly)
.githooks/test-and-log-to-note.sh --allow-regression

# Then follow normal workflow

The Wizard eyes you suspiciously. Youโ€™d better have a good explanation in your commit message!

Example good justification:

Allow regression: fixing core algorithm

The reservoir sampling fix causes 25 test failures because it changes
the RNG sequence. The failures are cascading effects, not actual bugs.
The algorithm is now correct per C source verification. Like killing
the Wizard to get the Book - necessary, but temporarily painful.

Acceptable. -1 Charisma, but +3 Wisdom for being honest.

Path C: Push Anyway (Chaotic, Forbidden)

git push --no-verify  # DON'T DO THIS

The Wizard of Yendor appears! โ€œSo thou thought thou couldst cheat?โ€ โ€“Moreโ€“

The Wizard casts a spell of CI FAILURE at you! GitHub Actions rejects your push.

You dieโ€ฆ Do you want your possessions identified? [ynq]

๐Ÿ› ๏ธ Troubleshooting (Common Mishaps)

โ€œTests Not Runningโ€ (You see here a scroll that does nothing)

# Verify hook setup (check if you're wearing the amulet)
git config core.hooksPath
# Should output: .githooks

# Ensure executable (bless the scrolls)
chmod +x .githooks/*

The scrolls were cursed (not executable)! They work now.

โ€œNotes Not Pushingโ€ (Your items scatter!)

# Check if notes exist (search the floor)
git notes --ref=test-results list

# Manual push (throw the items upstairs)
git push origin refs/notes/test-results

# Or configure automatic push (hire a pack animal)
git config --add remote.origin.push '+refs/notes/test-results:refs/notes/test-results'

Now your notes follow you everywhere! Like a loyal dog, but for git.

โ€œDashboard Not Updatingโ€ (The crystal ball is cloudy)

# Rebuild JSONL from git notes (polish the crystal ball)
.githooks/sync-notes-to-jsonl.sh

# Commit and push (present it to the Oracle)
git add oracle/results.jsonl
git commit -m "Rebuild dashboard from git notes"
git push

The mists clear. You see your test results!

โ€œMissing Notes After Cloneโ€ (You feel empty handed)

# Fetch notes (search the level you just arrived on)
git fetch origin refs/notes/test-results:refs/notes/test-results

# Rebuild dashboard (reconstruct from memory)
.githooks/sync-notes-to-jsonl.sh

You find everything where you left it! (Well, where git left it.)

๐Ÿ“š Scrolls of Knowledge

A library. The shelves are lined with dusty tomes:

Which scroll would you like to read?

๐ŸŽฏ The Four Noble Truths of Testing

The Oracle speaks:

  1. Prevent regressions - โ€œNever let test quality degrade silently, lest bugs multiply like killer beesโ€
  2. Track progress - โ€œVisualize test improvements over time, for what is measured improvesโ€
  3. Enforce discipline - โ€œEvery commit must be tested, as every meal must be eatenโ€
  4. Enable debugging - โ€œHistorical data helps identify when bugs were introduced, like tracking monster movementโ€

๐Ÿค Conduct for Adventurers (Contributing)

All who enter the dungeon must follow these rules:

  1. Enable git hooks: git config core.hooksPath .githooks โ€œEquip your armor before battleโ€

  2. Configure auto-push: git config --add remote.origin.push '+refs/notes/test-results:refs/notes/test-results' โ€œEnsure your achievements are recordedโ€

  3. Run tests before pushing โ€œLook before you leap into the pitโ€

  4. Never push regressions without explicit justification โ€œDo not anger the Wizard without good reasonโ€

  5. Use .githooks/commit-with-tests-notes.sh helper for easy workflow โ€œUse your blessed scroll - why make things harder?โ€

Violators will be turned into newts. (They might get better, but probably not.)

โ“ The Oracle Answers Common Questions

Q: Why git notes instead of files in commits? Oracle: โ€œThe chicken-and-egg problem - a commit cannot name itself ere it exists! Git notes are attached AFTER creation, solving the paradox. โ€˜Tis like casting identify AFTER picking up the ring.โ€

Q: Why is the dashboard one commit behind? Oracle: โ€œThe pre-commit hook syncs notes โ†’ JSONL, so the current commitโ€™s note isnโ€™t synced yet. This is the price of temporal consistency. Fear not - the dashboard shows historical data, not real-time divination.โ€

Q: Can I see notes in GitHub UI? Oracle: โ€œAlas, no. Notes dwell in the shadow plane, invisible to GitHubโ€™s web interface. Use git notes commands or view the dashboard instead.โ€

Q: What if I forget to push notes? Oracle: โ€œConfigure automatic push (see setup above). Then git push carries all - commits AND notes - like a bag of holding for your achievements.โ€

Q: What happens on merge? Oracle: โ€œNotes from both branches are preserved, like items from merged inventories. The sync script rebuilds JSONL sorted chronologically. All is well.โ€

Q: Can I still use the two-commit approach? Oracle: โ€œAye. Both scrolls work, though one is blessed. See TESTING.md for the ancient way.โ€

Q: What if I break the build? Oracle: โ€œThe Wizard will beโ€ฆ displeased. Fix it quickly, or face the wrath of CI. Your shame will be recorded in the dashboard for all to see. This is the way.โ€


You read the final line of the scrollโ€ฆ

View live dashboard: https://davidbau.github.io/mazesofmenace/oracle/

The scroll crumbles to dust. You feel enlightened about testing.

Would you like to write your name in the high score table? [yn] y

                    .githooks/commit-with-tests-notes.sh
                    =====================================
                       Your Path to Testing Glory

May your tests always pass, and your merges always be conflict-free.

Happy hacking, adventurer!

๐ŸŽฎ Achievement Unlocked

Your current conduct: Testing discipline (not broken). Keep it up!


๐Ÿ“Š Backfilling Test History

โ€œThe Oracle can see the pastโ€ฆ if you help her remember.โ€

Want to populate the dashboard with historical data? The backfill script runs tests on old commits:

Quick Start

# See what would be tested (dry run)
scripts/backfill-test-history-safe.sh --dry-run

# Backfill last 10 commits (safe, fast)
scripts/backfill-test-history-safe.sh

# Backfill more history
scripts/backfill-test-history.sh 50

# After backfilling, sync and commit
.githooks/sync-notes-to-jsonl.sh
git add oracle/results.jsonl
git commit -m "Backfill test history"
git push origin refs/notes/test-results

How It Works

The backfill script:

  1. โœ… Finds commits without test notes
  2. โœ… Checks out each commit
  3. โœ… Runs tests (if possible)
  4. โœ… Creates git note with results
  5. โœ… Skips commits where tests donโ€™t work
  6. โœ… Restores your original state

Each git note contains only that commitโ€™s results (not cumulative). The JSONL file aggregates all notes for the dashboard.

Safety Features

What Gets Skipped

This is fine! The backfill is best-effort.