apcascade · 2026-04-16 → 2026-10-07

The Correction Log

Chris started this project partly to learn how to work well with Claude Code. Six months later the learning exists as thirty-nine feedback_* memory files, written one at a time, each after something went wrong. Read in order, they have a shape.

39 lessons recorded 698 commits 1 reverse-engineered audio analyser

Latest session Twelve decibels were hiding in the meter's own range2026-10-22 05:25 → 2026-10-24 10:05 UTC

Start here

The app · theory, operation, why

What Cascade does

A Mac app that drives an Audio Precision SYS-2522 directly over USB, with no Windows PC. What it measures, the theory behind each measurement, how it talks to the instrument, and how we know the numbers are right.

Read it →
2026-07-03 → 2026-10-08 · 811 prompts

The other side of the log: how Chris learned to steer

The rest of this page is what Claude learned. This is what Chris learned, tested against every prompt Chris typed: where the record backs Chris's own account, and where it complicates it.

Read it →
2026-04-16 → now · 45 shipped items

Features: shipped and coming

What the app can do, when each piece first worked, whether it was verified on hardware, what broke later, and what comes next.

Read it →

Activity and lessons, by month

1
Apr
8
May
33
Jun
65
Jul
92
Aug
375
Sep
124
Oct 1–7
commits, repo and app lessons recorded (3px per lesson)

MAY · 6 LESSONS

Don't break it, don't guess

How do I stop this thing breaking my instrument?

The first lessons are about containment. A SYS-2522 is not a sandbox, and the earliest rule is still the strictest one in the project.

Never send a write with a guessed value. Bytes go to the instrument verbatim from a capture, or not at all. Still enforced six months later. Every generator write today is verbatim from a pcap or derived from a formula validated against one.

Its counterpart landed the same day: ask what the hardware can do rather than assuming. Both address one thing. Fluency is not knowledge, and where there is real hardware the gap gets expensive.

feedback_safety feedback_ask_dont_assume feedback_scan_all_usb feedback_memory_at_compaction feedback_sync_memory_to_repo feedback_e8_transact

JUNE–JULY · 10 LESSONS

Make the tool carry the work

How do I stop doing work it could do?

Workflow lessons, sharing a theme: stop making the human do what the model can. Grep the repo before asking for a file. Make the edits directly rather than narrating them, because a test cycle costs two minutes of replay. Commit the throwaway analysis scripts, because they are the record of what was already ruled out.

One epistemic lesson appears here in embryo, and it recurs for months: verify the UI before describing it. Claude had confidently described controls that did not exist.

feedback_check_before_asking feedback_validate_via_adjacent_regs feedback_build_workflow feedback_capture_order feedback_setup_diff_lastval feedback_commit_investigation_files feedback_long_test_cycles feedback_verify_ui_before_describing feedback_apwin_rename_on_edit feedback_probe_clean_shutdown

AUGUST · 5 LESSONS

Suspect the measurement

How do I tell a real measurement from a plausible one?

The project starts producing numbers, and the failures change character. They stop being crashes and start being plausible wrong answers, which are far more dangerous because nothing announces them.

When a number disagrees with expectation, suspect the measurement path before inventing physics. Cost: three sessions chasing a “cable loss” that was a decode bug.
Don't argue from the noisiest point. Weight by uncertainty before looking for a pattern. A “natural experiment” at 100 Hz turned out to be inside its own error bars: ±32.8 Hz against ±0.2 Hz at 20 kHz.
feedback_native_only feedback_naming_sys feedback_noisiest_point feedback_suspect_the_measurement_path feedback_transact_default_delay

SEPTEMBER · 13 LESSONS

Design an experiment that can fail

How do I know what I think I know?

Thirteen lessons in one month, and they are no longer about the tool or the instrument. They are about knowing things.

Interleave A/B/A/B in one session. An A→B→A cannot separate the variable from anything that changed once and changed back. Cost: a retracted conclusion about cable hum.
Before concluding “X never happens”, check the evidence could have shown X. Our captures began after APWIN launched, so a missing calibration read proved nothing, for months.
For analysis code, test invariants and directions, not golden numbers. “SINAD must not change when the spectrum moves 40 dB” catches a class of bug that a fixed expected value never will.

And the strangest one: instrumentation becomes configuration on replay. A frequency marker left in a capture was replayed as a real command, and it was the signal being measured for five consecutive bench runs.

feedback_interleave_ab feedback_single_bin_noise feedback_actionable_instructions feedback_dont_assume_stale_build feedback_procedures_self_log feedback_read_before_asserting feedback_absence_of_evidence feedback_invariant_tests feedback_test_signal_regimes feedback_instrumentation_in_replay feedback_record_what_you_skipped feedback_transcribe_responses_too feedback_comment_claimed_a_safeguard

OCTOBER 1–7 · 4 LESSONS

Hand over the bench

How do I let it run the experiment, safely?

Two long hunts finished in the first week. Native IMD, with no audio interface, came from Chris refusing a workaround. Arb playback, parked for weeks as “a dead end by construction”, played AP's file, then our own samples, then a 38-tone multitone flat to 0.01 dB.

“i'm going to be stubborn about not using the extra focusrite equipment. APWIN doesn't need it. neither should Cascade.” Result: native IMD, scope-confirmed, the same night.

Then Chris asked whether the bench could run itself:

“is this something you are able to script? Even script the interface so that you do get the real behavior of it? you could also screen shot just the cascade app for verification. then that makes this almost unattended”

Claude described a script runner and asked for two things, the first being permission to drive the 2522 unattended. Chris answered:

“yes, OK to 1. you know the safety protocols and have been staying within them. No overcooking the voltages. this is a good additional step, because it gives us something like the APBASIC procedures.” The script runner: bench runs become files Claude drops in a folder, validated before anything is sent, always ending with the generator off.

Running the bench unattended paid for itself the same evening. It surfaced:

  • a range read-back that lags a write, so one capture read 12.04 dB low, flat and believable
  • a click on HISTORY cutting a capture short, which the runner called done
  • the unit-test host, a second copy of the app, starting the same script
  • an intermittent broken capture, traced to an open-loop poll inside a replayed blob

Each became a check, not a rule. And one thing scripts could not see: every run used a loopback, so a change that broke external-signal FFTs passed them all. Chris's oscillator caught it.

feedback_exhaust_before_reporting feedback_picker_use_the_house_pattern feedback_blob_routing_overrides_ui feedback_unattended_scripting_ok

Read the session story: “The generator was never silent” →

A correction to the shape

The arc is Claude's, not Chris's

The phases date when Claude wrote a move down as a rule, not when the move first happened. Chris's prompts from July and August, recovered from the prompt history in October, show Chris doing September's experimental design months earlier. “Are you able to just send signal to one?” (Jul 25) was a controlled experiment that separated crosstalk from the physical connection. “I put a voltmeter in the banana plug output” (Aug 22) measured the real output instead of trusting the graph. “go back to why you thought the difference was so real.” (Jul 18) questioned a premise that had steered a month of work. Read the phases as how fast Claude caught up.

The unsolved ones

Five failures that writing down did not fix

Most recorded lessons hold. These have each produced multiple memories and keep recurring anyway, which makes them the most useful thing on this page.

  1. Asserting without reading

    Stating a fact about the code, the repo or the device without opening the primary source first.

    Jul “verify UI before describing” → Sep 5 “read before asserting” → three instances on Sep 25 → Oct: two numbers quoted unmeasured (“498”, “> 400”; real: 150), and “there is no story document” about this page
  2. Claiming a negative from evidence that could not show it

    Concluding something does not happen, when the measurement could never have revealed it happening.

    Sep 7 “absence of evidence” → Sep 27, the script written to test for it printed “NO DIVERGENCE” after exiting its loop early
  3. Believing code works because it exists

    Four components were implemented, correct, tested, and never called by anything.

    setArbWaveformMode · uploadWaveform · Multitone.analyse · arbWaveformStatus. “It shipped” ≠ “it runs”.
  4. A guard nobody runs

    A check that exists is not a check that runs. The guard keeping AP's program out of the bundle had been failing since two blobs were added, and nobody re-ran it.

    check_no_ap_code.py, found failing Oct 4. A mechanism only counts if something runs it.
  5. Declaring victory in the record before the evidence

    The claim of done is written first, and the file, the code or the hardware is checked later, or never. The oldest of the five: rebuilding April–August found it in every month.

    May: a memory headed SOLVED, its index line still “untested” → Jun 1: 94dfed4 names a Swift change it doesn't contain → Jun 19: 1c0b0e6 says it added the THD formula to a file that never got it → Jul 17 “ROOT CAUSE FOUND”, disproved on hardware hours later → Jul 25 “Recovered the device”, corrected 7 minutes later → Aug 22 a “SOLVED” amplitude law, overturned by Chris's voltmeter

The pattern that does work: every time one of these was converted from a rule into a mechanism (a test that fails, a check that fires, a log line that cannot be overlooked) it stopped recurring. Rules are for the things you do once. Guard rails are for the things you keep doing.

What the human does that works

Habits, each of which changed a conclusion

  • Challenges confident claims. “are you sure the 2 channels are 12db apart? doesn't look like it on the interface” They weren't.
  • Asks what a term means instead of nodding. “where do you see the −71.4db?” exposed a real gap between per-bin depth and integrated power.
  • Notices when the advice changes. “this is very different from the advice you gave a few minutes ago” caught an answer built from stale memory instead of the repo.
  • Supplies physical context the model cannot see: gain encoders with no end stop, an RCA adapter shorting a cold leg, relays clicking at a range boundary.
  • Asks where a rule came from. “is this what APWIN does or is it something you decided?” It was a decision, and checking led to a better design.
  • Asks for the procedure, not the goal. “those instructions are nonspecific. please write the steps that are needed”
  • Questions the premise, not just the number. “go back to why you thought the difference was so real.” Thirteen minutes later, APWIN's own export closed a month-old question.
  • Measures at the real node. A voltmeter on the output overturned an amplitude law “verified” to ±0.4 dB at the wrong point.
  • Proposes the faster method. “would it help you at all to connect directly to the machine” turned rebuild cycles into six experiments in 20 minutes.
  • Keeps a complaint alive past a “resolved” headline. “cascade always has the high THD part at the initial frequencies.” It was a real bug.
  • Overrides pacing when the work isn't done. “Why do you keep pushing to stop?” The session went on and captured the FFT gate that evening.
  • Tests something new unprompted. An external oscillator found what scripted loopback runs could not.

Still to learn

Open questions

  • Estimates. Consistently over-quoted when the change is “stop discarding a value” and the plumbing already exists. An hour quoted, two minutes actual.
  • When to stop hypothesising and start diffing. Four one-hypothesis-per-bench-run cycles preceded a structural diff that then found three defects in an evening.
  • Provenance. A 40,065-packet blob the whole app depends on, with no record of which capture built it. Artefacts need their origin written down at creation, not reconstructed archaeologically. Two commits describe changes they do not contain: a commit message is a claim, not a record.
  • Proposing to stop. Twice in August Claude suggested ending an unfinished session and Chris overrode it. It was only written down as a lesson in October. No later prompt pushes back, which is weak evidence it stopped, not proof.
  • What an unattended test cannot see. More runs on the same rig repeat the same blind spots. Scripts need rigs that differ.

Session stories

How a session got there

The phases above say what was learned. Session stories say how, newest first, with the dead ends left in. From late August on they are written from the session transcripts and quote Chris verbatim. The transcripts from April to August no longer exist, so those four chapters are reconstructed from git commits and the history of the memory files, and they say where the record is silent. For July and August, Chris's own prompts survived in Claude Code's prompt history and are quoted verbatim; Claude's side is lost. April to June has no words of Chris's at all.

2026-10-22 05:25 → 2026-10-24 10:05 UTC

Twelve decibels were hiding in the meter's own range

Do Cascade's measurements on a real, distorting device agree with APWIN's on the same device?

Read the story →
2026-10-19 03:07 → 2026-10-22 05:25 UTC

The manuals were readable, and the wiki was wrong

How does Cascade actually reach the instrument, and what do the manuals really say about it?

Read the story →
2026-10-18 02:37 → 09:10 UTC

The first non-sine signal Cascade ever made

Is the app actually right after a week of changes, and can it do real IMD?

Read the story →
2026-10-12 21:38 → 2026-10-13 05:29 UTC

The IMD we decoded was probably a sine

How do you make a record of what the manuals say that does not depend on Claude saying it read them?

Read the story →
2026-10-11 00:42 → 09:15 UTC

The manuals were readable all along

What should the app do next, in what order? By the end of the night the question was a different one: how much of what we "knew" from AP's manuals had ever actually been read?

Read the story →
2026-10-10 06:22 → 2026-10-11 00:42 UTC

The instrument said "not ready" and the replay wrote anyway

It started as "why doesn't the crosshair snap?" Within fifteen minutes it had become "why does the FFT return nothing at all?"

Read the story →
2026-10-07 19:56 → 2026-10-10 06:22 UTC

The record existed, in places nobody had looked

Can the path to "here" be told as a story people would read, and told accurately, when half the evidence seemed to be gone?

Read the story →
2026-10-03 → 2026-10-04

The generator was never silent

Why does arb play after an apib_fft_full reload and not without one?

Read the story →
2026-10-03, 03:57 → 08:47 UTC

Every non-sine failure was our stitched startup

What does it take for the AP's own generator to produce a multi-tone signal from Cascade?

Read the story →
2026-09-27 06:32 → 07:59 and 2026-09-28 02:48 → 04:04 UTC

Our startup was stitched from two APWIN sessions

Why do EC writes reach the generator for APWIN and not for us?

Read the story →
2026-09-26, 07:11 → 09:27 and 16:36 → 17:41 UTC

Multitone never needed arb

Can Cascade measure a multitone today, from a source other than the AP?

Read the story →
2026-09-26, 04:49 → 07:10 UTC

The arb code existed, and the generator ignored it

If Cascade sends APWIN's arb-entry bytes itself instead of replaying a blob, does the generator play the waveform?

Read the story →
2026-09-13, 00:37 → 07:49 UTC

Five runs measured our own marker tone

Do the queued changes work on hardware, and can Cascade play an arbitrary waveform?

Read the story →
2026-09-12, 16:58 → 20:59 UTC

0.049% of the packets, 19.7% of the bytes

What bytes set Fast/High Accuracy, the analyzer lowpass and InputFormat? And, as the session went on, can Cascade stop depending on AP's code?

Read the story →
2026-09-12, 04:36 → 09:25 UTC

The self-check was a folder away

Does Cascade agree with APWIN on an imperfect real source, and where do AP's own definitions of "in spec" live?

Read the story →
2026-09-08 → 2026-09-09

A capture that starts late cannot prove a negative

What would it take to run Cascade on other Audio Precision units, and what can be learned about that without the hardware?

Read the story →
2026-09-05 → 2026-09-06

The generator could always make those levels

Can the generator actually produce levels inside the table's gaps, and if it can, what model should replace the table?

Read the story →
2026-09-05, 04:29 → 08:30 UTC

The sweep offset was ten flag bits

Does the adapter chain change what the analyzer measures? Underneath it, a second question appeared during the session: why does the DUT-mode frequency sweep read 4.61 dB higher than the FFT?

Read the story →
2026-08-31, 01:03 → 05:08

Two frequency errors, and the generator's was in spec

What is the DUT-mode absolute offset, and is it one constant?

Read the story →
2026-08-29 16:43 → 2026-08-30 07:27

The 7.4 dB cable loss was a frozen exponent

Does the live meter read correct level and THD in GenMon, in DUT mode, and through a real DUT (the Schiit SYS passive preamp)?

Read the story →
2026-08-29, 05:23 → 08:45

Shift chains are relative: the T68 blob could never have worked

Can the app capture an FFT natively and read the same number APWIN does?

Read the story →
2026-08-24 → 2026-08-27

The exponent was inside the word

Can the live meter show THD as the level slider moves, on real hardware? And, two days later, where does the FFT keep its magnitudes?

Read the story →
2026-08-22 → 2026-08-23Reconstructed · Chris's prompts verbatim

The voltmeter outranked the analyzer

Can the app compute the generator's register writes for any level, and prove the output is right?

Read the story →
2026-07-03 → 2026-07-25Reconstructed · Chris's prompts verbatim

The −101 was one capture, not the instrument

Why does Cascade read 12 dB cleaner than APWIN? Then, once the GenMon number was settled: can Cascade measure THD on a real external device through the XLR inputs, on both channels?

Read the story →
2026-06-13 → 2026-06-24Reconstructed · no transcript

The whole word was the fundamental

Can the documented command model replace byte-level reverse engineering? And, as a test of it, why does THD fail at −20 dBV?

Read the story →
2026-04-16 → 2026-06-01Reconstructed · no transcript

The generator listened to 8A, not EC

Can a Mac drive the SYS-2522 at all? That meant: open the adapter, replay an init, set a frequency, read a level back, and do all of it without damaging the instrument.

Read the story →