What changed in each phase, the verification evidence and its commands, the findings that were reported rather than fixed, and the limits of what could be checked on this machine. The graft graph was rebuilt after the source moves.
11 KiB
Janitor round 2: structure, build separation, scripts
Executed on branch main from the round 1 checkpoint. Round 1 had left all of its
work uncommitted and HEAD did not compile without the FXProcessor repair, so
this round begins by committing that work and then lands two phases of its own.
Round 1's own task list is archived at docs/archive/JANITOR_TASKS_2026-05.md.
The user confirmed the scope before any file changed. The full set of decisions is in the commit messages; this file records what changed, the evidence, and what was left alone.
Commits
| Commit | Contents |
|---|---|
e4cea30 |
Round 1 checkpoint: the uncommitted FXProcessor repair, ExactCompare.h, KnobLookAndFeel, the AGENT.md to AGENTS.md renames, and graft integration. |
facd5c5 |
Phase 1: scripts/, the toolchain file in cmake/, build output under build/, clean.sh, docs/, the Windows manifest generated from CMake, and three code fixes. |
4b0db50 |
Phase 2: 36 source files into their module directories, and five directories renamed. |
This file and the refreshed graft graph land in a fourth commit.
Phase 1: repository root, build output, scripts
Layout
scripts/holdsbuild_linux.sh,build_macos.sh,build_windows.sh,build_harness.shandclean.sh. Each resolves the repository root from its own location, so the documented./scripts/build_harness.sh --runworks from any directory.cmake/holdsmingw64-toolchain.cmakebesidePlugin.cmakeandHarness.cmake.docs/holdsAUDIT_REPORT.mdandUI_UX_AUDIT.md;docs/archive/holds the finished round 1 list.- The repository root now holds
CMakeLists.txt,README.md,AGENTS.md,.gitignore, the tool configuration files, and four directories:Source/,cmake/,scripts/,docs/.
Build output
Each script defaults to a directory under build/: build/linux, build/macos,
build/windows and build/harness. BUILD_DIR still overrides any of them, and a
relative override resolves from the repository root. SerumAlt_Windows/ remains the
staging directory for the shippable Windows bundle, and OUTPUT_DIR still overrides
it.
scripts/clean.sh removes generated output:
| Invocation | Removes |
|---|---|
./scripts/clean.sh |
the trees under build/ |
--staging |
adds SerumAlt_Windows/ |
--legacy |
adds build_* and cmake-build-* left in the root by earlier script versions |
--all |
both of the above |
--dry-run |
nothing; prints each path with its size |
The script refuses a path outside the repository, a path under Source/,
third_party/, .git, scripts/, cmake/, docs/ or graft/, a path tracked by
git, and refuses to run at all when BUILD_DIR or OUTPUT_DIR resolves outside the
repository. Exit status 2 marks a refusal.
902 MB of stale trees were removed after the new layout built successfully:
build/'s original in-place tree, build_harness, build_windows,
build_windows_fresh and the three build_verify_* trees. build_linux/ and
SerumAlt_Windows/ were left in place; ./scripts/clean.sh --legacy --staging
removes them when you no longer need the artifacts in them.
Windows manifest
build_windows.sh used to carry a 60-line moduleinfo.json heredoc with the
version, vendor and class IDs written out by hand. The version also lives in
project(SerumAlt VERSION 1.0.0), so a version bump would have shipped a manifest
that disagreed with the binary.
cmake/Plugin.cmake now defines the plugin metadata once, passes it to
juce_add_plugin, and configures cmake/moduleinfo.json.in into the build
directory. The three VST3 class IDs are built from PLUGIN_MANUFACTURER_CODE and
PLUGIN_CODE the same way JUCE builds them, so they cannot drift from the codes
either. The script copies the configured file into the bundle and fails when it is
missing.
Code fixes
Source/PluginProcessor.hgainedusing juce::AudioProcessor::processBlock;. The float override hid the base class double overload, which produced three warning lines from three translation units.Source/GUI/Slider.{h,cpp}were deleted. Nothing constructedserum::Slider; it was reachable only through one include inPluginEditor.h.SERUMALT_INCLUDE_DIRSandGUI/AGENTS.mdwere updated to match, andKnobLookAndFeelwas added to the owned-files list, where it had been missing.- Prose in the five shell scripts, the two
.claude/helpers/*.cjsfiles and the CMake files was tightened. The scripts had no em dashes and no banned vocabulary left from round 1, so what changed was structure: numbered step headings, a paragraph explaining what a load failure would look like, and the manifest heredoc, all gone.
Unslop scope
The five shell scripts, .claude/helpers/graft-hooks.cjs,
.claude/helpers/graft-statusline.cjs, CMakeLists.txt, cmake/Plugin.cmake and
cmake/Harness.cmake. README.md and AGENTS.md keep their prose and received
path corrections only, so the layout changes stay reviewable.
Phase 2: source modules
The five directories engine/, modulation/, params/, plugin/ and synth/
held nothing but guidance pointing at root-level implementations. Every module doc
already claimed its files, so the move only had to honour those claims.
| Module | Files moved in |
|---|---|
Engine/ |
Engine.{h,cpp} |
Synth/ |
Wavetable, Oscillator, SubOscillator, NoiseOscillator, Envelope, LFO, Filter, FilterBank, SynthVoice (18 files) |
Modulation/ |
ModulationMatrix, MacroControls, RAVEButton (6 files) |
Params/ |
Params.{h,cpp} |
Plugin/ |
PluginProcessor.{h,cpp} |
GUI/ |
PluginEditor.{h,cpp} |
EffectUnits/ |
FXProcessor.{h,cpp} |
Resources/ |
Resources.{h,cpp} |
36 files moved, not the 31 stated when the plan was agreed. The five directories
were renamed to Engine/, Modulation/, Params/, Plugin/ and Synth/ so that
every subdirectory of Source/ uses one casing rule.
Source/ExactCompare.h stays at the Source/ root: five modules include it, and a
Common/ directory for one header would cost more than it explains.
SERUMALT_INCLUDE_DIRS now lists Source/ and one directory per module, which let
all 31 parent-relative includes become plain names such as Params.h. No header
basename is duplicated in the tree, so that resolution cannot pick the wrong file.
The module docs list owned files instead of describing a move that had not happened.
README.md and the Current source layout section of AGENTS.md describe the tree
that exists.
Verification
Every command below was run after the phase it verifies. Build directories are under
build/, which is git-ignored.
for s in scripts/*.sh; do bash -n "$s"; donepasses for all five scripts../scripts/build_harness.sh --runreaches100% tests passed out of 1from a clean directory, in both phases../scripts/build_linux.shlinksSerumAlt.vst3and theSerumAltStandalone../scripts/build_windows.shlinks the cross-compiled VST3 and passes its own checks: the module is x86-64, imports none oflibgcc_s_seh-1.dll,libstdc++-6.dllorlibwinpthread-1.dll, and exportsGetPluginFactory,InitDllandExitDll.- The generated manifest is identical to the previously hand-written one. Compared
with
python3 -m json.toolon both, after taking the old one fromgit show HEAD:build_windows.sh. - Target hygiene, read from
cmake --build <dir> --target help: the harness configure offersSerumAltTestand no plugin target; the Linux and Windows configures offerSerumAlt_VST3and noSerumAltTest. - First-party warning lines: 3 before the
processBlockfix, 0 after. The four warning lines that remain in a full run all name files underthird_party/JUCE(a-Wpedanticnote about::mainin the Standalone, two MinGW#warninglines injuce_graphics, and a deprecatedtznameinjuce_Time). - A full build leaves the source tree unchanged:
git status --porcelain -- Source third_party/JUCEbefore and after a three-target build is identical, so no build product lands in the source tree. ./scripts/clean.sh --dry-run --allprints each path with its size and removes nothing. Run before the stale trees were deleted it listed nine paths; it now lists the three that remain:build/,SerumAlt_Windows/andbuild_linux/.--staging,--legacyand the outside-repository refusal were each run.graft buildwas re-run after the moves. The graph now mirrors the new paths, for examplegraft/Source/Engine/Engine.md.
Kept, and why
MacroControls::removeAssignmentis still defined and never called. No control in the Macro tab would call it, so deleting it would remove the only path to a feature rather than clean up dead code.Source/GUI/PluginEditor.cppis still 1147 lines. It is the largest remaining readability problem in the tree, and it is a GUI refactor with no headless way to check the pixels.- The two
.claude/helpers/*.cjsfiles remain 66-line copies that differ in one line. Each is a self-contained hook thatgraft initcan regenerate; merging their shared body into a third file would break on regeneration. Only their comments changed. opencode.jsonand.mcp.jsoneach declare the same graft MCP server for a different host. Both hosts are configured this way deliberately, so removing either would break that host.third_party/JUCE/Projucerandthird_party/JUCE/DemoRunnerare 22 MB of upstream Linux binaries that ship with the vendored copy. They are not built here and were not deleted..gitignorenow covers them, so they no longer appear as untracked files.docs/UI_UX_AUDIT.mdanddocs/archive/JANITOR_TASKS_2026-05.mdstill contain the old./build_harness.shcommands. They record what was run at the time, and rewriting them would misreport that.README.mdandAGENTS.mdare the maintained sources for commands.- Nine em dashes remain inside the generated
<!-- graft:start -->block inAGENTS.md. They come from the installed@nanonets/grafttemplate and return on the nextgraft init; removing them needs a change to that package.
Limits
- The macOS build could not be run, because it needs a Mac and the Apple SDK.
scripts/build_macos.shwas syntax checked and reviewed, and nothing else. - No change in this round touched audio or GUI behaviour except deleting an unused class, so the harness result is a regression check, not sound or visual proof. There is still no headless way to verify a pixel.
- The staged cross-build for this round is at
build/windows-staged-check/SerumAlt.vst3. It is insidebuild/, so./scripts/clean.shremoves it.SerumAlt_Windows/SerumAlt.vst3is the older bundle and was not overwritten.