Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/copilot/constraints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Constraints

## Hard Rules

- Preserve the integration-first testing strategy documented in `docs/TESTING.md` and avoid replacing behavior coverage with narrow unit tests.
- Keep relative notation key-independent across all 12 chromatic roots and do not regress other notation modes when modifying scale generation.
- Maintain keyboard accessibility for interactive controls, including Enter/Space activation, focus visibility, and focus return from overlays.
- Treat Yarn as the package manager for repo workflows; if a shell lacks `yarn`, use `corepack yarn` rather than switching the repo guidance to npm.
- When runtime behavior changes in a documented path, update the matching flow doc in `.github/skills/flows/`.

## Protected Contracts

| Contract | Pattern | Enforcement | Why |
| --- | --- | --- | --- |
| Music scale generation and notation contracts | `src/Model/MusicScale.js` | `ask` | This file defines scale construction and all notation outputs, including relative solfege invariants used across the app. |
| App state orchestration and session hydration | `src/WholeApp.js` | `ask` | `WholeApp` owns most state transitions, menu callbacks, and Firebase session serialization/deserialization. |
| Shared-session route handoff | `src/WholeAppWrapper.js` | `ask` | The wrapper is the only bridge from React Router params into the class-based app shell. |

## Security Boundaries

| Boundary | Pattern | Enforcement | Why |
| --- | --- | --- | --- |
| Firebase client persistence boundary | `src/Firebase.js` | `ask` | This file controls client access to Firestore and is the only persistence boundary in the repo. |
| Session sharing surface | `src/components/menu/Share*.js` | `ask` | Share-link creation crosses from local UI state into persisted remote session data. |
| User-supplied video URL handling | `src/components/menu/CustomVideoPlayer.js` | `ask` | Video URLs flow into ReactPlayer or iframe embeds and should be treated as security-sensitive input handling. |

## Fragile Areas

| Area | Pattern | Enforcement | Why |
| --- | --- | --- | --- |
| Keyboard interaction and module-scoped state | `src/components/keyboard/**` | `ask` | Keyboard input, audio triggering, and module-level mutable state are tightly coupled and easy to regress. |
| Top-level menu fan-out | `src/components/menu/TopMenu.js` | `ask` | This file fans user actions into most app handlers and affects multiple runtime flows at once. |
| Accessibility integration tests | `src/__integration__/accessibility/**` | `ask` | These tests are the strongest automated guard for keyboard and aria regressions. |
| Relative-notation regression tests | `src/__test__/**/*relative*.test.js` | `ask` | These tests protect a domain invariant that has regressed before and should not be casually edited. |

## Performance Boundaries

| Path | Constraint |
| --- | --- |
| `src/Model/MusicScale.js` | Keep scale and notation generation effectively constant-time for the current recipe lookup strategy. |
| `src/components/keyboard/**` | Avoid unnecessary full-keyboard rebuilds or extra global DOM queries on every interaction. |
| `e2e/**` | Keep individual E2E cases within the 30-second Playwright timeout documented by the repo config. |

## Dangerous Commands

| Pattern | Why |
| --- | --- |
| `rm\s+-rf\s+build` | Build output removal is acceptable only when the user explicitly asks for a clean rebuild. |
| `git\s+push\s+.*--force` | Force-pushing on this repo can overwrite collaborator history. |
24 changes: 24 additions & 0 deletions .github/copilot/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
This project uses the copilot development system.

Active tasks: check `.github/copilot/tasks/`. If `task.md` phase is not `done`, read it first because the Changelog section is the recovery log.
Project context: `project-context.md` for stack, domain, module layout, and conventions.
Constraints: `constraints.md` before modifying code. Sections with `Pattern` and `Enforcement` columns are hook-enforced and may require user confirmation.
Hooks: `.github/hooks/` contains project guardrails. Do not change hook scripts without explicit user approval.
Flows: `.github/skills/flows/` contains the runtime flow catalog. Read the affected flow doc before behavior changes and update it after behavior changes.
Project skills: repo-local skills live under `.github/skills/` and should be preferred when relevant.

## Project-Specific Guidance

- This repo is a React 18 music-education SPA with a central `WholeApp` state container, `MusicScale` domain logic, `SoundMaker` audio adapters, and Firebase-backed session sharing.
- The repo uses Yarn workflows. If a shell lacks a global `yarn`, use `corepack yarn` instead of rewriting commands to npm.
- Testing is integration-first and accessibility-heavy. Preserve `docs/TESTING.md` expectations, especially the a11y layers and 100% coverage target.
- Changes in `src/Model/MusicScale.js`, `src/components/keyboard/`, `src/components/menu/CustomVideoPlayer.js`, or session-sharing files should trigger a flow review because they affect documented runtime paths.
- Treat `CLAUDE.md` as a source of domain-specific constraints, especially relative-notation invariants and accessibility expectations.

## Documentation References

- See `README.md` for install, dev server, build, deploy, and top-level testing commands.
- See `docs/TESTING.md` for the testing strategy, accessibility test layers, coverage expectations, and the test distribution validator.
- See `CLAUDE.md` for repo-specific accessibility patterns, relative-notation rules, and feature-derived development constraints.

Use `/begin-task` to start work. Use `/flows` to trace runtime behavior. Use `/flow-impact` to compare before and after behavior.
36 changes: 36 additions & 0 deletions .github/copilot/dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Dependencies

## Core

| Dependency | Version | Purpose | Notes |
| --- | --- | --- | --- |
| react | ^18.2.0 | Primary UI framework | App is still organized around a large class-based root component. |
| react-dom | ^18.2.0 | DOM renderer | Used with `createRoot` in the SPA entry point. |
| react-router-dom | ^6.3.0 | Client-side routing | Handles `/` and `/shared/:sessionId` flows. |
| react-scripts | 5.0.1 | Build and test toolchain | CRA stack with embedded ESLint config and Jest integration. |
| firebase | ^10.9.0 | Firestore session persistence | Client SDK only; session sharing depends on it. |
| tone | ^14.7.77 | Audio synthesis support | Used via `SoundMaker` adapters for playback. |
| @tonejs/piano | ^0.2.1 | Sampled piano playback | Tone.js-backed piano instrument. |
| soundfont-player | ^0.12.0 | Alternate audio backend | Present behind the adapter layer. |
| vexflow | ^4.0.3 | Music notation rendering | Used for staff rendering surfaces. |
| react-bootstrap | ^2.5.0 | Menu and UI components | Used in the top menu and related controls. |
| react-player | ^2.10.1 | Embedded video playback | Powers the custom video overlay. |
| react-draggable | ^4.4.5 | Draggable overlay behavior | Used by the custom video player UI. |
| react-tooltip | ^4.2.21 | Tooltip UI | Drives help and hover guidance across controls. |
| sass | ^1.54.9 | SCSS compilation | Styles are organized under `src/styles/`. |
| webmidi | ^2.0.0 | MIDI device input | Supports external keyboard interaction. |

## Dev

| Dependency | Version | Purpose |
| --- | --- | --- |
| eslint | ^8.3.0 | Standalone lint command for repo validation and DAL-A setup workflows |
| jest | ^29.0.3 | Test runner for unit and integration coverage |
| @testing-library/react | ^13.0.0 | Integration testing of React components |
| @testing-library/jest-dom | ^5.16.5 | DOM-focused Jest matchers |
| @testing-library/user-event | ^13.2.1 | User interaction simulation in tests |
| jest-axe | ^10.0.0 | Accessibility assertions in Jest |
| @playwright/test | ^1.56.1 | End-to-end testing |
| @axe-core/playwright | ^4.11.0 | Accessibility assertions in Playwright |
| @axe-core/react | ^4.11.0 | Development-time accessibility auditing |
| react-test-renderer | ^18.2.0 | Snapshot and renderer-based tests |
88 changes: 88 additions & 0 deletions .github/copilot/project-context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
project: "notio"
domain: "frontend"
stack:
language: "JavaScript ES6+"
framework: "React 18 with React Router v6"
build: "react-scripts (CRA)"
package_manager: "yarn (via Corepack when yarn is not globally installed)"
test_framework: "Jest, React Testing Library, Playwright"
architecture: "single-page React application with a central WholeApp state container, model helpers for music/audio logic, and Firebase-backed session sharing"
---

# Project Context

## Module Structure

```text
src/
components/
Model/
data/
styles/
__integration__/
__test__/
e2e/
accessibility/
docs/
.github/
copilot/
hooks/
skills/
```

## Patterns

| Concern | Approach |
| --- | --- |
| Error handling | UI state is managed centrally in `WholeApp`; some async flows still degrade silently and should be treated carefully during edits |
| State management | `WholeApp` owns app state and passes handlers/props down into menus, keyboard, overlays, and wrappers |
| Data access | Firebase Firestore is used directly from the client for shareable session persistence |
| Testing | Integration-first testing with accessibility coverage and Playwright for end-to-end validation |

## Conventions

- Preserve the integration-first testing split documented in the repo: integration tests first, E2E second, unit tests only for edge cases.
- Treat `src/Model/MusicScale.js` as a protected domain contract: notation arrays and relative solfege behavior must stay backward-compatible.
- Keep accessibility semantics on interactive UI elements, especially keyboard handlers, `aria-label`, and focus return behavior.
- Use Yarn-oriented workflow and commands for this repo; when the shell lacks a global `yarn`, use `corepack yarn`.
- Update the relevant flow doc under `.github/skills/flows/` whenever behavior changes in a documented runtime path.

## Existing Documentation

| Document | Covers |
| --- | --- |
| `README.md` | Project purpose, install/run/build/deploy commands, testing entry points, and dependency notes |
| `docs/TESTING.md` | Integration-first testing policy, accessibility testing layers, coverage requirements, and test distribution validation |
| `CLAUDE.md` | Repo-specific development guidance, accessibility patterns, relative-notation invariants, and recent feature constraints |

## System Flow Overview

```mermaid
flowchart TB
subgraph routing["Routing and App Shell"]
A["index.js routes"] --> B["WholeApp or WholeAppWrapper"]
end
subgraph state["App State and Domain"]
B --> C["WholeApp state handlers"]
C --> D["MusicScale and SoundMaker"]
end
subgraph ui["Interactive Surfaces"]
D --> E["Keyboard rendering and playback"]
C --> F["TopMenu, overlays, sharing"]
end
subgraph persistence["Persistence"]
C --> G["Firebase session save and restore"]
end
```

## Critical Flows

| Flow | Link |
| --- | --- |
| app-bootstrap | [→](../skills/flows/app-bootstrap.md) |
| scale-change-pipeline | [→](../skills/flows/scale-change-pipeline.md) |
| note-playback | [→](../skills/flows/note-playback.md) |
| session-share | [→](../skills/flows/session-share.md) |
| video-overlay | [→](../skills/flows/video-overlay.md) |
| settings-propagation | [→](../skills/flows/settings-propagation.md) |
26 changes: 26 additions & 0 deletions .github/copilot/tasks/dal-a-project-setup/task.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: "DAL-A project setup"
slug: "dal-a-project-setup"
phase: "done"
goal: "Initialize DAL-A project intelligence for this repo by scanning conventions and docs, documenting flows, and generating .github/copilot, flow docs, and applicable hooks."
current_action: "Generated DAL-A project files, repo-local flow docs, and hook scaffolding; validation completed with an environment note on lint installation."
---

Initialize DAL-A project intelligence for this repo by scanning conventions and docs, documenting flows, and generating `.github/copilot`, flow docs, and applicable hooks.

## Decisions

- 2026-04-18: Treat this as a first-time DAL-A setup because `.github/copilot/project-context.md` does not exist in the repo.

## Changelog

- 2026-04-18: Task created with confirmed goal; implementation not started yet.
- 2026-04-21: Inventoried `CLAUDE.md`, `README.md`, and `docs/TESTING.md`; confirmed a React-only frontend app with Firebase session sharing and no backend directory.
- 2026-04-21: Generated `.github/copilot/project-context.md`, `constraints.md`, `dependencies.md`, and `copilot-instructions.md`.
- 2026-04-21: Created repo-local runtime flow docs under `.github/skills/flows/` with Mermaid diagrams for bootstrap, scale, playback, sharing, video, and settings propagation.
- 2026-04-21: Added `.github/hooks/hooks.json` and hook scripts for constraint enforcement, dangerous command prompts, flow reminders, and constraint forwarding.
- 2026-04-21: Added a standalone `lint` script and direct `eslint` devDependency entry in `package.json`; executable lint validation remains blocked because this environment lacks installed dependencies and Yarn registry resolution failed.

## Improvements Queued

- None currently.
48 changes: 48 additions & 0 deletions .github/copilot/tasks/issue-350-order-of-notations/task.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: "Issue #350 order of notations"
slug: "issue-350-order-of-notations"
phase: "done"
goal: "Make notation layers stack bottom-to-top in the UI in the exact order of the Notation checkbox list, and keep that order stable across all interactions, without regressing other notation modes or accessibility."
current_action: "Task complete. Fix pushed to branch issue-350-order-of-notations-fix; PR #351 updated with new description."
---

Fix GitHub issue [#350](https://github.com/NYUMusEdLab/notio/issues/350). The reporter observed that notation stacking on the staff sometimes becomes reversed/random, with scale-step and chord-extension numbers ending up below note names. The expected behavior is a stable stacking order that matches the order of items in the Notation checkbox list, bottom-to-top.

## Constraints

- No regressions to other notation modes or accessibility.
- Must include automated regression tests.
- Scope: UI stacking order only (not an end-to-end re-architecture).
- This branch already has commit `fb80ceb` from a previous attempt; user chose "revert and replan", so the prior approach must be undone as part of this task.

## Decisions

| Date | Decision | Rationale |
| --- | --- | --- |
| 2026-04-21 | Revert prior fix commit `fb80ceb` and replan | Discovery showed it fixed the wrong seam (generic `ListCheckbox`) and missed the session-restore path |
| 2026-04-21 | Scope limited to UI stacking order | Keyboard label ordering out of scope unless proven same root cause |
| 2026-04-21 | Approach: Option 1 — state-boundary normalization in `WholeApp` | Single source of truth; fixes restored-array bug; small, test-friendly |
| 2026-04-21 | Visual direction: DOM order = canonical list order (Chord extensions on top, English at bottom) | `.noteWrapper` uses `flex-direction: column`, so DOM top = visual top; consistent with the issue reporter's expectation that numbers appear above note names |
| 2026-04-21 | Git cleanup via `git revert fb80ceb` (no force-push) | Preserves history; safe on already-pushed branch |

## Roadmap

- [x] Slice 1 — Revert `fb80ceb` and restore a clean baseline on branch `issue-350-order-of-notations-fix`.
- [x] Slice 2 — Add failing integration tests asserting rendered notation row order after menu writer and session-restore writer, with confirmed visual direction (Chord extensions on top, English at bottom).
- [x] Slice 3 — Introduce `normalizeNotationOrder` helper and apply it at every writer of `state.notation` in `WholeApp` (`handleChangeNotation`, session-restore, defaults); verify tests pass.
- [x] Slice 4 — Regression sweep: run full test suite + targeted a11y checks; update flow docs if behavior changed; push branch and update PR.

## Changelog

- 2026-04-21: Task created with confirmed goal and constraints; prior fix commit noted for revert.
- 2026-04-21: Discovery completed; identified `WholeApp` → `Keyboard` → `ColorKey` as the real ownership path and `WholeApp` session-restore as the missed seam.
- 2026-04-21: Roadmap confirmed (Option 1 — state-boundary normalization); visual direction and git cleanup strategy locked in.
- 2026-04-21: Slice 1 complete. Committed DAL-A setup (2348949), rewrote task.md (92a05bb), and reverted fb80ceb via `git revert` (72e321b). `src/components/form/ListCheckbox.js` and deletion of `src/__test__/ListCheckbox.order.test.js` now diff-clean vs `origin/master`. Branch is 3 commits ahead of master; origin PR not yet updated.
- 2026-04-21: Visual direction disambiguated with product: Chord extensions on top, English at bottom; DOM order = canonical order.
- 2026-04-21: Slice 2 complete. Added `src/__integration__/notation-order.test.js` with two failing tests covering the menu writer and session-restore writer paths. Both fail on current baseline with the expected "order mirrors scrambled input" diff. Test runtime ~4s (within integration-suite budget).
- 2026-04-21: Slice 3 complete. Added `src/Model/normalizeNotationOrder.js` helper and wired it into `handleChangeNotation`, `openSavedSession`, and a new `componentDidUpdate` safety net in `WholeApp.js` (Approach 3 — defense in depth). Both Slice 2 tests now pass; adjacent integration suites (34 tests) still pass.
- 2026-04-21: Slice 4 complete. Full test suite ran: 301/306 pass. The 5 failures (`notation-regression.test.js`, `relative-notenames.test.js`, `CustomVideoPlayer.integration.test.js`) were verified to fail identically on `origin/master` — pre-existing, unrelated to this fix. Updated `.github/skills/flows/settings-propagation.md` with the new canonical-order invariant. Pushed 7 commits to `origin/issue-350-order-of-notations-fix` (fast-forward, no force-push). Updated PR #351 body to reflect the new approach.

## Improvements Queued

- None yet.
34 changes: 34 additions & 0 deletions .github/hooks/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"hooks": {
"PreToolUse": [
{
"type": "command",
"command": "python .github/hooks/scripts/constraint-guard.py",
"windows": "python .github/hooks/scripts/constraint-guard.py",
"timeout": 10
},
{
"type": "command",
"command": "python .github/hooks/scripts/dangerous-command-guard.py",
"windows": "python .github/hooks/scripts/dangerous-command-guard.py",
"timeout": 10
}
],
"PostToolUse": [
{
"type": "command",
"command": "python .github/hooks/scripts/flow-verification-reminder.py",
"windows": "python .github/hooks/scripts/flow-verification-reminder.py",
"timeout": 10
}
],
"SubagentStart": [
{
"type": "command",
"command": "python .github/hooks/scripts/constraint-forwarding.py",
"windows": "python .github/hooks/scripts/constraint-forwarding.py",
"timeout": 10
}
]
}
}
Loading
Loading