fix(plugin-kit): regSubKeys could never return a subkey, and adopt biome #107

Merged
enricobuehler merged 2 commits from worktree-kit-regsubkeys into main 2026-08-08 00:23:51 +00:00
Owner

Two commits, split so the fix is reviewable apart from the formatter churn.

1. regSubKeys could never return a subkey (4edb662b)

Found on hardware by the GOG plugin's own parity gate, on a box with exactly one GOG game installed:

HKLM\SOFTWARE\WOW6432Node\GOG.com\Games -> 1 subkey (IRON NEST …)
host's built-in scanner:  1 entry
plugin:                   detect: absent, 0 games
parity FAILED — 1 missing, exit 1

reg.exe always echoes the full hive name, never the abbreviation it was given: query HKLM\SOFTWARE\… and every row comes back HKEY_LOCAL_MACHINE\SOFTWARE\…. regSubKeys built its match prefix from the HKLM\… string it was handed, so nothing ever matched and it returned [] — on every machine, for every key, always. Measured verbatim on .173:

reg.exe:     [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\GOG.com\Games\2013434102]
regSubKeys:  []

Its only consumer is the GOG plugin, so the symptom was "GOG reports no games installed" rather than an error — the same shape as the SQLite reader in 0.3.1: a total failure that every layer degrades into an empty library.

The contract was wrong too, and the hive bug hid it. regSubKeys returned whole key paths, while the GOG plugin uses each result as a bare name (const key = \${GAMES_KEY}\${id}`, and the subkey name *is* the product id that becomes external_id`). Even with the prefix fixed, paths would have composed nonsense keys. It now returns names — what the sole consumer, and its own doc comment, always assumed.

Parsing is split into an exported parseRegSubKeys(stdout, key) for the same reason parseRegQuery is exported: a text format that breaks quietly, and this one had no test coverage at all. Six tests added from the verbatim .173 output — names not paths, multiple subkeys, grandchildren ignored, the queried key is not its own subkey, case-insensitivity, empty/error input. Four of the six fail against the old behaviour.

0.3.1 → 0.3.2.

2. Adopt the biome config its own plugins already use (10a0ef32)

The kit had no biome config and no lint script, while every plugin repo that consumes it has both — so its source drifted with nothing to catch it. First run reported 20 findings across 8 files.

Adds plugin-kit/biome.json mirroring the plugin repos', a check script, and @biomejs/biome pinned to the same ^2.5.2 (without the pin, bunx biome resolved 2.4.6, which rejects the 2.5 rules.preset key). Two deliberate differences: no vcs.useIgnoreFile (those are standalone repos with a .gitignore beside the config; this is a subdirectory, and biome errors without one), and !examples/**/dist rather than !ui/dist.

css.parser.tailwindDirectives is carried over and is load-bearing — without it biome can't parse @theme in src/theme.css and reports three parse errors on perfectly valid Tailwind v4.

Beyond formatting, two real findings, both fixed:

  • Layer (library/define.ts) and Cause (sync-engine.ts) imported and never used;
  • test/spike-httpapi.test.ts read (reg?.body as …).ui.secret one line after expect(reg).toBeDefined(). The optional chain undoes the assertion — had reg been undefined, .ui would throw a TypeError instead of failing the test readably.

Wired into plugin-kit-publish.yml as a Lint & format step ahead of Typecheck, so it can't rot again.

Gates

biome clean (42 files), tsc --noEmit clean, 67/67 tests, build clean — on each commit.

After merge

Tag plugin-kit-v0.3.2 to publish, then GOG needs a lockfile refresh and a 0.1.1 release (the published 0.1.0 cannot see any game), and only then can it be added to index#4.

Two commits, split so the fix is reviewable apart from the formatter churn. ## 1. `regSubKeys` could never return a subkey (`4edb662b`) Found on hardware by the GOG plugin's own parity gate, on a box with exactly one GOG game installed: ``` HKLM\SOFTWARE\WOW6432Node\GOG.com\Games -> 1 subkey (IRON NEST …) host's built-in scanner: 1 entry plugin: detect: absent, 0 games parity FAILED — 1 missing, exit 1 ``` **`reg.exe` always echoes the full hive name**, never the abbreviation it was given: query `HKLM\SOFTWARE\…` and every row comes back `HKEY_LOCAL_MACHINE\SOFTWARE\…`. `regSubKeys` built its match prefix from the `HKLM\…` string it was handed, so nothing ever matched and it returned `[]` — on every machine, for every key, always. Measured verbatim on `.173`: ``` reg.exe: [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\GOG.com\Games\2013434102] regSubKeys: [] ``` Its only consumer is the GOG plugin, so the symptom was "GOG reports no games installed" rather than an error — **the same shape as the SQLite reader in 0.3.1**: a total failure that every layer degrades into an empty library. **The contract was wrong too, and the hive bug hid it.** `regSubKeys` returned whole key *paths*, while the GOG plugin uses each result as a bare *name* (`const key = \`${GAMES_KEY}\\${id}\``, and the subkey name *is* the product id that becomes `external_id`). Even with the prefix fixed, paths would have composed nonsense keys. It now returns names — what the sole consumer, and its own doc comment, always assumed. Parsing is split into an exported `parseRegSubKeys(stdout, key)` for the same reason `parseRegQuery` is exported: a text format that breaks quietly, and this one had **no test coverage at all**. Six tests added from the verbatim `.173` output — names not paths, multiple subkeys, grandchildren ignored, the queried key is not its own subkey, case-insensitivity, empty/error input. **Four of the six fail against the old behaviour.** `0.3.1 → 0.3.2`. ## 2. Adopt the biome config its own plugins already use (`10a0ef32`) The kit had **no biome config and no lint script**, while every plugin repo that consumes it has both — so its source drifted with nothing to catch it. First run reported 20 findings across 8 files. Adds `plugin-kit/biome.json` mirroring the plugin repos', a `check` script, and `@biomejs/biome` pinned to the same `^2.5.2` (without the pin, `bunx biome` resolved 2.4.6, which rejects the 2.5 `rules.preset` key). Two deliberate differences: no `vcs.useIgnoreFile` (those are standalone repos with a `.gitignore` beside the config; this is a subdirectory, and biome errors without one), and `!examples/**/dist` rather than `!ui/dist`. `css.parser.tailwindDirectives` is carried over and is load-bearing — without it biome can't parse `@theme` in `src/theme.css` and reports three parse errors on perfectly valid Tailwind v4. Beyond formatting, **two real findings**, both fixed: - `Layer` (`library/define.ts`) and `Cause` (`sync-engine.ts`) imported and never used; - `test/spike-httpapi.test.ts` read `(reg?.body as …).ui.secret` one line after `expect(reg).toBeDefined()`. The optional chain undoes the assertion — had `reg` been undefined, `.ui` would throw a TypeError instead of failing the test readably. Wired into `plugin-kit-publish.yml` as a `Lint & format` step ahead of Typecheck, so it can't rot again. ## Gates biome clean (42 files), `tsc --noEmit` clean, **67/67 tests**, build clean — on each commit. ## After merge Tag `plugin-kit-v0.3.2` to publish, then GOG needs a lockfile refresh and a **0.1.1** release (the published 0.1.0 cannot see any game), and only then can it be added to [index#4](https://git.unom.io/unom/punktfunk-plugin-index/pulls/4).
enricobuehler added 2 commits 2026-08-08 00:20:12 +00:00
The kit had NO biome config and no lint script, while every plugin repo that
consumes it has both. So its source quietly drifted — unused imports, unsorted
imports, formatting — with nothing to catch any of it. Running biome here for
the first time reported 20 findings across 8 files.

Adds `plugin-kit/biome.json` mirroring the plugin repos' (tab indent, double
quotes, recommended lint preset, organizeImports), a `check` script, and
`@biomejs/biome` pinned to the same `^2.5.2` the plugins pin — without that pin
`bunx biome` resolved 2.4.6, which rejects the 2.5 `rules.preset` key.

Two deliberate differences from the plugin repos' copy:

  * no `vcs.useIgnoreFile` — those are standalone repos with a .gitignore beside
    the config; plugin-kit is a directory inside this one, and biome errors with
    "couldn't find an ignore file". The `files.includes` exclusions cover it.
  * `!examples/**/dist` instead of `!ui/dist` — the kit has examples, not a UI.

`css.parser.tailwindDirectives` is carried over and is load-bearing: without it
biome cannot parse `@theme` in src/theme.css and reports three parse errors on
CSS that is perfectly valid Tailwind v4.

Everything here is formatter/import churn except two real findings, both fixed:

  * `Layer` (library/define.ts) and `Cause` (sync-engine.ts) were imported and
    never used;
  * test/spike-httpapi.test.ts read `(reg?.body as …).ui.secret` one line after
    `expect(reg).toBeDefined()`. The optional chain undoes the assertion: had
    `reg` been undefined the `.ui` access would throw a TypeError instead of
    failing the test readably. Now asserted to the type system too.

Wired into plugin-kit-publish.yml as a `Lint & format` step ahead of Typecheck,
so this cannot rot again.

Gates after: biome clean (42 files), tsc clean, 67/67 tests, build clean.
fix(plugin-kit): regSubKeys could never return a subkey
ci / rust-arm64 (pull_request) Successful in 2m40s
ci / web (pull_request) Successful in 1m13s
ci / bun-nix (pull_request) Successful in 22s
ci / docs-site (pull_request) Successful in 1m20s
ci / rust (pull_request) Successful in 11m48s
nix / flake (pull_request) Successful in 16m39s
4edb662b63
Found on hardware by the GOG plugin's own parity gate, on a box with exactly one
GOG game installed:

    HKLM\SOFTWARE\WOW6432Node\GOG.com\Games -> 1 subkey (IRON NEST ...)
    host's built-in scanner:  1 entry
    plugin:                   detect: absent, 0 games
    parity FAILED - 1 missing, exit 1

`reg.exe` ALWAYS echoes the full hive name in its output rows, never the
abbreviation it was given: query `HKLM\SOFTWARE\...` and every line comes back
`HKEY_LOCAL_MACHINE\SOFTWARE\...`. regSubKeys built its match prefix from the
`HKLM\...` string it was handed, so no line ever matched and it returned `[]` —
on every machine, for every key, always. Measured verbatim on .173:

    reg.exe:     [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\GOG.com\Games\2013434102]
    regSubKeys:  []

Its only consumer is the GOG plugin, so the symptom was "GOG reports no games
installed" rather than an error — the same shape as the SQLite reader in 0.3.1:
a total failure that every layer degrades into an empty library.

The contract was wrong too, and the hive bug hid it. regSubKeys returned whole
key PATHS while the GOG plugin uses each result as a bare NAME
(`const key = \`${GAMES_KEY}\\${id}\``, and the subkey name IS the product id
that becomes `external_id`). Even with the prefix fixed, paths would have
composed nonsense keys. It now returns names, which is what the sole consumer
and its own comment always assumed.

Parsing is split into an exported `parseRegSubKeys(stdout, key)` for the same
reason `parseRegQuery` is exported — this is a text format that breaks quietly,
and it had NO test coverage at all. Six added, using the verbatim .173 output:
names not paths, multiple subkeys, grandchildren ignored, the queried key is not
its own subkey, case-insensitivity, and empty/error input. Four of the six FAIL
against the old behaviour.

0.3.1 -> 0.3.2. Gates: biome clean, tsc clean, 67/67 tests, build clean.
enricobuehler merged commit 4adea10557 into main 2026-08-08 00:23:51 +00:00
enricobuehler deleted branch worktree-kit-regsubkeys 2026-08-08 00:23:58 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#107