From 8e11cbab88466fea3d57e9431b658ff404d5919f Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Wed, 22 Jul 2026 17:41:04 +0000 Subject: [PATCH 1/5] Add Claude Code web SessionStart hook (canonical Tap House setup) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fresh web-session containers clone bare: no submodules, no pre-commit hook — so commits run unformatted and the clang-format CI gate fails on code a local clone would have fixed at commit time (exactly what happened on the tap.tune~ PR). The hook closes the gap at session start: recursive submodule init, pre-commit install against the repo's canonical pinned config, and a hook-environment warm so the container snapshot caches the pinned clang-format. Web-only (CLAUDE_CODE_REMOTE guard), synchronous, idempotent. Candidate for the taphouse sync set so the whole Tap family carries the same hook. .gitignore now ignores .claude/* except the checked-in settings and hooks. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01BuUawafae7RR2ySWabuJcs --- .claude/hooks/session-start.sh | 36 ++++++++++++++++++++++++++++++++++ .claude/settings.json | 14 +++++++++++++ .gitignore | 4 +++- 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100755 .claude/hooks/session-start.sh create mode 100644 .claude/settings.json diff --git a/.claude/hooks/session-start.sh b/.claude/hooks/session-start.sh new file mode 100755 index 0000000..aedace8 --- /dev/null +++ b/.claude/hooks/session-start.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Canonical Tap House SessionStart hook for Claude Code on the web. +# +# Fresh web-session containers clone the repo bare: no submodules, no +# pre-commit hook installed — so `git commit` runs unformatted and the +# clang-format CI gate fails on code a local clone would have fixed at commit +# time. This hook closes that gap at session start: +# +# 1. init submodules recursively (kernels, SDKs, vendored test harnesses) +# 2. install pre-commit and register the repo's canonical hook +# (.pre-commit-config.yaml — the Tap-wide pinned clang-format) +# 3. warm the pinned clang-format binary so the first commit doesn't +# pay the download (the container snapshot caches it) +# +# Candidate for the taphouse sync set (scripts/sync.sh) alongside +# .clang-format / .clang-tidy / .pre-commit-config.yaml, so every Tap repo +# carries the same hook. Web-only; local clones are untouched. +set -euo pipefail + +if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then + exit 0 +fi + +cd "$CLAUDE_PROJECT_DIR" + +echo "session-start: initializing submodules ..." +git submodule update --init --recursive + +echo "session-start: installing pre-commit ..." +if ! python3 -m pre_commit --version >/dev/null 2>&1; then + python3 -m pip install --quiet pre-commit +fi +python3 -m pre_commit install +python3 -m pre_commit install-hooks + +echo "session-start: done." diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..e06b033 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,14 @@ +{ + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh" + } + ] + } + ] + } +} diff --git a/.gitignore b/.gitignore index 27d6dd7..993115e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,7 @@ compile_commands.json CMakeUserPresets.json .vscode/ .idea/ -.claude/ +.claude/* +!.claude/settings.json +!.claude/hooks/ build_capi/ From 90cc524c82155480b25ab71863d71857197ca0d9 Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Wed, 22 Jul 2026 17:46:56 +0000 Subject: [PATCH 2/5] =?UTF-8?q?Add=20CLAUDE.md=20=E2=80=94=20agent=20guida?= =?UTF-8?q?nce=20for=20the=20primitives=20repo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The design discipline (fixed numeric contracts, golden double model + float32 profile, real-time-safe construction, plain hot loops as backend seams, published-literature-only IP policy, honest limits), the style gates (pre-commit + the web SessionStart hook; clang-tidy as a second compiler), build/test conventions including the oracle patterns, the capi/notebook verification layer, an adding-a-primitive checklist, and the consumer pin flow. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01BuUawafae7RR2ySWabuJcs --- CLAUDE.md | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..20a7d86 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,87 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +**DspTap** — shared DSP primitives for the Tap family of audio libraries. Header-only, plain +portable C++20 (standard library only, no frameworks), consumed as a git submodule by the +individual libraries (TapTools pins it as `submodules/dsptap`; the AmbiTap/MuTap lineage is where +the FFT came from). Four primitives today: the real FFT (`fft.h`), the YIN pitch detector +(`yin.h`), and two pitch shifters (`psola.h`, `pvoc.h`). See `README.md` for each primitive's +contract summary. + +## The design discipline (load-bearing — every primitive follows it) + +- **Fixed numeric contracts.** Each header documents its packing, conventions, normalization, and + latency as *numbers*, and the tests pin them. Changing a documented contract point is a breaking + change for every consumer. +- **Double is the golden model; float32 is the embedded profile.** `basic_*` templates + with `using x = basic_x` / `x32 = basic_x` aliases. The double path never changes + for speed; accelerated float backends (vDSP, CMSIS-Helium for the FFT) must re-present the + *exact* golden contract, so the double test battery stays a valid oracle. Cross-precision + agreement is pinned by tests. +- **Real-time safe by construction.** Geometry fixed at construction, every buffer allocated + there; processing is `noexcept` and allocation-free. Numerically fragile recursions (e.g. the + order-48 Levinson–Durbin inside `pvoc`) run in double even in the float profile — documented + where it happens. +- **Hot loops stay plain.** The expensive inner loops (YIN's difference function above all) are + written as contiguous, branch-light scalar code on purpose: they are the designated seams for + future MVE/HVX backends behind the same contract. +- **Implement from published literature only.** This is an IP policy, not a citation habit: cite + the paper (YIN: de Cheveigné & Kawahara 2002; peak locking: Laroche–Dolson; LPC: standard + source-filter literature) and never reverse-engineer a shipping product's behavior. +- **Document honest limits.** When an algorithm has a known failure mode (PSOLA thinning pure + tones, YIN's first-dip rule on missing-fundamental synthetics), the header says so and a test + *pins* the behavior rather than papering over it. + +## Style + +`STYLE.md` is the shared Tap house style; `.clang-format` and `.clang-tidy` enforce it and CI runs +both (plus a drift check that the config files match the canonical taphouse copies — never edit +them locally). Run `pre-commit install` once per clone so commits are formatted automatically; on +Claude Code web the checked-in SessionStart hook (`.claude/hooks/session-start.sh`) does this for +you at session start. clang-tidy compiles with a *clang* front end — code that GCC accepts can +still fail there, so treat the tidy job as a second compiler. + +## Build & test + +```sh +cmake -S . -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build +ctest --test-dir build --output-on-failure +``` + +Tests are GoogleTest (FetchContent), typed over `float`/`double` (`TYPED_TEST_SUITE`). Patterns to +preserve: contract tests named for the promise they pin (`RoundTripReproducesInput`, +`PureToneOctaveUpThinsOut`); the certified-geometry parity tests for accelerated FFT backends; and +`tap::dsp::yin` (certified by its own battery) used as the pitch oracle for the shifters. The +CMSIS-Helium backend is compile-verified under `cmake/arm-cortex-m55-mps3.cmake`; its runtime +parity is the consuming library's job. + +## Verification layer (C ABI + notebooks) + +`tools/capi/` exposes the primitives through a minimal C ABI (`cmake -B build_capi -S tools/capi`); +`notebooks/dsptap_py.py` is the ctypes bridge (builds `build_capi/` on first import), and +`notebooks/pitchshift.ipynb` is committed *executed* — it measures the shipping C++, not a Python +re-implementation (the one deliberate exception is a labeled naive-phase-vocoder strawman). If you +change a primitive's behavior, re-execute the notebook; if you add a primitive that notebooks +should measure, extend the capi + bridge alongside it. + +## Adding a primitive (checklist) + +1. `include/tap/dsp/.h` — `basic_` + aliases, full contract docstring + (geometry, conventions, latency, limits), MIT SPDX banner. +2. `tests/test_.cpp` — typed battery pinning every contract point, plus float/double + cross-precision agreement; add to `tests/CMakeLists.txt`. +3. `README.md` section (and bump the primitive count in the intro line). +4. capi + `dsptap_py` exposure if the notebooks need it. +5. Vendored code goes under `third_party/` with license retained and a `NOTICE.md` entry — and is + excluded from formatting. + +## Consumers & release flow + +Changes land here first, then consumers bump their submodule pin (TapTools pins this repo; +TapTools-Max picks it up transitively through TapTools). After a PR merges via rebase/squash, +repoint any open consumer pins at the identical tree on `main` so they stay reachable after branch +cleanup. From 5b3548af3d8d79367cee3331e8a4f659ca142e5b Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Wed, 22 Jul 2026 18:24:36 +0000 Subject: [PATCH 3/5] Align SessionStart hook with the TapHouse canonical copy TapHouse has adopted the hook into its sync set; this re-sync updates the header to the canonical provenance wording so the copy is byte-identical and passes the drift guard once the TapHouse tag advances past v4. No functional change. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01BuUawafae7RR2ySWabuJcs --- .claude/hooks/session-start.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.claude/hooks/session-start.sh b/.claude/hooks/session-start.sh index aedace8..b7c2a49 100755 --- a/.claude/hooks/session-start.sh +++ b/.claude/hooks/session-start.sh @@ -12,9 +12,9 @@ # 3. warm the pinned clang-format binary so the first commit doesn't # pay the download (the container snapshot caches it) # -# Candidate for the taphouse sync set (scripts/sync.sh) alongside -# .clang-format / .clang-tidy / .pre-commit-config.yaml, so every Tap repo -# carries the same hook. Web-only; local clones are untouched. +# Canonical copy: taphouse (distributed by scripts/sync.sh alongside +# .clang-format / .clang-tidy / .pre-commit-config.yaml; drift-guarded where +# present). Web-only; local clones are untouched. set -euo pipefail if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then From c6caa611453b96c87bb659979ed9522d39875ca3 Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Wed, 22 Jul 2026 18:55:05 +0000 Subject: [PATCH 4/5] Bump TapHouse drift pin to v5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v5 canonicalizes the Claude Code web SessionStart hook (tap/TapHouse#4 merged); this branch already carries the synced hook, so the v5 drift guard — which now covers it — passes by construction. Both the reusable workflow ref and the comparison ref move together. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01BuUawafae7RR2ySWabuJcs --- .github/workflows/style.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 76546fd..c99e7dd 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -8,9 +8,9 @@ on: [push, pull_request] jobs: drift: - uses: tap/taphouse/.github/workflows/drift-check.yml@v3 + uses: tap/taphouse/.github/workflows/drift-check.yml@v5 with: - ref: v3 + ref: v5 clang-tidy: runs-on: ubuntu-latest From 65c81e5ef1be0ca70a721bb891e56c4b36cc85e5 Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Wed, 22 Jul 2026 19:42:39 +0000 Subject: [PATCH 5/5] Re-run CI: TapHouse v5 tag now published The style workflow references taphouse@v5, which did not exist when the ref bump was pushed; this empty commit re-triggers the runs now that the tag is live. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01BuUawafae7RR2ySWabuJcs