From 8c91fb32620b2c8894a9fa3df18165a897e208c9 Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Fri, 9 Oct 2026 13:13:04 -0500 Subject: [PATCH 1/9] The 9.0 spike's Windows runner (work in progress) Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz --- runtime-tests/spike/run_spike_windows.ps1 | 231 ++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 runtime-tests/spike/run_spike_windows.ps1 diff --git a/runtime-tests/spike/run_spike_windows.ps1 b/runtime-tests/spike/run_spike_windows.ps1 new file mode 100644 index 0000000..fa549fc --- /dev/null +++ b/runtime-tests/spike/run_spike_windows.ps1 @@ -0,0 +1,231 @@ +# SPDX-License-Identifier: MIT +# Copyright 2022-2026 Timothy Place. +# +# Run the plan 9.0 spike in Max on Windows and collect what the console said (THROWAWAY). +# +# cmake -S . -B build-spike -DTAP_PYTHON_SPIKE=ON +# cmake --build build-spike --config Release +# powershell -ExecutionPolicy Bypass -File runtime-tests\spike\run_spike_windows.ps1 +# powershell -ExecutionPolicy Bypass -File runtime-tests\spike\run_spike_windows.ps1 -Only q2,q3 +# +# The Windows counterpart of run_spike.py, which needs the macOS-only harness: each patcher runs in +# a fresh Max of its own, started as Explorer starts it (Max.exe "") together with a small +# patcher that sends Max `; max clean; max quit` once the patcher under test has had its time. Max +# must be quit first, and the package (and runtime-tests\spike, for the patchers) must be in a +# Packages folder — C:\ProgramData\Max 9\Packages\PythonTap and ...\PythonTap-spike as junctions +# to this checkout and to runtime-tests\spike, say. What Max said comes from its own log +# (%APPDATA%\Cycling '74\Max 9\Logs\Max.log); the lines of interest go to results\windows.txt, each +# whole log to runtime-tests\logs\spike-windows-.maxlog. +# +# Sessions: q1-control (init\tap.python.txt moved aside), q1-mapping, q1-spike-first, +# q1-tilde-first, then q2 to q6 each on its own, and q7 (q7\'s files copied into docs\ and extras\ +# until Max's file database reports its update complete; the database is then asked what it made of +# them). For the run, "Restore Windows on Launch" is off and Max's crash-recovery workspaces are +# moved aside to runtime-tests\logs; Max's preference files are put back as they were afterwards. + +[CmdletBinding()] +param( + [string[]]$Only = @(), + [string]$Max = "C:\Program Files\Cycling '74\Max 9\Max.exe" +) + +$ErrorActionPreference = 'Stop' +$ProgressPreference = 'SilentlyContinue' + +$Spike = $PSScriptRoot +$Root = (Resolve-Path (Join-Path $Spike '..\..')).Path +$Patchers = Join-Path $Spike 'patchers' +$Q7 = Join-Path $Spike 'q7' +$Results = Join-Path $Spike 'results' +$Logs = Join-Path $Root 'runtime-tests\logs' +$MaxData = Join-Path $env:APPDATA "Cycling '74\Max 9" +$MaxLog = Join-Path $MaxData 'Logs\Max.log' +$Settings = Join-Path $MaxData 'Settings' +$Init = Join-Path $Root 'init\tap.python.txt' +$InitAside = "$Init.spike-aside" +$Python = Join-Path $Root 'support\python.exe' + +# (session, patchers, seconds to give them before Max is told to quit) +$Sessions = @( + @('q1-control', @('q1-mapping'), 6), + @('q1-mapping', @('q1-mapping'), 6), + @('q1-spike-first', @('q1-spike-first'), 6), + @('q1-tilde-first', @('q1-tilde-first'), 6), + @('q2-outlets', @('q2-outlets'), 6), + @('q3-dumpout', @('q3-dumpout'), 6), + @('q4-dispatch', @('q4-dispatch'), 6), + @('q5-threads', @('q5-threads'), 12), + @('q6-strings', @('q6-strings'), 6), + @('q7', @(), 900) +) + +$Interesting = "spike|recorder|\bq[1-7]\b|tap\.python|No such object|python:|Loaded |doesn't understand|" + + "missing arguments|obex|error\]|crash|maxdb update complete" +$Noise = "RNBO|rnbo|j\.loader|bach|Could not load package|Error 126 loading external" + +function Write-QuitPatcher([int]$Seconds) { + $path = Join-Path $Logs "spike-quit-$Seconds.maxpat" + $ms = $Seconds * 1000 + $json = @" +{ "patcher": { "fileversion": 1, "appversion": { "major": 9, "minor": 1, "revision": 5, "architecture": "x64", "modernui": 1 }, + "classnamespace": "box", "rect": [ 900.0, 600.0, 320.0, 160.0 ], + "boxes": [ + { "box": { "id": "obj-1", "maxclass": "comment", "text": "spike: quits Max after $Seconds s (run_spike_windows.ps1)", "numinlets": 1, "numoutlets": 0, "patching_rect": [ 20.0, 10.0, 280.0, 20.0 ] } }, + { "box": { "id": "obj-2", "maxclass": "newobj", "text": "loadbang", "numinlets": 1, "numoutlets": 1, "outlettype": [ "bang" ], "patching_rect": [ 20.0, 40.0, 60.0, 22.0 ] } }, + { "box": { "id": "obj-3", "maxclass": "newobj", "text": "delay $ms", "numinlets": 2, "numoutlets": 1, "outlettype": [ "bang" ], "patching_rect": [ 20.0, 70.0, 90.0, 22.0 ] } }, + { "box": { "id": "obj-4", "maxclass": "message", "text": "; max clean; max quit", "numinlets": 2, "numoutlets": 1, "outlettype": [ "" ], "patching_rect": [ 20.0, 100.0, 150.0, 22.0 ] } } + ], + "lines": [ { "patchline": { "source": [ "obj-2", 0 ], "destination": [ "obj-3", 0 ] } }, + { "patchline": { "source": [ "obj-3", 0 ], "destination": [ "obj-4", 0 ] } } ] } } +"@ + Set-Content -Path $path -Value $json -Encoding ASCII + return $path +} + +function Clear-CrashRecovery { + $aside = Join-Path $Logs 'spike-windows-crash-recovery' + Get-ChildItem (Join-Path $MaxData 'Crash Recovery') -Filter 'maxworkspace-*.txt' -ErrorAction SilentlyContinue | + ForEach-Object { + New-Item -ItemType Directory -Force $aside | Out-Null + Move-Item -Force $_.FullName (Join-Path $aside $_.Name) + } +} + +function Install-Q7 { + $copied = @() + Get-ChildItem $Q7 -Recurse -File | ForEach-Object { + $relative = $_.FullName.Substring($Q7.Length + 1) + $destination = Join-Path $Root $relative + if (Test-Path $destination) { throw "$destination already exists" } + New-Item -ItemType Directory -Force (Split-Path $destination) | Out-Null + Copy-Item $_.FullName $destination + $copied += $relative + } + return , $copied +} + +function Remove-Q7([string[]]$Copied) { + foreach ($relative in $Copied) { Remove-Item -Force (Join-Path $Root $relative) -ErrorAction SilentlyContinue } + foreach ($folder in @('docs\tutorials\pythontap-tut', 'docs\tutorials', 'docs\vignettes', 'docs\topics', 'extras')) { + $path = Join-Path $Root $folder + if ((Test-Path $path) -and -not (Get-ChildItem $path)) { Remove-Item $path } + } +} + +function Get-Q7Database([string[]]$Copied) { + $database = Get-ChildItem (Join-Path $MaxData 'Database') -Filter '*.maxdb' | Where-Object { $_.Name -notmatch 'lock|userdata' } | + Sort-Object Length -Descending | Select-Object -First 1 + if (-not $database) { return @('(no file database found)') } + $copy = Join-Path $Logs 'spike-windows-q7.maxdb' + Copy-Item $database.FullName $copy -Force + $names = ($Copied | ForEach-Object { Split-Path $_ -Leaf }) -join '|' + $query = @" +import sqlite3, sys +names = sys.argv[2].split('|') +db = sqlite3.connect(sys.argv[1]) +for name in names: + stem = name + for suffix in ('.maxvig.xml', '.maxtut.xml', '.maxpat'): + if stem.endswith(suffix): stem = stem[: -len(suffix)] + rows = db.execute('SELECT _name, _kind, _typedesc, _path FROM _things WHERE _name = ? OR _filename = ?', (stem, name)).fetchall() + for row in rows: print(f" {name}: name '{row[0]}', kind {row[1]} ({row[2]}), folder {row[3]}") + if not rows: print(f" {name}: NOT in the database") +"@ + $script = Join-Path $Logs 'spike-windows-q7-query.py' + [System.IO.File]::WriteAllText($script, $query) + $lines = @('', "Max's file database ($($database.Name)), for the files q7 put in the package:") + $lines += & $Python $script $copy $names + return $lines +} + +function Invoke-Session([string]$Name, [string[]]$Which, [int]$Seconds) { + Write-Host "== $Name" + $copied = @() + if ($Name -eq 'q1-control') { Move-Item $Init $InitAside } + if ($Name -eq 'q7') { $copied = Install-Q7 } + try { + Clear-CrashRecovery + $arguments = @() + foreach ($patcher in $Which) { + $path = Join-Path $Patchers "tap.python.spike-$patcher.maxpat" + Write-Host " opening $(Split-Path $path -Leaf)" + $arguments += "`"$path`"" + } + $arguments += "`"$(Write-QuitPatcher $Seconds)`"" + $started = Get-Date + $process = Start-Process $Max -ArgumentList $arguments -PassThru + $deadline = $started.AddSeconds($Seconds + 180) + while (-not $process.HasExited -and (Get-Date) -lt $deadline) { + Start-Sleep -Seconds 2 + if ($Name -eq 'q7' -and (Test-Path $MaxLog) -and + (Select-String -Path $MaxLog -Pattern 'maxdb update complete' -Quiet)) { + Start-Sleep -Seconds 5 + Write-Host " Max's file database is up to date; stopping Max" + Stop-Process -Id $process.Id -Force + break + } + } + if (-not $process.HasExited) { + Write-Host " Max did not quit; stopping it" + Stop-Process -Id $process.Id -Force + } + $process.WaitForExit() + Start-Sleep -Seconds 1 + } + finally { + if (Test-Path $InitAside) { Move-Item $InitAside $Init } + } + $log = Join-Path $Logs "spike-windows-$Name.maxlog" + Copy-Item $MaxLog $log -Force + $lines = Get-Content $log | Where-Object { + $_ -match $Interesting -and $_ -notmatch '\] (->|<-) ' -and $_ -notmatch $Noise + } + $report = @("## session $Name", '') + $lines + if ($Name -eq 'q7') { + $report += Get-Q7Database $copied + Remove-Q7 $copied + } + $lines | ForEach-Object { Write-Host " $_" } + return , ($report + '') +} + +if (Get-Process Max -ErrorAction SilentlyContinue) { throw 'Max is running: quit it first' } +if (-not (Test-Path (Join-Path $Root 'externals\tap.python~.mxe64'))) { throw 'the external is not built' } +$binary = [System.Text.Encoding]::ASCII.GetString([System.IO.File]::ReadAllBytes((Join-Path $Root 'externals\tap.python~.mxe64'))) +if (-not $binary.Contains('plan 9.0 spike build')) { throw 'the external has no spike in it: build with -DTAP_PYTHON_SPIKE=ON' } +if (Test-Path $InitAside) { Move-Item $InitAside $Init } +New-Item -ItemType Directory -Force $Logs, $Results | Out-Null + +# Max's preference files, put back afterwards; Restore Windows on Launch off for the run +$backup = Join-Path $Logs 'spike-windows-preferences-before' +Remove-Item -Recurse -Force $backup -ErrorAction SilentlyContinue +New-Item -ItemType Directory -Force $backup | Out-Null +Get-ChildItem $Settings -File | Where-Object { $_.Name -match 'maxpreferences|audioprefs|@|recentitems' } | + ForEach-Object { Copy-Item $_.FullName $backup } +$preferencesFile = Join-Path $Settings 'maxpreferences.maxpref' +if (Test-Path $preferencesFile) { + $text = Get-Content $preferencesFile -Raw + $edited = $text -replace '"restorewindows"\s*:\s*1', '"restorewindows" : 0' + if ($edited -ne $text) { [System.IO.File]::WriteAllText($preferencesFile, $edited) } # UTF-8, no BOM +} + +$report = @() +try { + foreach ($session in $Sessions) { + $name = $session[0] + if ($Only.Count -and -not ($Only | Where-Object { $name -like "*$_*" })) { continue } + $report += Invoke-Session $name $session[1] $session[2] + } +} +finally { + Get-ChildItem $backup -File | ForEach-Object { Copy-Item $_.FullName $Settings -Force } + if (Test-Path $InitAside) { Move-Item $InitAside $Init } +} + +$version = (Get-Item $Max).VersionInfo.ProductVersion +$os = (Get-CimInstance Win32_OperatingSystem) +$header = @("# The plan 9.0 spike in Max $version, $($os.Caption) $($os.Version) $env:PROCESSOR_ARCHITECTURE", + '# (written by runtime-tests/spike/run_spike_windows.ps1: the lines of interest from Max''s log)', '') +$output = Join-Path $Results 'windows.txt' +[System.IO.File]::WriteAllLines($output, [string[]]($header + $report)) # UTF-8, no BOM +Write-Host "wrote $output" From 1a9133b2b386b0b4a568b85b15cf723f46f9ec2f Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Fri, 9 Oct 2026 13:15:11 -0500 Subject: [PATCH 2/9] run_spike_windows.ps1: -Only takes a comma-separated list under -File Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz --- runtime-tests/spike/run_spike_windows.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime-tests/spike/run_spike_windows.ps1 b/runtime-tests/spike/run_spike_windows.ps1 index fa549fc..e68cb92 100644 --- a/runtime-tests/spike/run_spike_windows.ps1 +++ b/runtime-tests/spike/run_spike_windows.ps1 @@ -31,6 +31,8 @@ param( $ErrorActionPreference = 'Stop' $ProgressPreference = 'SilentlyContinue' +# with -File, "-Only q2,q3" arrives as one string +$Only = @($Only | ForEach-Object { $_ -split ',' } | Where-Object { $_ }) $Spike = $PSScriptRoot $Root = (Resolve-Path (Join-Path $Spike '..\..')).Path From c1371611cef5fe0b72b341a545bb86dbdfea6953 Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Fri, 9 Oct 2026 13:25:20 -0500 Subject: [PATCH 3/9] run_spike_windows.ps1: open the patcher under test once Max has started up Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz --- runtime-tests/spike/README.md | 21 ++++++- runtime-tests/spike/run_spike_windows.ps1 | 69 +++++++++++++++-------- 2 files changed, 62 insertions(+), 28 deletions(-) diff --git a/runtime-tests/spike/README.md b/runtime-tests/spike/README.md index ac947e4..b87cd20 100644 --- a/runtime-tests/spike/README.md +++ b/runtime-tests/spike/README.md @@ -69,16 +69,31 @@ patcher with a `tap.python~` in it) loads the binary before the patcher under te then fresh — and it restores Max's preference files when it is done. The build writes the same `externals/` folder as `build/`: rebuild `build` afterwards to put the shipping external back. -## On Windows, by hand +## On Windows -The runner is macOS-only (as `run.py` is). With the runtime installed (`scripts/install-runtime.ps1`): +`run_spike_windows.ps1` is `run_spike.py`'s counterpart, without the macOS-only harness: each +patcher runs in a fresh Max of its own, started as Explorer starts it (`Max.exe ""`) +together with a small patcher that sends `; max clean; max quit` once the patcher under test has had +its time (q7 runs until Max's file database reports its update complete). It reads Max's log +(`%APPDATA%\Cycling '74\Max 9\Logs\Max.log`), writes `results\windows.txt`, turns off Restore Windows +on Launch for the run and puts Max's preference files back afterwards. With the runtime installed +(`scripts\install-runtime.ps1`) and Max quit: ```powershell cmake -S . -B build-spike -DTAP_PYTHON_SPIKE=ON cmake --build build-spike --config Release +mklink /J "C:\ProgramData\Max 9\Packages\PythonTap" +mklink /J "C:\ProgramData\Max 9\Packages\PythonTap-spike" \runtime-tests\spike +powershell -ExecutionPolicy Bypass -File runtime-tests\spike\run_spike_windows.ps1 ``` -then, with the package in `Documents\Max 9\Packages\PythonTap`: +(`C:\ProgramData\Max 9\Packages` is Max's system-wide Packages folder on Windows. In a Parallels VM +whose Documents folder is the Mac's, the per-user one is the Mac's own `~/Documents/Max 9/Packages`, +where a junction cannot be made — and which the Windows test should not touch. To run the glue test +there, put `support\` on `PATH` first, as CI does: without it the test stops at a modal "python313.dll +was not found" dialog.) + +Or by hand, with the package in a Packages folder: 1. In Max's preferences, turn off **Restore Windows on Launch** (or make sure no patcher with a `tap.python~` in it is open when you quit), and quit Max. diff --git a/runtime-tests/spike/run_spike_windows.ps1 b/runtime-tests/spike/run_spike_windows.ps1 index e68cb92..8171dc1 100644 --- a/runtime-tests/spike/run_spike_windows.ps1 +++ b/runtime-tests/spike/run_spike_windows.ps1 @@ -9,8 +9,11 @@ # powershell -ExecutionPolicy Bypass -File runtime-tests\spike\run_spike_windows.ps1 -Only q2,q3 # # The Windows counterpart of run_spike.py, which needs the macOS-only harness: each patcher runs in -# a fresh Max of its own, started as Explorer starts it (Max.exe "") together with a small -# patcher that sends Max `; max clean; max quit` once the patcher under test has had its time. Max +# a fresh Max of its own, started as Explorer starts it (Max.exe "") with a small starter +# patcher that waits for Max to finish starting up — a patcher opened with Max itself was found to +# have its main thread held for seconds after loading, which collapsed q5's timeline — then opens +# the patcher under test (`; max openfile`, by name: hence PythonTap-spike in Packages) and, once +# it has had its time, sends `; max clean; max quit`. Max # must be quit first, and the package (and runtime-tests\spike, for the patchers) must be in a # Packages folder — C:\ProgramData\Max 9\Packages\PythonTap and ...\PythonTap-spike as junctions # to this checkout and to runtime-tests\spike, say. What Max said comes from its own log @@ -65,22 +68,40 @@ $Interesting = "spike|recorder|\bq[1-7]\b|tap\.python|No such object|python:|Loa "missing arguments|obex|error\]|crash|maxdb update complete" $Noise = "RNBO|rnbo|j\.loader|bach|Could not load package|Error 126 loading external" -function Write-QuitPatcher([int]$Seconds) { - $path = Join-Path $Logs "spike-quit-$Seconds.maxpat" - $ms = $Seconds * 1000 - $json = @" -{ "patcher": { "fileversion": 1, "appversion": { "major": 9, "minor": 1, "revision": 5, "architecture": "x64", "modernui": 1 }, - "classnamespace": "box", "rect": [ 900.0, 600.0, 320.0, 160.0 ], - "boxes": [ - { "box": { "id": "obj-1", "maxclass": "comment", "text": "spike: quits Max after $Seconds s (run_spike_windows.ps1)", "numinlets": 1, "numoutlets": 0, "patching_rect": [ 20.0, 10.0, 280.0, 20.0 ] } }, - { "box": { "id": "obj-2", "maxclass": "newobj", "text": "loadbang", "numinlets": 1, "numoutlets": 1, "outlettype": [ "bang" ], "patching_rect": [ 20.0, 40.0, 60.0, 22.0 ] } }, - { "box": { "id": "obj-3", "maxclass": "newobj", "text": "delay $ms", "numinlets": 2, "numoutlets": 1, "outlettype": [ "bang" ], "patching_rect": [ 20.0, 70.0, 90.0, 22.0 ] } }, - { "box": { "id": "obj-4", "maxclass": "message", "text": "; max clean; max quit", "numinlets": 2, "numoutlets": 1, "outlettype": [ "" ], "patching_rect": [ 20.0, 100.0, 150.0, 22.0 ] } } - ], - "lines": [ { "patchline": { "source": [ "obj-2", 0 ], "destination": [ "obj-3", 0 ] } }, - { "patchline": { "source": [ "obj-3", 0 ], "destination": [ "obj-4", 0 ] } } ] } } -"@ - Set-Content -Path $path -Value $json -Encoding ASCII +$Settle = 15 # seconds for Max to finish starting up before the patcher under test opens + +# The starter: waits $Settle seconds, opens each patcher by name in turn, giving each $Seconds, and +# then has Max quit. It holds no tap.python, so for q1 the Max stays fresh until the patcher opens. +function Write-StarterPatcher([string]$Name, [string[]]$Which, [int]$Seconds) { + $steps = @() + $at = $Settle + foreach ($patcher in $Which) { + $steps += , @($at, "; max openfile spike$($steps.Count) tap.python.spike-$patcher.maxpat") + $at += $Seconds + } + if (-not $Which.Count) { $at += $Seconds } + $steps += , @($at, '; max clean; max quit') + + $boxes = @(@{ box = [ordered]@{ id = 'obj-0'; maxclass = 'newobj'; text = 'loadbang'; numinlets = 1; numoutlets = 1 + outlettype = @('bang'); patching_rect = @(20.0, 20.0, 60.0, 22.0) } }) + $lines = @() + $n = 1 + foreach ($step in $steps) { + $y = 20.0 + 30.0 * $n + $boxes += @{ box = [ordered]@{ id = "obj-d$n"; maxclass = 'newobj'; text = "delay $($step[0] * 1000)"; numinlets = 2 + numoutlets = 1; outlettype = @('bang'); patching_rect = @(20.0, $y, 90.0, 22.0) } } + $boxes += @{ box = [ordered]@{ id = "obj-m$n"; maxclass = 'message'; text = $step[1]; numinlets = 2; numoutlets = 1 + outlettype = @(''); patching_rect = @(130.0, $y, 420.0, 22.0) } } + $lines += @{ patchline = @{ source = @('obj-0', 0); destination = @("obj-d$n", 0) } } + $lines += @{ patchline = @{ source = @("obj-d$n", 0); destination = @("obj-m$n", 0) } } + $n++ + } + $patcher = @{ patcher = [ordered]@{ + fileversion = 1; classnamespace = 'box'; rect = @(900.0, 500.0, 580.0, 300.0) + appversion = [ordered]@{ major = 9; minor = 1; revision = 5; architecture = 'x64'; modernui = 1 } + boxes = $boxes; lines = $lines } } + $path = Join-Path $Logs "spike-windows-start-$Name.maxpat" + [System.IO.File]::WriteAllText($path, ($patcher | ConvertTo-Json -Depth 10)) return $path } @@ -147,16 +168,14 @@ function Invoke-Session([string]$Name, [string[]]$Which, [int]$Seconds) { if ($Name -eq 'q7') { $copied = Install-Q7 } try { Clear-CrashRecovery - $arguments = @() foreach ($patcher in $Which) { - $path = Join-Path $Patchers "tap.python.spike-$patcher.maxpat" - Write-Host " opening $(Split-Path $path -Leaf)" - $arguments += "`"$path`"" + if (-not (Test-Path (Join-Path $Patchers "tap.python.spike-$patcher.maxpat"))) { throw "no patcher $patcher" } + Write-Host " opening tap.python.spike-$patcher.maxpat" } - $arguments += "`"$(Write-QuitPatcher $Seconds)`"" + $starter = Write-StarterPatcher $Name $Which $Seconds $started = Get-Date - $process = Start-Process $Max -ArgumentList $arguments -PassThru - $deadline = $started.AddSeconds($Seconds + 180) + $process = Start-Process $Max -ArgumentList "`"$starter`"" -PassThru + $deadline = $started.AddSeconds($Settle + $Seconds * [Math]::Max(1, $Which.Count) + 180) while (-not $process.HasExited -and (Get-Date) -lt $deadline) { Start-Sleep -Seconds 2 if ($Name -eq 'q7' -and (Test-Path $MaxLog) -and From 50f6c250c6f2e3fa55d09f7cae5f28f6c147515f Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Fri, 9 Oct 2026 13:28:04 -0500 Subject: [PATCH 4/9] spike q5: check that audio really runs (dspstate~), and give the driver time to start Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz --- runtime-tests/spike/make_spike_patchers.py | 23 +- .../tap.python.spike-q5-threads.maxpat | 243 +++++++++++------- 2 files changed, 160 insertions(+), 106 deletions(-) diff --git a/runtime-tests/spike/make_spike_patchers.py b/runtime-tests/spike/make_spike_patchers.py index 5a64126..19c2b6c 100644 --- a/runtime-tests/spike/make_spike_patchers.py +++ b/runtime-tests/spike/make_spike_patchers.py @@ -229,7 +229,8 @@ def q5_threads() -> Script: "Q5 (M4): which thread a metro-driven message runs on with Overdrive off, Overdrive on, and " "Overdrive plus Scheduler in Audio Interrupt on — with audio on, then off. Each 'spike: thread' " "line gives systhread_ismainthread, isaudiothread and istimerthread on the thread the message " - "came on. Starts audio for a second (silence). Puts Overdrive and Audio Interrupt back as they " + "came on; q5-dsp-running says whether audio really ran. Starts audio for a few seconds (silence). " + "Puts Overdrive and Audio Interrupt back as they " "were (q5-was-…) at the end.") spike = s.spike("1", value_outlets=1) p = s.patcher @@ -283,16 +284,20 @@ def metro_phase(start: int, label: str, ms: int = 600) -> None: s.at(t + 1000, "", "; max preempt 1") report(t + 1100) metro_phase(t + 1250, "overdrive-on") + # whether audio really runs: the audio-running phase means nothing without it (dspstate~ says 1 + # when the audio starts, 0 when it stops), and an audio driver can take a while to start + dsp = p.box("dspstate~", inlets=1, outlets=4, column=2, outlettype=["int", "float", "int", "int"]) + p.connect(dsp, 0, s.recorder("q5-dsp-running")) s.at(t + 1950, "", "; dsp takeover 1; dsp start") report(t + 2050) - metro_phase(t + 3200, "overdrive-on-audio-interrupt-on-audio-running") - s.at(t + 3900, "", "; dsp stop") - metro_phase(t + 4100, "overdrive-on-audio-interrupt-on-audio-stopped") - s.say(t + 4800, "q5 putting Overdrive and Audio Interrupt back") - s.at(t + 4850, overdrive_was, "bang") - s.at(t + 4860, takeover_was, "bang") - report(t + 5000) - s.say(t + 5200, f"q5 {END}") + metro_phase(t + 4200, "overdrive-on-audio-interrupt-on-audio-running") + s.at(t + 4900, "", "; dsp stop") + metro_phase(t + 5100, "overdrive-on-audio-interrupt-on-audio-stopped") + s.say(t + 5800, "q5 putting Overdrive and Audio Interrupt back") + s.at(t + 5850, overdrive_was, "bang") + s.at(t + 5860, takeover_was, "bang") + report(t + 6000) + s.say(t + 6200, f"q5 {END}") return s diff --git a/runtime-tests/spike/patchers/tap.python.spike-q5-threads.maxpat b/runtime-tests/spike/patchers/tap.python.spike-q5-threads.maxpat index e6278d1..4dd84ed 100644 --- a/runtime-tests/spike/patchers/tap.python.spike-q5-threads.maxpat +++ b/runtime-tests/spike/patchers/tap.python.spike-q5-threads.maxpat @@ -35,7 +35,7 @@ 480, 128.0 ], - "text": "tap.python.spike-q5-threads\n\nQ5 (M4): which thread a metro-driven message runs on with Overdrive off, Overdrive on, and Overdrive plus Scheduler in Audio Interrupt on \u2014 with audio on, then off. Each 'spike: thread' line gives systhread_ismainthread, isaudiothread and istimerthread on the thread the message came on. Starts audio for a second (silence). Puts Overdrive and Audio Interrupt back as they were (q5-was-\u2026) at the end.", + "text": "tap.python.spike-q5-threads\n\nQ5 (M4): which thread a metro-driven message runs on with Overdrive off, Overdrive on, and Overdrive plus Scheduler in Audio Interrupt on \u2014 with audio on, then off. Each 'spike: thread' line gives systhread_ismainthread, isaudiothread and istimerthread on the thread the message came on; q5-dsp-running says whether audio really ran. Starts audio for a few seconds (silence). Puts Overdrive and Audio Interrupt back as they were (q5-was-\u2026) at the end.", "linecount": 8 } }, @@ -955,6 +955,43 @@ "box": { "id": "obj-53", "maxclass": "newobj", + "numinlets": 1, + "numoutlets": 4, + "outlettype": [ + "int", + "float", + "int", + "int" + ], + "patching_rect": [ + 520.0, + 468.0, + 79.0, + 22.0 + ], + "text": "dspstate~" + } + }, + { + "box": { + "id": "obj-54", + "maxclass": "newobj", + "numinlets": 1, + "numoutlets": 0, + "outlettype": [], + "patching_rect": [ + 520.0, + 498.0, + 296.0, + 22.0 + ], + "text": "tap.python.spike.recorder q5-dsp-running" + } + }, + { + "box": { + "id": "obj-55", + "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, "outlettype": [ @@ -971,7 +1008,7 @@ }, { "box": { - "id": "obj-54", + "id": "obj-56", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -989,7 +1026,7 @@ }, { "box": { - "id": "obj-55", + "id": "obj-57", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1007,7 +1044,7 @@ }, { "box": { - "id": "obj-56", + "id": "obj-58", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1025,7 +1062,7 @@ }, { "box": { - "id": "obj-57", + "id": "obj-59", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1043,7 +1080,7 @@ }, { "box": { - "id": "obj-58", + "id": "obj-60", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1061,7 +1098,7 @@ }, { "box": { - "id": "obj-59", + "id": "obj-61", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1079,7 +1116,7 @@ }, { "box": { - "id": "obj-60", + "id": "obj-62", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1097,7 +1134,7 @@ }, { "box": { - "id": "obj-61", + "id": "obj-63", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1110,12 +1147,12 @@ 86.0, 22.0 ], - "text": "delay 3250" + "text": "delay 4250" } }, { "box": { - "id": "obj-62", + "id": "obj-64", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1133,7 +1170,7 @@ }, { "box": { - "id": "obj-63", + "id": "obj-65", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1146,12 +1183,12 @@ 86.0, 22.0 ], - "text": "delay 3300" + "text": "delay 4300" } }, { "box": { - "id": "obj-64", + "id": "obj-66", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1169,7 +1206,7 @@ }, { "box": { - "id": "obj-65", + "id": "obj-67", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1182,12 +1219,12 @@ 86.0, 22.0 ], - "text": "delay 3900" + "text": "delay 4900" } }, { "box": { - "id": "obj-66", + "id": "obj-68", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1205,7 +1242,7 @@ }, { "box": { - "id": "obj-67", + "id": "obj-69", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1218,12 +1255,12 @@ 86.0, 22.0 ], - "text": "delay 4000" + "text": "delay 5000" } }, { "box": { - "id": "obj-68", + "id": "obj-70", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1241,7 +1278,7 @@ }, { "box": { - "id": "obj-69", + "id": "obj-71", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1259,7 +1296,7 @@ }, { "box": { - "id": "obj-70", + "id": "obj-72", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1277,7 +1314,7 @@ }, { "box": { - "id": "obj-71", + "id": "obj-73", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1290,12 +1327,12 @@ 86.0, 22.0 ], - "text": "delay 4150" + "text": "delay 5150" } }, { "box": { - "id": "obj-72", + "id": "obj-74", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1313,7 +1350,7 @@ }, { "box": { - "id": "obj-73", + "id": "obj-75", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1326,12 +1363,12 @@ 86.0, 22.0 ], - "text": "delay 4200" + "text": "delay 5200" } }, { "box": { - "id": "obj-74", + "id": "obj-76", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1349,7 +1386,7 @@ }, { "box": { - "id": "obj-75", + "id": "obj-77", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1362,12 +1399,12 @@ 86.0, 22.0 ], - "text": "delay 4800" + "text": "delay 5800" } }, { "box": { - "id": "obj-76", + "id": "obj-78", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1385,7 +1422,7 @@ }, { "box": { - "id": "obj-77", + "id": "obj-79", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1398,12 +1435,12 @@ 86.0, 22.0 ], - "text": "delay 4900" + "text": "delay 5900" } }, { "box": { - "id": "obj-78", + "id": "obj-80", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1421,7 +1458,7 @@ }, { "box": { - "id": "obj-79", + "id": "obj-81", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1434,12 +1471,12 @@ 86.0, 22.0 ], - "text": "delay 4950" + "text": "delay 5950" } }, { "box": { - "id": "obj-80", + "id": "obj-82", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1457,7 +1494,7 @@ }, { "box": { - "id": "obj-81", + "id": "obj-83", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1470,12 +1507,12 @@ 86.0, 22.0 ], - "text": "delay 4960" + "text": "delay 5960" } }, { "box": { - "id": "obj-82", + "id": "obj-84", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1493,7 +1530,7 @@ }, { "box": { - "id": "obj-83", + "id": "obj-85", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1506,12 +1543,12 @@ 86.0, 22.0 ], - "text": "delay 5100" + "text": "delay 6100" } }, { "box": { - "id": "obj-84", + "id": "obj-86", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1529,7 +1566,7 @@ }, { "box": { - "id": "obj-85", + "id": "obj-87", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1542,12 +1579,12 @@ 86.0, 22.0 ], - "text": "delay 5110" + "text": "delay 6110" } }, { "box": { - "id": "obj-86", + "id": "obj-88", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -1565,7 +1602,7 @@ }, { "box": { - "id": "obj-87", + "id": "obj-89", "maxclass": "newobj", "numinlets": 2, "numoutlets": 1, @@ -1578,12 +1615,12 @@ 86.0, 22.0 ], - "text": "delay 5300" + "text": "delay 6300" } }, { "box": { - "id": "obj-88", + "id": "obj-90", "maxclass": "message", "numinlets": 2, "numoutlets": 1, @@ -2357,18 +2394,6 @@ ] } }, - { - "patchline": { - "source": [ - "obj-2", - 0 - ], - "destination": [ - "obj-53", - 0 - ] - } - }, { "patchline": { "source": [ @@ -2405,18 +2430,6 @@ ] } }, - { - "patchline": { - "source": [ - "obj-56", - 0 - ], - "destination": [ - "obj-5", - 0 - ] - } - }, { "patchline": { "source": [ @@ -2448,7 +2461,7 @@ 0 ], "destination": [ - "obj-8", + "obj-5", 0 ] } @@ -2456,11 +2469,11 @@ { "patchline": { "source": [ - "obj-59", + "obj-2", 0 ], "destination": [ - "obj-60", + "obj-59", 0 ] } @@ -2468,11 +2481,11 @@ { "patchline": { "source": [ - "obj-60", + "obj-59", 0 ], "destination": [ - "obj-4", + "obj-60", 0 ] } @@ -2480,11 +2493,11 @@ { "patchline": { "source": [ - "obj-2", + "obj-60", 0 ], "destination": [ - "obj-61", + "obj-8", 0 ] } @@ -2508,7 +2521,7 @@ 0 ], "destination": [ - "obj-3", + "obj-4", 0 ] } @@ -2544,7 +2557,7 @@ 0 ], "destination": [ - "obj-59", + "obj-3", 0 ] } @@ -2580,7 +2593,7 @@ 0 ], "destination": [ - "obj-59", + "obj-61", 0 ] } @@ -2612,11 +2625,11 @@ { "patchline": { "source": [ - "obj-69", + "obj-68", 0 ], "destination": [ - "obj-70", + "obj-61", 0 ] } @@ -2624,11 +2637,11 @@ { "patchline": { "source": [ - "obj-70", + "obj-2", 0 ], "destination": [ - "obj-4", + "obj-69", 0 ] } @@ -2636,11 +2649,11 @@ { "patchline": { "source": [ - "obj-2", + "obj-69", 0 ], "destination": [ - "obj-71", + "obj-70", 0 ] } @@ -2664,7 +2677,7 @@ 0 ], "destination": [ - "obj-3", + "obj-4", 0 ] } @@ -2700,7 +2713,7 @@ 0 ], "destination": [ - "obj-69", + "obj-3", 0 ] } @@ -2736,7 +2749,7 @@ 0 ], "destination": [ - "obj-69", + "obj-71", 0 ] } @@ -2772,7 +2785,7 @@ 0 ], "destination": [ - "obj-3", + "obj-71", 0 ] } @@ -2808,7 +2821,7 @@ 0 ], "destination": [ - "obj-6", + "obj-3", 0 ] } @@ -2844,7 +2857,7 @@ 0 ], "destination": [ - "obj-9", + "obj-6", 0 ] } @@ -2880,7 +2893,7 @@ 0 ], "destination": [ - "obj-5", + "obj-9", 0 ] } @@ -2916,7 +2929,7 @@ 0 ], "destination": [ - "obj-8", + "obj-5", 0 ] } @@ -2951,6 +2964,42 @@ "obj-88", 0 ], + "destination": [ + "obj-8", + 0 + ] + } + }, + { + "patchline": { + "source": [ + "obj-2", + 0 + ], + "destination": [ + "obj-89", + 0 + ] + } + }, + { + "patchline": { + "source": [ + "obj-89", + 0 + ], + "destination": [ + "obj-90", + 0 + ] + } + }, + { + "patchline": { + "source": [ + "obj-90", + 0 + ], "destination": [ "obj-3", 0 From 9e9270934bb06c38286a8a9be508ad0b44fc75ba Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Fri, 9 Oct 2026 14:00:36 -0500 Subject: [PATCH 5/9] run_spike_windows.ps1: say when Max's database had not finished; -Only updates its sessions' sections Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz --- init/tap.python.txt | 1 - runtime-tests/spike/run_spike_windows.ps1 | 28 ++++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) delete mode 100644 init/tap.python.txt diff --git a/init/tap.python.txt b/init/tap.python.txt deleted file mode 100644 index 17a2420..0000000 --- a/init/tap.python.txt +++ /dev/null @@ -1 +0,0 @@ -max objectfile tap.python tap.python~; diff --git a/runtime-tests/spike/run_spike_windows.ps1 b/runtime-tests/spike/run_spike_windows.ps1 index 8171dc1..2a690d8 100644 --- a/runtime-tests/spike/run_spike_windows.ps1 +++ b/runtime-tests/spike/run_spike_windows.ps1 @@ -61,7 +61,7 @@ $Sessions = @( @('q4-dispatch', @('q4-dispatch'), 6), @('q5-threads', @('q5-threads'), 12), @('q6-strings', @('q6-strings'), 6), - @('q7', @(), 900) + @('q7', @(), 3600) ) $Interesting = "spike|recorder|\bq[1-7]\b|tap\.python|No such object|python:|Loaded |doesn't understand|" + @@ -156,7 +156,11 @@ for name in names: "@ $script = Join-Path $Logs 'spike-windows-q7-query.py' [System.IO.File]::WriteAllText($script, $query) - $lines = @('', "Max's file database ($($database.Name)), for the files q7 put in the package:") + $lines = @('') + if (-not (Select-String -Path $MaxLog -Pattern 'maxdb update complete' -Quiet)) { + $lines += "Max's file database had NOT finished its update when Max quit, so what follows is incomplete:" + } + $lines += "Max's file database ($($database.Name)), for the files q7 put in the package:" $lines += & $Python $script $copy $names return $lines } @@ -248,5 +252,23 @@ $os = (Get-CimInstance Win32_OperatingSystem) $header = @("# The plan 9.0 spike in Max $version, $($os.Caption) $($os.Version) $env:PROCESSOR_ARCHITECTURE", '# (written by runtime-tests/spike/run_spike_windows.ps1: the lines of interest from Max''s log)', '') $output = Join-Path $Results 'windows.txt' -[System.IO.File]::WriteAllLines($output, [string[]]($header + $report)) # UTF-8, no BOM +# With -Only, the sessions run replace their own sections of an existing results file. +$sections = [ordered]@{} +if ($Only.Count -and (Test-Path $output)) { + $current = $null + foreach ($line in (Get-Content $output)) { + if ($line -match '^## session (\S+)') { $current = $Matches[1]; $sections[$current] = @() } + if ($current) { $sections[$current] += $line } + } +} +$current = $null +foreach ($line in $report) { + if ($line -match '^## session (\S+)') { $current = $Matches[1]; $sections[$current] = @() } + if ($current) { $sections[$current] += $line } +} +$body = @() +foreach ($session in $Sessions) { + if ($sections.Contains($session[0])) { $body += $sections[$session[0]] } +} +[System.IO.File]::WriteAllLines($output, [string[]]($header + $body)) # UTF-8, no BOM Write-Host "wrote $output" From 5c69055b6741d155b3289546d175c203378ade87 Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Fri, 9 Oct 2026 14:07:24 -0500 Subject: [PATCH 6/9] Put back init/tap.python.txt, deleted by mistake in 9e92709 The commit was made with -a while the spike's runner had the file moved aside for its q1 control session. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz --- init/tap.python.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 init/tap.python.txt diff --git a/init/tap.python.txt b/init/tap.python.txt new file mode 100644 index 0000000..17a2420 --- /dev/null +++ b/init/tap.python.txt @@ -0,0 +1 @@ +max objectfile tap.python tap.python~; From 49fa5c1c187e41e999cdb7cd1bcdf2d509927261 Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Fri, 9 Oct 2026 14:07:41 -0500 Subject: [PATCH 7/9] spike: the Mac's results again, with q5's check that audio ran Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz --- runtime-tests/spike/results/macos.txt | 725 +++++++++++++------------- 1 file changed, 365 insertions(+), 360 deletions(-) diff --git a/runtime-tests/spike/results/macos.txt b/runtime-tests/spike/results/macos.txt index cc5709c..f1d2551 100644 --- a/runtime-tests/spike/results/macos.txt +++ b/runtime-tests/spike/results/macos.txt @@ -3,378 +3,383 @@ ## session q1-control -[2026-10-09 06:40:19.655320 error] [52026397] tap.python: No such object +[2026-10-09 14:00:29.493900 error] [52495599] tap.python: No such object ## session q1-mapping -[2026-10-09 06:40:44.824979 info] [52027661] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) -[2026-10-09 06:40:44.825056 info] [52027661] spike: new tap.python: 2 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 14:00:53.481432 info] [52497029] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) +[2026-10-09 14:00:53.481475 info] [52497029] spike: new tap.python: 2 value outlet(s) + dumpout, steps 8; main thread 1 ## session q1-spike-first -[2026-10-09 06:41:02.601669 info] [52028702] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) -[2026-10-09 06:41:02.601754 info] [52028702] spike: new tap.python: 2 value outlet(s) + dumpout, steps 8; main thread 1 -[2026-10-09 06:41:02.758876 info] [52028702] Loaded default.py: process() bound, one call per sample -[2026-10-09 06:41:03.357301 info] [52028702] q1 spike-first begin -[2026-10-09 06:41:03.357322 info] [52028702] spike: fire -[2026-10-09 06:41:03.357401 info] [52028702] recorder q1-spike: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:41:03.357410 info] [52028702] recorder q1-spike: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:41:03.357512 info] [52028702] python: hello q1, from python! -[2026-10-09 06:41:03.357530 info] [52028702] q1 spike-first end +[2026-10-09 14:01:13.179112 info] [52498275] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) +[2026-10-09 14:01:13.179163 info] [52498275] spike: new tap.python: 2 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 14:01:13.451868 info] [52498275] Loaded default.py: process() bound, one call per sample +[2026-10-09 14:01:14.585181 info] [52498275] q1 spike-first begin +[2026-10-09 14:01:14.585202 info] [52498275] spike: fire +[2026-10-09 14:01:14.585281 info] [52498275] recorder q1-spike: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:01:14.585289 info] [52498275] recorder q1-spike: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:01:14.585398 info] [52498275] python: hello q1, from python! +[2026-10-09 14:01:14.585414 info] [52498275] q1 spike-first end ## session q1-tilde-first -[2026-10-09 06:41:15.566672 error] [52029675] Node for Max process manager quit. Please restart any running node scripts. -[2026-10-09 06:41:28.410895 info] [52029539] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) -[2026-10-09 06:41:28.502563 info] [52029539] Loaded default.py: process() bound, one call per sample -[2026-10-09 06:41:28.506840 info] [52029539] spike: new tap.python: 2 value outlet(s) + dumpout, steps 8; main thread 1 -[2026-10-09 06:41:29.304473 info] [52029539] q1 tilde-first begin -[2026-10-09 06:41:29.304495 info] [52029539] spike: fire -[2026-10-09 06:41:29.304526 info] [52029539] recorder q1-spike: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:41:29.304535 info] [52029539] recorder q1-spike: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:41:29.304590 info] [52029539] python: hello q1, from python! -[2026-10-09 06:41:29.304606 info] [52029539] q1 tilde-first end +[2026-10-09 14:01:32.631300 info] [52499240] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) +[2026-10-09 14:01:32.772067 info] [52499240] Loaded default.py: process() bound, one call per sample +[2026-10-09 14:01:32.774882 info] [52499240] spike: new tap.python: 2 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 14:01:33.740577 info] [52499240] q1 tilde-first begin +[2026-10-09 14:01:33.740600 info] [52499240] spike: fire +[2026-10-09 14:01:33.741029 info] [52499240] recorder q1-spike: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:01:33.741040 info] [52499240] recorder q1-spike: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:01:33.741138 info] [52499240] python: hello q1, from python! +[2026-10-09 14:01:33.741166 info] [52499240] q1 tilde-first end ## session q2-q6 -[2026-10-09 06:41:45.633499 info] [52030442] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) -[2026-10-09 06:41:45.633550 info] [52030442] spike: new tap.python: 2 value outlet(s) + dumpout, steps 8; main thread 1 -[2026-10-09 06:41:46.436019 info] [52030442] q2 begin: two value outlets and the dumpout -[2026-10-09 06:41:46.436038 info] [52030442] spike: describe: outlet_count 3 (2 value outlet(s) held + dumpout) -[2026-10-09 06:41:46.436042 info] [52030442] spike: describe: outlet_nth(0) is value outlet 0 -[2026-10-09 06:41:46.436045 info] [52030442] spike: describe: outlet_nth(1) is value outlet 1 -[2026-10-09 06:41:46.436047 info] [52030442] spike: describe: outlet_nth(2) is the dumpout -[2026-10-09 06:41:46.436049 info] [52030442] spike: describe: the obex's dumpout is the one made first -[2026-10-09 06:41:46.436083 info] [52030442] spike: describe: cord from outlet 2 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.436086 info] [52030442] spike: describe: cord from outlet 1 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.436089 info] [52030442] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.436091 info] [52030442] spike: describe: 3 cord(s) from this box -[2026-10-09 06:41:46.436094 info] [52030442] spike: fire -[2026-10-09 06:41:46.436107 info] [52030442] recorder q2-dumpout: selector 'fired', 0 atom(s) -[2026-10-09 06:41:46.436115 info] [52030442] recorder q2-outlet-1: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:41:46.436121 info] [52030442] recorder q2-outlet-0: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:41:46.436128 info] [52030442] q2 widen: outlets 3 -[2026-10-09 06:41:46.436135 info] [52030442] spike: outlets: 2 -> 3 value outlet(s) -[2026-10-09 06:41:46.436264 info] [52030442] spike: describe: outlet_count 4 (3 value outlet(s) held + dumpout) -[2026-10-09 06:41:46.436269 info] [52030442] spike: describe: outlet_nth(0) is value outlet 0 -[2026-10-09 06:41:46.436271 info] [52030442] spike: describe: outlet_nth(1) is value outlet 1 -[2026-10-09 06:41:46.436273 info] [52030442] spike: describe: outlet_nth(2) is value outlet 2 -[2026-10-09 06:41:46.436274 info] [52030442] spike: describe: outlet_nth(3) is the dumpout -[2026-10-09 06:41:46.436278 info] [52030442] spike: describe: the obex's dumpout is the one made first -[2026-10-09 06:41:46.436291 info] [52030442] spike: describe: cord from outlet 3 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.436294 info] [52030442] spike: describe: cord from outlet 1 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.436296 info] [52030442] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.436298 info] [52030442] spike: describe: 3 cord(s) from this box -[2026-10-09 06:41:46.436406 info] [52030442] spike: describe: outlet_count 4 (3 value outlet(s) held + dumpout) -[2026-10-09 06:41:46.436412 info] [52030442] spike: describe: outlet_nth(0) is value outlet 0 -[2026-10-09 06:41:46.436414 info] [52030442] spike: describe: outlet_nth(1) is value outlet 1 -[2026-10-09 06:41:46.436415 info] [52030442] spike: describe: outlet_nth(2) is value outlet 2 -[2026-10-09 06:41:46.436417 info] [52030442] spike: describe: outlet_nth(3) is the dumpout -[2026-10-09 06:41:46.436421 info] [52030442] spike: describe: the obex's dumpout is the one made first -[2026-10-09 06:41:46.436425 info] [52030442] spike: describe: cord from outlet 2 to newprint inlet 0 -[2026-10-09 06:41:46.436436 info] [52030442] spike: describe: cord from outlet 3 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.436439 info] [52030442] spike: describe: cord from outlet 1 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.436441 info] [52030442] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.436443 info] [52030442] spike: describe: 4 cord(s) from this box -[2026-10-09 06:41:46.436463 info] [52030442] spike: fire -[2026-10-09 06:41:46.436466 info] [52030442] recorder q2-dumpout: selector 'fired', 0 atom(s) -[2026-10-09 06:41:46.436476 info] [52030442] recorder q2-new: selector 'int', 1 atom(s): 2 (int) -[2026-10-09 06:41:46.436478 info] [52030442] recorder q2-outlet-1: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:41:46.436486 info] [52030442] recorder q2-outlet-0: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:41:46.436494 info] [52030442] q2 narrow: outlets 1 -[2026-10-09 06:41:46.436498 info] [52030442] spike: outlets: 3 -> 1 value outlet(s) -[2026-10-09 06:41:46.442078 info] [52030442] spike: describe: outlet_count 2 (1 value outlet(s) held + dumpout) -[2026-10-09 06:41:46.442086 info] [52030442] spike: describe: outlet_nth(0) is value outlet 0 -[2026-10-09 06:41:46.442088 info] [52030442] spike: describe: outlet_nth(1) is the dumpout -[2026-10-09 06:41:46.442090 info] [52030442] spike: describe: the obex's dumpout is the one made first -[2026-10-09 06:41:46.442104 info] [52030442] spike: describe: cord from outlet 1 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.442107 info] [52030442] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.442109 info] [52030442] spike: describe: 2 cord(s) from this box -[2026-10-09 06:41:46.442115 info] [52030442] spike: fire -[2026-10-09 06:41:46.442118 info] [52030442] recorder q2-dumpout: selector 'fired', 0 atom(s) -[2026-10-09 06:41:46.442121 info] [52030442] recorder q2-outlet-0: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:41:46.442144 info] [52030442] q2 widen again: outlets 2 -[2026-10-09 06:41:46.487813 info] [52030442] spike: outlets: 1 -> 2 value outlet(s) -[2026-10-09 06:41:46.487939 info] [52030442] spike: describe: outlet_count 3 (2 value outlet(s) held + dumpout) -[2026-10-09 06:41:46.487945 info] [52030442] spike: describe: outlet_nth(0) is value outlet 0 -[2026-10-09 06:41:46.487947 info] [52030442] spike: describe: outlet_nth(1) is value outlet 1 -[2026-10-09 06:41:46.487949 info] [52030442] spike: describe: outlet_nth(2) is the dumpout -[2026-10-09 06:41:46.487961 info] [52030442] spike: describe: the obex's dumpout is the one made first -[2026-10-09 06:41:46.487982 info] [52030442] spike: describe: cord from outlet 2 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.487985 info] [52030442] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 -[2026-10-09 06:41:46.487987 info] [52030442] spike: describe: 2 cord(s) from this box -[2026-10-09 06:41:46.487990 info] [52030442] spike: fire -[2026-10-09 06:41:46.487995 info] [52030442] recorder q2-dumpout: selector 'fired', 0 atom(s) -[2026-10-09 06:41:46.487999 info] [52030442] recorder q2-outlet-0: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:41:46.670816 info] [52030442] q2 end -[2026-10-09 06:41:51.115099 info] [52030442] spike: steps setter called (instance attribute) <- 5 -[2026-10-09 06:41:51.115111 info] [52030442] spike: new tap.python: 1 value outlet(s) + dumpout, steps 5; main thread 1 -[2026-10-09 06:41:51.115242 info] [52030442] spike: steps setter called (instance attribute) <- 5 -[2026-10-09 06:41:51.115245 info] [52030442] spike: new tap.python.spike.nodumpout: 1 value outlet(s) + dumpout, steps 5; main thread 1 -[2026-10-09 06:41:51.248959 info] [52030442] q3 tap.python: the instance attribute steps -[2026-10-09 06:41:51.286607 info] [52030442] spike: steps getter called (instance attribute) -> 5 -[2026-10-09 06:41:51.286639 info] [52030442] recorder q3-dumpout: selector 'steps', 1 atom(s): 5 (int) -[2026-10-09 06:41:51.286660 info] [52030442] spike: steps setter called (instance attribute) <- 8 -[2026-10-09 06:41:51.286667 info] [52030442] spike: steps getter called (instance attribute) -> 8 -[2026-10-09 06:41:51.286669 info] [52030442] recorder q3-dumpout: selector 'steps', 1 atom(s): 8 (int) -[2026-10-09 06:41:51.321305 info] [52030442] q3 tap.python: the class attribute level -[2026-10-09 06:41:51.371290 info] [52030442] recorder q3-dumpout: selector 'level', 1 atom(s): 1 (int) -[2026-10-09 06:41:51.371302 info] [52030442] recorder q3-dumpout: selector 'level', 1 atom(s): 3 (int) -[2026-10-09 06:41:51.421349 info] [52030442] q3 tap.python: object_attr_getdump and object_attr_method -[2026-10-09 06:41:51.471337 info] [52030442] spike: getdump steps: calling object_attr_getdump() -[2026-10-09 06:41:51.471351 info] [52030442] recorder q3-dumpout: selector 'ps', 0 atom(s) -[2026-10-09 06:41:51.471355 info] [52030442] spike: getdump level: calling object_attr_getdump() -[2026-10-09 06:41:51.471365 info] [52030442] recorder q3-dumpout: selector 'el', 0 atom(s) -[2026-10-09 06:41:51.471372 info] [52030442] spike: attrmethod 'getsteps': object_attr_method found a method, attribute found, get 1 (steps' own getter) -[2026-10-09 06:41:51.471375 info] [52030442] spike: attrmethod 'steps': object_attr_method found a method, attribute found, get 0 (steps' own setter) -[2026-10-09 06:41:51.471380 info] [52030442] spike: attrmethod 'getlevel': object_attr_method found a method, attribute found, get 1 -[2026-10-09 06:41:51.471383 info] [52030442] spike: attrmethod 'level': object_attr_method found a method, attribute found, get 0 -[2026-10-09 06:41:51.471392 info] [52030442] spike: probe 'getsteps' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:51.471396 info] [52030442] spike: probe 'dumpout' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null -[2026-10-09 06:41:51.621301 info] [52030442] q3 tap.python.spike.nodumpout: the instance attribute steps -[2026-10-09 06:41:51.671391 info] [52030442] spike: steps setter called (instance attribute) <- 8 -[2026-10-09 06:41:51.721280 info] [52030442] q3 tap.python.spike.nodumpout: the class attribute level -[2026-10-09 06:41:51.821302 info] [52030442] q3 tap.python.spike.nodumpout: object_attr_getdump and object_attr_method -[2026-10-09 06:41:51.871285 info] [52030442] spike: getdump steps: calling object_attr_getdump() -[2026-10-09 06:41:51.871292 info] [52030442] spike: getdump level: calling object_attr_getdump() -[2026-10-09 06:41:51.871324 info] [52030442] spike: attrmethod 'getsteps': object_attr_method found a method, attribute found, get 1 (steps' own getter) -[2026-10-09 06:41:51.871327 info] [52030442] spike: attrmethod 'steps': object_attr_method found a method, attribute found, get 0 (steps' own setter) -[2026-10-09 06:41:51.871347 info] [52030442] spike: attrmethod 'getlevel': object_attr_method found a method, attribute found, get 1 -[2026-10-09 06:41:51.871350 info] [52030442] spike: attrmethod 'level': object_attr_method found a method, attribute found, get 0 -[2026-10-09 06:41:51.871357 info] [52030442] spike: probe 'getsteps' on this tap.python.spike.nodumpout: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:51.871362 info] [52030442] spike: probe 'dumpout' on this tap.python.spike.nodumpout: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:52.021275 info] [52030442] q3 end -[2026-10-09 06:41:57.192188 info] [52030442] spike: new tap.python: 1 value outlet(s) + dumpout, steps 8; main thread 1 -[2026-10-09 06:41:57.192315 info] [52030442] spike: new tap.python (bare: no instance attribute or methods): 1 value outlet(s) + dumpout, steps 8; main thread 1 -[2026-10-09 06:41:57.283786 info] [52030442] Loaded default.py: process() bound, one call per sample -[2026-10-09 06:41:57.439243 info] [52030442] q4 begin: dispatch on the spike -[2026-10-09 06:41:57.449904 info] [52030442] spike: steps setter called (instance attribute) <- 8 -[2026-10-09 06:41:57.449921 info] [52030442] spike: steps getter called (instance attribute) -> 8 -[2026-10-09 06:41:57.449937 info] [52030442] recorder q4-dumpout: selector 'steps', 1 atom(s): 8 (int) -[2026-10-09 06:41:57.449942 info] [52030442] spike: instance method hello called (object_addmethod, A_GIMME): 1 2 -[2026-10-09 06:41:57.449945 info] [52030442] spike: who: the INSTANCE method (object_addmethod) answered -[2026-10-09 06:41:57.449953 info] [52030442] spike: instance method int called (object_addmethod, A_LONG): 5 -[2026-10-09 06:41:57.449961 error] [52030442] doesn't understand "float" -[2026-10-09 06:41:57.449964 info] [52030442] spike: bang: the INSTANCE method (object_addmethod) answered -[2026-10-09 06:41:57.449967 info] [52030442] spike: instance method int called (object_addmethod, A_LONG): 1 -[2026-10-09 06:41:57.449970 info] [52030442] spike: instance method int called (object_addmethod, A_LONG): 4 -[2026-10-09 06:41:57.449975 info] [52030442] spike: class anything received: selector 'symbol', 1 argument(s): foo -[2026-10-09 06:41:57.449979 info] [52030442] spike: class anything received: selector 'foo', 2 argument(s): 1 2 -[2026-10-09 06:41:57.524248 info] [52030442] q4 dispatch on the bare spike -[2026-10-09 06:41:57.598797 info] [52030442] spike: class anything received: selector 'steps', 1 argument(s): 8 -[2026-10-09 06:41:57.598809 info] [52030442] spike: class anything received: selector 'getsteps', 0 argument(s): -[2026-10-09 06:41:57.598820 info] [52030442] spike: class anything received: selector 'hello', 2 argument(s): 1 2 -[2026-10-09 06:41:57.598823 info] [52030442] spike: who: the CLASS method (class_addmethod) answered -[2026-10-09 06:41:57.598827 error] [52030442] doesn't understand "int" -[2026-10-09 06:41:57.598829 error] [52030442] doesn't understand "float" -[2026-10-09 06:41:57.598832 info] [52030442] spike: bang: the CLASS method (class_addmethod) answered -[2026-10-09 06:41:57.598835 error] [52030442] doesn't understand "int" -[2026-10-09 06:41:57.598837 error] [52030442] doesn't understand "int" -[2026-10-09 06:41:57.598842 info] [52030442] spike: class anything received: selector 'symbol', 1 argument(s): foo -[2026-10-09 06:41:57.598846 info] [52030442] spike: class anything received: selector 'foo', 2 argument(s): 1 2 -[2026-10-09 06:41:57.598855 info] [52030442] q4 probes on the spike (it has a class-level anything) -[2026-10-09 06:41:57.667588 info] [52030442] spike: probe 'foo' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:57.667600 info] [52030442] spike: probe 'anything' on this tap.python: object_getmethod is this class's anything; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null -[2026-10-09 06:41:57.667605 info] [52030442] spike: probe 'steps' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:57.667610 info] [52030442] spike: probe 'getsteps' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:57.667614 info] [52030442] spike: probe 'level' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:57.667618 info] [52030442] spike: probe 'getlevel' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:57.667622 info] [52030442] spike: probe 'hello' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null -[2026-10-09 06:41:57.667625 info] [52030442] spike: probe 'who' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null -[2026-10-09 06:41:57.667629 info] [52030442] spike: probe 'int' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null -[2026-10-09 06:41:57.667632 info] [52030442] spike: probe 'float' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:57.667637 info] [52030442] spike: probe 'bang' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null -[2026-10-09 06:41:57.667646 info] [52030442] spike: probe 'list' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:57.667650 info] [52030442] spike: probe 'symbol' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:57.667655 info] [52030442] spike: probe 'outlets' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null -[2026-10-09 06:41:57.795050 info] [52030442] q4 probes on tap.python~ (no anything) -[2026-10-09 06:41:57.845109 info] [52030442] spike: probe 'foo' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:57.845137 info] [52030442] spike: probe 'anything' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:57.845155 info] [52030442] spike: probe 'gain' on tilde (tap.python~): object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:57.845172 info] [52030442] spike: probe 'greet' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null -[2026-10-09 06:41:57.845188 info] [52030442] spike: probe 'int' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null -[2026-10-09 06:41:57.845205 info] [52030442] spike: probe 'dsp64' on tilde (tap.python~): object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null -[2026-10-09 06:41:57.845230 info] [52030442] spike: probe 'bang' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null -[2026-10-09 06:41:57.997444 info] [52030442] q4 end -[2026-10-09 06:42:03.259331 info] [52030442] spike: new tap.python: 1 value outlet(s) + dumpout, steps 8; main thread 1 -[2026-10-09 06:42:03.416543 info] [52030442] q6 begin -[2026-10-09 06:42:03.434941 info] [52030442] spike: q6 ---- as a message: 'C' -[2026-10-09 06:42:03.434977 info] [52030442] recorder q6-msgbox: selector 'C', 0 atom(s) -[2026-10-09 06:42:03.434994 info] [52030442] recorder q6-prepend: selector 'got', 1 atom(s): 'C' (symbol) -[2026-10-09 06:42:03.435010 info] [52030442] recorder q6-sel-C: selector 'bang', 0 atom(s) -[2026-10-09 06:42:03.435021 info] [52030442] recorder q6-route-C: selector 'bang', 0 atom(s) -[2026-10-09 06:42:03.435047 info] [52030442] recorder q6-raw: selector 'C', 0 atom(s) -[2026-10-09 06:42:03.435054 info] [52030442] spike: q6 ---- as a message: 'hello world' -[2026-10-09 06:42:03.435059 info] [52030442] recorder q6-msgbox: selector 'hello world', 0 atom(s) -[2026-10-09 06:42:03.435063 info] [52030442] recorder q6-prepend: selector 'got', 1 atom(s): 'hello world' (symbol) -[2026-10-09 06:42:03.435074 info] [52030442] recorder q6-sel-reject: selector 'hello world', 0 atom(s) -[2026-10-09 06:42:03.435084 info] [52030442] recorder q6-route-reject: selector 'hello world', 0 atom(s) -[2026-10-09 06:42:03.435086 info] [52030442] recorder q6-raw: selector 'hello world', 0 atom(s) -[2026-10-09 06:42:03.435092 info] [52030442] spike: q6 ---- as a message: '60' -[2026-10-09 06:42:03.435097 info] [52030442] recorder q6-msgbox: selector '60', 0 atom(s) -[2026-10-09 06:42:03.435100 info] [52030442] recorder q6-prepend: selector 'got', 1 atom(s): '60' (symbol) -[2026-10-09 06:42:03.435111 info] [52030442] recorder q6-sel-reject: selector '60', 0 atom(s) -[2026-10-09 06:42:03.435114 info] [52030442] recorder q6-route-reject: selector '60', 0 atom(s) -[2026-10-09 06:42:03.435116 info] [52030442] recorder q6-raw: selector '60', 0 atom(s) -[2026-10-09 06:42:03.435124 info] [52030442] spike: q6 ---- as a message: '1.5' -[2026-10-09 06:42:03.435128 info] [52030442] recorder q6-msgbox: selector '1.5', 0 atom(s) -[2026-10-09 06:42:03.435131 info] [52030442] recorder q6-prepend: selector 'got', 1 atom(s): '1.5' (symbol) -[2026-10-09 06:42:03.435134 info] [52030442] recorder q6-sel-reject: selector '1.5', 0 atom(s) -[2026-10-09 06:42:03.435136 info] [52030442] recorder q6-route-reject: selector '1.5', 0 atom(s) -[2026-10-09 06:42:03.435138 info] [52030442] recorder q6-raw: selector '1.5', 0 atom(s) -[2026-10-09 06:42:03.435143 info] [52030442] spike: q6 ---- as a message: 'list' -[2026-10-09 06:42:03.435151 info] [52030442] spike: q6 ---- as a message: 'int' -[2026-10-09 06:42:03.435163 error] [52030442] missing arguments for message "int" -[2026-10-09 06:42:03.435172 error] [52030442] missing arguments for message "int" -[2026-10-09 06:42:03.435180 error] [52030442] missing arguments for message "int" -[2026-10-09 06:42:03.435188 error] [52030442] missing arguments for message "int" -[2026-10-09 06:42:03.435190 error] [52030442] missing arguments for message "int" -[2026-10-09 06:42:03.435195 info] [52030442] spike: q6 ---- as a message: 'float' -[2026-10-09 06:42:03.435199 error] [52030442] missing arguments for message "float" -[2026-10-09 06:42:03.435201 error] [52030442] missing arguments for message "float" -[2026-10-09 06:42:03.435203 error] [52030442] missing arguments for message "float" -[2026-10-09 06:42:03.435208 error] [52030442] missing arguments for message "float" -[2026-10-09 06:42:03.435210 error] [52030442] missing arguments for message "float" -[2026-10-09 06:42:03.435215 info] [52030442] spike: q6 ---- as a message: 'symbol' -[2026-10-09 06:42:03.435217 error] [52030442] missing arguments for message "symbol" -[2026-10-09 06:42:03.435221 info] [52030442] recorder q6-prepend: selector 'got', 1 atom(s): 'symbol' (symbol) -[2026-10-09 06:42:03.435226 info] [52030442] recorder q6-sel-reject: selector 'symbol', 1 atom(s): '' (symbol) -[2026-10-09 06:42:03.435228 info] [52030442] recorder q6-route-reject: selector 'symbol', 0 atom(s) -[2026-10-09 06:42:03.435230 info] [52030442] recorder q6-raw: selector 'symbol', 0 atom(s) -[2026-10-09 06:42:03.435235 info] [52030442] spike: q6 ---- as a message: 'bang' -[2026-10-09 06:42:03.435239 info] [52030442] recorder q6-msgbox: selector '1.5', 0 atom(s) -[2026-10-09 06:42:03.435245 info] [52030442] recorder q6-prepend: selector 'got', 1 atom(s): 'bang' (symbol) -[2026-10-09 06:42:03.435248 info] [52030442] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'bang' (symbol) -[2026-10-09 06:42:03.435251 info] [52030442] recorder q6-route-reject: selector 'bang', 0 atom(s) -[2026-10-09 06:42:03.435253 info] [52030442] recorder q6-raw: selector 'bang', 0 atom(s) -[2026-10-09 06:42:03.435258 info] [52030442] spike: q6 ---- as a message: '' -[2026-10-09 06:42:03.435262 info] [52030442] recorder q6-msgbox: selector '', 0 atom(s) -[2026-10-09 06:42:03.435264 info] [52030442] recorder q6-prepend: selector 'got', 1 atom(s): '' (symbol) -[2026-10-09 06:42:03.435267 info] [52030442] recorder q6-sel-reject: selector '', 0 atom(s) -[2026-10-09 06:42:03.435270 info] [52030442] recorder q6-route-reject: selector '', 0 atom(s) -[2026-10-09 06:42:03.435272 info] [52030442] recorder q6-raw: selector '', 0 atom(s) -[2026-10-09 06:42:03.571907 info] [52030442] spike: q6 ---- as symbol: 'C' -[2026-10-09 06:42:03.571921 info] [52030442] recorder q6-msgbox: selector 'C', 0 atom(s) -[2026-10-09 06:42:03.571927 info] [52030442] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'C' (symbol) -[2026-10-09 06:42:03.571931 info] [52030442] recorder q6-sel-C: selector 'bang', 0 atom(s) -[2026-10-09 06:42:03.571935 info] [52030442] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'C' (symbol) -[2026-10-09 06:42:03.571938 info] [52030442] recorder q6-raw: selector 'symbol', 1 atom(s): 'C' (symbol) -[2026-10-09 06:42:03.571943 info] [52030442] spike: q6 ---- as symbol: 'hello world' -[2026-10-09 06:42:03.571945 info] [52030442] recorder q6-msgbox: selector 'hello world', 0 atom(s) -[2026-10-09 06:42:03.571947 info] [52030442] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'hello world' (symbol) -[2026-10-09 06:42:03.571950 info] [52030442] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'hello world' (symbol) -[2026-10-09 06:42:03.571957 info] [52030442] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'hello world' (symbol) -[2026-10-09 06:42:03.571959 info] [52030442] recorder q6-raw: selector 'symbol', 1 atom(s): 'hello world' (symbol) -[2026-10-09 06:42:03.571962 info] [52030442] spike: q6 ---- as symbol: '60' -[2026-10-09 06:42:03.571965 info] [52030442] recorder q6-msgbox: selector '60', 0 atom(s) -[2026-10-09 06:42:03.571967 info] [52030442] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), '60' (symbol) -[2026-10-09 06:42:03.571969 info] [52030442] recorder q6-sel-reject: selector 'symbol', 1 atom(s): '60' (symbol) -[2026-10-09 06:42:03.571970 info] [52030442] recorder q6-route-reject: selector 'symbol', 1 atom(s): '60' (symbol) -[2026-10-09 06:42:03.571972 info] [52030442] recorder q6-raw: selector 'symbol', 1 atom(s): '60' (symbol) -[2026-10-09 06:42:03.571976 info] [52030442] spike: q6 ---- as symbol: '1.5' -[2026-10-09 06:42:03.571979 info] [52030442] recorder q6-msgbox: selector '1.5', 0 atom(s) -[2026-10-09 06:42:03.571982 info] [52030442] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), '1.5' (symbol) -[2026-10-09 06:42:03.571984 info] [52030442] recorder q6-sel-reject: selector 'symbol', 1 atom(s): '1.5' (symbol) -[2026-10-09 06:42:03.571986 info] [52030442] recorder q6-route-reject: selector 'symbol', 1 atom(s): '1.5' (symbol) -[2026-10-09 06:42:03.571987 info] [52030442] recorder q6-raw: selector 'symbol', 1 atom(s): '1.5' (symbol) -[2026-10-09 06:42:03.571990 info] [52030442] spike: q6 ---- as symbol: 'list' -[2026-10-09 06:42:03.571993 info] [52030442] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'list' (symbol) -[2026-10-09 06:42:03.571995 info] [52030442] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'list' (symbol) -[2026-10-09 06:42:03.571996 info] [52030442] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'list' (symbol) -[2026-10-09 06:42:03.571998 info] [52030442] recorder q6-raw: selector 'symbol', 1 atom(s): 'list' (symbol) -[2026-10-09 06:42:03.572000 info] [52030442] spike: q6 ---- as symbol: 'int' -[2026-10-09 06:42:03.572013 info] [52030442] trying to register object, but no obex pointer -[2026-10-09 06:42:03.572013 error] [52030442] missing arguments for message "int" -[2026-10-09 06:42:03.572016 info] [52030442] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'int' (symbol) -[2026-10-09 06:42:03.572018 info] [52030442] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'int' (symbol) -[2026-10-09 06:42:03.572019 info] [52030442] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'int' (symbol) -[2026-10-09 06:42:03.572021 info] [52030442] recorder q6-raw: selector 'symbol', 1 atom(s): 'int' (symbol) -[2026-10-09 06:42:03.572024 info] [52030442] spike: q6 ---- as symbol: 'float' -[2026-10-09 06:42:03.572030 info] [52030442] trying to register object, but no obex pointer -[2026-10-09 06:42:03.572031 error] [52030442] missing arguments for message "float" -[2026-10-09 06:42:03.572033 info] [52030442] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'float' (symbol) -[2026-10-09 06:42:03.572037 info] [52030442] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'float' (symbol) -[2026-10-09 06:42:03.572038 info] [52030442] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'float' (symbol) -[2026-10-09 06:42:03.572040 info] [52030442] recorder q6-raw: selector 'symbol', 1 atom(s): 'float' (symbol) -[2026-10-09 06:42:03.572043 info] [52030442] spike: q6 ---- as symbol: 'symbol' -[2026-10-09 06:42:03.572044 info] [52030442] recorder q6-msgbox: selector 'symbol', 0 atom(s) -[2026-10-09 06:42:03.572046 info] [52030442] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'symbol' (symbol) -[2026-10-09 06:42:03.572048 info] [52030442] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'symbol' (symbol) -[2026-10-09 06:42:03.572049 info] [52030442] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'symbol' (symbol) -[2026-10-09 06:42:03.572051 info] [52030442] recorder q6-raw: selector 'symbol', 1 atom(s): 'symbol' (symbol) -[2026-10-09 06:42:03.572053 info] [52030442] spike: q6 ---- as symbol: 'bang' -[2026-10-09 06:42:03.572057 info] [52030442] recorder q6-msgbox: selector 'bang', 0 atom(s) -[2026-10-09 06:42:03.572059 info] [52030442] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'bang' (symbol) -[2026-10-09 06:42:03.572060 info] [52030442] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'bang' (symbol) -[2026-10-09 06:42:03.572062 info] [52030442] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'bang' (symbol) -[2026-10-09 06:42:03.572063 info] [52030442] recorder q6-raw: selector 'symbol', 1 atom(s): 'bang' (symbol) -[2026-10-09 06:42:03.572066 info] [52030442] spike: q6 ---- as symbol: '' -[2026-10-09 06:42:03.572068 info] [52030442] recorder q6-msgbox: selector '', 0 atom(s) -[2026-10-09 06:42:03.572069 info] [52030442] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), '' (symbol) -[2026-10-09 06:42:03.572071 info] [52030442] recorder q6-sel-reject: selector 'symbol', 1 atom(s): '' (symbol) -[2026-10-09 06:42:03.572072 info] [52030442] recorder q6-route-reject: selector 'symbol', 1 atom(s): '' (symbol) -[2026-10-09 06:42:03.572075 info] [52030442] recorder q6-raw: selector 'symbol', 1 atom(s): '' (symbol) -[2026-10-09 06:42:03.821899 info] [52030442] q6 end -[2026-10-09 06:42:09.344679 info] [52030442] spike: new tap.python: 1 value outlet(s) + dumpout, steps 8; main thread 1 -[2026-10-09 06:42:09.372233 info] [52030442] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:09.372249 info] [52030442] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:09.511985 info] [52030442] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:09.512001 info] [52030442] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:09.560527 info] [52030442] spike: thread 'loadbang': main 1, audio 0, timer 1, thread id 189247 -[2026-10-09 06:42:09.624087 info] [52030442] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:09.624104 info] [52030442] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:09.672296 info] [52030442] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:09.682288 info] [52030442] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:09.722309 info] [52030442] q5 phase overdrive-off -[2026-10-09 06:42:09.772333 info] [52030442] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 189247 -[2026-10-09 06:42:09.872303 info] [52030442] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 189247 -[2026-10-09 06:42:09.972295 info] [52030442] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 189247 -[2026-10-09 06:42:10.072287 info] [52030442] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 189247 -[2026-10-09 06:42:10.172288 info] [52030442] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 189247 -[2026-10-09 06:42:10.272286 info] [52030442] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 189247 -[2026-10-09 06:42:10.572280 info] [52030460] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:10.582242 info] [52030460] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:10.672268 info] [52030460] q5 phase overdrive-on -[2026-10-09 06:42:10.722329 info] [52030442] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 211281 -[2026-10-09 06:42:10.822262 info] [52030442] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 211281 -[2026-10-09 06:42:10.922258 info] [52030442] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 211281 -[2026-10-09 06:42:11.022250 info] [52030442] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 211281 -[2026-10-09 06:42:11.122259 info] [52030442] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 211281 -[2026-10-09 06:42:11.222246 info] [52030442] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 211281 -[2026-10-09 06:42:11.423892 info] [52030442] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:11.423902 info] [52030442] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:11.594618 info] [52030442] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:11.594629 info] [52030442] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:11.594635 info] [52030442] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:11.594637 info] [52030442] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:11.688790 info] [52031476] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:11.694294 info] [52031476] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:12.787421 info] [52031476] q5 phase overdrive-on-audio-interrupt-on-audio-running -[2026-10-09 06:42:12.835440 info] [52030442] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 333811 -[2026-10-09 06:42:12.936735 info] [52030442] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 333811 -[2026-10-09 06:42:13.038061 info] [52030442] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 333811 -[2026-10-09 06:42:13.134169 info] [52030442] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 333811 -[2026-10-09 06:42:13.235424 info] [52030442] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 333811 -[2026-10-09 06:42:13.336712 info] [52030442] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 333811 -[2026-10-09 06:42:13.660377 info] [52030442] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:13.660390 info] [52030442] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:13.660405 info] [52030442] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:13.660408 info] [52030442] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) -[2026-10-09 06:42:13.689361 info] [52031700] q5 phase overdrive-on-audio-interrupt-on-audio-stopped -[2026-10-09 06:42:13.739348 info] [52030442] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 920006 -[2026-10-09 06:42:13.839355 info] [52030442] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 920006 -[2026-10-09 06:42:13.939330 info] [52030442] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 920006 -[2026-10-09 06:42:14.039330 info] [52030442] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 920006 -[2026-10-09 06:42:14.139324 info] [52030442] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 920006 -[2026-10-09 06:42:14.239319 info] [52030442] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 920006 -[2026-10-09 06:42:14.439298 info] [52031700] q5 putting Overdrive and Audio Interrupt back -[2026-10-09 06:42:14.489303 info] [52031700] recorder q5-was-overdrive: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:14.538877 info] [52030442] recorder q5-was-takeover: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:14.544689 info] [52030442] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:14.544703 info] [52030442] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:14.639320 info] [52030442] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:14.649312 info] [52030442] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) -[2026-10-09 06:42:14.839288 info] [52030442] q5 end +[2026-10-09 14:01:45.238253 error] [52500317] Node for Max process manager quit. Please restart any running node scripts. +[2026-10-09 14:01:57.795364 info] [52500174] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) +[2026-10-09 14:01:57.795407 info] [52500174] spike: new tap.python: 2 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 14:01:58.441899 info] [52500174] q2 begin: two value outlets and the dumpout +[2026-10-09 14:01:58.441917 info] [52500174] spike: describe: outlet_count 3 (2 value outlet(s) held + dumpout) +[2026-10-09 14:01:58.441921 info] [52500174] spike: describe: outlet_nth(0) is value outlet 0 +[2026-10-09 14:01:58.441923 info] [52500174] spike: describe: outlet_nth(1) is value outlet 1 +[2026-10-09 14:01:58.441924 info] [52500174] spike: describe: outlet_nth(2) is the dumpout +[2026-10-09 14:01:58.441927 info] [52500174] spike: describe: the obex's dumpout is the one made first +[2026-10-09 14:01:58.441957 info] [52500174] spike: describe: cord from outlet 2 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.441961 info] [52500174] spike: describe: cord from outlet 1 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.441965 info] [52500174] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.441967 info] [52500174] spike: describe: 3 cord(s) from this box +[2026-10-09 14:01:58.441973 info] [52500174] spike: fire +[2026-10-09 14:01:58.441983 info] [52500174] recorder q2-dumpout: selector 'fired', 0 atom(s) +[2026-10-09 14:01:58.441994 info] [52500174] recorder q2-outlet-1: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:01:58.442001 info] [52500174] recorder q2-outlet-0: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:01:58.442008 info] [52500174] q2 widen: outlets 3 +[2026-10-09 14:01:58.442013 info] [52500174] spike: outlets: 2 -> 3 value outlet(s) +[2026-10-09 14:01:58.442156 info] [52500174] spike: describe: outlet_count 4 (3 value outlet(s) held + dumpout) +[2026-10-09 14:01:58.442163 info] [52500174] spike: describe: outlet_nth(0) is value outlet 0 +[2026-10-09 14:01:58.442165 info] [52500174] spike: describe: outlet_nth(1) is value outlet 1 +[2026-10-09 14:01:58.442167 info] [52500174] spike: describe: outlet_nth(2) is value outlet 2 +[2026-10-09 14:01:58.442175 info] [52500174] spike: describe: outlet_nth(3) is the dumpout +[2026-10-09 14:01:58.442176 info] [52500174] spike: describe: the obex's dumpout is the one made first +[2026-10-09 14:01:58.442191 info] [52500174] spike: describe: cord from outlet 3 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.442194 info] [52500174] spike: describe: cord from outlet 1 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.442197 info] [52500174] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.442199 info] [52500174] spike: describe: 3 cord(s) from this box +[2026-10-09 14:01:58.442339 info] [52500174] spike: describe: outlet_count 4 (3 value outlet(s) held + dumpout) +[2026-10-09 14:01:58.442346 info] [52500174] spike: describe: outlet_nth(0) is value outlet 0 +[2026-10-09 14:01:58.442347 info] [52500174] spike: describe: outlet_nth(1) is value outlet 1 +[2026-10-09 14:01:58.442349 info] [52500174] spike: describe: outlet_nth(2) is value outlet 2 +[2026-10-09 14:01:58.442354 info] [52500174] spike: describe: outlet_nth(3) is the dumpout +[2026-10-09 14:01:58.442356 info] [52500174] spike: describe: the obex's dumpout is the one made first +[2026-10-09 14:01:58.442360 info] [52500174] spike: describe: cord from outlet 2 to newprint inlet 0 +[2026-10-09 14:01:58.442372 info] [52500174] spike: describe: cord from outlet 3 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.442375 info] [52500174] spike: describe: cord from outlet 1 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.442377 info] [52500174] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.442379 info] [52500174] spike: describe: 4 cord(s) from this box +[2026-10-09 14:01:58.442411 info] [52500174] spike: fire +[2026-10-09 14:01:58.442416 info] [52500174] recorder q2-dumpout: selector 'fired', 0 atom(s) +[2026-10-09 14:01:58.442429 info] [52500174] recorder q2-new: selector 'int', 1 atom(s): 2 (int) +[2026-10-09 14:01:58.442441 info] [52500174] recorder q2-outlet-1: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:01:58.442444 info] [52500174] recorder q2-outlet-0: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:01:58.442454 info] [52500174] q2 narrow: outlets 1 +[2026-10-09 14:01:58.771659 info] [52500174] spike: outlets: 3 -> 1 value outlet(s) +[2026-10-09 14:01:58.781521 info] [52500174] spike: describe: outlet_count 2 (1 value outlet(s) held + dumpout) +[2026-10-09 14:01:58.781537 info] [52500174] spike: describe: outlet_nth(0) is value outlet 0 +[2026-10-09 14:01:58.781540 info] [52500174] spike: describe: outlet_nth(1) is the dumpout +[2026-10-09 14:01:58.781569 info] [52500174] spike: describe: the obex's dumpout is the one made first +[2026-10-09 14:01:58.781598 info] [52500174] spike: describe: cord from outlet 1 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.781604 info] [52500174] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.781607 info] [52500174] spike: describe: 2 cord(s) from this box +[2026-10-09 14:01:58.781615 info] [52500174] spike: fire +[2026-10-09 14:01:58.781621 info] [52500174] recorder q2-dumpout: selector 'fired', 0 atom(s) +[2026-10-09 14:01:58.781627 info] [52500174] recorder q2-outlet-0: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:01:58.781650 info] [52500174] q2 widen again: outlets 2 +[2026-10-09 14:01:58.781659 info] [52500174] spike: outlets: 1 -> 2 value outlet(s) +[2026-10-09 14:01:58.781800 info] [52500174] spike: describe: outlet_count 3 (2 value outlet(s) held + dumpout) +[2026-10-09 14:01:58.781808 info] [52500174] spike: describe: outlet_nth(0) is value outlet 0 +[2026-10-09 14:01:58.781810 info] [52500174] spike: describe: outlet_nth(1) is value outlet 1 +[2026-10-09 14:01:58.781812 info] [52500174] spike: describe: outlet_nth(2) is the dumpout +[2026-10-09 14:01:58.781814 info] [52500174] spike: describe: the obex's dumpout is the one made first +[2026-10-09 14:01:58.781828 info] [52500174] spike: describe: cord from outlet 2 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.781831 info] [52500174] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 14:01:58.781833 info] [52500174] spike: describe: 2 cord(s) from this box +[2026-10-09 14:01:58.781840 info] [52500174] spike: fire +[2026-10-09 14:01:58.781843 info] [52500174] recorder q2-dumpout: selector 'fired', 0 atom(s) +[2026-10-09 14:01:58.781845 info] [52500174] recorder q2-outlet-0: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:01:58.876192 info] [52500174] q2 end +[2026-10-09 14:02:03.277642 info] [52500174] spike: steps setter called (instance attribute) <- 5 +[2026-10-09 14:02:03.277652 info] [52500174] spike: new tap.python: 1 value outlet(s) + dumpout, steps 5; main thread 1 +[2026-10-09 14:02:03.277752 info] [52500174] spike: steps setter called (instance attribute) <- 5 +[2026-10-09 14:02:03.277756 info] [52500174] spike: new tap.python.spike.nodumpout: 1 value outlet(s) + dumpout, steps 5; main thread 1 +[2026-10-09 14:02:03.435246 info] [52500174] q3 tap.python: the instance attribute steps +[2026-10-09 14:02:03.435266 info] [52500174] spike: steps getter called (instance attribute) -> 5 +[2026-10-09 14:02:03.435283 info] [52500174] recorder q3-dumpout: selector 'steps', 1 atom(s): 5 (int) +[2026-10-09 14:02:03.435291 info] [52500174] spike: steps setter called (instance attribute) <- 8 +[2026-10-09 14:02:03.435297 info] [52500174] spike: steps getter called (instance attribute) -> 8 +[2026-10-09 14:02:03.435299 info] [52500174] recorder q3-dumpout: selector 'steps', 1 atom(s): 8 (int) +[2026-10-09 14:02:03.534629 info] [52500174] q3 tap.python: the class attribute level +[2026-10-09 14:02:03.534658 info] [52500174] recorder q3-dumpout: selector 'level', 1 atom(s): 1 (int) +[2026-10-09 14:02:03.534670 info] [52500174] recorder q3-dumpout: selector 'level', 1 atom(s): 3 (int) +[2026-10-09 14:02:03.584296 info] [52500174] q3 tap.python: object_attr_getdump and object_attr_method +[2026-10-09 14:02:03.634269 info] [52500174] spike: getdump steps: calling object_attr_getdump() +[2026-10-09 14:02:03.634281 info] [52500174] recorder q3-dumpout: selector 'ps', 0 atom(s) +[2026-10-09 14:02:03.634285 info] [52500174] spike: getdump level: calling object_attr_getdump() +[2026-10-09 14:02:03.634288 info] [52500174] recorder q3-dumpout: selector 'el', 0 atom(s) +[2026-10-09 14:02:03.634294 info] [52500174] spike: attrmethod 'getsteps': object_attr_method found a method, attribute found, get 1 (steps' own getter) +[2026-10-09 14:02:03.634297 info] [52500174] spike: attrmethod 'steps': object_attr_method found a method, attribute found, get 0 (steps' own setter) +[2026-10-09 14:02:03.634309 info] [52500174] spike: attrmethod 'getlevel': object_attr_method found a method, attribute found, get 1 +[2026-10-09 14:02:03.634329 info] [52500174] spike: attrmethod 'level': object_attr_method found a method, attribute found, get 0 +[2026-10-09 14:02:03.634337 info] [52500174] spike: probe 'getsteps' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:03.634341 info] [52500174] spike: probe 'dumpout' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 14:02:03.784271 info] [52500174] q3 tap.python.spike.nodumpout: the instance attribute steps +[2026-10-09 14:02:03.834282 info] [52500174] spike: steps setter called (instance attribute) <- 8 +[2026-10-09 14:02:03.884294 info] [52500174] q3 tap.python.spike.nodumpout: the class attribute level +[2026-10-09 14:02:03.984273 info] [52500174] q3 tap.python.spike.nodumpout: object_attr_getdump and object_attr_method +[2026-10-09 14:02:04.034268 info] [52500174] spike: getdump steps: calling object_attr_getdump() +[2026-10-09 14:02:04.034278 info] [52500174] spike: getdump level: calling object_attr_getdump() +[2026-10-09 14:02:04.034298 info] [52500174] spike: attrmethod 'getsteps': object_attr_method found a method, attribute found, get 1 (steps' own getter) +[2026-10-09 14:02:04.034301 info] [52500174] spike: attrmethod 'steps': object_attr_method found a method, attribute found, get 0 (steps' own setter) +[2026-10-09 14:02:04.034306 info] [52500174] spike: attrmethod 'getlevel': object_attr_method found a method, attribute found, get 1 +[2026-10-09 14:02:04.034309 info] [52500174] spike: attrmethod 'level': object_attr_method found a method, attribute found, get 0 +[2026-10-09 14:02:04.034316 info] [52500174] spike: probe 'getsteps' on this tap.python.spike.nodumpout: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:04.034321 info] [52500174] spike: probe 'dumpout' on this tap.python.spike.nodumpout: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:04.184273 info] [52500174] q3 end +[2026-10-09 14:02:09.333057 info] [52500174] spike: new tap.python: 1 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 14:02:09.333150 info] [52500174] spike: new tap.python (bare: no instance attribute or methods): 1 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 14:02:09.414381 info] [52500174] Loaded default.py: process() bound, one call per sample +[2026-10-09 14:02:09.600692 info] [52500174] q4 begin: dispatch on the spike +[2026-10-09 14:02:09.600724 info] [52500174] spike: steps setter called (instance attribute) <- 8 +[2026-10-09 14:02:09.600738 info] [52500174] spike: steps getter called (instance attribute) -> 8 +[2026-10-09 14:02:09.600757 info] [52500174] recorder q4-dumpout: selector 'steps', 1 atom(s): 8 (int) +[2026-10-09 14:02:09.600774 info] [52500174] spike: instance method hello called (object_addmethod, A_GIMME): 1 2 +[2026-10-09 14:02:09.600779 info] [52500174] spike: who: the INSTANCE method (object_addmethod) answered +[2026-10-09 14:02:09.600787 info] [52500174] spike: instance method int called (object_addmethod, A_LONG): 5 +[2026-10-09 14:02:09.600826 error] [52500174] doesn't understand "float" +[2026-10-09 14:02:09.600836 info] [52500174] spike: bang: the INSTANCE method (object_addmethod) answered +[2026-10-09 14:02:09.600850 info] [52500174] spike: instance method int called (object_addmethod, A_LONG): 1 +[2026-10-09 14:02:09.600856 info] [52500174] spike: instance method int called (object_addmethod, A_LONG): 4 +[2026-10-09 14:02:09.600864 info] [52500174] spike: class anything received: selector 'symbol', 1 argument(s): foo +[2026-10-09 14:02:09.600871 info] [52500174] spike: class anything received: selector 'foo', 2 argument(s): 1 2 +[2026-10-09 14:02:09.633663 info] [52500174] q4 dispatch on the bare spike +[2026-10-09 14:02:09.720491 info] [52500174] spike: class anything received: selector 'steps', 1 argument(s): 8 +[2026-10-09 14:02:09.720515 info] [52500174] spike: class anything received: selector 'getsteps', 0 argument(s): +[2026-10-09 14:02:09.720525 info] [52500174] spike: class anything received: selector 'hello', 2 argument(s): 1 2 +[2026-10-09 14:02:09.720529 info] [52500174] spike: who: the CLASS method (class_addmethod) answered +[2026-10-09 14:02:09.720532 error] [52500174] doesn't understand "int" +[2026-10-09 14:02:09.720964 error] [52500174] doesn't understand "float" +[2026-10-09 14:02:09.720970 info] [52500174] spike: bang: the CLASS method (class_addmethod) answered +[2026-10-09 14:02:09.720973 error] [52500174] doesn't understand "int" +[2026-10-09 14:02:09.720976 error] [52500174] doesn't understand "int" +[2026-10-09 14:02:09.720983 info] [52500174] spike: class anything received: selector 'symbol', 1 argument(s): foo +[2026-10-09 14:02:09.720988 info] [52500174] spike: class anything received: selector 'foo', 2 argument(s): 1 2 +[2026-10-09 14:02:09.727758 info] [52500174] q4 probes on the spike (it has a class-level anything) +[2026-10-09 14:02:09.778113 info] [52500174] spike: probe 'foo' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:09.778124 info] [52500174] spike: probe 'anything' on this tap.python: object_getmethod is this class's anything; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 14:02:09.778129 info] [52500174] spike: probe 'steps' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:09.778140 info] [52500174] spike: probe 'getsteps' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:09.778144 info] [52500174] spike: probe 'level' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:09.778148 info] [52500174] spike: probe 'getlevel' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:09.778152 info] [52500174] spike: probe 'hello' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 14:02:09.778169 info] [52500174] spike: probe 'who' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 14:02:09.778173 info] [52500174] spike: probe 'int' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 14:02:09.778176 info] [52500174] spike: probe 'float' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:09.778179 info] [52500174] spike: probe 'bang' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 14:02:09.778183 info] [52500174] spike: probe 'list' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:09.778186 info] [52500174] spike: probe 'symbol' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:09.778190 info] [52500174] spike: probe 'outlets' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 14:02:09.924089 info] [52500174] q4 probes on tap.python~ (no anything) +[2026-10-09 14:02:09.974124 info] [52500174] spike: probe 'foo' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:09.974148 info] [52500174] spike: probe 'anything' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:09.974164 info] [52500174] spike: probe 'gain' on tilde (tap.python~): object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:09.974180 info] [52500174] spike: probe 'greet' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 14:02:09.974194 info] [52500174] spike: probe 'int' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 14:02:09.974210 info] [52500174] spike: probe 'dsp64' on tilde (tap.python~): object_getmethod is a function; differs from what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 14:02:09.974225 info] [52500174] spike: probe 'bang' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, equal to method_false as this module sees it); zgetfn null +[2026-10-09 14:02:10.124091 info] [52500174] q4 end +[2026-10-09 14:02:15.396728 info] [52500174] spike: new tap.python: 1 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 14:02:15.573367 info] [52500174] q6 begin +[2026-10-09 14:02:15.573384 info] [52500174] spike: q6 ---- as a message: 'C' +[2026-10-09 14:02:15.573402 info] [52500174] recorder q6-msgbox: selector 'C', 0 atom(s) +[2026-10-09 14:02:15.573413 info] [52500174] recorder q6-prepend: selector 'got', 1 atom(s): 'C' (symbol) +[2026-10-09 14:02:15.573422 info] [52500174] recorder q6-sel-C: selector 'bang', 0 atom(s) +[2026-10-09 14:02:15.573431 info] [52500174] recorder q6-route-C: selector 'bang', 0 atom(s) +[2026-10-09 14:02:15.573439 info] [52500174] recorder q6-raw: selector 'C', 0 atom(s) +[2026-10-09 14:02:15.573446 info] [52500174] spike: q6 ---- as a message: 'hello world' +[2026-10-09 14:02:15.573449 info] [52500174] recorder q6-msgbox: selector 'hello world', 0 atom(s) +[2026-10-09 14:02:15.573460 info] [52500174] recorder q6-prepend: selector 'got', 1 atom(s): 'hello world' (symbol) +[2026-10-09 14:02:15.573468 info] [52500174] recorder q6-sel-reject: selector 'hello world', 0 atom(s) +[2026-10-09 14:02:15.573474 info] [52500174] recorder q6-route-reject: selector 'hello world', 0 atom(s) +[2026-10-09 14:02:15.573476 info] [52500174] recorder q6-raw: selector 'hello world', 0 atom(s) +[2026-10-09 14:02:15.573480 info] [52500174] spike: q6 ---- as a message: '60' +[2026-10-09 14:02:15.573483 info] [52500174] recorder q6-msgbox: selector '60', 0 atom(s) +[2026-10-09 14:02:15.573485 info] [52500174] recorder q6-prepend: selector 'got', 1 atom(s): '60' (symbol) +[2026-10-09 14:02:15.573486 info] [52500174] recorder q6-sel-reject: selector '60', 0 atom(s) +[2026-10-09 14:02:15.573488 info] [52500174] recorder q6-route-reject: selector '60', 0 atom(s) +[2026-10-09 14:02:15.573489 info] [52500174] recorder q6-raw: selector '60', 0 atom(s) +[2026-10-09 14:02:15.573495 info] [52500174] spike: q6 ---- as a message: '1.5' +[2026-10-09 14:02:15.573498 info] [52500174] recorder q6-msgbox: selector '1.5', 0 atom(s) +[2026-10-09 14:02:15.573500 info] [52500174] recorder q6-prepend: selector 'got', 1 atom(s): '1.5' (symbol) +[2026-10-09 14:02:15.573501 info] [52500174] recorder q6-sel-reject: selector '1.5', 0 atom(s) +[2026-10-09 14:02:15.573503 info] [52500174] recorder q6-route-reject: selector '1.5', 0 atom(s) +[2026-10-09 14:02:15.573504 info] [52500174] recorder q6-raw: selector '1.5', 0 atom(s) +[2026-10-09 14:02:15.573507 info] [52500174] spike: q6 ---- as a message: 'list' +[2026-10-09 14:02:15.573510 info] [52500174] spike: q6 ---- as a message: 'int' +[2026-10-09 14:02:15.573519 error] [52500174] missing arguments for message "int" +[2026-10-09 14:02:15.573525 error] [52500174] missing arguments for message "int" +[2026-10-09 14:02:15.573533 error] [52500174] missing arguments for message "int" +[2026-10-09 14:02:15.573540 error] [52500174] missing arguments for message "int" +[2026-10-09 14:02:15.573542 error] [52500174] missing arguments for message "int" +[2026-10-09 14:02:15.573545 info] [52500174] spike: q6 ---- as a message: 'float' +[2026-10-09 14:02:15.573547 error] [52500174] missing arguments for message "float" +[2026-10-09 14:02:15.573548 error] [52500174] missing arguments for message "float" +[2026-10-09 14:02:15.573550 error] [52500174] missing arguments for message "float" +[2026-10-09 14:02:15.573551 error] [52500174] missing arguments for message "float" +[2026-10-09 14:02:15.573552 error] [52500174] missing arguments for message "float" +[2026-10-09 14:02:15.573555 info] [52500174] spike: q6 ---- as a message: 'symbol' +[2026-10-09 14:02:15.573558 error] [52500174] missing arguments for message "symbol" +[2026-10-09 14:02:15.573560 info] [52500174] recorder q6-prepend: selector 'got', 1 atom(s): 'symbol' (symbol) +[2026-10-09 14:02:15.573563 info] [52500174] recorder q6-sel-reject: selector 'symbol', 1 atom(s): '' (symbol) +[2026-10-09 14:02:15.573565 info] [52500174] recorder q6-route-reject: selector 'symbol', 0 atom(s) +[2026-10-09 14:02:15.573566 info] [52500174] recorder q6-raw: selector 'symbol', 0 atom(s) +[2026-10-09 14:02:15.573569 info] [52500174] spike: q6 ---- as a message: 'bang' +[2026-10-09 14:02:15.573572 info] [52500174] recorder q6-msgbox: selector '1.5', 0 atom(s) +[2026-10-09 14:02:15.573574 info] [52500174] recorder q6-prepend: selector 'got', 1 atom(s): 'bang' (symbol) +[2026-10-09 14:02:15.573576 info] [52500174] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'bang' (symbol) +[2026-10-09 14:02:15.573577 info] [52500174] recorder q6-route-reject: selector 'bang', 0 atom(s) +[2026-10-09 14:02:15.573580 info] [52500174] recorder q6-raw: selector 'bang', 0 atom(s) +[2026-10-09 14:02:15.573584 info] [52500174] spike: q6 ---- as a message: '' +[2026-10-09 14:02:15.573586 info] [52500174] recorder q6-msgbox: selector '', 0 atom(s) +[2026-10-09 14:02:15.573587 info] [52500174] recorder q6-prepend: selector 'got', 1 atom(s): '' (symbol) +[2026-10-09 14:02:15.573589 info] [52500174] recorder q6-sel-reject: selector '', 0 atom(s) +[2026-10-09 14:02:15.573590 info] [52500174] recorder q6-route-reject: selector '', 0 atom(s) +[2026-10-09 14:02:15.573591 info] [52500174] recorder q6-raw: selector '', 0 atom(s) +[2026-10-09 14:02:15.716330 info] [52500174] spike: q6 ---- as symbol: 'C' +[2026-10-09 14:02:15.716345 info] [52500174] recorder q6-msgbox: selector 'C', 0 atom(s) +[2026-10-09 14:02:15.716352 info] [52500174] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'C' (symbol) +[2026-10-09 14:02:15.716363 info] [52500174] recorder q6-sel-C: selector 'bang', 0 atom(s) +[2026-10-09 14:02:15.716366 info] [52500174] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'C' (symbol) +[2026-10-09 14:02:15.716369 info] [52500174] recorder q6-raw: selector 'symbol', 1 atom(s): 'C' (symbol) +[2026-10-09 14:02:15.716373 info] [52500174] spike: q6 ---- as symbol: 'hello world' +[2026-10-09 14:02:15.716375 info] [52500174] recorder q6-msgbox: selector 'hello world', 0 atom(s) +[2026-10-09 14:02:15.716378 info] [52500174] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'hello world' (symbol) +[2026-10-09 14:02:15.716382 info] [52500174] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'hello world' (symbol) +[2026-10-09 14:02:15.716383 info] [52500174] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'hello world' (symbol) +[2026-10-09 14:02:15.716385 info] [52500174] recorder q6-raw: selector 'symbol', 1 atom(s): 'hello world' (symbol) +[2026-10-09 14:02:15.716389 info] [52500174] spike: q6 ---- as symbol: '60' +[2026-10-09 14:02:15.716394 info] [52500174] recorder q6-msgbox: selector '60', 0 atom(s) +[2026-10-09 14:02:15.716396 info] [52500174] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), '60' (symbol) +[2026-10-09 14:02:15.716398 info] [52500174] recorder q6-sel-reject: selector 'symbol', 1 atom(s): '60' (symbol) +[2026-10-09 14:02:15.716399 info] [52500174] recorder q6-route-reject: selector 'symbol', 1 atom(s): '60' (symbol) +[2026-10-09 14:02:15.716401 info] [52500174] recorder q6-raw: selector 'symbol', 1 atom(s): '60' (symbol) +[2026-10-09 14:02:15.716406 info] [52500174] spike: q6 ---- as symbol: '1.5' +[2026-10-09 14:02:15.716409 info] [52500174] recorder q6-msgbox: selector '1.5', 0 atom(s) +[2026-10-09 14:02:15.716411 info] [52500174] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), '1.5' (symbol) +[2026-10-09 14:02:15.716413 info] [52500174] recorder q6-sel-reject: selector 'symbol', 1 atom(s): '1.5' (symbol) +[2026-10-09 14:02:15.716414 info] [52500174] recorder q6-route-reject: selector 'symbol', 1 atom(s): '1.5' (symbol) +[2026-10-09 14:02:15.716417 info] [52500174] recorder q6-raw: selector 'symbol', 1 atom(s): '1.5' (symbol) +[2026-10-09 14:02:15.716420 info] [52500174] spike: q6 ---- as symbol: 'list' +[2026-10-09 14:02:15.716423 info] [52500174] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'list' (symbol) +[2026-10-09 14:02:15.716425 info] [52500174] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'list' (symbol) +[2026-10-09 14:02:15.716427 info] [52500174] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'list' (symbol) +[2026-10-09 14:02:15.716428 info] [52500174] recorder q6-raw: selector 'symbol', 1 atom(s): 'list' (symbol) +[2026-10-09 14:02:15.716430 info] [52500174] spike: q6 ---- as symbol: 'int' +[2026-10-09 14:02:15.716441 info] [52500174] trying to register object, but no obex pointer +[2026-10-09 14:02:15.716442 error] [52500174] missing arguments for message "int" +[2026-10-09 14:02:15.716445 info] [52500174] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'int' (symbol) +[2026-10-09 14:02:15.716448 info] [52500174] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'int' (symbol) +[2026-10-09 14:02:15.716450 info] [52500174] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'int' (symbol) +[2026-10-09 14:02:15.716452 info] [52500174] recorder q6-raw: selector 'symbol', 1 atom(s): 'int' (symbol) +[2026-10-09 14:02:15.716455 info] [52500174] spike: q6 ---- as symbol: 'float' +[2026-10-09 14:02:15.716461 info] [52500174] trying to register object, but no obex pointer +[2026-10-09 14:02:15.716461 error] [52500174] missing arguments for message "float" +[2026-10-09 14:02:15.716463 info] [52500174] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'float' (symbol) +[2026-10-09 14:02:15.716465 info] [52500174] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'float' (symbol) +[2026-10-09 14:02:15.716467 info] [52500174] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'float' (symbol) +[2026-10-09 14:02:15.716468 info] [52500174] recorder q6-raw: selector 'symbol', 1 atom(s): 'float' (symbol) +[2026-10-09 14:02:15.716473 info] [52500174] spike: q6 ---- as symbol: 'symbol' +[2026-10-09 14:02:15.716475 info] [52500174] recorder q6-msgbox: selector 'symbol', 0 atom(s) +[2026-10-09 14:02:15.716477 info] [52500174] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'symbol' (symbol) +[2026-10-09 14:02:15.716478 info] [52500174] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'symbol' (symbol) +[2026-10-09 14:02:15.716480 info] [52500174] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'symbol' (symbol) +[2026-10-09 14:02:15.716482 info] [52500174] recorder q6-raw: selector 'symbol', 1 atom(s): 'symbol' (symbol) +[2026-10-09 14:02:15.716484 info] [52500174] spike: q6 ---- as symbol: 'bang' +[2026-10-09 14:02:15.716487 info] [52500174] recorder q6-msgbox: selector 'bang', 0 atom(s) +[2026-10-09 14:02:15.716488 info] [52500174] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'bang' (symbol) +[2026-10-09 14:02:15.716490 info] [52500174] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'bang' (symbol) +[2026-10-09 14:02:15.716493 info] [52500174] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'bang' (symbol) +[2026-10-09 14:02:15.716495 info] [52500174] recorder q6-raw: selector 'symbol', 1 atom(s): 'bang' (symbol) +[2026-10-09 14:02:15.716497 info] [52500174] spike: q6 ---- as symbol: '' +[2026-10-09 14:02:15.716500 info] [52500174] recorder q6-msgbox: selector '', 0 atom(s) +[2026-10-09 14:02:15.716502 info] [52500174] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), '' (symbol) +[2026-10-09 14:02:15.716508 info] [52500174] recorder q6-sel-reject: selector 'symbol', 1 atom(s): '' (symbol) +[2026-10-09 14:02:15.716510 info] [52500174] recorder q6-route-reject: selector 'symbol', 1 atom(s): '' (symbol) +[2026-10-09 14:02:15.716511 info] [52500174] recorder q6-raw: selector 'symbol', 1 atom(s): '' (symbol) +[2026-10-09 14:02:15.966304 info] [52500174] q6 end +[2026-10-09 14:02:21.463219 info] [52500174] spike: new tap.python: 1 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 14:02:21.522846 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:21.522864 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:21.705179 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:21.705190 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:21.754085 info] [52500174] spike: thread 'loadbang': main 1, audio 0, timer 1, thread id 189247 +[2026-10-09 14:02:21.789794 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:21.789808 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:21.867852 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:21.867866 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:21.889980 info] [52500174] q5 phase overdrive-off +[2026-10-09 14:02:21.923019 info] [52500174] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 189247 +[2026-10-09 14:02:22.022974 info] [52500174] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 189247 +[2026-10-09 14:02:22.123027 info] [52500174] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 189247 +[2026-10-09 14:02:22.223568 info] [52500174] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 189247 +[2026-10-09 14:02:22.323009 info] [52500174] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 189247 +[2026-10-09 14:02:22.423016 info] [52500174] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 189247 +[2026-10-09 14:02:22.722989 info] [52500214] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:22.732915 info] [52500214] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:22.822957 info] [52500214] q5 phase overdrive-on +[2026-10-09 14:02:22.873004 info] [52500174] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 195098 +[2026-10-09 14:02:22.972981 info] [52500174] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 195098 +[2026-10-09 14:02:23.072945 info] [52500174] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 195098 +[2026-10-09 14:02:23.172950 info] [52500174] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 195098 +[2026-10-09 14:02:23.272996 info] [52500174] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 195098 +[2026-10-09 14:02:23.372966 info] [52500174] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 195098 +[2026-10-09 14:02:23.573026 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:23.573038 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:23.743906 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:23.743918 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:23.743972 info] [52500174] recorder q5-dsp-running: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:23.743985 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:23.743988 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:23.743995 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:23.743997 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:23.840618 info] [52501605] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:23.851267 info] [52501605] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:25.942065 info] [52501605] q5 phase overdrive-on-audio-interrupt-on-audio-running +[2026-10-09 14:02:25.990029 info] [52500174] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 187749 +[2026-10-09 14:02:26.091266 info] [52500174] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 187749 +[2026-10-09 14:02:26.187306 info] [52500174] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 187749 +[2026-10-09 14:02:26.288630 info] [52500174] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 187749 +[2026-10-09 14:02:26.389958 info] [52500174] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 187749 +[2026-10-09 14:02:26.491250 info] [52500174] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 187749 +[2026-10-09 14:02:26.814612 info] [52500174] recorder q5-dsp-running: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:26.814643 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:26.814648 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:26.814656 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:26.814660 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:26.814667 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:26.814670 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 14:02:26.842848 info] [52501876] q5 phase overdrive-on-audio-interrupt-on-audio-stopped +[2026-10-09 14:02:26.892816 info] [52500174] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 202170 +[2026-10-09 14:02:26.992859 info] [52500174] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 202170 +[2026-10-09 14:02:27.092811 info] [52500174] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 202170 +[2026-10-09 14:02:27.192840 info] [52500174] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 202170 +[2026-10-09 14:02:27.292871 info] [52500174] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 202170 +[2026-10-09 14:02:27.392879 info] [52500174] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 202170 +[2026-10-09 14:02:27.592800 info] [52501876] q5 putting Overdrive and Audio Interrupt back +[2026-10-09 14:02:27.642847 info] [52501876] recorder q5-was-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:27.689128 info] [52500174] recorder q5-was-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:27.696954 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:27.696965 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:27.792818 info] [52500174] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 14:02:27.802829 info] [52500174] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) ## session q7 From afc69937223fb469c167af92bd1330cf54b73c32 Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Fri, 9 Oct 2026 14:19:10 -0500 Subject: [PATCH 8/9] =?UTF-8?q?The=20plan:=209.0=20on=20Windows=20?= =?UTF-8?q?=E2=80=94=20every=20answer=20the=20same;=209.0=20done?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz --- CLAUDE.md | 22 ++++---- docs/PRODUCTION-PLAN.md | 10 ++-- docs/TAP-PYTHON-PLAN.md | 122 +++++++++++++++++++++++----------------- 3 files changed, 86 insertions(+), 68 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 38c4579..f76a1e3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -143,17 +143,17 @@ attaches all the zips + SHA256s to a release — a pre-release for 0.x, a draft `&method_false` is its own import thunk (the SDK declares it without `dllimport`), so 1.0.1's comparison reserved every name again, on Windows only. The object asks Max what it answers for a name no class can have (`not_found_method()`) and compares with that (`found_method()`, 1.0.2). - And what the object itself registers can answer its name too — its *attributes* do, and the - guard must leave them out, or a reload reserves every field (1.0.1, found in Max); its messages, - added with `object_addmethod()`, answer as unknown (the 9.0 spike, on the Mac), and are left out - as well. The mock kernel is thinner than Max: when a stub decides a behavior, make the test's - stub faithful to the SDK (as `attr_args_offset` and `object_getmethod` are — the glue test's - kernel answers an unknown name with a function the module cannot take the address of, as - Windows does, and an added attribute's name, as Max does), and give each fake function a body - of its own: MSVC's Release link folds identical functions (`/OPT:ICF`), which once gave a fake - "found" method `method_false()`'s address on Windows only. Three releases in a row shipped what - only a host platform could show, and the third was Windows-only: a change to Max glue is - verified in Max on **both** platforms before it is tagged. + And what the object itself registers can answer its name too — its *attributes* do, and the guard + must leave them out, or a reload reserves every field (1.0.1, found in Max); its messages, added + with `object_addmethod()`, answer as unknown (the 9.0 spike, on both platforms), and are left out + as well. The mock kernel is thinner than Max: when a stub decides a behavior, make the test's stub + faithful to the SDK (as `attr_args_offset` and `object_getmethod` are — the glue test's kernel + answers an unknown name with a function the module cannot take the address of, as Windows does, + and an added attribute's name, as Max does), and give each fake function a body of its own: MSVC's + Release link folds identical functions (`/OPT:ICF`), which once gave a fake "found" method + `method_false()`'s address on Windows only. Three releases in a row shipped what only a host + platform could show, and the third was Windows-only: a change to Max glue is verified in Max on + **both** platforms before it is tagged. - **Say what is true of a class once, what is true of an instance per instance.** Many objects can share one class file; only the processor whose `load()` ran the file (`load_script` says so) announces the class — its `Loaded` line and its diagnostics — through `announce()` (plan 6.7). diff --git a/docs/PRODUCTION-PLAN.md b/docs/PRODUCTION-PLAN.md index ab0268d..37fe0b6 100644 --- a/docs/PRODUCTION-PLAN.md +++ b/docs/PRODUCTION-PLAN.md @@ -798,16 +798,16 @@ where a PR decides differently. One PR per item, in this order, each against tes before it. 9.0 runs in Max on a Mac *and* on Windows before anything else: three releases in a row shipped what only a host platform could show. -- [ ] **9.0 The spike,** in Max on both platforms: a throwaway second class in `tap.python~`'s +- [x] **9.0 The spike,** in Max on both platforms: a throwaway second class in `tap.python~`'s binary answers what only Max can — one binary, two classes (D11) and the `init/` `objectfile` mapping (or the stub external); `outlet_insert_after` before an obex-stored dumpout and `get` through it; the dispatch order of a class-level `anything` against instance methods and attributes, and `object_getmethod()` on such a class; the thread of a `metro`-driven message under Overdrive and under Scheduler in Audio Interrupt; `symbol` or `anything` for a `str` - return. The answers go into the plan before 9.1. *Run on a Mac 2026-10-09 (#43, Max 9.1.5), - every question answered in TAP-PYTHON-PLAN.md under 9.0: the `init/` mapping works; `get` - needs the class's `dumpout` method; `int`, `float`, `bang` and `list` never reach a class-level - `anything`; a `str` is output as `symbol `. Windows still to run.* + return. The answers go into the plan before 9.1. *Done 2026-10-09: run on a Mac (#43) and on + Windows (#44), Max 9.1.5, the same answers on both, in TAP-PYTHON-PLAN.md under 9.0: the `init/` + mapping works; `get` needs the class's `dumpout` method; `int`, `float`, `bang` and `list` + never reach a class-level `anything`; a `str` is output as `symbol `.* - [ ] **9.1 The core:** output items and their conversion in `value.h`; `message_info::return_count` (depth-aware for string hints), `outlet_count()`, `call_with_output()`; the `bind_audio` option, gating the tuple rule; a last parameter hinted `list[…]` or `np.ndarray` taking the remaining diff --git a/docs/TAP-PYTHON-PLAN.md b/docs/TAP-PYTHON-PLAN.md index 5f9a7f6..095dbf3 100644 --- a/docs/TAP-PYTHON-PLAN.md +++ b/docs/TAP-PYTHON-PLAN.md @@ -8,8 +8,8 @@ change — and the plan to build it (Phase 9 of the production plan, which point Drafted 2026-10-02 against 1.0.0 and audited the same day (`AUDIT-TAP-PYTHON-PLAN.md`: two blockers, six major findings, nine minor; its addendum of 2026-10-09 records what 1.0.1 and 1.0.2 changed). **Revised 2026-10-09 against 1.0.2** for every finding; the [revision record](#revision-record) -at the end says what each changed. Nothing is built yet, but the 9.0 spike has run in Max on a Mac: -its answers are under [9.0](#what-90-found-on-a-mac), and the design below follows them. Tick the +at the end says what each changed. Nothing is built yet, but the 9.0 spike has run in Max on a Mac +and on Windows: its answers are under [9.0](#what-90-found), and the design below follows them. Tick the items below (with the PR) as they land, and keep the design current where a PR decides differently. ## What it is for @@ -51,7 +51,7 @@ ordinary Max object model, which is what makes it composable with `trigger`, `me | D8 | How output works | **A method's return value is output from the object's outlets, by its type; its return *hint* fixes how many outlets, at bind time.** No injected outlet API in 2.0 (nothing for the class to import, so it still runs in a notebook): `None` outputs nothing; a number or a string one atom; a sequence a list; a method hinted `-> tuple[A, B]` outputs one value per outlet, right to left. The object has as many outlets as the widest return hint among its methods (at least one), plus a dumpout outlet at the right, as Max objects with attributes do; a save that changes the count changes the outlets in place. The rules are in [Output](#output-what-a-method-returns). | | D9 | Inlets | **One inlet in the first release.** Messages are the methods; state is the attributes (`steps 8`, `@pulses 3`, attrui), which is what a right inlet is for in most Max objects. More inlets are a later option (how, in [Later](#later-not-planned)), not a 1.x promise. | | D10 | Threads | **A message runs on the thread it arrives on, holding the GIL while Python runs, and outputs on that thread after the GIL is released.** That is Max's main thread, the scheduler thread under Overdrive — or, with Scheduler in Audio Interrupt on, the audio thread itself, which the object says once per session and the ReadMe states as a limit. As every ordinary Max object does, and as `tap.python~`'s messages already do. No worker. The limits, in [Threads](#threads-and-the-gil). | -| D11 | Code layout | **One binary registers both Max classes; the second is a plain SDK class, not a min class; the core gains one option.** *Why one binary (decided 2026-10-09, audit B1):* the core is header-only and keeps its process-wide state in function-local statics, so two externals would each start the interpreter — the second `PyImport_AppendInittab()` after `Py_Initialize()` aborts Max (reproduced with two shared objects in one process) — and, as 1.0.1's Windows failure showed, a function's address is not its identity across a DLL boundary. *Why a plain SDK class:* min keeps one file-scope `this_class` per translation unit and returns early from a second `wrap_as_max_external()` (`c74_min_api.h:325`, `c74_min_object_wrapper.h:780`); a second min class in a second translation unit would work by accident of internal linkage and violate the one-definition rule the moment a test instantiated its templates elsewhere. A plain class (`class_new`/`class_addmethod`/`class_register` in the same `ext_main`, after min's) is what the shared glue already speaks — `object_addattr`, `object_addmethod`, the nobox file watcher — and what the outlets need (M1). Max finds the object through the package's `init/` mapping (`objectfile`), with a stub external as the fallback; the 9.0 spike found the mapping works (on the Mac; Windows still to run). The core's `processor` takes `bind_audio` (true for `tap.python~`): with it off, `process` and `prepare` are plain methods and nothing is prepared. The shared glue moves into templates on the host object (`python_glue`) so both classes use one copy. | +| D11 | Code layout | **One binary registers both Max classes; the second is a plain SDK class, not a min class; the core gains one option.** *Why one binary (decided 2026-10-09, audit B1):* the core is header-only and keeps its process-wide state in function-local statics, so two externals would each start the interpreter — the second `PyImport_AppendInittab()` after `Py_Initialize()` aborts Max (reproduced with two shared objects in one process) — and, as 1.0.1's Windows failure showed, a function's address is not its identity across a DLL boundary. *Why a plain SDK class:* min keeps one file-scope `this_class` per translation unit and returns early from a second `wrap_as_max_external()` (`c74_min_api.h:325`, `c74_min_object_wrapper.h:780`); a second min class in a second translation unit would work by accident of internal linkage and violate the one-definition rule the moment a test instantiated its templates elsewhere. A plain class (`class_new`/`class_addmethod`/`class_register` in the same `ext_main`, after min's) is what the shared glue already speaks — `object_addattr`, `object_addmethod`, the nobox file watcher — and what the outlets need (M1). Max finds the object through the package's `init/` mapping (`objectfile`), with a stub external as the fallback; the 9.0 spike found the mapping works, on a Mac and on Windows, so no stub is needed. The core's `processor` takes `bind_audio` (true for `tap.python~`): with it off, `process` and `prepare` are plain methods and nothing is prepared. The shared glue moves into templates on the host object (`python_glue`) so both classes use one copy. | ## The class contract @@ -97,7 +97,7 @@ returns. The rules reproduce how Max objects and `js` behave, so a patch sees wh | `bool`, or numpy's `bool_` | an int, 0 or 1 | | an `int` (anything with `__index__`: `np.int64`, an `IntEnum`) | an int (`t_atom_long`, 64-bit; a value past it is reported) | | a `float` (anything with `__float__` and no `__index__`: `np.float32`) | a float; a non-finite value passes through as the atom Max can carry (`tap.python~` zeroes them for the audio's sake; a control value is the class's to make) | -| a `str` | `symbol `: one symbol, whatever it holds (`"hello world"` is one symbol, `"60"` the symbol and not the number). *Decided by the 9.0 spike, in Max:* output as the message it names, the strings `list`, `int`, `float`, `symbol`, `bang` and `""` are not data — dropped, an error in every receiver, a real bang — while `symbol ` reaches `sel`, a message box's `$1` and every other receiver as itself ([what 9.0 found](#what-90-found-on-a-mac), 6). To output the message a string names, return it in a list (`["start"]`, the next row) | +| a `str` | `symbol `: one symbol, whatever it holds (`"hello world"` is one symbol, `"60"` the symbol and not the number). *Decided by the 9.0 spike, in Max:* output as the message it names, the strings `list`, `int`, `float`, `symbol`, `bang` and `""` are not data — dropped, an error in every receiver, a real bang — while `symbol ` reaches `sel`, a message box's `$1` and every other receiver as itself ([what 9.0 found](#what-90-found), 6). To output the message a string names, return it in a list (`["start"]`, the next row) | | a sequence: a `list`, a `tuple` without a `tuple[…]` hint, a `range`, or a 1-D `np.ndarray` | a list, each element an atom by the rules above; if the first element is a `str`, the message it names with the rest as arguments (Max's own rule: `["note", 60, 100]` outputs `note 60 100`); an empty sequence outputs nothing; an element that is not an atom (`None`, a nested sequence) is reported and the list is not output | | a sequence of *n* values, from a method hinted `-> tuple[…]` with *n* members | one value per outlet, outlets *n*…1, right to left, each by these rules (`None` in a slot outputs nothing from that outlet); a result that is not a sequence of exactly *n* values is reported | | anything else: a `dict`, a `set`, `bytes`, a generator, a 2-D array, an object | reported, with its type; nothing output (a `dict` as a Max dictionary is a later item) | @@ -217,11 +217,11 @@ registered by the project's own `ext_main` in `tap.python_tilde.cpp` after min's maps — the same members as the min object, through the shared glue. - **How Max finds it.** The package's `init/tap.python.txt` maps the object name to the file: `max objectfile tap.python tap.python~;` — the mapping Max's own `init/` text files use for - objects that live in a file of another name. *Verified on the Mac by 9.0:* a fresh Max finds - `[tap.python]` through it, and says `tap.python: No such object` without it; Windows is still to - run. If Max will not map it there, the fallback is a stub external `tap.python.mxo` / `.mxe64` - with no core in it, whose `ext_main` has Max load `tap.python~`'s file (which registers both - classes) and returns. `assemble-package.py` ships `init/` (since 9.0). + objects that live in a file of another name. *Verified by 9.0 on a Mac and on Windows:* a fresh + Max finds `[tap.python]` through it, and says `tap.python: No such object` without it. So the + fallback the plan held in reserve — a stub external `tap.python.mxo` / `.mxe64` whose `ext_main` + has Max load `tap.python~`'s file — is not needed. `assemble-package.py` ships `init/` (since + 9.0). - **Ports (audit M1).** In `new`, `outlet_new()` for the dumpout first (Max orders outlets by creation, right to left), stored with `object_obex_store(x, _sym_dumpout, …)` as the SDK's own example does, then the value outlets from last to first. **And the class registers @@ -322,16 +322,15 @@ before any code the others depend on, and runs on a Mac and on Windows** — thr row (1.0.0, 1.0.1, 1.0.1's Windows package) shipped what only a host platform could show, and the third was Windows-only. -- [ ] **9.0 The spike, in Max on both platforms.** A throwaway second class in `tap.python~`'s +- [x] **9.0 The spike, in Max on both platforms.** A throwaway second class in `tap.python~`'s binary, enough to answer what only Max can, written into this plan before 9.1. **Run on a Mac - (2026-10-09, #43): every question answered — the verdicts below, the evidence in - [What 9.0 found](#what-90-found-on-a-mac). Windows: still to run** (questions 1, 3, 4 and 5 at - least; `runtime-tests/spike/README.md` says how). Verified in Max 9.1.5 (3db35fa476d), macOS - 15.7.9, x86_64: + (2026-10-09, #43) and on Windows (2026-10-09, #44): every question answered, the same on both — + the verdicts below, the evidence in [What 9.0 found](#what-90-found).** Verified in Max 9.1.5 + (3db35fa476d) on macOS 15.7.9 x86_64 and on Windows 11 x64 (a Parallels VM): - a plain SDK class registered beside min's in one `ext_main` loads, and both objects work in one patch created in either order (D11) — **yes**; - `init/tap.python.txt`'s `objectfile` mapping makes `[tap.python]` load the file in a fresh - Max — or the stub external does — **the mapping does; no stub needed on the Mac**; + Max — or the stub external does — **the mapping does, on both; no stub is needed**; - `outlet_insert_after` places an outlet before the dumpout, and patch cords survive it (M1) — **yes, and `outlet_delete` removes exactly the outlets it is given, with their cords**; - `get` reaches the obex-stored dumpout (M1) — **only if the class also registers @@ -349,10 +348,10 @@ third was Windows-only. box (m2) — *the maintainer's choice (2026-10-09): the spike decides* — **`symbol `** (the output table now says so, and why); - where Max picks up a vignette (`.maxvig.xml`) and a tutorial (`.maxtut.xml`) dropped into - the package's `docs/`, and a patcher in `extras/`, for 9.4 — **Max's file database records - them anywhere under `docs/`, and an `extras/` patcher as the package's; that the - Documentation window and the Extras menu show them is still to be seen** (the run's screen - was locked). + the package's `docs/`, and a patcher in `extras/`, for 9.4 — **anywhere under `docs/`: Max's + file database records each, and the Documentation window lists the package under Package + Docs; an `extras/` patcher is in the Extras menu** (seen on the Mac; which of the window's + tabs shows which file is 9.4's to look at, when it writes them). - [ ] **9.1 The core: output, outlets and the audio option.** `value.h`'s `output_item`/`output` and the Python-to-output conversion; `message_info::return_count` (depth-aware for strings), `outlet_count()`, `call_with_output()`; `bind_audio`, gating the tuple rule; the @@ -391,9 +390,10 @@ third was Windows-only. (its `homepatcher` is empty today). The help patchers with tabs: `tap.python`'s from the start, and `tap.python~`'s gaining the numpy, allpass and `mc.` tabs 5.2 asked for. 9.0 found Max records a vignette and a tutorial anywhere under `docs/` (so `docs/vignettes/` and - `docs/tutorials/-tut/`, as Cycling '74's packages lay them out), and an `extras/` - patcher as the package's; still to see that the window and the menu show them, and which folder - `homepatcher` reads (Max's Packages page says `patchers/`). CI checks for what is written + `docs/tutorials/-tut/`, as Cycling '74's packages lay them out), lists the package in the + Documentation window's Package Docs, and shows an `extras/` patcher in the Extras menu; still to + see which of the window's tabs lists which file, and which folder `homepatcher` reads (Max's + Packages page says `patchers/`). CI checks for what is written by hand: the reference page, the vignette and the tutorials well-formed XML, and the help patchers' JSON as 5.2 checked by hand (ids unique, every line connects), in one script. All checked open in Max in 9.6. @@ -423,12 +423,16 @@ third was Windows-only. the short form, written separately — a few screens in Max's own conventions that point to the ReadMe and the book for the contract's facts — not generated from the book's source. -## What 9.0 found, on a Mac +## What 9.0 found -Verified in Max 9.1.5 (3db35fa476d) on macOS 15.7.9, x86_64, 2026-10-09, with the spike built into -`tap.python~`'s binary (`-DTAP_PYTHON_SPIKE=ON`, off by default; `tap.python_spike.cpp`). The -patchers, the runner and how to repeat it — on Windows by hand — are in `runtime-tests/spike/`; the -lines of Max's log behind every answer below are `runtime-tests/spike/results/macos.txt`. The +Verified 2026-10-09 in Max 9.1.5 (3db35fa476d) on macOS 15.7.9, x86_64, and in the same Max on +Windows 11 Home (10.0.26200, x64, in a Parallels VM), with the spike built into `tap.python~`'s +binary (`-DTAP_PYTHON_SPIKE=ON`, off by default; `tap.python_spike.cpp`) — on Windows by MSVC +(Visual Studio 2026, CMake 4.3.1) with no warnings, the glue test passing. The patchers and a runner +for each platform (`run_spike.py`, `run_spike_windows.ps1`) are in `runtime-tests/spike/`; the lines +of Max's log behind every answer below are `runtime-tests/spike/results/macos.txt` and +`windows.txt`. **Every answer is the same on both platforms**; where Windows says more, it is said +below. The spike's `tap.python` is a plain SDK class with no Python in it: a dumpout stored in the obex, value outlets, an instance attribute and instance methods, a class attribute, a class-level `anything`, and messages that ask Max things; a second class, `tap.python.spike.recorder`, posts each message @@ -439,7 +443,8 @@ it receives with its selector and atom types (Max's log drops a `[print]`'s name `tap.python~` file, whose `ext_main` registers `tap.python~` (min) and then `tap.python`, and the object is made; with the file moved aside, `tap.python: No such object`. Both objects in one patch, each created first in its own fresh Max: both load, the spike's outlets output, and `tap.python~` -(`default.py`) answers `greet`. The stub external is not needed on the Mac. A Max is fresh only if +(`default.py`) answers `greet`. The same on Windows — the first build of a plain SDK class beside +min's in the `.mxe64` — so the stub external is not needed. A Max is fresh only if nothing loads the binary first: with **Restore Windows on Launch** on, a window left open at the last quit (`tap.python~`'s help patcher, here) is reopened at launch and loads it — 9.5's test of the mapping must see to that, as the spike's runner does. @@ -461,7 +466,8 @@ attribute's own getter and outputs `steps 5` from the dumpout (`steps 8` after ` class attribute answers `getlevel` the same way. Without that method, `get` on either kind of attribute is **dropped silently**: no getter call, no output, no error, and the class's `anything` never sees it — although `object_attr_method()` resolves `getsteps` to the getter and -`object_getmethod()` finds it. In passing: `object_attr_getdump()`, which its header says takes the +`object_getmethod()` finds it. On Windows the method is registered by the address the module sees, +its import thunk (1.0.1's lesson), and works the same: Max calls through it. In passing: `object_attr_getdump()`, which its header says takes the attribute's name, strips three characters from the name it is given (`steps` came out as `ps`) — it wants the message, `getsteps`. The object has no use for it once the `dumpout` method exists. @@ -486,7 +492,9 @@ it wants the message, `getsteps`. The object has no use for it once the `dumpout `dumpout`, `dsp64` on `tap.python~`); and it answers methods added with `object_addmethod()` — the spike's `hello` and `int`, `default.py`'s `greet` and `int` on `tap.python~` — with `method_false()`, as unknown (`zgetfn()` finds them). `dumpout` is answered, so it joins the - reserved names. + reserved names. On Windows every one of these answers is the same; only Max's `method_false()` + is not the module's `&method_false` there (its import thunk), as 1.0.2 assumes — so the guard + works unchanged on both. **5. Threads (M4).** A `[metro 100]` into a message box into the object; `systhread_*` noted on the thread the message came on: @@ -502,8 +510,9 @@ thread the message came on: So `systhread_isaudiothread()` is true exactly when Python would run on the audio thread, and is the test for the Threads section's notice; `systhread_istimerthread()` is 1 in every case (with Overdrive off the main thread services the scheduler) and tells nothing. Max's log shows three -different posting threads for the last three rows. The patcher put both settings back as it found -them. +different posting threads for the last three rows. The patcher checks that audio really ran +(`dspstate~`) and puts both settings back as it found them. Windows (MME, 44.1 kHz): the same table, +row for row. **6. A `str` return (m2) — decided: `symbol `.** Each string was output from one outlet as the message it names (`outlet_anything(o, gensym(s), 0, nullptr)`) and as `symbol `, into `[route @@ -542,11 +551,17 @@ into the package and Max was started; once its file database reported ready, it | `extras/PythonTap Spike Extras.maxpat` | `patcher` in `Package:/PythonTap/extras` | So Max reads the files from anywhere under `docs/`; 9.4 can lay them out as Cycling '74's packages -do (`docs/vignettes/`, `docs/tutorials/-tut/`). **Not yet seen:** that the Documentation -window lists them and the Extras menu shows the patcher — the run's screen was locked; anyone can -check by hand with `runtime-tests/spike/q7/` copied in. And Max's Packages page describes -`homepatcher` as a patcher in the package's `patchers/` folder, where 9.4 plans the overview in -`extras/`: 9.4 checks which `homepatcher` finds, or ships it in both. +do (`docs/vignettes/`, `docs/tutorials/-tut/`). And in Max itself, with them in place: the +Extras menu lists **PythonTap Spike Extras** among the packages' entries, and the Documentation +window's Package Docs lists **PythonTap** beside the packages that ship vignettes or tutorials +(bach, cage, Ease, FrameLib, HIRT, Jamoma, Link, Node for Max, RNBO, Zero), with its Topics, +Guides and Tutorials tabs. Which tab lists which of the files was not looked at (macOS refused the +UI scripting mid-way); 9.4 sees it when it writes the real ones. On Windows the database was still +scanning when Max was quit — in this VM Windows' Documents folder is the Mac's, so Max indexes +every one of the Mac's packages over the share — so `windows.txt` says the query is incomplete; +nothing here is platform-specific. And Max's Packages page describes `homepatcher` as a patcher in +the package's `patchers/` folder, where 9.4 plans the overview in `extras/`: 9.4 checks which +`homepatcher` finds, or ships it in both. **For later items, learned on the way.** The harness's OSC dispatch (`oscar`) calls every method as `(symbol, argc, argv)`: `max openfile` — Max's, typed with two symbols — crashed Max reading @@ -557,20 +572,13 @@ CLAUDE.md said an object's own messages answer their names, as its attributes do attributes do, which the guard was right to leave out either way (CLAUDE.md now says so; the comment on `answered_by_max()` says the same, for 9.2's move to correct). -**Still to run on Windows** (by hand, `runtime-tests/spike/README.md`), before 9.1: - -1. the `init/` mapping in Windows' Max, and the DLL build of the second class — the first - Windows compile of a plain SDK class beside min's — loading in either order (question 1); -2. `get` with the `dumpout` method registered by the address of an imported function, which - on Windows is the module's import thunk (the 1.0.1 lesson) — Max calls it, so it should work; - verify (3); -3. the guard's sentinel on a class with `anything`: what `object_getmethod()` answers for an - unknown name there (4) — the probe lines will say "not equal to `method_false` as this module - sees it", as expected; "SAME AS what it answers for a name no class has" is what matters; -4. the threads, with Windows' audio drivers and Scheduler in Audio Interrupt (5). - -Questions 2 and 6 are Max's own message semantics and cheap to repeat; 7's window and menu can be -checked on either platform. +**On Windows, learned on the way** (for 9.5 and 9.6, which run Windows by hand). A patcher opened +together with Max (`Max.exe ""`, as Explorer opens one) had its scheduler held for +seconds after loading, so every `delay` in it fired at once: the Windows runner opens the patcher +under test from a starter patcher once Max has settled. The glue test needs `support\` on `PATH`, +as CI gives it; without it the test stops at a modal "python313.dll was not found". And a first +Q5 run, before the patcher checked `dspstate~`, showed no audio thread at all — the evidence that +audio ran is what makes that row mean anything. ## Later (not planned) @@ -645,7 +653,7 @@ the vignette is written separately as the short form:* runtime harness is macOS only, written down as a limit rather than fixed here. *2026-10-09, the 9.0 spike in Max on a Mac (Max 9.1.5; #43; Windows still to run) — answers in -[What 9.0 found](#what-90-found-on-a-mac):* +[What 9.0 found](#what-90-found):* - **D11 / How Max finds it:** the `init/` mapping verified; `init/tap.python.txt` added and shipped. - **Ports:** the class registers `object_obex_dumpout` as its `dumpout` method, without which @@ -661,3 +669,13 @@ the vignette is written separately as the short form:* - **Output:** a `str` is `symbol ` (the maintainer left it to the spike); a list names a message. - **9.4 and 9.5:** where Max reads vignettes, tutorials and extras; what the runner learned. + +*2026-10-09, the 9.0 spike on Windows (Max 9.1.5 in a Windows 11 VM; #44) — 9.0 done:* + +- **Every answer the same as on the Mac:** the `init/` mapping (so no stub), the plain SDK class in + the `.mxe64`, the ports and the dumpout method (registered through the import thunk), the + dispatch and the guard's sentinel, the threads, the strings. 9.0 is ticked. +- **Q7 on the Mac, in Max's own windows:** the Extras menu lists an `extras/` patcher, and Package + Docs lists the package; which tab lists which file is left to 9.4. +- **Q5's patcher now checks that audio ran** (`dspstate~`), after a run that could not tell. +- **9.5/9.6 notes:** how to drive Max on Windows (a starter patcher, `support\` on `PATH`). From 1b40e34898f5ec9dbea28495c1f5b303539bfdde Mon Sep 17 00:00:00 2001 From: Timothy Place Date: Fri, 9 Oct 2026 14:24:30 -0500 Subject: [PATCH 9/9] spike: Windows' results (Max 9.1.5, Windows 11 x64) Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz --- docs/PRODUCTION-PLAN.md | 2 +- docs/TAP-PYTHON-PLAN.md | 4 +- runtime-tests/spike/results/windows.txt | 409 ++++++++++++++++++++++++ 3 files changed, 412 insertions(+), 3 deletions(-) create mode 100644 runtime-tests/spike/results/windows.txt diff --git a/docs/PRODUCTION-PLAN.md b/docs/PRODUCTION-PLAN.md index 37fe0b6..80b32bb 100644 --- a/docs/PRODUCTION-PLAN.md +++ b/docs/PRODUCTION-PLAN.md @@ -805,7 +805,7 @@ row shipped what only a host platform could show. and attributes, and `object_getmethod()` on such a class; the thread of a `metro`-driven message under Overdrive and under Scheduler in Audio Interrupt; `symbol` or `anything` for a `str` return. The answers go into the plan before 9.1. *Done 2026-10-09: run on a Mac (#43) and on - Windows (#44), Max 9.1.5, the same answers on both, in TAP-PYTHON-PLAN.md under 9.0: the `init/` + Windows (#45), Max 9.1.5, the same answers on both, in TAP-PYTHON-PLAN.md under 9.0: the `init/` mapping works; `get` needs the class's `dumpout` method; `int`, `float`, `bang` and `list` never reach a class-level `anything`; a `str` is output as `symbol `.* - [ ] **9.1 The core:** output items and their conversion in `value.h`; `message_info::return_count` diff --git a/docs/TAP-PYTHON-PLAN.md b/docs/TAP-PYTHON-PLAN.md index 095dbf3..0f9b706 100644 --- a/docs/TAP-PYTHON-PLAN.md +++ b/docs/TAP-PYTHON-PLAN.md @@ -324,7 +324,7 @@ third was Windows-only. - [x] **9.0 The spike, in Max on both platforms.** A throwaway second class in `tap.python~`'s binary, enough to answer what only Max can, written into this plan before 9.1. **Run on a Mac - (2026-10-09, #43) and on Windows (2026-10-09, #44): every question answered, the same on both — + (2026-10-09, #43) and on Windows (2026-10-09, #45): every question answered, the same on both — the verdicts below, the evidence in [What 9.0 found](#what-90-found).** Verified in Max 9.1.5 (3db35fa476d) on macOS 15.7.9 x86_64 and on Windows 11 x64 (a Parallels VM): - a plain SDK class registered beside min's in one `ext_main` loads, and both objects work in @@ -670,7 +670,7 @@ the vignette is written separately as the short form:* message. - **9.4 and 9.5:** where Max reads vignettes, tutorials and extras; what the runner learned. -*2026-10-09, the 9.0 spike on Windows (Max 9.1.5 in a Windows 11 VM; #44) — 9.0 done:* +*2026-10-09, the 9.0 spike on Windows (Max 9.1.5 in a Windows 11 VM; #45) — 9.0 done:* - **Every answer the same as on the Mac:** the `init/` mapping (so no stub), the plain SDK class in the `.mxe64`, the ports and the dumpout method (registered through the import thunk), the diff --git a/runtime-tests/spike/results/windows.txt b/runtime-tests/spike/results/windows.txt new file mode 100644 index 0000000..5edd2a7 --- /dev/null +++ b/runtime-tests/spike/results/windows.txt @@ -0,0 +1,409 @@ +# The plan 9.0 spike in Max 9.1.5.3db35fa476d, Microsoft Windows 11 Home 10.0.26200 AMD64 +# (written by runtime-tests/spike/run_spike_windows.ps1: the lines of interest from Max's log) + +## session q1-control + +[2026-10-09 13:33:13.626774 error] [11840] tap.python: No such object + +## session q1-mapping + +[2026-10-09 13:34:17.061817 info] [6036] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) +[2026-10-09 13:34:17.061884 info] [6036] spike: new tap.python: 2 value outlet(s) + dumpout, steps 8; main thread 1 + +## session q1-spike-first + +[2026-10-09 13:35:17.450419 info] [11368] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) +[2026-10-09 13:35:17.450534 info] [11368] spike: new tap.python: 2 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 13:35:17.542318 info] [11368] Loaded default.py: process() bound, one call per sample +[2026-10-09 13:35:17.711326 info] [11368] q1 spike-first begin +[2026-10-09 13:35:17.711365 info] [11368] spike: fire +[2026-10-09 13:35:17.711407 info] [11368] recorder q1-spike: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:35:17.711412 info] [11368] recorder q1-spike: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:35:17.746760 info] [11368] python: hello q1, from python! +[2026-10-09 13:35:17.940152 info] [11368] q1 spike-first end + +## session q1-tilde-first + +[2026-10-09 13:36:19.179057 info] [5196] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) +[2026-10-09 13:36:19.283722 info] [5196] Loaded default.py: process() bound, one call per sample +[2026-10-09 13:36:19.286722 info] [5196] spike: new tap.python: 2 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 13:36:19.494447 info] [5196] q1 tilde-first begin +[2026-10-09 13:36:19.494490 info] [5196] spike: fire +[2026-10-09 13:36:19.494534 info] [5196] recorder q1-spike: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:36:19.494538 info] [5196] recorder q1-spike: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:36:19.494605 info] [5196] python: hello q1, from python! +[2026-10-09 13:36:19.661442 info] [5196] q1 tilde-first end + +## session q2-outlets + +[2026-10-09 13:37:20.568015 info] [6564] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) +[2026-10-09 13:37:20.568074 info] [6564] spike: new tap.python: 2 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 13:37:20.786763 info] [6564] q2 begin: two value outlets and the dumpout +[2026-10-09 13:37:20.786817 info] [6564] spike: describe: outlet_count 3 (2 value outlet(s) held + dumpout) +[2026-10-09 13:37:20.786825 info] [6564] spike: describe: outlet_nth(0) is value outlet 0 +[2026-10-09 13:37:20.786828 info] [6564] spike: describe: outlet_nth(1) is value outlet 1 +[2026-10-09 13:37:20.786832 info] [6564] spike: describe: outlet_nth(2) is the dumpout +[2026-10-09 13:37:20.786836 info] [6564] spike: describe: the obex's dumpout is the one made first +[2026-10-09 13:37:20.786870 info] [6564] spike: describe: cord from outlet 2 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:20.786875 info] [6564] spike: describe: cord from outlet 1 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:20.786879 info] [6564] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:20.786883 info] [6564] spike: describe: 3 cord(s) from this box +[2026-10-09 13:37:20.786888 info] [6564] spike: fire +[2026-10-09 13:37:20.786905 info] [6564] recorder q2-dumpout: selector 'fired', 0 atom(s) +[2026-10-09 13:37:20.786934 info] [6564] recorder q2-outlet-1: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:37:20.786944 info] [6564] recorder q2-outlet-0: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:37:20.818821 info] [6564] q2 widen: outlets 3 +[2026-10-09 13:37:20.864541 info] [6564] spike: outlets: 2 -> 3 value outlet(s) +[2026-10-09 13:37:20.864941 info] [6564] spike: describe: outlet_count 4 (3 value outlet(s) held + dumpout) +[2026-10-09 13:37:20.864972 info] [6564] spike: describe: outlet_nth(0) is value outlet 0 +[2026-10-09 13:37:20.864976 info] [6564] spike: describe: outlet_nth(1) is value outlet 1 +[2026-10-09 13:37:20.864979 info] [6564] spike: describe: outlet_nth(2) is value outlet 2 +[2026-10-09 13:37:20.864982 info] [6564] spike: describe: outlet_nth(3) is the dumpout +[2026-10-09 13:37:20.864987 info] [6564] spike: describe: the obex's dumpout is the one made first +[2026-10-09 13:37:20.865016 info] [6564] spike: describe: cord from outlet 3 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:20.865020 info] [6564] spike: describe: cord from outlet 1 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:20.865024 info] [6564] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:20.865129 info] [6564] spike: describe: 3 cord(s) from this box +[2026-10-09 13:37:21.059294 info] [6564] spike: describe: outlet_count 4 (3 value outlet(s) held + dumpout) +[2026-10-09 13:37:21.059335 info] [6564] spike: describe: outlet_nth(0) is value outlet 0 +[2026-10-09 13:37:21.059338 info] [6564] spike: describe: outlet_nth(1) is value outlet 1 +[2026-10-09 13:37:21.059341 info] [6564] spike: describe: outlet_nth(2) is value outlet 2 +[2026-10-09 13:37:21.059345 info] [6564] spike: describe: outlet_nth(3) is the dumpout +[2026-10-09 13:37:21.059349 info] [6564] spike: describe: the obex's dumpout is the one made first +[2026-10-09 13:37:21.059364 info] [6564] spike: describe: cord from outlet 2 to newprint inlet 0 +[2026-10-09 13:37:21.059388 info] [6564] spike: describe: cord from outlet 3 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:21.059392 info] [6564] spike: describe: cord from outlet 1 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:21.059396 info] [6564] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:21.059398 info] [6564] spike: describe: 4 cord(s) from this box +[2026-10-09 13:37:21.059484 info] [6564] spike: fire +[2026-10-09 13:37:21.059490 info] [6564] recorder q2-dumpout: selector 'fired', 0 atom(s) +[2026-10-09 13:37:21.059511 info] [6564] recorder q2-new: selector 'int', 1 atom(s): 2 (int) +[2026-10-09 13:37:21.059516 info] [6564] recorder q2-outlet-1: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:37:21.059519 info] [6564] recorder q2-outlet-0: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:37:21.159311 info] [6564] q2 narrow: outlets 1 +[2026-10-09 13:37:21.209311 info] [6564] spike: outlets: 3 -> 1 value outlet(s) +[2026-10-09 13:37:21.214674 info] [6564] spike: describe: outlet_count 2 (1 value outlet(s) held + dumpout) +[2026-10-09 13:37:21.214706 info] [6564] spike: describe: outlet_nth(0) is value outlet 0 +[2026-10-09 13:37:21.214710 info] [6564] spike: describe: outlet_nth(1) is the dumpout +[2026-10-09 13:37:21.214714 info] [6564] spike: describe: the obex's dumpout is the one made first +[2026-10-09 13:37:21.214738 info] [6564] spike: describe: cord from outlet 1 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:21.214742 info] [6564] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:21.214745 info] [6564] spike: describe: 2 cord(s) from this box +[2026-10-09 13:37:21.214750 info] [6564] spike: fire +[2026-10-09 13:37:21.214755 info] [6564] recorder q2-dumpout: selector 'fired', 0 atom(s) +[2026-10-09 13:37:21.214760 info] [6564] recorder q2-outlet-0: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:37:21.309967 info] [6564] q2 widen again: outlets 2 +[2026-10-09 13:37:21.359307 info] [6564] spike: outlets: 1 -> 2 value outlet(s) +[2026-10-09 13:37:21.359527 info] [6564] spike: describe: outlet_count 3 (2 value outlet(s) held + dumpout) +[2026-10-09 13:37:21.359552 info] [6564] spike: describe: outlet_nth(0) is value outlet 0 +[2026-10-09 13:37:21.359556 info] [6564] spike: describe: outlet_nth(1) is value outlet 1 +[2026-10-09 13:37:21.359558 info] [6564] spike: describe: outlet_nth(2) is the dumpout +[2026-10-09 13:37:21.359562 info] [6564] spike: describe: the obex's dumpout is the one made first +[2026-10-09 13:37:21.359585 info] [6564] spike: describe: cord from outlet 2 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:21.359634 info] [6564] spike: describe: cord from outlet 0 to [tap.python.spike.recorder] inlet 0 +[2026-10-09 13:37:21.359638 info] [6564] spike: describe: 2 cord(s) from this box +[2026-10-09 13:37:21.359645 info] [6564] spike: fire +[2026-10-09 13:37:21.359650 info] [6564] recorder q2-dumpout: selector 'fired', 0 atom(s) +[2026-10-09 13:37:21.359656 info] [6564] recorder q2-outlet-0: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:37:21.559286 info] [6564] q2 end + +## session q3-dumpout + +[2026-10-09 13:38:21.819173 info] [4680] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) +[2026-10-09 13:38:21.819237 info] [4680] spike: steps setter called (instance attribute) <- 5 +[2026-10-09 13:38:21.819242 info] [4680] spike: new tap.python: 1 value outlet(s) + dumpout, steps 5; main thread 1 +[2026-10-09 13:38:21.819429 info] [4680] spike: steps setter called (instance attribute) <- 5 +[2026-10-09 13:38:21.819469 info] [4680] spike: new tap.python.spike.nodumpout: 1 value outlet(s) + dumpout, steps 5; main thread 1 +[2026-10-09 13:38:22.034199 info] [4680] q3 tap.python: the instance attribute steps +[2026-10-09 13:38:22.034247 info] [4680] spike: steps getter called (instance attribute) -> 5 +[2026-10-09 13:38:22.034274 info] [4680] recorder q3-dumpout: selector 'steps', 1 atom(s): 5 (int) +[2026-10-09 13:38:22.034283 info] [4680] spike: steps setter called (instance attribute) <- 8 +[2026-10-09 13:38:22.034291 info] [4680] spike: steps getter called (instance attribute) -> 8 +[2026-10-09 13:38:22.034295 info] [4680] recorder q3-dumpout: selector 'steps', 1 atom(s): 8 (int) +[2026-10-09 13:38:22.034302 info] [4680] q3 tap.python: the class attribute level +[2026-10-09 13:38:22.061756 info] [4680] recorder q3-dumpout: selector 'level', 1 atom(s): 1 (int) +[2026-10-09 13:38:22.061792 info] [4680] recorder q3-dumpout: selector 'level', 1 atom(s): 3 (int) +[2026-10-09 13:38:22.114191 info] [4680] q3 tap.python: object_attr_getdump and object_attr_method +[2026-10-09 13:38:22.159788 info] [4680] spike: getdump steps: calling object_attr_getdump() +[2026-10-09 13:38:22.159838 info] [4680] recorder q3-dumpout: selector 'ps', 0 atom(s) +[2026-10-09 13:38:22.159847 info] [4680] spike: getdump level: calling object_attr_getdump() +[2026-10-09 13:38:22.159851 info] [4680] recorder q3-dumpout: selector 'el', 0 atom(s) +[2026-10-09 13:38:22.159863 info] [4680] spike: attrmethod 'getsteps': object_attr_method found a method, attribute found, get 1 (steps' own getter) +[2026-10-09 13:38:22.159868 info] [4680] spike: attrmethod 'steps': object_attr_method found a method, attribute found, get 0 (steps' own setter) +[2026-10-09 13:38:22.159876 info] [4680] spike: attrmethod 'getlevel': object_attr_method found a method, attribute found, get 1 +[2026-10-09 13:38:22.159881 info] [4680] spike: attrmethod 'level': object_attr_method found a method, attribute found, get 0 +[2026-10-09 13:38:22.159893 info] [4680] spike: probe 'getsteps' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:38:22.159900 info] [4680] spike: probe 'dumpout' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 13:38:22.307849 info] [4680] q3 tap.python.spike.nodumpout: the instance attribute steps +[2026-10-09 13:38:22.357871 info] [4680] spike: steps setter called (instance attribute) <- 8 +[2026-10-09 13:38:22.407810 info] [4680] q3 tap.python.spike.nodumpout: the class attribute level +[2026-10-09 13:38:22.507792 info] [4680] q3 tap.python.spike.nodumpout: object_attr_getdump and object_attr_method +[2026-10-09 13:38:22.557792 info] [4680] spike: getdump steps: calling object_attr_getdump() +[2026-10-09 13:38:22.557826 info] [4680] spike: getdump level: calling object_attr_getdump() +[2026-10-09 13:38:22.557842 info] [4680] spike: attrmethod 'getsteps': object_attr_method found a method, attribute found, get 1 (steps' own getter) +[2026-10-09 13:38:22.557848 info] [4680] spike: attrmethod 'steps': object_attr_method found a method, attribute found, get 0 (steps' own setter) +[2026-10-09 13:38:22.557854 info] [4680] spike: attrmethod 'getlevel': object_attr_method found a method, attribute found, get 1 +[2026-10-09 13:38:22.557858 info] [4680] spike: attrmethod 'level': object_attr_method found a method, attribute found, get 0 +[2026-10-09 13:38:22.557869 info] [4680] spike: probe 'getsteps' on this tap.python.spike.nodumpout: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:38:22.557876 info] [4680] spike: probe 'dumpout' on this tap.python.spike.nodumpout: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:38:22.707758 info] [4680] q3 end + +## session q4-dispatch + +[2026-10-09 13:39:22.769776 info] [10280] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) +[2026-10-09 13:39:22.769863 info] [10280] spike: new tap.python: 1 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 13:39:22.770062 info] [10280] spike: new tap.python (bare: no instance attribute or methods): 1 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 13:39:22.898618 info] [10280] Loaded default.py: process() bound, one call per sample +[2026-10-09 13:39:23.159684 info] [10280] q4 begin: dispatch on the spike +[2026-10-09 13:39:23.159735 info] [10280] spike: steps setter called (instance attribute) <- 8 +[2026-10-09 13:39:23.159747 info] [10280] spike: steps getter called (instance attribute) -> 8 +[2026-10-09 13:39:23.159771 info] [10280] recorder q4-dumpout: selector 'steps', 1 atom(s): 8 (int) +[2026-10-09 13:39:23.159778 info] [10280] spike: instance method hello called (object_addmethod, A_GIMME): 1 2 +[2026-10-09 13:39:23.159783 info] [10280] spike: who: the INSTANCE method (object_addmethod) answered +[2026-10-09 13:39:23.159802 info] [10280] spike: instance method int called (object_addmethod, A_LONG): 5 +[2026-10-09 13:39:23.159808 error] [10280] doesn't understand "float" +[2026-10-09 13:39:23.159812 info] [10280] spike: bang: the INSTANCE method (object_addmethod) answered +[2026-10-09 13:39:23.159817 info] [10280] spike: instance method int called (object_addmethod, A_LONG): 1 +[2026-10-09 13:39:23.159821 info] [10280] spike: instance method int called (object_addmethod, A_LONG): 4 +[2026-10-09 13:39:23.159827 info] [10280] spike: class anything received: selector 'symbol', 1 argument(s): foo +[2026-10-09 13:39:23.159833 info] [10280] spike: class anything received: selector 'foo', 2 argument(s): 1 2 +[2026-10-09 13:39:23.159841 info] [10280] q4 dispatch on the bare spike +[2026-10-09 13:39:23.159848 info] [10280] spike: class anything received: selector 'steps', 1 argument(s): 8 +[2026-10-09 13:39:23.159852 info] [10280] spike: class anything received: selector 'getsteps', 0 argument(s): +[2026-10-09 13:39:23.159857 info] [10280] spike: class anything received: selector 'hello', 2 argument(s): 1 2 +[2026-10-09 13:39:23.159861 info] [10280] spike: who: the CLASS method (class_addmethod) answered +[2026-10-09 13:39:23.159864 error] [10280] doesn't understand "int" +[2026-10-09 13:39:23.159867 error] [10280] doesn't understand "float" +[2026-10-09 13:39:23.159871 info] [10280] spike: bang: the CLASS method (class_addmethod) answered +[2026-10-09 13:39:23.159874 error] [10280] doesn't understand "int" +[2026-10-09 13:39:23.159878 error] [10280] doesn't understand "int" +[2026-10-09 13:39:23.159882 info] [10280] spike: class anything received: selector 'symbol', 1 argument(s): foo +[2026-10-09 13:39:23.159887 info] [10280] spike: class anything received: selector 'foo', 2 argument(s): 1 2 +[2026-10-09 13:39:23.159895 info] [10280] q4 probes on the spike (it has a class-level anything) +[2026-10-09 13:39:23.159906 info] [10280] spike: probe 'foo' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:39:23.159914 info] [10280] spike: probe 'anything' on this tap.python: object_getmethod is this class's anything; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 13:39:23.159920 info] [10280] spike: probe 'steps' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:39:23.159927 info] [10280] spike: probe 'getsteps' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:39:23.159933 info] [10280] spike: probe 'level' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:39:23.159940 info] [10280] spike: probe 'getlevel' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:39:23.159946 info] [10280] spike: probe 'hello' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 13:39:23.159952 info] [10280] spike: probe 'who' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 13:39:23.159957 info] [10280] spike: probe 'int' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 13:39:23.159963 info] [10280] spike: probe 'float' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:39:23.159969 info] [10280] spike: probe 'bang' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 13:39:23.159975 info] [10280] spike: probe 'list' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:39:23.159981 info] [10280] spike: probe 'symbol' on this tap.python: object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:39:23.159988 info] [10280] spike: probe 'outlets' on this tap.python: object_getmethod is a function; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 13:39:23.272297 info] [10280] q4 probes on tap.python~ (no anything) +[2026-10-09 13:39:23.303964 info] [10280] spike: probe 'foo' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:39:23.304016 info] [10280] spike: probe 'anything' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:39:23.304037 info] [10280] spike: probe 'gain' on tilde (tap.python~): object_getmethod is a function; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:39:23.304058 info] [10280] spike: probe 'greet' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 13:39:23.304078 info] [10280] spike: probe 'int' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 13:39:23.304098 info] [10280] spike: probe 'dsp64' on tilde (tap.python~): object_getmethod is a function; differs from what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn non-null +[2026-10-09 13:39:23.304117 info] [10280] spike: probe 'bang' on tilde (tap.python~): object_getmethod is a function; SAME AS what it answers for a name no class has (which is a function, not equal to method_false as this module sees it); zgetfn null +[2026-10-09 13:39:23.453932 info] [10280] q4 end + +## session q5-threads + +[2026-10-09 13:40:29.988006 info] [11108] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) +[2026-10-09 13:40:29.988083 info] [11108] spike: new tap.python: 1 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 13:40:30.009590 info] [11108] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:30.009627 info] [11108] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:30.271748 info] [11108] spike: thread 'loadbang': main 1, audio 0, timer 1, thread id 872648 +[2026-10-09 13:40:30.271924 info] [11108] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:30.271960 info] [11108] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:30.300058 info] [11108] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:30.300100 info] [11108] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:30.300224 info] [11108] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:30.300279 info] [11108] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:30.356364 info] [11108] q5 phase overdrive-off +[2026-10-09 13:40:30.386139 info] [11108] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 872648 +[2026-10-09 13:40:30.474284 info] [11108] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 872648 +[2026-10-09 13:40:30.574268 info] [11108] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 872648 +[2026-10-09 13:40:30.674269 info] [11108] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 872648 +[2026-10-09 13:40:30.774244 info] [11108] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 872648 +[2026-10-09 13:40:30.874252 info] [11108] spike: thread 'overdrive-off': main 1, audio 0, timer 1, thread id 872648 +[2026-10-09 13:40:31.174161 info] [4348] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:31.184171 info] [4348] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:31.274165 info] [4348] q5 phase overdrive-on +[2026-10-09 13:40:31.324261 info] [11108] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 663929 +[2026-10-09 13:40:31.424227 info] [11108] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 663929 +[2026-10-09 13:40:31.524228 info] [11108] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 663929 +[2026-10-09 13:40:31.624212 info] [11108] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 663929 +[2026-10-09 13:40:31.724241 info] [11108] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 663929 +[2026-10-09 13:40:31.824218 info] [11108] spike: thread 'overdrive-on': main 0, audio 0, timer 1, thread id 663929 +[2026-10-09 13:40:32.024497 info] [11108] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:32.024543 info] [11108] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:32.027368 info] [11108] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:32.027412 info] [11108] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:32.027433 info] [11108] recorder q5-dsp-running: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:32.027440 info] [11108] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:32.027443 info] [11108] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:32.308494 info] [1996] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:32.321174 info] [1996] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:34.414569 info] [1996] q5 phase overdrive-on-audio-interrupt-on-audio-running +[2026-10-09 13:40:34.458012 info] [11108] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 602980 +[2026-10-09 13:40:34.567978 info] [11108] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 602980 +[2026-10-09 13:40:34.659895 info] [11108] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 602980 +[2026-10-09 13:40:34.762103 info] [11108] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 602980 +[2026-10-09 13:40:34.854376 info] [11108] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 602980 +[2026-10-09 13:40:34.956104 info] [11108] spike: thread 'overdrive-on-audio-interrupt-on-audio-running': main 0, audio 1, timer 1, thread id 602980 +[2026-10-09 13:40:35.273684 info] [11108] recorder q5-dsp-running: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:35.273744 info] [11108] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:35.273751 info] [11108] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:35.273759 info] [11108] recorder q5-takeover: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:35.273762 info] [11108] recorder q5-overdrive: selector 'int', 1 atom(s): 1 (int) +[2026-10-09 13:40:35.316297 info] [8464] q5 phase overdrive-on-audio-interrupt-on-audio-stopped +[2026-10-09 13:40:35.366361 info] [11108] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 336826 +[2026-10-09 13:40:35.466257 info] [11108] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 336826 +[2026-10-09 13:40:35.566283 info] [11108] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 336826 +[2026-10-09 13:40:35.666274 info] [11108] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 336826 +[2026-10-09 13:40:35.766279 info] [11108] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 336826 +[2026-10-09 13:40:35.866264 info] [11108] spike: thread 'overdrive-on-audio-interrupt-on-audio-stopped': main 0, audio 0, timer 1, thread id 336826 +[2026-10-09 13:40:36.066178 info] [8464] q5 putting Overdrive and Audio Interrupt back +[2026-10-09 13:40:36.116179 info] [8464] recorder q5-was-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:36.136480 info] [11108] recorder q5-was-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:36.136910 info] [11108] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:36.136935 info] [11108] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:36.266608 info] [11108] recorder q5-overdrive: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:36.279237 info] [11108] recorder q5-takeover: selector 'int', 1 atom(s): 0 (int) +[2026-10-09 13:40:36.466254 info] [11108] q5 end + +## session q6-strings + +[2026-10-09 13:41:33.606894 info] [10716] spike: tap.python registered by tap.python~'s ext_main, after tap.python~ (plan 9.0 spike build) +[2026-10-09 13:41:33.606984 info] [10716] spike: new tap.python: 1 value outlet(s) + dumpout, steps 8; main thread 1 +[2026-10-09 13:41:33.843205 info] [10716] q6 begin +[2026-10-09 13:41:33.843254 info] [10716] spike: q6 ---- as a message: 'C' +[2026-10-09 13:41:33.843280 info] [10716] recorder q6-msgbox: selector 'C', 0 atom(s) +[2026-10-09 13:41:33.843293 info] [10716] recorder q6-prepend: selector 'got', 1 atom(s): 'C' (symbol) +[2026-10-09 13:41:33.843303 info] [10716] recorder q6-sel-C: selector 'bang', 0 atom(s) +[2026-10-09 13:41:33.843314 info] [10716] recorder q6-route-C: selector 'bang', 0 atom(s) +[2026-10-09 13:41:33.843322 info] [10716] recorder q6-raw: selector 'C', 0 atom(s) +[2026-10-09 13:41:33.843327 info] [10716] spike: q6 ---- as a message: 'hello world' +[2026-10-09 13:41:33.843332 info] [10716] recorder q6-msgbox: selector 'hello world', 0 atom(s) +[2026-10-09 13:41:33.843337 info] [10716] recorder q6-prepend: selector 'got', 1 atom(s): 'hello world' (symbol) +[2026-10-09 13:41:33.843347 info] [10716] recorder q6-sel-reject: selector 'hello world', 0 atom(s) +[2026-10-09 13:41:33.843356 info] [10716] recorder q6-route-reject: selector 'hello world', 0 atom(s) +[2026-10-09 13:41:33.843358 info] [10716] recorder q6-raw: selector 'hello world', 0 atom(s) +[2026-10-09 13:41:33.843364 info] [10716] spike: q6 ---- as a message: '60' +[2026-10-09 13:41:33.843368 info] [10716] recorder q6-msgbox: selector '60', 0 atom(s) +[2026-10-09 13:41:33.843371 info] [10716] recorder q6-prepend: selector 'got', 1 atom(s): '60' (symbol) +[2026-10-09 13:41:33.843374 info] [10716] recorder q6-sel-reject: selector '60', 0 atom(s) +[2026-10-09 13:41:33.843376 info] [10716] recorder q6-route-reject: selector '60', 0 atom(s) +[2026-10-09 13:41:33.843378 info] [10716] recorder q6-raw: selector '60', 0 atom(s) +[2026-10-09 13:41:33.843386 info] [10716] spike: q6 ---- as a message: '1.5' +[2026-10-09 13:41:33.843390 info] [10716] recorder q6-msgbox: selector '1.5', 0 atom(s) +[2026-10-09 13:41:33.843393 info] [10716] recorder q6-prepend: selector 'got', 1 atom(s): '1.5' (symbol) +[2026-10-09 13:41:33.843396 info] [10716] recorder q6-sel-reject: selector '1.5', 0 atom(s) +[2026-10-09 13:41:33.843398 info] [10716] recorder q6-route-reject: selector '1.5', 0 atom(s) +[2026-10-09 13:41:33.843400 info] [10716] recorder q6-raw: selector '1.5', 0 atom(s) +[2026-10-09 13:41:33.843405 info] [10716] spike: q6 ---- as a message: 'list' +[2026-10-09 13:41:33.843422 info] [10716] spike: q6 ---- as a message: 'int' +[2026-10-09 13:41:33.843432 error] [10716] missing arguments for message "int" +[2026-10-09 13:41:33.843440 error] [10716] missing arguments for message "int" +[2026-10-09 13:41:33.843448 error] [10716] missing arguments for message "int" +[2026-10-09 13:41:33.843455 error] [10716] missing arguments for message "int" +[2026-10-09 13:41:33.843457 error] [10716] missing arguments for message "int" +[2026-10-09 13:41:33.843462 info] [10716] spike: q6 ---- as a message: 'float' +[2026-10-09 13:41:33.843465 error] [10716] missing arguments for message "float" +[2026-10-09 13:41:33.843466 error] [10716] missing arguments for message "float" +[2026-10-09 13:41:33.843468 error] [10716] missing arguments for message "float" +[2026-10-09 13:41:33.843470 error] [10716] missing arguments for message "float" +[2026-10-09 13:41:33.843472 error] [10716] missing arguments for message "float" +[2026-10-09 13:41:33.843476 info] [10716] spike: q6 ---- as a message: 'symbol' +[2026-10-09 13:41:33.843478 error] [10716] missing arguments for message "symbol" +[2026-10-09 13:41:33.843481 info] [10716] recorder q6-prepend: selector 'got', 1 atom(s): 'symbol' (symbol) +[2026-10-09 13:41:33.843485 info] [10716] recorder q6-sel-reject: selector 'symbol', 1 atom(s): '' (symbol) +[2026-10-09 13:41:33.843487 info] [10716] recorder q6-route-reject: selector 'symbol', 0 atom(s) +[2026-10-09 13:41:33.843489 info] [10716] recorder q6-raw: selector 'symbol', 0 atom(s) +[2026-10-09 13:41:33.843494 info] [10716] spike: q6 ---- as a message: 'bang' +[2026-10-09 13:41:33.843498 info] [10716] recorder q6-msgbox: selector '1.5', 0 atom(s) +[2026-10-09 13:41:33.843501 info] [10716] recorder q6-prepend: selector 'got', 1 atom(s): 'bang' (symbol) +[2026-10-09 13:41:33.843504 info] [10716] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'bang' (symbol) +[2026-10-09 13:41:33.843507 info] [10716] recorder q6-route-reject: selector 'bang', 0 atom(s) +[2026-10-09 13:41:33.843509 info] [10716] recorder q6-raw: selector 'bang', 0 atom(s) +[2026-10-09 13:41:33.843513 info] [10716] spike: q6 ---- as a message: '' +[2026-10-09 13:41:33.843517 info] [10716] recorder q6-msgbox: selector '', 0 atom(s) +[2026-10-09 13:41:33.843520 info] [10716] recorder q6-prepend: selector 'got', 1 atom(s): '' (symbol) +[2026-10-09 13:41:33.843523 info] [10716] recorder q6-sel-reject: selector '', 0 atom(s) +[2026-10-09 13:41:33.843525 info] [10716] recorder q6-route-reject: selector '', 0 atom(s) +[2026-10-09 13:41:33.843527 info] [10716] recorder q6-raw: selector '', 0 atom(s) +[2026-10-09 13:41:33.928080 info] [10716] spike: q6 ---- as symbol: 'C' +[2026-10-09 13:41:33.928134 info] [10716] recorder q6-msgbox: selector 'C', 0 atom(s) +[2026-10-09 13:41:33.928147 info] [10716] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'C' (symbol) +[2026-10-09 13:41:33.928153 info] [10716] recorder q6-sel-C: selector 'bang', 0 atom(s) +[2026-10-09 13:41:33.928159 info] [10716] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'C' (symbol) +[2026-10-09 13:41:33.928163 info] [10716] recorder q6-raw: selector 'symbol', 1 atom(s): 'C' (symbol) +[2026-10-09 13:41:33.928175 info] [10716] spike: q6 ---- as symbol: 'hello world' +[2026-10-09 13:41:33.928179 info] [10716] recorder q6-msgbox: selector 'hello world', 0 atom(s) +[2026-10-09 13:41:33.928185 info] [10716] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'hello world' (symbol) +[2026-10-09 13:41:33.928190 info] [10716] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'hello world' (symbol) +[2026-10-09 13:41:33.928193 info] [10716] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'hello world' (symbol) +[2026-10-09 13:41:33.928196 info] [10716] recorder q6-raw: selector 'symbol', 1 atom(s): 'hello world' (symbol) +[2026-10-09 13:41:33.928203 info] [10716] spike: q6 ---- as symbol: '60' +[2026-10-09 13:41:33.928207 info] [10716] recorder q6-msgbox: selector '60', 0 atom(s) +[2026-10-09 13:41:33.928212 info] [10716] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), '60' (symbol) +[2026-10-09 13:41:33.928215 info] [10716] recorder q6-sel-reject: selector 'symbol', 1 atom(s): '60' (symbol) +[2026-10-09 13:41:33.928218 info] [10716] recorder q6-route-reject: selector 'symbol', 1 atom(s): '60' (symbol) +[2026-10-09 13:41:33.928221 info] [10716] recorder q6-raw: selector 'symbol', 1 atom(s): '60' (symbol) +[2026-10-09 13:41:33.928229 info] [10716] spike: q6 ---- as symbol: '1.5' +[2026-10-09 13:41:33.928233 info] [10716] recorder q6-msgbox: selector '1.5', 0 atom(s) +[2026-10-09 13:41:33.928237 info] [10716] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), '1.5' (symbol) +[2026-10-09 13:41:33.928240 info] [10716] recorder q6-sel-reject: selector 'symbol', 1 atom(s): '1.5' (symbol) +[2026-10-09 13:41:33.928243 info] [10716] recorder q6-route-reject: selector 'symbol', 1 atom(s): '1.5' (symbol) +[2026-10-09 13:41:33.928246 info] [10716] recorder q6-raw: selector 'symbol', 1 atom(s): '1.5' (symbol) +[2026-10-09 13:41:33.928251 info] [10716] spike: q6 ---- as symbol: 'list' +[2026-10-09 13:41:33.928257 info] [10716] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'list' (symbol) +[2026-10-09 13:41:33.928260 info] [10716] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'list' (symbol) +[2026-10-09 13:41:33.928263 info] [10716] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'list' (symbol) +[2026-10-09 13:41:33.928266 info] [10716] recorder q6-raw: selector 'symbol', 1 atom(s): 'list' (symbol) +[2026-10-09 13:41:33.928270 info] [10716] spike: q6 ---- as symbol: 'int' +[2026-10-09 13:41:33.928283 info] [10716] trying to register object, but no obex pointer +[2026-10-09 13:41:33.928285 error] [10716] missing arguments for message "int" +[2026-10-09 13:41:33.928289 info] [10716] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'int' (symbol) +[2026-10-09 13:41:33.928293 info] [10716] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'int' (symbol) +[2026-10-09 13:41:33.928296 info] [10716] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'int' (symbol) +[2026-10-09 13:41:33.928299 info] [10716] recorder q6-raw: selector 'symbol', 1 atom(s): 'int' (symbol) +[2026-10-09 13:41:33.928304 info] [10716] spike: q6 ---- as symbol: 'float' +[2026-10-09 13:41:33.928310 info] [10716] trying to register object, but no obex pointer +[2026-10-09 13:41:33.928311 error] [10716] missing arguments for message "float" +[2026-10-09 13:41:33.928315 info] [10716] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'float' (symbol) +[2026-10-09 13:41:33.928318 info] [10716] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'float' (symbol) +[2026-10-09 13:41:33.928322 info] [10716] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'float' (symbol) +[2026-10-09 13:41:33.928325 info] [10716] recorder q6-raw: selector 'symbol', 1 atom(s): 'float' (symbol) +[2026-10-09 13:41:33.928329 info] [10716] spike: q6 ---- as symbol: 'symbol' +[2026-10-09 13:41:33.928333 info] [10716] recorder q6-msgbox: selector 'symbol', 0 atom(s) +[2026-10-09 13:41:33.928337 info] [10716] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'symbol' (symbol) +[2026-10-09 13:41:33.928340 info] [10716] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'symbol' (symbol) +[2026-10-09 13:41:33.928345 info] [10716] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'symbol' (symbol) +[2026-10-09 13:41:33.928348 info] [10716] recorder q6-raw: selector 'symbol', 1 atom(s): 'symbol' (symbol) +[2026-10-09 13:41:33.928357 info] [10716] spike: q6 ---- as symbol: 'bang' +[2026-10-09 13:41:33.928361 info] [10716] recorder q6-msgbox: selector 'bang', 0 atom(s) +[2026-10-09 13:41:33.928365 info] [10716] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), 'bang' (symbol) +[2026-10-09 13:41:33.928368 info] [10716] recorder q6-sel-reject: selector 'symbol', 1 atom(s): 'bang' (symbol) +[2026-10-09 13:41:33.928371 info] [10716] recorder q6-route-reject: selector 'symbol', 1 atom(s): 'bang' (symbol) +[2026-10-09 13:41:33.928373 info] [10716] recorder q6-raw: selector 'symbol', 1 atom(s): 'bang' (symbol) +[2026-10-09 13:41:33.928378 info] [10716] spike: q6 ---- as symbol: '' +[2026-10-09 13:41:33.928381 info] [10716] recorder q6-msgbox: selector '', 0 atom(s) +[2026-10-09 13:41:33.928385 info] [10716] recorder q6-prepend: selector 'got', 2 atom(s): 'symbol' (symbol), '' (symbol) +[2026-10-09 13:41:33.928388 info] [10716] recorder q6-sel-reject: selector 'symbol', 1 atom(s): '' (symbol) +[2026-10-09 13:41:33.928391 info] [10716] recorder q6-route-reject: selector 'symbol', 1 atom(s): '' (symbol) +[2026-10-09 13:41:33.928394 info] [10716] recorder q6-raw: selector 'symbol', 1 atom(s): '' (symbol) +[2026-10-09 13:41:34.144122 info] [10716] q6 end + +## session q7 + + +Max's file database had NOT finished its update when Max quit, so what follows is incomplete: +Max's file database (c--program files-cycling '74-max 9-max.x64.maxdb), for the files q7 put in the package: + pythontap-spike-tut-docs.maxtut.xml: NOT in the database + pythontap-spike-vig-docs.maxvig.xml: NOT in the database + pythontap-spike-vig-topics.maxvig.xml: NOT in the database + pythontap-spike-tut-tutorials.maxtut.xml: NOT in the database + pythontap-spike-tut-nested.maxtut.xml: NOT in the database + pythontap-spike-tutorial.maxpat: NOT in the database + pythontap-spike-vig-vignettes.maxvig.xml: NOT in the database + PythonTap Spike Extras.maxpat: NOT in the database +