badline 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.claude/hooks/session-start.sh +57 -0
- data/.claude/settings.json +14 -0
- data/CHANGELOG.md +65 -0
- data/CLAUDE.md +45 -16
- data/CONTRIBUTING.md +95 -3
- data/README.md +111 -61
- data/SECURITY.md +9 -0
- data/doc/pinned-behaviour.md +275 -33
- data/exe/badline-ruby +59 -0
- data/lib/badline/address_bus.rb +22 -10
- data/lib/badline/audio/aiff.rb +8 -3
- data/lib/badline/audio/cli.rb +17 -12
- data/lib/badline/audio/console.rb +12 -58
- data/lib/badline/audio/playback.rb +3 -0
- data/lib/badline/audio/sdl_sink.rb +20 -52
- data/lib/badline/audio/terminal.rb +90 -0
- data/lib/badline/audio.rb +2 -2
- data/lib/badline/cartridge/geo_ram.rb +63 -0
- data/lib/badline/cartridge.rb +1 -0
- data/lib/badline/cia/interrupt_register.rb +34 -10
- data/lib/badline/cia.rb +15 -8
- data/lib/badline/computer.rb +28 -13
- data/lib/badline/gui/application.rb +33 -21
- data/lib/badline/gui/gamepads.rb +22 -22
- data/lib/badline/gui/joy_map.rb +1 -1
- data/lib/badline/gui/key_map.rb +6 -1
- data/lib/badline/gui/pane.rb +7 -6
- data/lib/badline/gui/screen_pane.rb +9 -13
- data/lib/badline/gui/window.rb +35 -20
- data/lib/badline/gui.rb +1 -1
- data/lib/badline/input/mouse1351.rb +21 -6
- data/lib/badline/input/paddles.rb +11 -6
- data/lib/badline/kernal_trap/channel.rb +3 -0
- data/lib/badline/kernal_trap/drive/block_commands.rb +33 -4
- data/lib/badline/kernal_trap/drive/status.rb +3 -0
- data/lib/badline/kernal_trap/drive/write_file.rb +41 -0
- data/lib/badline/kernal_trap/drive/writes.rb +92 -0
- data/lib/badline/kernal_trap/drive.rb +51 -51
- data/lib/badline/kernal_trap/file.rb +6 -9
- data/lib/badline/kernal_trap/save.rb +9 -4
- data/lib/badline/keyboard.rb +19 -3
- data/lib/badline/media.rb +42 -11
- data/lib/badline/options.rb +209 -0
- data/lib/badline/ram_expansion/banking.rb +30 -0
- data/lib/badline/ram_expansion/plus256k.rb +38 -0
- data/lib/badline/ram_expansion/plus60k.rb +31 -0
- data/lib/badline/ram_expansion/unexpanded.rb +22 -0
- data/lib/badline/ram_expansion.rb +21 -0
- data/lib/badline/region.rb +51 -0
- data/lib/badline/sdl/events.rb +47 -0
- data/lib/badline/sdl/functions.rb +73 -0
- data/lib/badline/sdl.rb +67 -0
- data/lib/badline/sid/waveform/noise_writeback.rb +32 -14
- data/lib/badline/sid/waveform.rb +1 -1
- data/lib/badline/sid.rb +3 -1
- data/lib/badline/storage/d64_image.rb +10 -0
- data/lib/badline/storage/d71_image.rb +12 -0
- data/lib/badline/storage/d81_image.rb +9 -0
- data/lib/badline/storage/disk_image/bam.rb +111 -0
- data/lib/badline/storage/disk_image/directory.rb +79 -0
- data/lib/badline/storage/disk_image/writing.rb +110 -0
- data/lib/badline/storage/disk_image.rb +27 -4
- data/lib/badline/storage/host_directory.rb +2 -1
- data/lib/badline/storage.rb +15 -0
- data/lib/badline/time_of_day.rb +4 -2
- data/lib/badline/version.rb +1 -1
- data/lib/badline/via/control_lines.rb +104 -0
- data/lib/badline/via/interrupt_register.rb +58 -0
- data/lib/badline/via/shift_register.rb +135 -0
- data/lib/badline/via/timer1.rb +82 -0
- data/lib/badline/via/timer2.rb +84 -0
- data/lib/badline/via.rb +262 -0
- data/lib/badline/vic/bank.rb +4 -3
- data/lib/badline/vic/color_patches.rb +6 -3
- data/lib/badline/vic/display_state.rb +4 -0
- data/lib/badline/vic/graphics_shifter.rb +42 -7
- data/lib/badline/vic/registers.rb +3 -0
- data/lib/badline/vic/sequencer.rb +18 -18
- data/lib/badline/vic/sequencer_output.rb +4 -4
- data/lib/badline/vic/sprite/internal_bus.rb +4 -0
- data/lib/badline/vic/sprite/shifter.rb +25 -3
- data/lib/badline/vic/sprite.rb +5 -4
- data/lib/badline/vic/sprites.rb +8 -3
- data/lib/badline/vic.rb +93 -44
- data/lib/badline.rb +4 -0
- data/packaging/homebrew/badline.rb +34 -0
- metadata +30 -20
- data/exe/badline +0 -78
- data/exe/badline-sid +0 -34
- data/lib/badline/audio/options.rb +0 -137
data/README.md
CHANGED
|
@@ -10,22 +10,36 @@ are modelled at the cycle level.
|
|
|
10
10
|
|
|
11
11
|
It runs programs, disk and tape images, cartridges and SID tunes, and
|
|
12
12
|
the SDL2 front end supports the keyboard, joysticks, game controllers,
|
|
13
|
-
paddles and a 1351 mouse.
|
|
14
|
-
|
|
15
|
-
[What's emulated](#whats-emulated) for the details.
|
|
13
|
+
paddles and a 1351 mouse. See [What's emulated](#whats-emulated) for the
|
|
14
|
+
details.
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
It comes in two builds of the same emulator:
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
- **`badline`**, compiled ahead of time with
|
|
19
|
+
[Spinel](https://github.com/matz/spinel). It runs in real time with
|
|
20
|
+
sound, so it's the one to play games with.
|
|
21
|
+
- **`badline-ruby`**, which comes with the Ruby gem and runs on CRuby. It
|
|
22
|
+
runs slower than a real C64, so its sound is off by default. The gem is
|
|
23
|
+
also a library, which runs a `Badline::Computer` from Ruby without a
|
|
24
|
+
window.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
The native `badline`, with Homebrew:
|
|
20
29
|
|
|
21
30
|
```sh
|
|
22
|
-
brew install
|
|
23
|
-
apt install libsdl2-dev # Debian/Ubuntu
|
|
31
|
+
brew install elektronaut/tap/badline
|
|
24
32
|
```
|
|
25
33
|
|
|
26
|
-
|
|
34
|
+
The formula builds it from the release's generated C, so it needs no
|
|
35
|
+
Spinel or Ruby. To build it from a checkout instead, see
|
|
36
|
+
[native/README.md](native/README.md).
|
|
37
|
+
|
|
38
|
+
The gem needs Ruby 4.0 or newer and the SDL2 library:
|
|
27
39
|
|
|
28
40
|
```sh
|
|
41
|
+
brew install sdl2 # macOS
|
|
42
|
+
apt install libsdl2-2.0-0 # Debian/Ubuntu
|
|
29
43
|
gem install badline
|
|
30
44
|
```
|
|
31
45
|
|
|
@@ -37,22 +51,27 @@ Run `badline` with no arguments to boot to the BASIC prompt, or give it
|
|
|
37
51
|
something to load:
|
|
38
52
|
|
|
39
53
|
```sh
|
|
40
|
-
badline
|
|
41
|
-
badline game.prg
|
|
42
|
-
badline game.d64
|
|
43
|
-
badline game.tap
|
|
44
|
-
badline game.crt
|
|
45
|
-
badline tune.sid
|
|
46
|
-
badline ~/c64
|
|
54
|
+
badline # READY.
|
|
55
|
+
badline game.prg # Load and run a program
|
|
56
|
+
badline game.d64 # Mount a disk image as device 8 and load it
|
|
57
|
+
badline game.tap # Insert a tape and load it
|
|
58
|
+
badline game.crt # Attach a cartridge
|
|
59
|
+
badline tune.sid # Play a SID tune
|
|
60
|
+
badline ~/c64 # Mount a directory as device 8
|
|
47
61
|
```
|
|
48
62
|
|
|
63
|
+
`badline-ruby` takes the same media and the same options, with the
|
|
64
|
+
differences noted below.
|
|
65
|
+
|
|
49
66
|
Programs, disk and tape images and SID tunes start automatically, and
|
|
50
67
|
a cartridge starts itself. A mounted directory waits for you to `LOAD`
|
|
51
68
|
from it. `--no-autostart` attaches the media and stops at `READY.`, so
|
|
52
|
-
you can type the `LOAD` yourself. `--
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
`
|
|
69
|
+
you can type the `LOAD` yourself. `--read-only` mounts a disk image
|
|
70
|
+
write-protected, so the drive reports `26,WRITE PROTECT ON` for any
|
|
71
|
+
write and the image file stays as it was. `--song N` picks a subtune of a
|
|
72
|
+
`.sid` file and `--sid 8580` fits the newer SID. `badline-ruby` also
|
|
73
|
+
takes `--disable-jit`, which runs without YJIT, otherwise switched on at
|
|
74
|
+
startup. `--help` lists the options.
|
|
56
75
|
|
|
57
76
|
The KERNAL, BASIC and character ROMs come with the gem. To run other
|
|
58
77
|
images, such as a patched KERNAL, point `BADLINE_ROM_PATH` at a
|
|
@@ -61,20 +80,22 @@ plus `eapi/eapi-am29f040-14` if you attach EasyFlash cartridges. From
|
|
|
61
80
|
Ruby, `Badline.rom_path = dir` does the same before a
|
|
62
81
|
`Badline::Computer` is built, and `nil` restores the bundled set.
|
|
63
82
|
|
|
64
|
-
|
|
65
|
-
mutes and unmutes it.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
83
|
+
`badline` plays the SID through the host's audio device, and `F10`
|
|
84
|
+
mutes and unmutes it. `--no-sound` turns it off. The window is paced by
|
|
85
|
+
the display's vsync; `--no-vsync` paces it by a timer, or by the sound
|
|
86
|
+
while it plays.
|
|
87
|
+
|
|
88
|
+
In `badline-ruby` sound is off by default, and `--sound` turns it on.
|
|
89
|
+
The machine runs below real time there, so the sound stutters: it plays
|
|
90
|
+
in bursts with silent gaps between them, at the right pitch, and never
|
|
91
|
+
slows the emulation down.
|
|
71
92
|
|
|
72
93
|
## Media
|
|
73
94
|
|
|
74
95
|
| Format | Handling |
|
|
75
96
|
|--------|----------|
|
|
76
97
|
| `.prg`, `.p00` | Loaded into memory after boot. A program at the BASIC start (`$0801`) is `RUN`, anything else is left for you to `SYS` |
|
|
77
|
-
| `.d64`, `.d71`, `.d81` | Mounted read-
|
|
98
|
+
| `.d64`, `.d71`, `.d81` | Mounted read-write as device 8, then `LOAD"*",8,1` and `RUN`. Writes go straight back to the image file. With `--read-only`, or an image the host can't write, it acts as a write-protected disk |
|
|
78
99
|
| `.t64` | Mounted read-only as device 8 and loaded like a disk image. The files load by name, and no tape is involved |
|
|
79
100
|
| `.tap` | Inserted in the datasette with PLAY pressed, then `LOAD` and `RUN`. It loads at the speed of a real tape |
|
|
80
101
|
| `.crt` | The hardware types listed under [Cartridges](#whats-emulated). Other types are rejected |
|
|
@@ -85,36 +106,47 @@ There is no 1541. Device 8 works by trapping the KERNAL's `LOAD` and
|
|
|
85
106
|
`SAVE` routines and its serial bus primitives, so files open by name
|
|
86
107
|
through `OPEN` and `CHRIN` as well. The command channel answers `I`,
|
|
87
108
|
`B-P` and `U1` block reads, which covers loaders that read blocks
|
|
88
|
-
directly.
|
|
89
|
-
|
|
109
|
+
directly. On a disk image it also takes `SAVE` (with `@0:` to replace a
|
|
110
|
+
file), files opened for writing or appending, `S` to scratch, `U2` and
|
|
111
|
+
`B-W` block writes, and `B-A` and `B-F`. Loaders that upload their own
|
|
112
|
+
code to the drive with `M-W` and `M-E`, and copy protection that reads
|
|
113
|
+
raw GCR, won't work.
|
|
114
|
+
|
|
115
|
+
`Badline::Media.insert_disk(computer, path)` swaps the disk image or
|
|
116
|
+
directory in device 8 while the machine runs, for software that asks for
|
|
117
|
+
another disk. It takes `read_only: true`, and `Badline::Media.attach`
|
|
118
|
+
takes `disk: { read_only: true }`, to mount a disk image write-protected,
|
|
119
|
+
as the test harnesses under `bin/` do.
|
|
90
120
|
|
|
91
121
|
## Playing and rendering SID tunes
|
|
92
122
|
|
|
93
|
-
`badline-
|
|
94
|
-
|
|
95
|
-
|
|
123
|
+
`badline-ruby --headless` plays a `.sid` tune on the host's audio
|
|
124
|
+
device without opening the window, and `--audio-out` renders it to a
|
|
125
|
+
16-bit PCM file instead. The file's extension picks the format, `.wav`
|
|
126
|
+
or `.aiff`. The native `badline` has both modes too.
|
|
96
127
|
|
|
97
128
|
```sh
|
|
98
|
-
badline-
|
|
99
|
-
badline-
|
|
100
|
-
badline-
|
|
101
|
-
badline-
|
|
102
|
-
badline-
|
|
103
|
-
badline-
|
|
129
|
+
badline-ruby --headless tune.sid # play, length from HVSC
|
|
130
|
+
badline-ruby --headless -s 3 tune.sid # play the third subtune
|
|
131
|
+
badline-ruby --seconds 180 tune.sid --audio-out out.aiff
|
|
132
|
+
badline-ruby -s 3 --rate 48000 tune.sid --audio-out out.wav
|
|
133
|
+
badline-ruby --headless --sid 8580 tune.sid
|
|
134
|
+
badline-ruby --filter-chunk 1 tune.sid --audio-out out.wav # exact filter, slower
|
|
104
135
|
```
|
|
105
136
|
|
|
106
|
-
Both modes take the same options.
|
|
107
|
-
|
|
108
|
-
|
|
137
|
+
Both modes take the same options. The window's own, `--no-autostart`
|
|
138
|
+
and `--sound`, don't apply to them. `--song` (or `-s`) picks the
|
|
139
|
+
subtune, counting from 1 as HVSC does, and defaults to the tune's own
|
|
140
|
+
start song. Playback asks the device for 44.1 kHz and takes whatever rate it
|
|
109
141
|
offers, unless `--rate` says otherwise. Ctrl-C stops it.
|
|
110
142
|
|
|
111
|
-
Played on a terminal, `
|
|
143
|
+
Played on a terminal, `--headless` shows the tune's name, author and
|
|
112
144
|
release, the song number and the time played against the song's
|
|
113
145
|
length. `n` or → skips to the next song, `p` or ← goes back one, space
|
|
114
146
|
pauses and `q` quits. `--no-tui`, or output that isn't a terminal,
|
|
115
147
|
gives plain progress output instead.
|
|
116
148
|
|
|
117
|
-
A `.sid` file doesn't store its length, so `badline-
|
|
149
|
+
A `.sid` file doesn't store its length, so `badline-ruby` looks the
|
|
118
150
|
tune up by MD5 in HVSC's `Songlengths.md5`. It finds the database
|
|
119
151
|
through `--songlengths`, in a `DOCUMENTS` directory in any of the
|
|
120
152
|
tune's parent directories (the layout of an HVSC collection), or under
|
|
@@ -124,10 +156,15 @@ tune's parent directories (the layout of an HVSC collection), or under
|
|
|
124
156
|
PSID tunes run on a CPU and RAM with only the SID clocked, at about
|
|
125
157
|
twice real time, so they play smoothly. RSID tunes set up their own
|
|
126
158
|
interrupts, so they boot a full C64 first and run at about half real
|
|
127
|
-
time. They render fine but stutter when played, and `badline-
|
|
159
|
+
time. They render fine but stutter when played, and `badline-ruby` says
|
|
128
160
|
so when it falls behind. The filter steps four cycles at a time;
|
|
129
161
|
`--filter-chunk 1` steps it every cycle, which is exact and takes about
|
|
130
|
-
twice as long. `badline-
|
|
162
|
+
twice as long. `badline-ruby --help` lists the options.
|
|
163
|
+
|
|
164
|
+
The native `badline` takes the same options and runs the same code, so
|
|
165
|
+
it renders the same file sample for sample, and it plays RSID tunes
|
|
166
|
+
without stuttering. See
|
|
167
|
+
[native/README.md](native/README.md#without-the-window).
|
|
131
168
|
|
|
132
169
|
## Input
|
|
133
170
|
|
|
@@ -140,15 +177,15 @@ same-named host key:
|
|
|
140
177
|
| `RUN/STOP` | `Escape` |
|
|
141
178
|
| `CLR/HOME` | `Home` |
|
|
142
179
|
| `INST/DEL` | `Backspace` |
|
|
143
|
-
| `CRSR ⇔` / `CRSR ⇕` | `Right` / `Down`
|
|
144
|
-
| `←` / `↑` | `
|
|
180
|
+
| `CRSR ⇔` / `CRSR ⇕` | `Right` / `Down`, and `Left` / `Up` for the shifted directions |
|
|
181
|
+
| `←` / `↑` | `` ` `` / `]` |
|
|
145
182
|
| `CTRL` | `Left Ctrl` |
|
|
146
183
|
| `C=` | `Left Alt` |
|
|
147
184
|
| `@` | `\` |
|
|
148
185
|
| `:` | `'` |
|
|
149
186
|
| `£` | `End` |
|
|
150
187
|
| `+` / `*` | Keypad `+` / Keypad `*` |
|
|
151
|
-
| `RESTORE` |
|
|
188
|
+
| `RESTORE` | `Page Up` |
|
|
152
189
|
|
|
153
190
|
`Tab` steps through the input modes and `Shift-Tab` steps back. The
|
|
154
191
|
window title shows the current mode:
|
|
@@ -175,8 +212,8 @@ Control port 1's fire line is also the VIC-II's light pen input, so
|
|
|
175
212
|
joystick 1's fire button and the 1351's left button in port 1 latch the
|
|
176
213
|
light pen registers.
|
|
177
214
|
|
|
178
|
-
|
|
179
|
-
|
|
215
|
+
`F10` mutes and unmutes the sound, and the window title shows `[MUTED]`
|
|
216
|
+
while it's off.
|
|
180
217
|
|
|
181
218
|
## What's emulated
|
|
182
219
|
|
|
@@ -185,14 +222,21 @@ title shows `[MUTED]` while it's off.
|
|
|
185
222
|
[65x02 single step tests](https://github.com/SingleStepTests/65x02).
|
|
186
223
|
`JAM` opcodes halt the CPU until reset.
|
|
187
224
|
- **Memory**: banking through the 6510 port, including the cartridge
|
|
188
|
-
`EXROM`/`GAME` lines and Ultimax mode.
|
|
225
|
+
`EXROM`/`GAME` lines and Ultimax mode. The +60K and +256K RAM
|
|
226
|
+
expansions fit with `Badline::Computer.new(ram_expansion: :plus60k)` or
|
|
227
|
+
`:plus256k`, banked through their register at `$D100`.
|
|
189
228
|
- **VIC-II** (PAL 6569): the five standard graphics modes and the
|
|
190
229
|
invalid ones, sprites with multicolour, expansion, priority and
|
|
191
230
|
pixel-level collisions, raster interrupts, bad lines, sprite DMA, the
|
|
192
231
|
border, VIC banks and the light pen.
|
|
232
|
+
`Badline::Computer.new(vic_model: :mos8565)` fits the C64C's 8565
|
|
233
|
+
instead, with its grey dots on colour register writes and its own
|
|
234
|
+
timing for mode splits, sprite multicolour splits and the light pen.
|
|
193
235
|
- **CIA 1 and 2**: timers, time-of-day clocks with alarms, the serial
|
|
194
236
|
shift register, interrupts, the keyboard matrix with its ghost keys,
|
|
195
|
-
the control ports and the paddle multiplexer.
|
|
237
|
+
the control ports and the paddle multiplexer. The machine has the
|
|
238
|
+
original 6526s; `Badline::Computer.new(cia_model: :mos6526a)` fits the
|
|
239
|
+
C64C's 6526As instead, whose interrupt register timing differs.
|
|
196
240
|
- **SID**: the 6581 and the 8580, with oscillators, ring modulation and
|
|
197
241
|
sync, the envelope generator including the ADSR delay bug, the filter,
|
|
198
242
|
and the RC network on the board that removes the DC offset from the
|
|
@@ -217,24 +261,30 @@ title shows `[MUTED]` while it's off.
|
|
|
217
261
|
`Media.attach(computer, path, cartridge: { flash_jumper: true })`, with
|
|
218
262
|
`bank_jumper: true` to run from the second 64K of a 128K image. The
|
|
219
263
|
GMod2 EEPROM and the Retro Replay clock port aren't there.
|
|
264
|
+
- **GEO-RAM**: 64K to 4M of RAM seen through the `$DE00` page, with the
|
|
265
|
+
`$DFFE`/`$DFFF` page and block registers. It takes the expansion port,
|
|
266
|
+
so it can't sit alongside a cartridge:
|
|
267
|
+
`computer.attach_cartridge(Badline::Cartridge::GeoRAM.new(size: 512))`.
|
|
268
|
+
Its contents are lost when the emulator quits.
|
|
220
269
|
|
|
221
270
|
Known gaps:
|
|
222
271
|
|
|
223
|
-
-
|
|
224
|
-
|
|
225
|
-
|
|
272
|
+
- `badline-ruby` runs below real time, so its live audio stutters.
|
|
273
|
+
`badline` plays smoothly, and so do PSID tunes under
|
|
274
|
+
`badline-ruby --headless`.
|
|
226
275
|
- No drive emulation, so fast loaders and anything else that runs code
|
|
227
|
-
on the drive won't work (see [Media](#media)).
|
|
228
|
-
|
|
229
|
-
|
|
276
|
+
on the drive won't work (see [Media](#media)). The command channel
|
|
277
|
+
doesn't rename, copy, format or validate disks, and `LOAD"$",8`
|
|
278
|
+
doesn't list a disk's directory yet.
|
|
279
|
+
- No NTSC machine and no REU.
|
|
230
280
|
- The emulator window has no freeze button yet, so a freezer cartridge
|
|
231
281
|
runs its menu but can't freeze a program.
|
|
232
282
|
|
|
233
283
|
## Contributing
|
|
234
284
|
|
|
235
|
-
Bug reports and pull requests are welcome
|
|
236
|
-
|
|
237
|
-
[CONTRIBUTING.md](CONTRIBUTING.md) covers running the tests and the
|
|
285
|
+
Bug reports, feature requests, and pull requests are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) first. Report security vulnerabilities privately as described in [SECURITY.md](SECURITY.md).
|
|
286
|
+
|
|
287
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) also covers running the tests and the
|
|
238
288
|
commit format, and the project has a
|
|
239
289
|
[code of conduct](CODE_OF_CONDUCT.md).
|
|
240
290
|
|
data/SECURITY.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Don't report security vulnerabilities in public issues, pull requests, or discussions.
|
|
6
|
+
|
|
7
|
+
Report them privately through GitHub: open the repository's **Security** tab and choose **Report a vulnerability**, or go directly to https://github.com/elektronaut/badline/security/advisories/new.
|
|
8
|
+
|
|
9
|
+
The principles in [CONTRIBUTING.md](CONTRIBUTING.md) apply here too: describe what you observed, give minimal steps you actually ran, and include raw output. Report what you verified; the maintainers will assess the impact.
|