promotional bannermobile promotional banner

Ka0s Panel Master

Draws plain backdrop panels behind your UI, so a screen full of separate frames reads as a few deliberate groups
Back to Files

1.2.0-release

File namePanelMaster-1.2.0-release.zip
Uploaded
Sep 26, 2026
Downloads
5
Size
106.2 MB
Flavors
Retail
File ID
8985133
Type
R
Release
Supported game versions
  • 12.1.0

What's new

commit 528ee29750771843400a2befdd130411e9ca9275
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Sep 27 03:22:50 2026 +0530

    Automated tests after the Artwork splits (20260927-032003)

    Verdict green at 8cda106. Lint 0/0 over 68 files (66 -> 68, the two new
    split files); tests 964 passed / 0 skipped / 964, unchanged, name for name;
    perf skip (no tests/perf.lua); complexity 16138 NLOC / 1917 functions,
    avg NLOC 7.4, avg CCN 2.0, max CCN 15, 0 warnings.

    modules/Artwork.lua and tests/test_artwork.lua are out of the 1000-1500
    band, which drops from 3 files to 1; only tests/test_libka0s.lua (1131)
    remains, and its RESULTS.md disposition is refreshed to this run.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 8cda106b5096fa627e36ab68a3735a23206a41e2
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Sep 27 03:18:58 2026 +0530

    Split tests/test_artwork.lua: the single-texture geometry sections move to tests/test_artwork_geometry.lua

    A move along the same catalog / geometry seam as modules/Artwork.lua, with
    no case changed. The Fill (FIT, FILL, STATIC, STRETCH, TILE), Resize,
    Position, UV composition, Color and Degenerate input sections move whole,
    with the panel x art matrix and the uv helpers only they use (PANELS, ARTS,
    forEachCombo, specFor, cropOf, assertUV). The small fixtures both halves
    need (record, the seed row, withRows, withArt) are restated in the new
    suite so each stays loadable on its own. tests/test_artwork.lua keeps the
    Catalog, Upgrade inertness, Persistence, Renderer and Composite sections.
    tests/run.lua lists the new suite straight after test_artwork.

    Line counts: tests/test_artwork.lua 1356 -> 738;
    tests/test_artwork_geometry.lua 0 -> 670.
    Test cases: 964 before, 964 after, and the sorted `lua tests/run.lua --list`
    names are identical; test_artwork 98 -> 46, test_artwork_geometry 52.
    luacheck 0 warnings / 0 errors; lizard -C 15 -w 0 warnings.

    Ripple: docs/test-cases.md regenerated with --list, docs/module-map.md
    (new row, test_artwork row narrowed), docs/ARCHITECTURE.md (census and band
    prose) and the Disposition cell of this file's row in
    docs/automated-tests/RESULTS.md.

    anti-pattern #53: Accepted at three release runs (1.0.0, 1.1.0, 1.2.0).

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit bca7fabdbfda3db9e95b951d9e54eeb64c187b5c
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Sep 27 03:16:25 2026 +0530

    Split modules/Artwork.lua: the geometry moves to modules/ArtworkGeometry.lua

    A move along the catalog / geometry seam, with no behavior change.
    modules/Artwork.lua keeps the generated catalog, CUSTOM_NATIVE_SIZE,
    MAX_ART_QUADS and the lookups (Entry, List and the record resolver).
    BuildArtSpec, NativeSize, the fill matrix, UV composition and composite
    slicing move whole to modules/ArtworkGeometry.lua, which extends the same
    NS.Artwork table. The one local the geometry reached across the seam,
    resolve, is published as Artwork.__resolve, following the double-underscore
    seam convention settings/PanelEditor.lua uses, and read at call time. The
    TOC loads the new file straight after modules/Artwork.lua, ahead of Canvas.
    tools/artwork/update_catalog.py still targets modules/Artwork.lua.

    Line counts: modules/Artwork.lua 1188 -> 693; modules/ArtworkGeometry.lua
    0 -> 518.
    Test cases: 964 before, 964 after (lua tests/run.lua, 0 failed);
    luacheck 0 warnings / 0 errors; lizard -C 15 -w 0 warnings.

    Ripple: docs/module-map.md (new row), docs/ARCHITECTURE.md (census and
    band prose), docs/rendering.md, docs/common-tasks.md, docs/smoke-tests.md,
    the two code comments in modules/Canvas.lua and modules/SunnArt.lua that
    name where the geometry lives, and the Disposition cell of this file's row
    in docs/automated-tests/RESULTS.md.

    anti-pattern #53: Accepted at three release runs (1.0.0, 1.1.0, 1.2.0).

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 3173f1cf179a4eba52d543f69ee01b7ab84a3589
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Sep 27 03:09:02 2026 +0530

    Release 1.2.0: version bump, release notes and the gated release run

    Version 1.1.1 -> 1.2.0 (owner-approved minor).

    Release gate, read from docs/automated-tests/20260927-030403/manifest.json
    (run with --release 1.2.0 on the clean tree at 83e958f):
    - Lint: PASS, 0 warnings / 0 errors in 66 files
    - Tests: PASS, 964 passed, 0 failed, 0 skipped of 964
    - Perf: PASS by the no-scenarios exception; the addon ships no
      tests/perf.lua, so perf was skipped, not measured
    - Complexity: PASS, lizard 1.24.0 ran; 16108 NLOC, 1915 functions,
      avg CCN 2.0
    - CCN <= 15: PASS, 0 warnings, max CCN 15

    Files:
    - PanelMaster.toc: ## Version 1.2.0
    - core/Namespace.lua: NS.version = "1.2.0"
    - core/Database.lua: the [Init] summary example comment reads v1.2.0
    - docs/smoke-tests.md: /pm version, /pm help header and the TOC-vs-constant
      smoke case read 1.2.0
    - README.md: new 1.2.0 row at the top of Version History (bulleted
      highlights, de-AI pass run, plus the perf-skip note); old rows untouched
    - docs/automated-tests/20260927-030403/: the release bundle, with its
      ANALYSIS.md
    - docs/automated-tests/RESULTS.md: the runner's row, plus refreshed
      watch-list dispositions. modules/Artwork.lua and tests/test_artwork.lua
      have now been Accepted across three consecutive release runs and are
      owed a fix or a tracking issue (anti-pattern #53).

    Left alone: the CLAUDE.md LibKa0s provenance (v1.62.0, the vendored tag),
    the auto-derived CurseForge badge, and the 1.1.1 history row.
    docs/test-cases.md did not change. Post-edit harness re-run: 964/964 pass,
    lint 0/0.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 83e958f1f7ba649a8a255b96f4455a4225727770
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Sep 27 03:03:50 2026 +0530

    README: Usage as the four-step panel setup, and sync-docs

    - README Usage is restructured as the four steps of setting up a panel.
    - "How panels work" now opens on frame strata and corrects the claim about
      mouse handling.
    - sync-docs: refreshed file:line citations in DEPENDENCIES.md,
      docs/compat-layer.md, docs/media.md, docs/performance.md and docs/testing.md.
    - core/Database.lua: the frame-name backfill citation now points at
      modules/Registry.lua:205-207 (was :204-206); comment-only.

    Green gate: lua tests/run.lua 964 passed / 0 failed; luacheck 0 warnings / 0 errors.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit d11eb877f9c02796d3efd6d2f3e9ae7164e99e8a
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Sep 27 02:28:34 2026 +0530

    README: credit the third-party font and icons the addon ships

    Credits now names the debug console's JetBrains Mono (SIL OFL 1.1), beside the artwork credit. Both ship inside the vendored LibKa0s payload with their license text,
    and documentation-§1 item 12 keeps Credits for exactly this kind of external asset (a font, an icon
    set), never a library list.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 3feaf3d437d9cc4ffcb7993641d0bc23fd1927e7
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Sep 27 00:15:50 2026 +0530

    README: plain-language pass for readers

    Rewrote the prose for the person reading it: long run-on paragraphs split by topic, em dashes
    and reflexive bold removed, passive and subjectless sentences given someone doing the action,
    and sentence length varied. Every fact, command, setting name, link, badge, heading and the
    section order are unchanged, as is every section a test or the tooling cites verbatim.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 61c3b954940c9edcfcda4d008f54a586a071ed00
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 23:03:29 2026 +0530

    PM-ATS-SDR: Correct stale comment citations (owner-approved sync-docs follow-up)

    Comment-only citation fixes after the PM-ATS-02 peel of the editor's tabs
    into settings/PanelEditorTabs.lua:

    - core/Constants.lua:23 - the `label` reader is settings/PanelEditorTabs.lua
      (opt.label at :182), not settings/PanelEditor.lua.
    - core/CoreSetup.lua:8,20-22 - printer-upvalue list gains
      settings/PanelEditorTabs.lua (:5 `local print = NS.Print`); five -> six.
    - tests/test_schema.lua:315 - EDITOR_TABS is defined in
      settings/PanelEditorTabs.lua:73.
    - tests/wow_mock.lua:386 - buildPanelEditor is defined in
      settings/PanelEditorTabs.lua:113.
    - tests/test_options_groups.lua:3 - the suite scans
      settings/PanelEditorTabs.lua (EDITOR at :39), where the blocks are drawn.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 61c3b954940c9edcfcda4d008f54a586a071ed00
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 23:03:29 2026 +0530

    PM-ATS-SDR: Correct stale comment citations (owner-approved sync-docs follow-up)

    Comment-only citation fixes after the PM-ATS-02 peel of the editor's tabs
    into settings/PanelEditorTabs.lua:

    - core/Constants.lua:23 - the `label` reader is settings/PanelEditorTabs.lua
      (opt.label at :182), not settings/PanelEditor.lua.
    - core/CoreSetup.lua:8,20-22 - printer-upvalue list gains
      settings/PanelEditorTabs.lua (:5 `local print = NS.Print`); five -> six.
    - tests/test_schema.lua:315 - EDITOR_TABS is defined in
      settings/PanelEditorTabs.lua:73.
    - tests/wow_mock.lua:386 - buildPanelEditor is defined in
      settings/PanelEditorTabs.lua:113.
    - tests/test_options_groups.lua:3 - the suite scans
      settings/PanelEditorTabs.lua (EDITOR at :39), where the blocks are drawn.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 76d4bd9db43e82e83bc908e9485ac79dafbd6f9d
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 19:45:58 2026 +0530

    PM-ATS-SD: Sync docs to the tree after the automated-tests sweep

    - docs/testing.md: the linter's scoped file count is 66, not 61 (two places;
      the PM-ATS-01/02 peels added tests/test_panels_page.lua and
      settings/PanelEditorTabs.lua).
    - docs/module-map.md: six files take NS.Print as a file-scope upvalue, not
      five; settings/PanelEditorTabs.lua:5 is the new one.
    - docs/ARCHITECTURE.md: the events-frames-taint-§8 deviation row names
      settings/PanelEditorTabs.lua among the files with pre-formatted print
      lines (PanelEditorTabs.lua:632).
    - docs/common-tasks.md: the Panels page draws its strip in
      settings/PanelEditor.lua and dispatches on ctx.activeTab in
      settings/PanelEditorTabs.lua (:785).

    docs/test-cases.md regenerates byte-identical (964 cases). README.md,
    CLAUDE.md and DEPENDENCIES.md unchanged. Five stale source/test comment
    citations are reported for owner confirmation, not edited.

    Gate: lua tests/run.lua 964 passed / 0 failed; lint 0 warnings / 0 errors
    in 66 files.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 7c46ae66075044b95964a644489115fc215d587e
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 19:33:11 2026 +0530

    PM-ATS-99: Final automated-tests sweep run (20260926-193106)

    The closing four-suite run of the 2026-09-26 automated-tests sweep, at
    5119ae1 on a clean tree. Verdict green.

    - lint: 0 warnings / 0 errors in 66 files (64 at 20260926-160448; the two
      peel targets are new files)
    - tests: 964 passed, 0 skipped, 0 failed of 964 (unchanged; PM-ATS-01
      moved cases between suites)
    - perf: skip, no tests/perf.lua (unchanged)
    - complexity: 16108 NLOC / 1915 functions (+50 / +1), avg NLOC 7.4, avg
      CCN 2.0, max CCN 15, avg tokens 58.0, 0 warnings (all unchanged)

    Compared with 20260926-160448, the 1000-1500 band went from 5 files to 3.
    tests/test_panel.lua (1491) and settings/PanelEditor.lua (1464) left it
    through PM-ATS-01 and PM-ATS-02 and are now 721 and 746 lines. Nothing
    crossed into the band and nothing is over the cap. The three dispositions
    carried forward keep their rulings, updated to today's figures (ATS-23).
    ANALYSIS.md is written in CRLF, as .gitattributes requires.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 5119ae11afc150de1fab9ad58135b97e108c5e8c
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 19:02:20 2026 +0530

    PM-ATS-02: Peel the editor's six tabs out of settings/PanelEditor.lua into settings/PanelEditorTabs.lua

    ATS-10 (automated-tests sweep 2026-09-26): settings/PanelEditor.lua stood at
    1464 lines, 36 under the layout-§1 cap, with its split already tracked as #47.

    The cut is the page / tab-content seam #47 verified. What each tab holds
    moved whole, unchanged, into settings/PanelEditorTabs.lua (798): the TAB_*
    names, EDITOR_TABS / E.TABS / IS_EDITOR_TAB, the editor's vertical-rhythm
    constants and buildPanelEditor. settings/PanelEditor.lua (1464 -> 746) keeps
    the page: the selection, the mutation actions, the control kit the tabs draw
    with, the strip, the chrome band, the rebuilder and the bus.

    No behavior change. The two halves share through NS.PanelEditor, bound on first
    use the way both already bind settings/Panel.lua's NS.Panel.__ui helpers, so
    the files may load in either order: the page publishes its kit as
    E.__controls (editorRow, editorSpacer, editorHeading, addRefresher and the
    media, color-pair and edge makers) and the tabs file reaches the page's
    existing E.__pageActions / E.__panelsByName; the tabs file publishes
    E.__editorTabs (EDITOR_TABS, IS_EDITOR_TAB, buildPanelEditor) back.
    buildPanelEditor binds at its first statement. makePairButton and
    BUTTON_PAIR_REL move to the tabs file's binder, the only file that uses them.

    The TOC gains settings\PanelEditorTabs.lua after PanelEditor.lua, before
    Panel.lua, with its load-order comment. The four source-scanning cases follow
    the code: the numberField bounds scan and the options-ui-§16 block gate read
    the tabs file, and the NS.Debug-gate and disabledIf scans cover both files.

    Tests: 964 cases before and after, same names in the same order. Docs:
    module-map row for the new file, ARCHITECTURE.md census, settings-panel.md,
    smoke-tests.md, compat-layer.md line references, and the RESULTS.md watch-list
    disposition.

    Fixes #47

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 9bfd6a83ac20d40040a6387d609663d4a2e13e5b
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 18:52:25 2026 +0530

    PM-ATS-01: Peel the built Panels page's cases out of tests/test_panel.lua into tests/test_panels_page.lua

    ATS-05: tests/test_panel.lua had grown to 1491 lines, past its re-check-at-1400
    trigger and 9 lines under the layout-§1 cap. It splits on its own seam, the
    "Panels page's tab strip" block: those 18 cases drive the real E:BuildPage /
    E:Rebuild against the AceGUI mock through their own helpers (freshPanelsCtx,
    labelsBuiltBy, descendants, captionsBuiltBy, actsOnGeneral) and reach none of
    the head's locals (fakeCtx, pctx, watch, freshPanels, R/Canvas/PC).

    - tests/test_panel.lua 1491 -> 721 (65 -> 47 cases): registration, opening,
      Defaults, the repaint policy, panel scale.
    - tests/test_panels_page.lua new, 780 (18 cases): tab strip, chrome band,
      editor tabs, swatches. Moved verbatim; only the two comments that said
      "above" now name tests/test_panel.lua.
    - tests/run.lua lists it straight after test_panel, so the PASS lines run in
      the identical order (diffed): 964 total before and after.
    - docs/test-cases.md regenerated; module-map, testing.md (swatch case), the
      ARCHITECTURE.md band census and largest-file line, and the RESULTS.md
      watch-list disposition updated.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 8b7a45493350db00fa7d6915a7a7d385d89c0c1b
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 18:45:45 2026 +0530

    PM-ATS-RVR: Restore CRLF working copies of four v1.62.0 revendor bundle files

    docs/revendor/2026-09-26-v1.62.0/01_DELTA.md, 02_CANDIDATES.md,
    03_DECISIONS.md and 05_SUMMARY.md sat on disk as bare LF while
    .gitattributes pins them to eol=crlf, which failed the eol test
    (963 passed / 1 failed). Each was removed and re-checked out from the
    index; CR count now equals LF count in all four (65/65, 6/6, 5/5,
    15/15). The index copies were already LF, so the committed content is
    unchanged and this commit is empty; it records the fix.

    Green gate (bounded): lua tests/run.lua 964 passed / 0 failed / 964
    total; 0 warnings / 0 errors in 64 files from the linter; no function
    above CCN 15 from the complexity check.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 84b25be0867541c0d31ad6cdd55d63e59e13365a
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 18:42:34 2026 +0530

    PM-ATS-RV: Re-vendor LibKa0s v1.62.0 and kit revision 31

    Both payloads come from the local v1.62.0 tag (e660362), whole folders. libs/LibKa0s: Options 25 -> 26, OptionsWidgets 31 -> 32, OptionsTabs 5 -> 6, and the four peeled files OptionsRegistry, OptionsIds, OptionsIdList and OptionsCombat at minor 1 (Options key 26.1.32.1.1.6.1.7.4.1). tests/_kit: kit revision 27 -> 31, with the new inventory.lua, prose_coverage.lua and prose_selftests.lua. The kit carries the runner fixes for ATS-20 (None. under an empty watch-list table in RESULTS.md) and ATS-21 (generated files left out of the band table). The CLAUDE.md provenance line rolls with the bytes.

    No member, descriptor field or row field changed upstream, so the library-absent stub and the surface-parity case need nothing, and no hand-typed library list here names the moved files. docs/test-cases.md regenerated with --list is byte-identical (964 cases). Bundle docs/revendor/2026-09-26-v1.62.0/ records the delta; no adoption in this item.

    Gate: 964 passed / 0 failed (964 before), luacheck 0/0 in 64 files, lizard no function above CCN 15, vendor gate clean against the tag and ../LibKa0s.

    ATS-20, ATS-21

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 12b1c61cfd3a76eac0a14ea997e753949de6dcfd
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 16:19:30 2026 +0530

    PM-ATS-00: Record the 2026-09-26 automated-tests sweep run (20260926-160448)

    The collection-wide sweep's bundle and RESULTS.md, as the sweep left them. The fix queue it
    produced is Ka0sAddonsCommonTasks docs/2026-09-26-AUTOMATED_TESTS_SWEEP.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 73d9b8b8670f0cc754ca91e7b126e444662a2eb8
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 15:33:02 2026 +0530

    Docs: record the owner's in-client results for the settings layout

    The owner ran this build's checks in the client on 2026-09-26 and reported
    every one passing, then gave the go-ahead to merge.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 73d9b8b8670f0cc754ca91e7b126e444662a2eb8
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 15:33:02 2026 +0530

    Docs: record the owner's in-client results for the settings layout

    The owner ran this build's checks in the client on 2026-09-26 and reported
    every one passing, then gave the go-ahead to merge.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 3a7ac1974d7563782733326d56160187f9190d03
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 15:15:09 2026 +0530

    pm-band-fix-01: Show the Panels band's block and lay its row out at the band's width

    THE PANEL PICKER AND THE CREATE NEW PANEL BOX COULD VANISH, leaving the band's
    height and divider above the tab strip with nothing in them. drawPageHeader
    builds the band's block with AceGUI:Create("SimpleGroup"), parents it by hand to
    the header frame and anchors it, but never showed it. Real AceGUI pools widgets:
    Release hides the frame and a later Create hands it back hidden, and only a
    parent container's layout shows a child. The block is no container's child, so
    once any addon had released a SimpleGroup earlier in the session, the band came
    back hidden. First bad commit 081ee2c, which created the band; 1b8c672 fixed a
    zero-width layout race that was never the mechanism, because the List layout
    reads content.width, which a SimpleGroup starts at 300.

    That 300 is the second defect. Anchoring the block to both sides of the header
    stretches the frame and leaves content.width alone, so every DoLayout, the
    OnSizeChanged re-layout included, laid the row out at 300 pixels and each
    half-width control at 150. The hook now calls block:SetWidth(width) before
    DoLayout, and the build does the same when the header already has a width.

    Two cases in tests/test_panel.lua: the band is handed a hidden SimpleGroup, as
    the pool hands it one, and its block, picker and create box must be shown; and a
    size change must reach the layout as the block's width. Both red before the fix.
    The comments in settings/PanelEditor.lua and the older test that described the
    zero-width mechanism are corrected. docs/settings-panel.md explains both
    defects, docs/smoke-tests.md 5-w checks the half-band widths and the new 5-x
    opens another addon's settings first, docs/test-cases.md is regenerated, and
    the README badge reads 964.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 3a7ac1974d7563782733326d56160187f9190d03
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 15:15:09 2026 +0530

    pm-band-fix-01: Show the Panels band's block and lay its row out at the band's width

    THE PANEL PICKER AND THE CREATE NEW PANEL BOX COULD VANISH, leaving the band's
    height and divider above the tab strip with nothing in them. drawPageHeader
    builds the band's block with AceGUI:Create("SimpleGroup"), parents it by hand to
    the header frame and anchors it, but never showed it. Real AceGUI pools widgets:
    Release hides the frame and a later Create hands it back hidden, and only a
    parent container's layout shows a child. The block is no container's child, so
    once any addon had released a SimpleGroup earlier in the session, the band came
    back hidden. First bad commit 081ee2c, which created the band; 1b8c672 fixed a
    zero-width layout race that was never the mechanism, because the List layout
    reads content.width, which a SimpleGroup starts at 300.

    That 300 is the second defect. Anchoring the block to both sides of the header
    stretches the frame and leaves content.width alone, so every DoLayout, the
    OnSizeChanged re-layout included, laid the row out at 300 pixels and each
    half-width control at 150. The hook now calls block:SetWidth(width) before
    DoLayout, and the build does the same when the header already has a width.

    Two cases in tests/test_panel.lua: the band is handed a hidden SimpleGroup, as
    the pool hands it one, and its block, picker and create box must be shown; and a
    size change must reach the layout as the block's width. Both red before the fix.
    The comments in settings/PanelEditor.lua and the older test that described the
    zero-width mechanism are corrected. docs/settings-panel.md explains both
    defects, docs/smoke-tests.md 5-w checks the half-band widths and the new 5-x
    opens another addon's settings first, docs/test-cases.md is regenerated, and
    the README badge reads 964.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 9357c0743ea95705c6332bb1130d6edf276ce3fc
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 14:44:11 2026 +0530

    NR-PM-01: Re-vendor LibKa0s v1.61.0 and stub NavRail

    LibKa0s payload from the v1.61.0 tag: Options 24 -> 25, OptionsTabs 4 -> 5, the new OptionsNav minor 1 (Options key 25.31.5.7.4.1). tests/_kit is unchanged at kit revision 27. CLAUDE.md provenance rolls with it. The stub's table literal gains a NavRail no-op for the Options surface-parity case. The vendor diff gate is clean against ../LibKa0s.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 90c93353a111f53ae71fad50efff4719383a956d
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 09:15:26 2026 +0530

    DR-PM-07: Standards refresh to v2.68.0, docs synced, AUD-01 self-check passes

    revendor-standards against WowAddonStandards v2.68.0 (2026-09-26, master
    2854053, identical to origin/master): nothing to change.
    - The three-place reference is intact: PanelMaster.toc:12 X-Standard, the
      bare README badge (no link wrapper, no %20), and CLAUDE.md's Standards
      compliance section with the stop-and-flag directive and the two-way
      classification. None carries a version stamp.
    - Notation sweep: grep -rEn '§[0-9]+\.[0-9]' . --exclude-dir=.git
      --exclude-dir=libs --exclude-dir=_kit --exclude-dir=audits
      --exclude-dir=reviews --exclude-dir=automated-tests -> 4 hits, all in
      the frozen docs/revendor/2026-09-23-v1.55.0/ bundle, where they quote
      the library's compat.md. Left as evidence.
    - Every filename-§N reference range-checked against the section files'
      own ### N. headings: none out of range, malformed or naming an unknown
      file.
    - No retired doc-set counts or labels outside frozen bundles. The standard
      has no quirks-catalogue section, so there is no vendored block.
      testing.md and automated-tests/README.md already name both checkpoints
      (the RESULTS.md lead-in is runner-generated and not swept).
      .gitattributes pins CRLF with the *.sh carve-out and binary markings;
      0 worktree stragglers by the line-endings-§7 check.

    sync-docs: one AUD-01 gap and one drift, both closed here.
    - AUD-01 step 3 reads "tests/test_disabled.lua dispatches both forms".
      Here Disabled 7 dispatched `/pm diagnostics` only, and the debug form
      was covered by the kit's shared contract case alone. test_disabled.lua
      gains "Disabled 7c: both diagnostics forms reach RunDiagnostics, each
      once, with no refusal". It is a characterization case, since the route
      already worked. Falsified twice, each time restoring the file: the
      COMMANDS row's RunDiagnostics call removed (7c red, plus five others),
      and the debug handler's DebugVerb call bypassed (7c red).
      docs/testing.md describes 7c under the test_disabled.lua section.
    - docs/ARCHITECTURE.md's localization-§1 deviation row said the one
      NS.L string is printed by Sl:LibraryAbsentLine; the degraded DebugLog
      stub's RunDiagnostics (core/DebugLogSetup.lua) prints it too now.
    - docs/test-cases.md regenerated (961 -> 962); README badge 962/962. The
      README change is the badge number only, so the de-AI pass had no prose
      to review.
    - Checked and unchanged: 20 verbs in NS.COMMANDS and the thirteen
      reserved verbs (ARCHITECTURE, slash-dispatch.md), the Documentation map
      both ways, module-map against the TOC load list and every suite, the
      v1.60.0 provenance line, DEPENDENCIES.md, the path citations the
      rollout's comments added.

    AUD-01 (AUDIT.md diagnostics check), run by hand on this commit:
    1. grep '"diagnostics"' settings/*.lua core/*.lua: one COMMANDS row
       (Slash.lua:405); the other hits are the degraded fallback live list
       (Slash.lua:455) and the stub's DebugVerb (DebugLogSetup.lua:87). The
       debug handler (Slash.lua:400) hands the word to DebugVerb, which tests
       `diagnostics` before on/off. PASS
    2. grep -rniE '"(diag|dump|dx)"' settings core modules: one hit,
       modules/Diagnostics.lua:25 `local TAG = "Diag"`, the report's line tag,
       not a verb, debug word or alias. PASS
    3. No liveVerbs passed (Slash.lua:441), so the live set is Slash 16's
       LIVE_VERBS; the degraded fallback list carries diagnostics;
       test_disabled.lua now dispatches both forms while disabled. PASS
    4. Both forms call NS.DebugLog:RunDiagnostics (Slash.lua:406 directly,
       Slash.lua:400 through DebugVerb); no :Clear in modules/Diagnostics.lua.
       PASS
    5. The stub's RunDiagnostics prints the library-absent line
       (core/DebugLogSetup.lua:74-77). PASS
    6. README ## Reporting a bug sits between Troubleshooting and Issues and
       feature requests and matches documentation-§1 item 9 verbatim for /pm.
       PASS
    Result: AUD-01 passes (vendor v1.60.0, so no #47/#90).

    Gate: lua tests/run.lua 962 passed, 0 failed; luacheck 0 warnings / 0
    errors in 64 files; lizard -C 15 -w clean (libs and tests/_kit
    excluded); largest Lua file 1447 lines. Every edited file keeps CRLF.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 90c93353a111f53ae71fad50efff4719383a956d
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 09:15:26 2026 +0530

    DR-PM-07: Standards refresh to v2.68.0, docs synced, AUD-01 self-check passes

    revendor-standards against WowAddonStandards v2.68.0 (2026-09-26, master
    2854053, identical to origin/master): nothing to change.
    - The three-place reference is intact: PanelMaster.toc:12 X-Standard, the
      bare README badge (no link wrapper, no %20), and CLAUDE.md's Standards
      compliance section with the stop-and-flag directive and the two-way
      classification. None carries a version stamp.
    - Notation sweep: grep -rEn '§[0-9]+\.[0-9]' . --exclude-dir=.git
      --exclude-dir=libs --exclude-dir=_kit --exclude-dir=audits
      --exclude-dir=reviews --exclude-dir=automated-tests -> 4 hits, all in
      the frozen docs/revendor/2026-09-23-v1.55.0/ bundle, where they quote
      the library's compat.md. Left as evidence.
    - Every filename-§N reference range-checked against the section files'
      own ### N. headings: none out of range, malformed or naming an unknown
      file.
    - No retired doc-set counts or labels outside frozen bundles. The standard
      has no quirks-catalogue section, so there is no vendored block.
      testing.md and automated-tests/README.md already name both checkpoints
      (the RESULTS.md lead-in is runner-generated and not swept).
      .gitattributes pins CRLF with the *.sh carve-out and binary markings;
      0 worktree stragglers by the line-endings-§7 check.

    sync-docs: one AUD-01 gap and one drift, both closed here.
    - AUD-01 step 3 reads "tests/test_disabled.lua dispatches both forms".
      Here Disabled 7 dispatched `/pm diagnostics` only, and the debug form
      was covered by the kit's shared contract case alone. test_disabled.lua
      gains "Disabled 7c: both diagnostics forms reach RunDiagnostics, each
      once, with no refusal". It is a characterization case, since the route
      already worked. Falsified twice, each time restoring the file: the
      COMMANDS row's RunDiagnostics call removed (7c red, plus five others),
      and the debug handler's DebugVerb call bypassed (7c red).
      docs/testing.md describes 7c under the test_disabled.lua section.
    - docs/ARCHITECTURE.md's localization-§1 deviation row said the one
      NS.L string is printed by Sl:LibraryAbsentLine; the degraded DebugLog
      stub's RunDiagnostics (core/DebugLogSetup.lua) prints it too now.
    - docs/test-cases.md regenerated (961 -> 962); README badge 962/962. The
      README change is the badge number only, so the de-AI pass had no prose
      to review.
    - Checked and unchanged: 20 verbs in NS.COMMANDS and the thirteen
      reserved verbs (ARCHITECTURE, slash-dispatch.md), the Documentation map
      both ways, module-map against the TOC load list and every suite, the
      v1.60.0 provenance line, DEPENDENCIES.md, the path citations the
      rollout's comments added.

    AUD-01 (AUDIT.md diagnostics check), run by hand on this commit:
    1. grep '"diagnostics"' settings/*.lua core/*.lua: one COMMANDS row
       (Slash.lua:405); the other hits are the degraded fallback live list
       (Slash.lua:455) and the stub's DebugVerb (DebugLogSetup.lua:87). The
       debug handler (Slash.lua:400) hands the word to DebugVerb, which tests
       `diagnostics` before on/off. PASS
    2. grep -rniE '"(diag|dump|dx)"' settings core modules: one hit,
       modules/Diagnostics.lua:25 `local TAG = "Diag"`, the report's line tag,
       not a verb, debug word or alias. PASS
    3. No liveVerbs passed (Slash.lua:441), so the live set is Slash 16's
       LIVE_VERBS; the degraded fallback list carries diagnostics;
       test_disabled.lua now dispatches both forms while disabled. PASS
    4. Both forms call NS.DebugLog:RunDiagnostics (Slash.lua:406 directly,
       Slash.lua:400 through DebugVerb); no :Clear in modules/Diagnostics.lua.
       PASS
    5. The stub's RunDiagnostics prints the library-absent line
       (core/DebugLogSetup.lua:74-77). PASS
    6. README ## Reporting a bug sits between Troubleshooting and Issues and
       feature requests and matches documentation-§1 item 9 verbatim for /pm.
       PASS
    Result: AUD-01 passes (vendor v1.60.0, so no #47/#90).

    Gate: lua tests/run.lua 962 passed, 0 failed; luacheck 0 warnings / 0
    errors in 64 files; lizard -C 15 -w clean (libs and tests/_kit
    excluded); largest Lua file 1447 lines. Every edited file keeps CRLF.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit f9d00dfcd6c0203aeb300a81932297f9f7ca10d3
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 09:05:25 2026 +0530

    DR-PM-05: Document /pm diagnostics in debug.md, smoke tests and the doc set

    debug-logging-14 "Documented" (standard v2.68.0, STD-20): docs/debug.md
    now documents the report that replaced /pm debug dump.

    - debug.md: a `/pm diagnostics` section with both forms (and no alias;
      `debug dump` and `debug diag` toggle the console), append and ungated
      semantics, the one chat line, the shape (library frame, then the ten
      sections of modules/Diagnostics.lua in order, all tagged [Diag]), the
      per-panel lines, how to read it for a rendering bug, the stood-down
      behavior, the caps (min(1200, 3000 - 100) = 1200 lines, 40 ids per
      list, 200-char wrap), what it never does (no setter, Recover,
      FitToArtwork, SetPoint, Show or queue replay; secret-safe; pcall per
      section and per panel), the library-absent line, and nothing redacted
      (owner ruling Q11). The rejected-events paragraph now describes the
      `events` section. The buffer is named as lib.MAX_BUFFER, 3000.
    - smoke-tests.md: the :685/:718/:881 counter lines read 3000 (DR-OW-02);
      section 11 step 9 runs the report instead of the dump, and new steps
      12-17 cover S2/S4 (trace kept, Copy clean), S5 (ungated, flag
      untouched), S1 (disabled, both forms), S3 (combat, queue not flushed),
      S8 (no alias) and S7 (the cap). The 11b and 12b-2 dump steps read the
      report's frames line; section 14 step 10 expects the library-absent
      line from both forms.
    - common-tasks.md: "Debug a rendering problem" points at the report's
      panels and frames lines; new "Add a section to the diagnostics report".
    - ARCHITECTURE.md :189: the rejected list is the report's events section.
    - module-map.md: State and DebugLogSetup rows no longer name the dump or
      D:Diagnose; Unlock row names PendingSnapshot; new rows for
      modules/Diagnostics.lua and tests/test_diagnostics.lua.
    - core/DebugLogSetup.lua:9: the comment no longer states the line cap.

    Documentation and one comment only; tests unchanged (test-cases.md and
    the badge stand at 961). Every edited file keeps CRLF.

    Gate (ka0s-bounded): lua tests/run.lua 961 passed, 0 failed, 0 skipped,
    961 total; luacheck 0 warnings / 0 errors in 64 files; lizard -C 15 -w
    clean (libs and tests/_kit excluded); largest Lua file 1447 lines.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 53fc258aef8cb10c29312c37b1c6280f0728cab7
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 08:59:54 2026 +0530

    DR-PM-04: README gains ## Reporting a bug; Troubleshooting and Issues point at it

    documentation-§1 item 9 (standard v2.68.0, STD-17): a `## Reporting a bug`
    section between `## Troubleshooting` and `## Issues and feature requests`,
    the standard's text verbatim with `/pm` as the slash. Step 3 reads "include
    it with your bug report"; the section names no destination and carries no
    GitHub link (owner ruling DR-OW-01).

    STD-18: the Troubleshooting row "Something is genuinely broken", which told
    players to copy the debug log and attach it to an issue, now reads
    "Something looks wrong and I want to report it -> Follow Reporting a bug
    below." The Issues paragraph's "A debug log (see above) helps" line now
    points at the section too.

    The Usage paragraph on the disabled state lists `diagnostics` among the
    verbs that still answer while the addon is off, which DR-PM-01 made true.

    Verification (plan section 4): the section diffs clean against STD-17 apart
    from the slash; no GitHub link in it. De-AI pass run on the new text; one
    wording change to the Issues pointer. README keeps CRLF (303 CR / 303 LF).
    Documentation only; tests unchanged.

    Gate: lua tests/run.lua 961 passed, 0 failed; luacheck 0 warnings / 0
    errors in 64 files; lizard -C 15 -w clean (libs and tests/_kit excluded);
    largest Lua file 1447 lines.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit c3af1945eb9fd58713aa9319d03e51308fec1d16
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 08:57:48 2026 +0530

    DR-PM-03R: Retire the last comments that still name the debug dump

    The independent review of DR-PM-03 (497cad1) found the report, the
    dispatcher and the tests sound, and found five comments that still named
    the retired dump:

    - modules/Registry.lua (two, in destroy and DeleteAll) and
      tests/test_registry.lua: a stale unlocked id would show up "in a debug
      dump". It now shows up in the `/pm diagnostics` report's "unlocked
      panels" list, so the comments name the report.
    - modules/Canvas.lua releaseArt and tests/test_canvas.lua: "a debug dump"
      was listed among the things that show a pooled frame. Neither the old
      dump nor the read-only report shows a panel frame, so it is dropped.
    - tests/test_canvas.lua: "the kind of thing a `/pm debug dump` is read to
      rule out" now names `/pm diagnostics`.

    Comment-only; CRLF kept in all four files.

    Gate (ka0s-bounded): lua tests/run.lua 961 passed, 0 failed, 0 skipped,
    961 total; luacheck 0 warnings / 0 errors in 64 files; lizard -C 15 -w
    clean; no file over 1500 lines.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 497cad19d6d26033ec07c4116f89c2397ab99977
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 08:53:46 2026 +0530

    DR-PM-03: Diagnostics report on the LibKa0s helper; retire /pm debug dump

    /pm diagnostics and /pm debug diagnostics now write the debug-logging-14
    report (DX-PM) into the debug console, through LibKa0s DebugLog 14.1. The
    library writes the markers, the identity header, the per-section pcall,
    the cap and the ungated append; this addon supplies sections only.

    - modules/Diagnostics.lua (new, in the TOC after Unlock.lua): ten sections
      in order: state (schema stamp, profile, stored switch against the
      latch, lifecycle holds, test mode), master (switches, global unlock,
      individually unlocked ids), unlock queue (through
      Unlock:PendingSnapshot, never flushed), settings (the Schema walk via
      out:nonDefaults with settings.enabled always printed, plus
      state.locked), screen, panels (per panel under its own out:section:
      id, name, enabled, frame name, fields differing from PANEL_TEMPLATE,
      renderer vs record size, live alpha vs target and mouseover floor, live
      vs record anchor with recover's off-screen test, media resolution and
      fallback per field, artwork resolution with custom paths verbatim;
      "renderer: stood down" while stood down), frames (active, pooled,
      orphaned), mouseover ticker, artwork catalog and Sunn packs, rejected
      events. Read-only: no setter, no Recover, FitToArtwork, SetPoint or
      Show, no queue replay; frame numbers are compared only when
      out:readable says so.
    - modules/Registry.lua: recover's clamp is lifted into the pure
      R.RecoveredOffsets, and R.IsOffScreen asks the same question without
      moving anything. R:Recover calls it; behavior unchanged.
    - core/DebugLogSetup.lua: the descriptor passes brandName (NS.BRAND) and
      diagnostics; D:Diagnose and its writers are removed from both arms.
    - settings/Slash.lua: `debug` routes through DebugVerb (diagnostics
      first, any case; on/off; anything else toggles the window), and a new
      `diagnostics` row (20 verbs). `dump` is an ordinary unknown word now.

    Tests (STD-19): tests/run.lua sets Kit.diagnostics, so the kit's
    test_diagnostics_contract runs against the real dispatcher (both forms,
    both while disabled, append, ungated, markers, retired `dump`); new
    tests/test_diagnostics.lua holds 22 domain cases (sections and order,
    stood-down run, queue left intact, off-screen flag without moving,
    media and artwork resolution, a raising section and a raising panel
    each costing one line, the over-cap truncated line, a secret mock, a
    read-only watch over every writer, `debug dump` toggling the window).
    The retired Diagnose cases in test_debuglog, test_disabled,
    test_libka0s and test_slash are rewritten onto the report.

    Docs: ARCHITECTURE.md verb counts (19 -> 20, diagnostics no longer a
    reservation) and the debug.md trigger row; slash-dispatch.md verb lists;
    code comments that named /pm debug dump. debug.md, common-tasks,
    module-map and smoke-tests are DR-PM-05. test-cases.md regenerated
    (961 cases), README badge 961/961.

    Verification: grep -rniE '"(diag|dump|dx)"' settings core modules
    matches only modules/Diagnostics.lua's line tag `"Diag"`, which is not a
    verb or word; no report alias exists.

    Gate (ka0s-bounded): lua tests/run.lua 961 passed, 0 failed, 0 skipped,
    961 total; luacheck 0 warnings / 0 errors in 64 files; lizard -C 15 -w
    clean; no file over 1500 lines.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 7d381ac244617063a715ad15ba5308de2bf47def
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 04:12:27 2026 +0530

    DR-PM-02: Add a read-only snapshot of the combat unlock queue

    The diagnostics report (DX-PM, DR-PM-03) prints the combat unlock
    queue, but pendingUnlock and pendingPanels are file-locals in
    modules/Unlock.lua and the only way in was the __hasPending test seam.

    Unlock:PendingSnapshot() returns a fresh table every call: `unlock` is
    the global request and `panels` the queued per-panel ids in ascending
    order. It is a copy, so no reader can flush or edit the queue, and
    reading it never replays anything.

    New case in test_unlock.lua: the snapshot reports the queue, is sorted,
    does not alias the live state, and reading it neither flushes the queue
    nor applies the unlock. docs/test-cases.md regenerated (936 cases) and
    the README badge moves to 935/935.

    Gate: lua tests/run.lua 935 passed, 0 failed, 1 skipped (the
    diagnostics contract, wired in DR-PM-03); luacheck 0/0; lizard -C 15
    clean.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 8a7af84241be69c31152abb6da5594785b11069f
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 03:56:22 2026 +0530

    Docs: Count diagnostics among the thirteen reserved live verbs

    LibKa0s v1.60.0 (Slash minor 16) added `diagnostics` to lib.LIVE_VERBS,
    so the standard's reserved set is thirteen verbs, not twelve. ARCHITECTURE.md
    and slash-dispatch.md still named twelve at Slash minor 13. ARCHITECTURE.md
    now lists `diagnostics` beside `perf` as a reservation this addon does not
    register, so the eleven shipped reserved verbs are unchanged.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 8a7af84241be69c31152abb6da5594785b11069f
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 03:56:22 2026 +0530

    Docs: Count diagnostics among the thirteen reserved live verbs

    LibKa0s v1.60.0 (Slash minor 16) added `diagnostics` to lib.LIVE_VERBS,
    so the standard's reserved set is thirteen verbs, not twelve. ARCHITECTURE.md
    and slash-dispatch.md still named twelve at Slash minor 13. ARCHITECTURE.md
    now lists `diagnostics` beside `perf` as a reservation this addon does not
    register, so the eleven shipped reserved verbs are unchanged.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit 0371307bb691ce6434e2e9d10364326e4b62e65a
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 26 03:52:15 2026 +0530

    DR-PM-01: Re-vendor LibKa0s v1.60.0; stub RunDiagnostics, diagnostics joins the live list

    Re-vendor both payloads whole from tag v1.60.0 (commit bed0eb1), carrying
    v1.59.0 in the same copy: DebugLog 13 -> 14, the new DebugLogDiagnostics.lua
    minor 1, Slash 15 -> 16, WidgetsDragHandle 2 -> 3, kit revision 26 -> 27. The
    CLAUDE.md provenance line moves to v1.60.0 in this commit.

    What the copy made owed, in the same commit so the suite stays green:

    - core/DebugLogSetup.lua: the library-absent DebugLog stub gains
      RunDiagnostics (the collection's library-absent line naming
      /pm diagnostics, nothing written, returns 0), BuildDiagnostics and
      DebugVerb, so the surface-parity case matches DebugLog 14.1.
    - settings/Slash.lua: the degraded LIVE_VERBS fallback gains diagnostics.
    - tests/test_slash.lua: the live-set pin gains diagnostics.
    - tests/run.lua: declares the kit's test_diagnostics_contract suite, which
      skips with its reason until DR-PM-03 sets Kit.diagnostics.
    - tests/test_libka0s.lua: one case for the stub's three members.

    No host test pins the 1500-line buffer. The report itself, the unlock
    queue accessor and the retirement of /pm debug dump are DR-PM-02 and
    DR-PM-03. No decline issues filed; the rollout plan decided every surface.

    The revendor bundle is docs/revendor/2026-09-26-v1.60.0/. test-cases.md is
    regenerated and the README badge reads 934/934.

    Gate (ka0s-bounded): lua tests/run.lua 934 passed, 0 failed, 1 skipped,
    935 total; luacheck 0 warnings / 0 errors in 62 files; lizard, no function
    above CCN 15.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_0137w2iyvwbPYwaYca4pi2Bz

commit c078d7e4c995b842566c1b48ece7fe447d273adc
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Fri Sep 25 00:13:12 2026 +0530

    M6-PM: address review — drop stale "LibDBIcon right-click menu" comments

    What: reword the comments in tests/test_launcher.lua (header, the
    Minimap-row path test, the table-identity test), settings/Schema.lua
    (S.MINIMAP_STORE note, the inversion note) and defaults/Global.lua
    that still said LibDBIcon's own right-click menu writes `hide`.

    Why: after 494c479 right-click opens the Ka0s options menu, which never
    writes `hide`, and LibDBIcon ships no such menu. The writers of `hide`
    are the Minimap button row (NS.Launcher:SetShown) and
    /pm set global.minimap.shown; LibDBIcon only reads it and writes
    minimapPos on drag. The comments now match docs/schema.md as reworded
    in 494c479.

    Departures: comments only, so there is no test to write first. Also
    reworded a seventh comment in the same identity test ("as its menu
    does") carrying the same claim.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit c078d7e4c995b842566c1b48ece7fe447d273adc
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Fri Sep 25 00:13:12 2026 +0530

    M6-PM: address review — drop stale "LibDBIcon right-click menu" comments

    What: reword the comments in tests/test_launcher.lua (header, the
    Minimap-row path test, the table-identity test), settings/Schema.lua
    (S.MINIMAP_STORE note, the inversion note) and defaults/Global.lua
    that still said LibDBIcon's own right-click menu writes `hide`.

    Why: after 494c479 right-click opens the Ka0s options menu, which never
    writes `hide`, and LibDBIcon ships no such menu. The writers of `hide`
    are the Minimap button row (NS.Launcher:SetShown) and
    /pm set global.minimap.shown; LibDBIcon only reads it and writes
    minimapPos on drag. The comments now match docs/schema.md as reworded
    in 494c479.

    Departures: comments only, so there is no test to write first. Also
    reworded a seventh comment in the same identity test ("as its menu
    does") carrying the same claim.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 494c47959a71e9a33d01d2922fd1318231142753
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Fri Sep 25 00:08:43 2026 +0530

    M6-PM: Re-vendor LibKa0s v1.58.0; launcher menu is Enabled and Locked

    What: replace libs/LibKa0s/ and tests/_kit/ whole from the local tag
    v1.58.0 (tag 93cf3ad -> commit 34931c9), extracted with git archive
    (never a checkout in ../LibKa0s), and roll the CLAUDE.md provenance
    line v1.57.0 -> v1.58.0. One minor moves, Launcher 3 -> 4; the kit
    stays at revision 26, byte-identical. Frozen bundle
    docs/revendor/2026-09-25-v1.58.0/ (01_DELTA.md, 05_SUMMARY.md), shaped
    like M5-PM's v1.57.0 bundle.

    Adoption (launcher-section 2, WowAddonStandards v2.67.0): left-click
    opens settings (the library's), right-click opens the options menu.
    core/LauncherSetup.lua passes the two pairs this addon really has:
    - isEnabled + setEnabled -> NS.Slash:CliEnable, the body of
      /pm enable and /pm disable;
    - isLocked + toggleLock -> NS.Slash:CliLock(not isLocked()), the body
      of /pm lock and /pm unlock (CliSet on state.locked: the single write
      seam, one [Set] trace, the path = value echo, the combat deferral).
    No test mode (unlocking is the preview) and no primary window, so no
    toggleTestMode and no isWindowShown/toggleWindow. The menu matches the
    row WowAddonStandards' ADDONS.md records (WS-11): "Enabled . Locked".
    Removed onClick (rung b), leftClickLabel (and its two NS.L keys in
    locales/enUS.lua, with the PostLoad.lua note restored) and the retired
    disabledLine. Kept version, isLocked, isEnabled.

    Tests (written against the copy; red against the old LauncherSetup):
    tests/mock_menu.lua is LibKa0s v1.58.0's own repo-local MenuUtil mock,
    copied with a provenance header (the kit ships none). test_launcher.lua
    re-pins the clicks and hints and adds the menu: exact entries and order,
    state read per open, each entry routing to its slash handler both ways,
    the write seam and combat deferral, grayed Locked while disabled writing
    nothing, and the no-MenuUtil fallback. test_disabled.lua case 8 now
    proves the disabled left click opens the panel and writes nothing.

    Docs: README (minimap paragraph, disabled paragraph, badge 933/933),
    ARCHITECTURE.md (launcher table, disabled-survivor row, localization
    row), settings-panel.md (Minimap button row), module-map.md (seam row,
    test_launcher row, mock_menu.lua row), smoke-tests.md 7b steps 3-4c,
    slash-dispatch.md, schema.md, testing.md tree, test-cases.md
    regenerated (test_launcher 32 -> 37, total 933).

    Departures:
    - One commit rather than copy-then-adopt: the copy alone reddens ten
      cases pinning the retired rung (b) click, refusal and hints.
    - The lint config gains a narrow files["tests/mock_menu.lua"] stanza
      (212/self, 432/self) so the copied mock stays byte-identical below
      its header.
    - smoke-tests.md steps 8/8b and schema.md described hiding the button
      through "LibDBIcon's own right-click menu"; right-click is now the
      options menu, so those lines point at the Minimap button row instead.

    Gates (all through ka0s-bounded): tests 933/933; lint 0/0 in 62 files;
    complexity nothing above CCN 15; largest authored file 1447 lines.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit efbd2d90e3f3375eed0aed70b864af99791dae13
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 23:13:43 2026 +0530

    M5-PM: Launcher tooltip fields: version, isEnabled, isLocked, left label

    What: core/LauncherSetup.lua passes the Launcher minor 3 descriptor
    fields launcher-section 1 (WowAddonStandards v2.66.0) owes, each read
    on every show by the library-drawn status tooltip:
    - version -> NS.Version(), the TOC's ## Version (the /pm version seam);
    - isEnabled -> NS.IsAddonEnabled (the master switch, not the Lifecycle
      latch), with disabledLine -> the Slash dispatcher's DisabledLine(), so
      the tooltip reads Enabled: Yes|No and, while disabled,
      "Left-click: disabled -- /pm enable";
    - isLocked -> state.locked, the accessor the Lock frame row reads;
    - leftClickLabel -> "Unlock frame" / "Lock frame" by lock state (rung
      (b), "lock / unlock" in ADDONS.md), through NS.L (two keys added to
      locales/enUS.lua).
    No isTestMode (this addon has no test mode; unlocking is its preview)
    and no onTooltipShow (it never passed one and has no line of its own).

    Tests (written first, red on the vendored library alone): seven cases in
    tests/test_launcher.lua that hover the object's OnTooltipShow into a
    recording tooltip and pin the whole block enabled and disabled, the TOC
    version, re-reading on every show, the green/red values, the absent
    Test mode line, and the library's gate refusing a disabled left click
    exactly once.

    Docs: ARCHITECTURE.md launcher table gains the tooltip row, the
    disabled-state row and the localization-section-1 row are updated;
    settings-panel.md Minimap button row, module-map.md, README (the
    minimap paragraph, the disabled paragraph, the Tests badge 928/928),
    smoke-tests.md step 7b.4c, and docs/test-cases.md regenerated
    (test_launcher 25 -> 32, total 928).

    Departures:
    - Passing isEnabled (needed for a true Enabled: line) makes the
      library's minor-2 gate refuse the disabled left click, so the host's
      own copy of that gate inside toggleLock is removed: one refusal, same
      line, same single chat line (tests/test_disabled.lua case 8 unchanged
      and green).
    - The first M5-PM commit (f993d63) wrote the revendor bundle's two .md
      files with doubled CRs (CR CR LF), which the kit's eol gate reads as
      lone CRs; its "921/921" was measured before the bundle was added. This
      commit restores CRLF in both files; no content change.

    Gates (ka0s-bounded): tests 928/928; luacheck 0/0 in 61 files; lizard
    nothing above CCN 15; largest authored file 1447 lines.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit f993d632b2b6afdd484c491c84babf373694cb13
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 23:12:38 2026 +0530

    M5-PM: Re-vendor LibKa0s v1.57.0 and record its delta bundle

    What: replace libs/LibKa0s/ and tests/_kit/ whole from the local tag
    v1.57.0 (tag d03e836 -> commit aa37bc9), extracted with git archive
    (never a checkout in ../LibKa0s), and roll the CLAUDE.md provenance
    line v1.56.0 -> v1.57.0 in the same commit. One library file moves a
    minor: Launcher 2 -> 3. The kit stays at revision 26, byte-identical.
    Both payloads diff empty against the tag, with and without
    --strip-trailing-cr.

    Adds the frozen bundle docs/revendor/2026-09-24-v1.57.0/ (01_DELTA.md,
    05_SUMMARY.md), shaped like the RV-PM bundle for v1.56.0: base,
    per-file minors, both diffs, kit pairing, consumption map, contract
    delta. No contract blocker: this host never passed onTooltipShow.

    Why: M5 (the owner's 2026-09-24 smoke ruling, WowAddonStandards
    v2.66.0 launcher-section 1): the library now always draws the minimap
    button's status tooltip. The descriptor fields this addon owes are the
    second M5-PM commit.

    Gates after the copy (all through ka0s-bounded): tests 921/921; lint
    0/0 in 61 files; complexity nothing above CCN 15, largest authored
    file 1447 lines.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit a3b4390f2f6879fcad4ad3cfe514548926a893e2
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 13:26:48 2026 +0530

    PM-16: Refresh the standards reference against v2.65.0

    Ran the /wow-addon:revendor-standards procedure against the standard as
    published on WowAddonStandards master (v2.65.0, 2026-09-23). The
    execution gate held: gh api .../contents/standards/STANDARDS.md reads
    v2.65.0 on the default branch.

    Three-place reference (documentation-§6): TOC ## X-Standard carries the
    repo URL, the README badge is the bare image with no link wrapper and no
    %20 escapes, and CLAUDE.md "Standards compliance (read first)" matches
    the canonical block verbatim, stop-and-flag and the two-way
    classification intact. Nothing to change.

    Sweep (whole repo, excluding libs/, tests/_kit/ and the frozen docs/
    audits, reviews, automated-tests, revendor, superpowers, investigations):
      grep -rEn '§[0-9]+\.[0-9]' . <those exclude-dirs>  -> 0 hits
      Every filename-§N citation range-checked against the fetched section
      files' '^### N.' counts: none unknown or out of range. The one
      malformed one was tests/prose_waivers.lua:3 'localization-5'.
    No doc-set counts without members, no drop-in wording. 3f gate
    statements in docs/testing.md, docs/automated-tests/README.md and
    CLAUDE.md already name both checkpoints (commit, tag). The standard has
    no quirks catalogue section, so nothing is vendored. .gitattributes is
    the canonical CRLF body with the *.sh carve-out and binary marks;
    worktree stragglers: 0. No renormalization done.

    Changes (comment-only):
    - tests/prose_waivers.lua:3: 'localization-5' -> 'localization-§5'.
    - settings/Slash.lua:279: the library-absent line comment now cites
      slash-commands-§1 at standard v2.65.0, as PM-09 relied on it. Kept to
      one line so no file:line citation elsewhere shifts.
    The savedvariables-§1 schemaVersion = 0 citation (defaults/Global.lua:9,
    tests/test_database.lua:92) and the launcher-§3 minimap.shown citation
    (tests/test_launcher.lua:220/303, docs/smoke-tests.md:475) already
    carried v2.65.0 from PM-10/PM-11; verified, not touched.

    Deviation: the item's verify expects 'v2.65.0' in README.md and
    CLAUDE.md. Neither file carries a standard version, and the procedure
    forbids writing one into the reference (a version on a pointer goes
    stale silently; documentation-§6 prescribes no version). Left as is.
    'v2.64.0' appears nowhere in README.md, CLAUDE.md, PanelMaster.toc or
    docs/*.md.

    Findings: none (item carries no finding ids).

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 689a7919e1a81d4db7aad86d642ad4fd7b51706d
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 10:50:14 2026 +0530

    PM-DOCS: Sync docs and record the remediation's automated-test bundle

    Closes the 2026-09-23 remediation's PanelMaster docs item (finding
    PanelMaster-A-18). No version bump, no tag, no TOC change.

    sync-docs pass:
    - CLAUDE.md already matched (provenance line v1.56.0 as RV-PM rolled it,
      ten of fifteen majors adopted; kit revision 26 is vendored, and no live
      doc claims a current kit revision). Its Canvas citation was stale.
    - Stale file:line citations re-derived against HEAD: the mouseover tick
      Canvas.lua:650-656 -> 647-652 and its install :660/:666 -> :662
      (CLAUDE.md, ARCHITECTURE.md, performance.md); mouseover default
      Constants.lua:306 -> 311; NS.COMMANDS Slash.lua:285 -> 322;
      PANEL_TEMPLATE :262 -> 267, PANEL_FIELD_ORDER :504 -> 509, preview
      marker :548 -> 546; enUS.lua reasoning 8-14 -> 8-10; scheduleTimer seam
      OptionsSetup.lua:234 -> 248; the 212/filter ignore :203 -> 217.
    - performance.md's RegisterEvent table named core/PanelMaster.lua lines
      that no longer register anything: the three stand-up events are
      registered from core/LifecycleSetup.lua:73-75 (handlers at
      core/PanelMaster.lua:112/124/137) and PLAYER_LOGIN from :67.
    - settings-panel.md still said the General Defaults tooltip promised
      "Your panels are untouched"; 900b085 fixed tooltip and comment, so the
      paragraph now says what they read.
    - ARCHITECTURE.md cap census recounted: PanelEditor.lua 1476 -> 1447,
      test_panel.lua 1353 -> 1399, five files in the band, not four.
    - Slash parity: 19 verbs in NS.COMMANDS, all named in ARCHITECTURE.md and
      slash-dispatch.md. Dead-export sweep over core/modules/settings: none.
    - docs/test-cases.md already equals `tests/run.lua --list` (921) and the
      README Tests badge already reads 921/921; neither needed a change.

    Bundle docs/automated-tests/20260924-104311/ (label
    remediation-2026-09-23, not --release): lint pass 0/0 over 61 files,
    tests 921/0/921, perf skip with reason (1) "no tests/perf.lua" (the
    register row is performance-§1, so reason (2) is correctly not written),
    complexity pass, 0 functions above CCN 15. Run on bf1291d with only the
    doc edits above uncommitted; ANALYSIS.md says so. RESULTS.md rolled by
    the runner; dispositions carried forward and updated for PanelEditor.lua,
    test_panel.lua, test_artwork.lua and Artwork.lua. ANALYSIS.md records
    once, forward-only, that 1.1.1-release (dd04000) was tagged with no
    release bundle on a TOC reading 1.1.0 (automated-tests-§6). No bundle is
    stamped 1.1.1.

    Deviations:
    - The item expected four band files; the run found five. The fifth,
      tests/test_libka0s.lua (1086, up from 971 through PM-09 and PM-12),
      arrived with a blank Disposition and has been given one (Accepted,
      re-check at 1300, seam = its Degraded cases).
    - Comment citation not corrected (the item allows that only on
      confirmation): core/Database.lua:86 cites modules/Registry.lua:204-206
      for the frame-name backfill, which now sits at :205-207.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit bf1291da8ba9f851c18dda427a7b472118cfdd1e
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 10:36:53 2026 +0530

    PM-24: README Usage drops placeholders, ends on the config pointer

    README.md Usage section, per documentation-§1:
    - `/pm delete <name>` becomes `/pm delete ChatBG`, and `/pm get <setting>`
      / `/pm reset <setting>` become `/pm get settings.gridSize` /
      `/pm reset settings.gridSize` (a real schema path), so CurseForge no
      longer strips the argument. The only remaining angle-bracket markup is
      the <br> in the Version History table.
    - The two disabled-state paragraphs are merged into one, and the
      `/pm disable` / `/pm enable` sentences move out of the settings-CLI
      paragraph into it, so the disabled state is described in one place.
    - The "Everything else is configuration..." pointer moves to be the last
      paragraph of Usage (dropping the stale "now").
    - A light de-AI pass over the edited paragraphs: em dashes out, "Those
      settings" re-anchored now that the pointer no longer precedes it.

    Finding: PanelMaster-A-14.

    Deviation: the README never shows the minimap row's CLI path, so the
    item's global.minimap.shown clause (PM-11) had nothing to rewrite.

    Gates: luacheck 0/0, tests 921/921.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 2e1dc643928312aea1b3a8cf0a0ef4aa2d0be822
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 10:34:12 2026 +0530

    PM-23: Cite the kit by function name as well as by re-derived line

    DEPENDENCIES.md's toolchain rows cited tests/_kit by bare line number,
    and two of those numbers predated the v1.56.0 payload (LK-01 peeled the
    assertions out into tests/_kit/asserts.lua, shifting framework.lua).

    - POSIX-shell row: `framework.lua:515-516` becomes `listDir` (:432, the
      ls -A / dir /b shell-outs at :444-445); `framework.lua:498-500`
      becomes the LuaFileSystem note on listDir (:427-431); the find
      citation names `localNames` (:111, find at :126).
    - Lua 5.1 row: loader.lua :68/:72 verified and named `Loader.load`.
    - git row: vendor_sync.lua :195/:194 verified; names `gitOut` (:193).
    Every line re-derived with sed -n against the vendored v1.56.0 kit.
    docs/testing.md and CLAUDE.md carry no tests/_kit/<f>:<n> citations.

    Resolves PanelMaster-A-13.

    Deviation: docs/testing.md's harness tree still said framework.lua holds
    "the assertions"; it now lists asserts.lua beside it, the same LK-01
    drift the item names.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit c1a377741896bcf4098c2e2e10d1b133aaa639d4
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 10:32:43 2026 +0530

    PM-22: address review — scope the atomic-write claim, name every degraded_env consumer

    module-map's tools/ intro said all four generators write through .tmp and
    os.replace; build_manifest.py and artwork_cleaner.py's TGAs write in place.
    The degraded_env.lua row now names all five suites that load it
    (test_disabled, test_launcher, test_libka0s, test_schema, test_surface_parity).

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit d4b014cb0c335834bc89372c91028d61702f3a6a
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 10:28:55 2026 +0530

    PM-22: Inventory tests/ and tools/ in module-map; recount stale claims

    Resolves PanelMaster-A-11 and PanelMaster-A-12.

    A-11: docs/module-map.md gains a "## tests/" section (run.lua,
    wow_mock.lua, degraded_env.lua, prose_waivers.lua, and one row per
    test_*.lua suite, all 28) and a "## tools/" section with the four
    generators and what each writes. The basename check over tests/*.lua,
    tools/artwork/*.py and tools/sunn/*.py now finds every file.

    A-12, recounted by command:
    - Adopted seams: ten (seven Setup files in core/, three in settings/).
      ARCHITECTURE.md's Module Map said "six of the eight" and "the other
      two"; it now says seven of the ten and the other three.
    - Majors: fifteen NewLibrary calls in libs/LibKa0s, fourteen resolving
      LibKa0s-Core-1.0. testing.md:106 and module-map's TOC-order note
      ("the other nine") now say fourteen of fifteen / the other fourteen.
    - Parity cases: eight. testing.md's degradation-stub section already
      said eight seams (PM-13), so it needed no change.
    - ARCHITECTURE.md's doc table no longer calls RESULTS.md "never
      hand-edited": its watch-list Disposition column is authored.
    - testing.md's historical "six of the eight scripts" note is reworded
      so it no longer reads as a current seam count.

    settings/PanelEditor.lua: the tab-constants block no longer says
    General is GONE (it is back and first), the strip-order note puts
    General first, and the page-header block describes the one-row band
    and the in-place picker refresh instead of three rows and the deleted
    refreshHeaderActs. 1487 -> 1447 lines. The shifted line citations in
    docs/compat-layer.md, docs/settings-panel.md and docs/smoke-tests.md
    are rolled to match (settings-panel's :77/:1328 pair was already off
    and now points at currentRecord's definition and call).

    .gitignore: re-pointed from the nonexistent wiki_import.py to
    tools/artwork/artwork_cleaner.py.

    Deviations:
    - The item says artwork_cleaner.py writes manifest.tsv.root and
      .stamps.tsv. grep shows it writes only .stamps.tsv (it has no
      manifest). The .root ignore line is kept, commented as the retired
      importer's, so a stale copy on an old checkout cannot be committed.
    - The item's grep for the stale phrases still hits the frozen
      docs/audits/2026-09-23/ bundle (which quotes them as evidence) and
      a frozen docs/superpowers spec (wiki_import.py). Frozen bundles are
      not edited; every live doc and .gitignore is clean.

    Gates: luacheck 0/0; tests 921 passed, 0 failed; complexity 0
    functions above CCN 15; largest authored .lua is
    settings/PanelEditor.lua at 1447 lines.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit edca9b9008b2c5d9c24c97d519c303a281024918
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 10:21:41 2026 +0530

    PM-21: Restore ARCHITECTURE.md to the hub shape; spill runtime to schema

    docs/ARCHITECTURE.md was 489 lines with a 106-line Settings Schema
    section (documentation-§3 hub-and-spill rule). It is now 380 lines, and
    the Settings Schema section is 42.

    - Settings Schema keeps a five-line summary, the panel-registry block
      (storage keys, writer, load pass) and one link out to schema.md. The
      fields-on-a-panel narrative shrinks to a pointer at its register row.
    - docs/schema.md gains '## The schema runtime': the 15 rows in 3 tabs,
      the Master controls composition, the writeThrough enable path when the
      composed row is missing (PM-09: Set/SetMany store settings.enabled raw,
      Sl:CliEnable re-runs NS.RefreshEnabled), the global.minimap.shown row
      and its inversion (PM-11), the library instance, and the degradation
      stub (now citing docs/api/Schema/version-2-docs.md, as the code does).
    - Retired-row narratives collapse to one entry each: options-ui-§16 x3
      (#48, docs/revendor/2026-09-12-v1.31.0/), documentation-§4 (PM-029),
      options-ui-§1 and line-endings-§5 (same M5-02 pass, docs/audits/
      2026-09-08/), and the band gate (docs/revendor/2026-09-23-v1.55.0/).
    - Headings renamed to the canonical '## Message Bus' and
      '## Taint Notes'; the Documentation map's message-bus.md row follows.
      No in-repo anchor pointed at either old heading, and tests/test_docs.lua
      pins neither.

    Finding: PanelMaster-A-10.

    Deviations:
    - The existing fields-on-a-panel paragraph in schema.md already carried
      that narrative, so it was not duplicated; instead its stale trigger
      ("an explicit record argument on NS.Schema:Set") was brought into line
      with the PM-15 register row (host-side resolveRoot + id forwarding,
      #54), and its "ARCHITECTURE.md -> Settings Schema lists them" now
      points at the register row, which does.
    - The item's line cites (:47-78, :80-103, :380-428) predate PM-09..PM-20;
      the moved blocks were located by content.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 3145831eb52162401ec659a8b1706052382090aa
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 10:17:25 2026 +0530

    PM-20: address review — compat-layer test note names the five covered shims

    docs/compat-layer.md said tests/test_compat.lua covers the degraded answers
    of seven shims. Only five (GetUIScale, FetchMedia, MediaList, RegisterMedia,
    InCombat) have degraded-path tests; GetScreenSize and MouseIsOver are tested
    on their normal answers only. Reword the note to name the five and state the
    two gaps plainly.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit b81f45076d897232626490ef089ecef2b7164a96
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 10:14:44 2026 +0530

    PM-20: Write docs/compat-layer.md for the eight Compat shims

    core/Compat.lua publishes eight shims (documentation-§3's mechanical
    grep), over the trigger's threshold of three, yet the Tier 2 page was
    missing and the map row said Not applicable. The new page has one
    section per shim: what varies, what the guard answers when the API is
    absent, and who calls it (grepped NS.Compat.<X>). InCombat is written
    up in its PM-03 form (UnitAffectingCombat first, then InCombatLockdown,
    then false). It links #53, the declined LibKa0s-Compat-1.0 adoption,
    as the reason all eight stay addon-owned, and cites compat's v2.65.0
    applicability condition (WS-05): this addon owns version-variant calls,
    so Compat.lua is required. The ARCHITECTURE.md map row flips to
    Present. tests/test_docs.lua does not pin the map, so no test changed.

    Resolves: PanelMaster-A-04 (PanelMaster#53 referenced)

    Deviations: the item's line cites were stale after PM-03 lengthened the
    InCombat comment. Re-derived: InCombat :86, RegisterMedia :115,
    FetchMedia :136, MediaList :151, MouseIsOver :176 (item said :79, :103,
    :124, :139, :164). The map row is at docs/ARCHITECTURE.md:345, not :327.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 9b015fbd747df9d6e7842ca7025105a45a9a8ec7
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 10:10:30 2026 +0530

    PM-19: Correct stale printer, AceConsole and PEW-rationale comments

    Text only (PanelMaster-R-09, the sentences PM-09/PM-10 left):
    - core/PanelMaster.lua reclaim comment: NS.Print is built by
      core/CoreSetup.lua (the LibKa0s-Core printer), not defined in
      core/Util.lua.
    - core/CoreSetup.lua: the embed overwrites NS.Print with AceConsole's
      :Print, not AceGUI's.
    - core/PanelMaster.lua (OnEnterWorld), core/LifecycleSetup.lua
      (NS.StandUp's gate note), docs/ARCHITECTURE.md and docs/data-flow.md
      event tables: drop "the registry's off-screen recovery measures
      UIParent" (recovery is on demand only, /pm recover). The real reason
      for painting at PLAYER_ENTERING_WORLD is stated instead: panels are
      anchored to UIParent (modules/Canvas.lua), whose final size and the
      frame anchors are settled by that event and not at OnEnable. The
      boot stand-up explanation is kept.

    tests/test_docs.lua pins none of these strings. No line citations into
    core/PanelMaster.lua needed rolling after its two added comment lines.

    Deviations: the item's line cites had drifted (LifecycleSetup 120-122,
    ARCHITECTURE.md:240, data-flow.md:204); the intended sentences were
    edited at their current locations.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit d805e0b1a7801d8d4d099f0720f05c814a2e81ef
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 10:06:51 2026 +0530

    PM-18: Record the 28 unrecorded LibKa0s tags in one span bundle

    Add docs/revendor/2026-09-24-v1.16.0-v1.54.2/ (01_DELTA.md and
    05_SUMMARY.md only), the consolidated span bundle audit-review-history
    sanctions for a lapsed re-vendor record. Line 1 of 01_DELTA.md is the
    WS-01/WA-01 grammar, `Delta: LibKa0s v1.16.0 -> v1.54.2 (span: ...)`,
    naming every tag this addon vendored since the store's horizon
    (2026-08-25) that no bundle names. The body states the true previous
    base (v1.15.0, b7b744c), the two listing commands and their output, and
    a tag / vendoring commit / date table; 05_SUMMARY.md carries one line
    per tag (carried by sweep, nothing adopted, or the adopting commit's
    sha) and why the record is consolidated. Frozen bundles are not edited.

    With the folder in place, the AUDIT.md re-vendor check (and Step 3h's
    walk with provenance rolls) prints nothing. Tests 921/0, luacheck 0/0,
    no function above CCN 15.

    Resolves: PanelMaster-A-15

    Deviation: the item's list has 27 tags and omits v1.43.0, which
    eaa7807 vendored (kit revision 23) and no bundle names. The re-derived
    list the item asks for has 28, so the span names 28; without v1.43.0
    the audit check would still print it. The item's own derivation
    command (grep 'LibKa0s[^v]*v...' on CLAUDE.md) no longer matches the
    provenance line's wording, so the listing uses AUDIT.md's
    `Bundles [LibKa0s](...) vX.Y.Z` pattern instead. The span separator is
    a space, per the audit-review-history grammar, not the comma-separated
    form in the item text.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 7db8c12cdb7aea7e002e6ce23f2d8eafa84fd86c
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 10:01:43 2026 +0530

    PM-17: Restore 'catalogued' in the two frozen superpowers specs

    Line 5 of docs/superpowers/specs/2026-07-31-panel-artwork-design.md and
    docs/superpowers/specs/2026-08-02-wiki-artwork-import-design.md is put back
    byte-for-byte from e30e329^, undoing that commit's respelling of the frozen
    text ("catalogued" had been mangled to "catalogd"). Both specs are frozen
    records, not this repo's live English to correct.

    The kit's prose gate no longer reads them: kit revision 26 (LibKa0s v1.56.0,
    LK-07) adds docs/superpowers/ to SKIPPED_DIRS in tests/_kit/prose_lists.lua.
    tests/prose_waivers.lua carried no interim skipDirs entry for that folder, so
    nothing there needed removing. Prose gate green, 921 passed / 0 failed.

    Finding: PanelMaster-A-09.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 62a16838ecc088ba1d6967a7e6017a6bdb9b8684
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:58:49 2026 +0530

    PM-15: Re-decide the architecture-§5 trigger as host-side, cite #54

    The architecture-§5 register row (the fields on a panel) had a re-check
    trigger, "the schema helper gains instance addressing", that the library
    already met: LibKa0s-Schema-1.0 has forwarded instanceId to resolveRoot
    since minor 2. The host never used it, so the trigger was ambiguous and
    un-evaluated (audit-review-history's third MUST).

    Re-decided as keep (option b, the default decision):
    - The trigger now names the host-side condition: settings/Schema.lua's
      resolveRoot maps an instance id to a registry record AND
      NS.Schema:Set/:Get forward that id.
    - Decided is re-dated to 2026-09-24.
    - Option (a), the adopt path, is filed as #54 (enhancement,
      state:triaged, severity:low) and cited from the row.

    Issue store (A-19), done through gh with 5 s between writes:
    - #19, #20, #22, #23 relabelled state:done and closed with evidence.
    - #24 relabelled state:will-not-do and closed as not planned, citing the
      ratified performance-§1 row.

    Findings: PanelMaster-A-07, PanelMaster-A-19.

    Deviation: the item cites CLAUDE.md:83 for the agent-context.md
    deletion; the sentence is at CLAUDE.md:84, and #19's close comment cites
    :84.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 10f750cfff1a4dca9ca9f82a6ae283c577f1a09b
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:55:01 2026 +0530

    PM-14: Comment the TOC's load-bearing positions and conventional groups

    PanelMaster.toc now says why two positions matter and which runs are
    convention only (PanelMaster-A-02, PanelMaster-A-03):
    - Util AFTER Constants is load-bearing: core/Util.lua:4 captures
      `local C = NS.Constants` at file scope.
    - Slash AFTER Schema is load-bearing: its dispatcher descriptor takes
      NS.SchemaRuntime's members as values at file load
      (settings/Slash.lua:601-605).
    - Conventional notes on the Namespace/State run, the
      PanelMaster/Database run, # Defaults, and # Modules (where Unlock is
      the one conventional entry among the pinned ones).

    Comments only. Loader.tocFiles skips '#' lines, so the TOC-derived load
    list and tests/test_harness.lua's pin are unchanged (921 passed).

    Deviations: the item cited Slash.lua:554-558; the lines are 601-605
    today. Namespace/State and PanelMaster/Database got separate notes,
    since CoreSetup sits between them with its own pin.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit e2a8ce98d01546d5ad2587a8be8a7c1ae83ccc32
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:52:30 2026 +0530

    PM-13: Add the surface-parity case for the Lifecycle degradation stub

    core/LifecycleSetup.lua's library-absent arm keeps the stand-down latch
    itself, and its comment (and docs/module-map.md) claimed
    tests/test_surface_parity.lua compared the two member sets. No case did.
    Now one does (PanelMaster-A-08).

    - tests/test_surface_parity.lua: new case "Parity: the Lifecycle seam's
      degraded surface matches the live one". The degraded arm is a real
      load with Lifecycle.lua alone omitted: Perf.lua's NEEDS_LIFECYCLE
      floor is a silent return, not a raise, so Perf/PerfPanel stay in the
      list and simply do not register (said in a comment). Asserts the
      degraded instance is not the live one, runs the two-table
      assertSurfaceParity against NS.Lifecycle with an empty ignore set (the
      stub carries every live key, `name` included; the grep for the
      addon's call sites is named in the comment), and adds the Slash case's
      function-only reverse check. Header recounted to eight seams, and the
      by-name/two-table paragraph says why Lifecycle uses the two-table
      form.
    - tests/run.lua: Kit.setSurfaceSource gains
      ["LibKa0s-Lifecycle-1.0"] = NS.Lifecycle.
    - docs/testing.md: the degradation-stub section named four seams and
      two by-name callers; it now lists all eight and which form each uses.
    - docs/test-cases.md regenerated (921); README Tests badge 921/921.

    Shown able to fail: with `LC.PrintHolds` deleted from the stub the case
    went red with "Lifecycle stub: ... PrintHolds is missing (live:
    function)"; reverted.

    core/LifecycleSetup.lua and docs/module-map.md give no count, so they
    are unchanged (their claim is now true).

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 33b3f831b0e7567772f9fb93b96c11ad0525d861
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:46:48 2026 +0530

    PM-12: Declare the bus messages through LibKa0s-Bus-1.0's Catalog

    The three message constants are now declared once each through the
    dot-called LibKa0s-Bus-1.0 Catalog, behind a new core/BusSetup.lua seam
    (NS.BusLib). Catalog validates the declaration at load and answers a
    strict table, so a mistyped key raises at the read instead of a
    publisher silently sending nil (PanelMaster#52).

    - core/BusSetup.lua: publishes the library table as NS.BusLib, or a
      stub whose Catalog hands back the host's table unchanged (same wire
      names, no strictness). Only Catalog is adopted; Bus:New and tracked
      targets are not, and NS.NewBusTarget stays.
    - PanelMaster.toc: BusSetup right after CoreSetup, with a load-bearing
      comment (Registry.lua and Schema.lua call Catalog at file load).
    - modules/Registry.lua: R.MSG = Catalog{PANELS, PANEL}; fire(MSG.*).
      R.MSG_PANELS / R.MSG_PANEL deleted.
    - settings/Schema.lua: S.MSG = Catalog{SETTINGS}; announce sends
      S.MSG.SETTINGS. S.MSG_SETTINGS deleted.
    - Every reader (Canvas:Enable, PanelEditor wirePanelsBus, comments in
      Panel.lua/PanelEditor.lua/Canvas.lua, tests, rendering.md,
      settings-panel.md) moved to the strict MSG.<KEY> read; the grep for
      MSG_PANELS|MSG_PANEL\b|MSG_SETTINGS prints nothing.
    - tests: red-first parity case for the Bus seam (ignore New; same wire
      names on both arms), strict-read cases for Registry.MSG and
      Schema.MSG, the degraded arm answering nil without raising, and a
      TOC-order pin in test_harness. tests/run.lua registers
      LibKa0s-Bus-1.0 as a surface source.
    - Docs: ARCHITECTURE message-bus section, module-map row and load-order
      bullet, adopted-majors count nine -> ten in CLAUDE.md and
      module-map.md. test-cases.md regenerated; badge 920/920.

    Deviations:
    - core/BusSetup.lua added to test_libka0s.lua SEAM_FILES: the "seam-file
      list covers every file that resolves a LibKa0s major" case requires
      it; not named in the item.
    - test_harness's TOC case only pinned presence, so the "TOC-order pin"
      is a new order assertion (BusSetup before Registry and Schema).
    - Item cited Canvas.lua:858-860; the subscriptions were at :917-919.
    - Registry.lua grew four lines, so its line citations were rolled:
      core/Database.lua (:200-202 -> :204-206), docs/smoke-tests.md
      (:278-285 -> :282-289). The two .luacheckrc citations (:573, :576)
      were already stale and now name the real lines (:517, :520).

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit c8fca4caf38972fc8870eeef2af7d75981650dbd
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:39:47 2026 +0530

    PM-11: Read the minimap row's CLI path as global.minimap.shown

    launcher-§3 (standard v2.65.0, WS-06): the row's schema path is its CLI
    name, so it reads in the row's own sense. S.MINIMAP_PATH is now
    "global.minimap.shown"; the new S.MINIMAP_STORE = "global.minimap.hide"
    is LibDBIcon's key and the only stored key. The row's get/set invert onto
    the store, S:SnapshotPersisted still excludes the row by its path, and
    S:Register's defaultsRoot answers no root for the row (the one
    closure-backed row, architecture-§5) and checks the store against the
    global defaults instead, counting one missing with a printed schema error
    if it does not resolve. No `shown` key is ever written or declared
    (anti-pattern #81). Comments in settings/Schema.lua and
    core/LauncherSetup.lua rewritten to name the store.

    No SavedVariables migration and no schema-version bump: the stored key
    did not move. A test pins it: a legacy store { hide = true,
    minimapPos = 200 } reads `get global.minimap.shown` as false, the button
    stays hidden, minimapPos is untouched, and no `shown` key lands in the
    raw store after a set.

    Player-facing CLI rename, for the next Version History roll:
    `/pm set global.minimap.hide <v>` became
    `/pm set global.minimap.shown <not v>`; the old path now answers the
    unknown-setting refusal ("Setting not found"), it is not an alias.

    Tests (red first): the path pin, the /pm get/set echo case and the
    legacy-store case in tests/test_launcher.lua; Register also asserted to
    count an undeclared store. tests/test_schema.lua reads the minimap
    default through the store and expects the new path in the Master
    controls order. docs/ARCHITECTURE.md, docs/schema.md, a new smoke step
    7b.8b, docs/test-cases.md regenerated, README badge 916/916.

    Finding ids: none (item carries none).
    Deviations: the item's line cites (:187, :530-539, :170-186, :516-529)
    had drifted; the intended code was edited at its current location.
    Added a smoke step 8b in section 7b, which the item's smoke checks
    referenced but the doc did not yet carry.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 560e4d82b1badc8c48aab19f7bf7cf4f48976c92
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:35:22 2026 +0530

    PM-10: address review — roll core/Database.lua line citations past the new comment line

    dea8d67 added a comment line to core/Database.lua above InitDB, so everything
    below it moved down by one. The citations of those lines now point at the new
    positions:
    - tests/test_database.lua:12 cites the RunMigrations call at :20 (was :19)
    - docs/ARCHITECTURE.md:34 cites the AceDB:New open at :19 (was :18)
    - docs/profiles.md:4 cites the AceDB:New open at :19 (was :18)
    - .luacheckrc:152 cites the NS.Registry.ReloadProfile probe at :99 (was
      :80). This one was already stale before dea8d67 (the probe sat at :97);
      the fix is the same, so it goes in here too.

    Comment and doc changes only. Lint 0/0; tests 914/0; no function above
    CCN 15.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit dea8d6729ed6652b767e09d46abf052a63d5cffb
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:32:35 2026 +0530

    PM-10: Declare schemaVersion 0 and migrate every stored profile

    Migration stamp per WS-03 (savedvariables-§1, toc-file-§2, standard
    v2.65.0): the runner owns the stamp, the defaults declare its floor.

    - defaults/Global.lua: NS.defaults.global now declares schemaVersion = 0.
      The "DELIBERATELY NOT SEEDED" block is replaced by the v2.65.0 reason:
      0 masks no legacy account (an unstamped file reads 0 and the gate
      opens), and a current-version default would be stripped by
      removeDefaults and never persist.
    - core/Database.lua: RunMigrations reads `tonumber(g.schemaVersion) or 0`
      and returns early when current. The v1 -> v2 frame-name stamp is
      extracted into stampFrameNames(profile) and now walks EVERY profile in
      db.sv.profiles, plus db.profile when it is not among them (identity
      check), because the account-wide stamp alone must not gate a
      profile-scoped step. The stamp is written only after the step returns.
      RunMigrations is CCN 6 (stampFrameNames 7, stampEveryProfile 6).
    - RegisterProfileCallbacks comment: inactive profiles are stamped at
      init; R.Sanitize stays the per-record repair for imported/copied
      profiles. Stale sentences fixed (R-09): Database.lua "global holds only
      the schema stamp", the [Init] example "schema v1" -> "schema v2", and
      defaults/Profile.lua:4-5.
    - Docs (A-06): ARCHITECTURE.md, common-tasks.md, module-map.md and
      profiles.md now say Global.lua declares schemaVersion = 0 (the runner's
      floor; the runner writes the real stamp) and LibDBIcon's minimap table.
      docs/schema.md left as is. No Documented-deviations row: declaring 0 is
      now compliance, which closes A-05 and A-17.
    - Tests (red first): defaults declare schemaVersion 0; a legacy record in
      a NON-active stored profile gets its frame name; the stamp lands above
      the declared default. "stamps a version onto an unstamped DB" now
      asserts the exact version; MigrationSummary expectation is v0 -> v2.
      docs/test-cases.md regenerated and the README badge moved to 914/914.

    Findings: PanelMaster-A-05, PanelMaster-A-06, PanelMaster-A-17,
    PanelMaster-R-09.

    Deviations: docs/settings-panel.md:321-324 repeated the callback comment's
    reasoning, so it gets the same update (inactive profiles are migrated at
    init); the item did not list it.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 2568e655a2e6962a6d7abac3d15cd7a724494736
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:29:17 2026 +0530

    PM-09: address review — module-map enUS row and localization paragraph

    docs/module-map.md: the locales/enUS.lua row said it carries no keys;
    it now carries the library-absent line Sl:LibraryAbsentLine formats.

    docs/localization.md: split the paragraph so "a later pass can wrap
    those labels" refers to the hardcoded labels again, reflow it, and name
    every verb that prints the library-absent line — /pm lock and /pm unlock
    when the Lock frame row is absent, and /pm enable and /pm disable when
    even their write-through is refused (Sl:CliEnable), matching
    locales/enUS.lua.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit b956b4bc25ab1fc82eb7d38f57c9a1828f75f481
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:25:37 2026 +0530

    PM-09: Route library-absent enable/disable/lock/unlock per WS-02

    The composed Master-controls rows (settings.enabled, state.locked) vanish
    whenever the Options major is absent, on a fully library-less load and on
    a partial load missing only Options. /pm disable and /pm enable then
    printed the settings-CLI notice and left the latch up; lock/unlock did
    the same with no library-absent line.

    - settings/Schema.lua: pass writeThrough = { S.ENABLED_PATH } on the
      descriptor (Schema minor 2, LK-23). hostSchemaStub builds the set and
      one synthetic { path, writeThrough = true } row per path once in New;
      Set and SetMany resolve a row-less listed path to that row, so it is
      stored raw (copy, no validate/normalize/onChange) and announced with
      the synthetic row. Every other row-less path is still refused.
      Stub header comment updated.
    - settings/Slash.lua: Sl:CliEnable (route a: CliSet when the row exists,
      else write through, NS.RefreshEnabled(), FormatKV echo; the
      library-absent line if even that is refused), Sl:CliLock (route b),
      Sl:LibraryAbsentLine via NS.L. NS.COMMANDS enable/disable/unlock/lock
      call them. The stale comment claiming announce("enabled") now names
      NS.RefreshEnabled() and says the row does not announce (R-09).
    - Slash degradation arm per LK-18's stub shape: Sl.DISABLED_LINE_FORMAT
      published on both arms (live = lib.DISABLED_LINE_FORMAT), DisabledLine
      formats from it; degraded PrintHelp prints the notice once then one
      "/pm <cmd>  <desc>" row per verb.
    - locales/enUS.lua: the library-absent key, documented as the one string
      routed through NS.L. ARCHITECTURE localization-§1 row, localization.md,
      slash-dispatch.md ("Library-absent load"), module-map.md, smoke-tests.md
      and locales/PostLoad.lua comment updated.
    - Tests (red first): three degraded/partial cases in test_libka0s.lua,
      two writeThrough cases in test_schema.lua, assertLibraryConstant in
      the Slash parity case. test-cases.md regenerated; badge 906 -> 911.

    Deviations:
    - core/LifecycleSetup.lua: NS.RefreshEnabled moved above the Lifecycle
      degradation branch, which returned before defining it; on a fully
      library-less load it was nil, so route (a) (and the AceDB profile
      callbacks) could not move the latch.
    - The Slash stub's UNAVAILABLE text no longer claims the help index is
      unavailable (it now prints one); the bare-/pm-without-config and
      unknown-verb fallbacks print the degraded index instead of the notice
      alone. The existing bare-/pm case was updated to match.
    - The stub's writeThrough also covers SetMany (same list, same plan),
      matching the library contract; the item named only R.Set.
    - No tests/run.lua surface-source entry was needed: assertLibraryConstant
      falls back to the mock LibStub.

    Finding: PanelMaster-R-09 (the settings/Slash.lua:292-293 part).

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 14f9656b91d0b090e5aae481860a96d03cb9c3e4
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:17:23 2026 +0530

    PM-08: address review — module-map rows for SafeRegisterEvent and rejectedEvents

    The core/CoreSetup.lua row now lists NS.SafeRegisterEvent among the seam's
    exports, gives its degraded single-pcall rung, and records that
    SafeRegisterUnitEvent and SafeRegisterEvents are deliberately not
    re-exported. The core/State.lua row now lists the session-only
    State.rejectedEvents, which the registration paths write and the debug dump
    reads.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 8ccee1cef510eb59a211bf874e73fd931a49b6d7
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:14:22 2026 +0530

    PM-08: Route every event registration through Core's SafeRegisterEvent

    NS.StandUp's three registrations and OnInitialize's PLAYER_LOGIN were bare
    RegisterEvent calls: an unknown name would raise out of the stand-up and
    leave the later registrations, Canvas:Enable and the repaint unbound, with
    no record anywhere (events-frames-taint-§1, finding PanelMaster-A-01).

    - core/CoreSetup.lua: live arm republishes lib.SafeRegisterEvent (Core
      minor 8) at column zero so the Core parity derivation checks it; the
      degraded arm gets a one-rung pcall stub that appends a refused name once.
      SafeRegisterUnitEvent / SafeRegisterEvents are not re-exported (no caller).
    - core/State.lua: session-only State.rejectedEvents.
    - core/LifecycleSetup.lua: NS.StandUp registers from a STAND_UP_EVENTS
      table through NS.SafeRegisterEvent and logs NS.Debug("Events",
      "rejected %s") on a false return. NS.StandDown keeps bare unregisters.
    - core/PanelMaster.lua: PLAYER_LOGIN goes through the same helper.
    - core/DebugLogSetup.lua: Diagnose ends with "rejected events: <n>
      (<names>)" or "rejected events: 0", so /pm debug dump reaches the list.
    - docs/debug.md, docs/ARCHITECTURE.md (Event Subscriptions): say so.
    - tests/test_disabled.lua: red-first cases for the IsEventValid rung and the
      C_EventUtils = nil rung (two stand-ups, one recorded name, dump line),
      the empty-list dump line, and the degraded stub directly.
    - tests/test_panel.lua: the F-013 source scan now matches the
      SafeRegisterEvent(self, "PLAYER_LOGIN" form.
    - docs/test-cases.md and the README badge regenerated (906).

    Deviations: the three StandUp registrations are a loop over a local table
    rather than three literal calls (same calls, same order, same logging).
    The source scan in tests/test_panel.lua had to follow the new call form.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 49ea41abdfc6790f093e5ca57f24e486da43b588
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:08:12 2026 +0530

    PM-07: Make C.MAX_GRID 64 and have the grid slider declare it

    The Grid size slider's max was a literal 64 while its validate and the
    drag clamp in modules/Unlock.lua read C.MAX_GRID, which was 128, so the
    three disagreed on the largest grid. No UI or CLI path could ever store
    more than 64 (the CLI clamps to the row's max), so the constant comes
    down to 64 and the settings.gridSize row declares max = C.MAX_GRID: the
    slider, the write seam and U.SnapPosition now share one maximum. A
    hand-edited SavedVariables value of 65-128 snaps on a grid of 64 at the
    next drag and is otherwise harmless; the Constants comment says so.

    Tests (red first): test_schema "the grid-size slider and the write seam
    share one maximum" and test_unlock "a grid above the slider's 64 snaps
    on a grid of 64". The existing 99999 clamp case keeps its value (100 on
    a 64 grid still lands on 128); its comment now names 64.
    tests/test_constants.lua never pinned 128 for the grid, so nothing to
    update there. docs/test-cases.md regenerated, README badge 902/902.

    Finding: PanelMaster-R-07

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 3174cc9b8ee1da5974333475a04c075d5433be78
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 09:04:18 2026 +0530

    PM-06: Keep the Panels page's per-panel Unlock tick on the real state

    The per-panel Unlock checkbox read NS.Unlock:IsPanelUnlocked once at
    build and had no refresher, so it could show a state the panel was not
    in: a global unlock left it unticked (and unticking it did nothing), a
    global lock cleared per-panel unlocks behind it, and a combat-deferred
    tick replayed at PLAYER_REGEN_ENABLED left it unticked (PanelMaster-R-08,
    review F-008).

    - settings/PanelEditor.lua: the tick gets a scalar refresher that
      re-reads IsPanelUnlocked and disables the box while the global unlock
      is on (also set at build); the tooltip says why it is grayed out.
      wirePanelsBus remembers its ctx in E.__ctx, and the new
      E:RefreshUnlock runs NS.Helpers.RefreshPanel(ctx, false), the scalar
      tier, which only repaints a shown page. No new bus message. File is
      1487 lines (+11 net, budget 1488).
    - modules/Unlock.lua: U:SetUnlocked, U:SetPanelUnlocked (non-deferred
      path) and U:ResumePending end with a presence-guarded
      NS.PanelEditor:RefreshUnlock() call (precedent modules/Registry.lua).
    - tests/test_panel.lua: 'Panels page: the per-panel Unlock tick tracks
      global, per-panel and deferred unlocks' covers (a) global unlock ticks
      and disables the box, global lock clears and re-enables it, and (b) a
      tick in combat is deferred and reads false, then OnRegenEnabled
      replays it and the box reads true. Confirmed red before the change
      ("the tick does not show the global unlock").
    - docs/test-cases.md regenerated, README badge 899 -> 900,
      docs/smoke-tests.md section 9 step 11 gains the Lock frame / combat
      checks.

    Deviations: the tooltip says "Grayed out" rather than the item's
    "Greyed out", because the localization-5 prose gate rejects British
    spellings. E.__ctx is assigned before the once-only guard in
    wirePanelsBus so it always names the registered page. The test points
    E.__ctx at its own freshly built page context (restoring it after),
    since the suite's page contexts are not the one P:Register wires.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit 823985315903f7e34a1c21bbe592b38ad54e004a
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 08:59:07 2026 +0530

    PM-05: Release mismatched frames before RenderAll renders any panel

    Panel ids are per profile, so a profile switch can hand the same pair
    of frame names to the same pair of ids the other way round. RenderAll
    resolved each id one at a time: id 1 asked for the name still held by
    active[2], found the pool empty, and CreateFrame'd a second frame under
    that global name, orphaning one frame on every switch (PanelMaster-R-05).

    - modules/Canvas.lua: RenderAll is now two passes over a file-local
      scratch table `want` (id -> NS.Registry.FrameName(rec)), refilled in
      place by fillWant so a rebuild allocates nothing. releaseMismatched
      returns every active frame whose id is gone or wants another name to
      the pool, and only then does each record Render. Render's single-id
      mismatch branch stays, and its comment now calls it the fallback for
      the per-id MSG_PANEL path. The pool comment says the one-frame-per-
      name bound now holds across a name-swapping profile switch.
      CCN: RenderAll 2, releaseMismatched 3, fillWant 3.
    - tests/test_profiles.lua: 'Profiles: swapping frame names across ids
      creates no second named frame'. Seeds P1 {1 = Alpha, 2 = Xray} and
      P2 swapped, switches six times through OnProfileChanged, counts
      named CreateFrame calls (0 after the first render), checks each name
      resolves to Canvas:FrameFor(id), and that PooledCount never grows.
      Confirmed red before the fix for the right reason (expected 0, got 6).
    - docs/test-cases.md regenerated, README badge 898 -> 899;
      docs/smoke-tests.md 12b-2 gains the swapped-names switch check.

    Deviations: the test keeps the two profiles itself and swaps them the
    way the mock's __switchProfile does (replace db.profile, fire
    OnProfileChanged) rather than calling NS.db:SetProfile, because the
    mock AceDB models one live profile table. The mock CreateFrame does not
    bind _G, so the wrapper records each named frame in a local `globals`
    table that stands in for _G (last CreateFrame wins, as in the client).
    Scratch clearing uses a pairs() loop, not wipe(), which luacheck does
    not know in this repo.

    Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01HTuhyvd3dgxDekBFUvKcoZ

commit cab60d8d2540017df2c554619b11f55825cb4478
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 08:01:47 2026 +0530

    PM-04: Bound /pm recover in the panel's scaled units via EffectiveScale

    applySpec calls SetScale before SetPoint, so a panel's stored x/y are in
    its own scaled units (own scale x master scale). R:Recover clamped them
    against Compat.GetScreenSize() in UIParent units, so at s=0.5 it dragged
    a visible panel inward and at s>1 it left a genuinely lost one in place.

    - core/Util.lua: Util.EffectiveScale(rec, settings) = own scale clamped
      to MIN/MAX_PANEL_SCALE (template fallback) x master scale (nil, <= 0 or
      non-number guarded to 1). Documented as the one definition render and
      recover share (options-ui-§15); the master-scale guard comment moved
      here from Canvas.
    - modules/Canvas.lua: addGeometry sets spec.scale from EffectiveScale;
      the local masterScale is deleted.
    - modules/Registry.lua: R:Recover reads the settings once and bounds with
      offsetRange(relPoint, w / s) / offsetRangeY(relPoint, h / s), with a
      comment on why the offsets are in scaled units.
    - tests: two Registry.Recover cases (scale 0.5 at 1.5 x screen width is
      left alone; master 2 at 0.75 x width is moved to w/2), confirmed red
      before the fix for the right reason; one Util.EffectiveScale case
      (clamp bounds, master nil/0/negative/junk -> 1, the product). The five
      scale-1 Recover cases and the test_canvas scale cases are unchanged.
    - docs/test-cases.md regenerated, README badge 895 -> 898;
      docs/schema.md explains the scaled-unit bound; docs/smoke-tests.md §10
      gains the Master scale 0.5 / 2 steps.

    Finding: PanelMaster-R-04.

    Deviation: the settings lookup (NS.db and ... or {}) lives in a small
    local currentSettings() rather than inline in R:Recover. Inline it took
    R:Recover to CCN 15 (at the cap); with the helper it stays at 12.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Ldej1stXpdhQLvEJxKqube

commit 9a85d626347fa0238740b9c35616aa83da7bd1df
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 07:56:29 2026 +0530

    PM-03: Flip combat visibility at combat start from the REGEN event

    "Only in combat" and "Only out of combat" never flipped at the pull:
    Compat.InCombat() asked InCombatLockdown, which starts after
    PLAYER_REGEN_DISABLED, so OnRegenDisabled rebuilt every spec with
    inCombat=false and the out-of-combat look held for the whole fight.

    - core/Compat.lua: Compat.InCombat prefers UnitAffectingCombat("player")
      (presence-guarded), falls back to InCombatLockdown, else false.
      Comment rewritten: display reads the combat flag
      (events-frames-taint-§2); lockdown starts after REGEN_DISABLED.
    - modules/Canvas.lua: Render(id, inCombat) defaults a nil inCombat to
      NS.Compat.InCombat(); RenderAll(inCombat) and RenderForCombat(inCombat)
      thread it through. BuildSpec stays pure.
    - core/PanelMaster.lua: OnRegenDisabled -> RenderForCombat(true);
      OnRegenEnabled -> ResumePending, then RenderForCombat(false).
    - modules/Unlock.lua: unchanged gate; SetUnlocked comment says why it
      keeps asking InCombatLockdown (a lockdown question, not a display one).
    - .luacheckrc: UnitAffectingCombat in read_globals (test_lintconfig does
      not pin the list, so nothing to extend there).
    - tests/test_canvas.lua: the combat case now delivers OnRegenDisabled
      with the flag still false (client order) and a mirrored inCombat case
      was added, both marked "red under: drop the explicit inCombat argument
      from OnRegenDisabled". Confirmed red before the fix and red again with
      the argument dropped.
    - tests/test_compat.lua: three InCombat cases (flag vs lockdown diverged
      locally in the case, the lockdown fallback, both APIs absent). The kit
      mock is untouched.
    - docs: smoke-tests §8 gains the Only-in-combat / Only-out-of-combat pull
      checks; ARCHITECTURE, data-flow and performance event tables show the
      explicit argument; test-cases.md regenerated (895) and README badge.

    Findings: PanelMaster-R-03, PanelMaster-R-06.

    Deviations: the ARCHITECTURE / data-flow / performance event-table
    updates are not named in the item; they keep the docs matching the code.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Ldej1stXpdhQLvEJxKqube

commit af56239578386232f2b30af4663c90d223f97d9f
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 07:51:14 2026 +0530

    PM-02: Strip the unlock overlay while stood down, and test the routes

    Canvas:Render read the stand-down latch only to set spec.shown = false,
    then called NS.Unlock:Decorate unconditionally. Decorate shows an
    unlocked panel regardless of spec.shown and arms drag on it, so a
    disabled addon still drew, outlined and let the player drag every
    unlocked panel (and a drag wrote db.profile.panels while the addon was
    off). That broke slash-commands-§7's "disabled is total".

    Render now reads the latch once. Stood down, it calls
    NS.Unlock:StripOverlay (hidden, mouse-transparent, not movable) and
    Decorate never runs; otherwise Decorate runs as before. The session
    unlock state (NS.State.unlocked, unlockedPanels) is untouched, so
    NS.StandUp -> RenderAll decorates again from current state
    (performance-§6). No imperative hide or force-lock was added to
    NS.StandDown (anti-pattern #85). The stand-down rung comment and the
    header note on the method-presence guards now cover both branches.
    Render stays at CCN 13.

    Test first: "Disabled 5b" in tests/test_disabled.lua drives route A
    (unlock, then disable), route B (disabled, then the state.locked row and
    `/pm set state.locked false`) and route C (disabled, then a per-panel
    unlock). It asserts no panel is shown and none takes the mouse, then
    re-enables and asserts both panels come back shown and draggable. Before
    the Canvas change it went red with shown = 2/2/2/1 for A/B-schema/
    B-slash/C. It carries the "red under" line.

    docs/test-cases.md is regenerated (891), the README badge is bumped to
    891/891, and docs/smoke-tests.md §7 gains step 13 (unlock, then disable;
    untick Lock frame and tick a panel's Unlock while disabled; enable).

    Findings: PanelMaster-R-01, PanelMaster-R-02.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Ldej1stXpdhQLvEJxKqube

commit 3abaa9008756dfc856efa489db24c6400698786d
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 07:46:59 2026 +0530

    PM-01: Bring the Schema stub to v1.56.0: normalize, id forwarding, tests

    The host degradation stub in settings/Schema.lua (hostSchemaStub) now
    matches LibKa0s-Schema-1.0 minor 2 on everything but the log and tally:
    - prepare() runs row.normalize(value, rid) after validate and before the
      nowhere-to-store refusal; the returned value is what gets stored, and a
      nil answer refuses as `false, "invalid value", why` (Set) or
      `false, "invalid value", why, i` (SetMany), nothing stored.
    - R.Get(path, id) hands id to row.get; R.ApplyDefault(row, id) forwards
      id to R.Set (LK-22 R-14 parity).
    - The header comment names SetMany, normalize and the id forwarding, and
      cites docs/api/Schema/version-2-docs.md.
    SetMany itself (and the prepare/commit split) landed in PM-00; verified
    here, not redone. Every stub function stays at CCN 10 or below.

    Tests (tests/test_schema.lua), on degraded arms built with
    tests/degraded_env.lua loadPartial({ Schema = true }):
    (a) SetMany stores every entry in order and runs each onChange
    (b) SetMany is all-or-nothing (gridSize 999 -> false, "invalid value",
        nil, 2; entry 1 unstored; no onChange)
    (c) SetMany with opts.act runs inside one bracket
    (d) the live runtime and the stub answer SetMany identically (answers,
        arity and stored values over three batches)
    plus two for the new behavior: row.normalize (replace / refuse) and
    Get/ApplyDefault id forwarding. The normalize and id cases were red
    first (7.6 stored unnormalized; row.get got nil). (a)-(d) were checked
    red by deleting R.SetMany from the stub in a scratch copy ("attempt to
    call field 'SetMany'", and the surface parity case red), as the
    "red under" comment says.

    docs/test-cases.md regenerated (884 -> 890) and the README Tests badge
    rolled with it. The regeneration also restores the section sign in
    three kit case names (localization-§5, layout-§1) that the previous
    inventory had without it; that is the runner's own output.

    Deviations: (a)-(d) were not red before this item's stub change, because
    PM-00 already added SetMany; the red was confirmed by deletion instead.
    PM-00's phase 2 order (every store, then every onChange, the live
    commitBatch order) is kept rather than the item's per-plan store+onChange.
    No other PanelMaster red from the LK dry-runs remained after RV-PM/PM-00.

    Findings: none (the item resolves no finding ids).

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Ldej1stXpdhQLvEJxKqube

commit 3a09ad830e42102de71811ce418a221cd81a3efc
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 07:42:12 2026 +0530

    PM-00: Give the Schema degradation stub SetMany, clearing the RV-PM red

    RV-PM re-vendored LibKa0s v1.56.0 and recorded one red:
      Parity: the Schema seam's degraded surface matches the live one, on
      both levels -- schema instance vs host stub: SetMany is missing
      (live: function)
    Schema minor 2 added SetMany to the live instance; hostSchemaStub() in
    settings/Schema.lua did not have it.

    This does the "stub gains SetMany" part of PM-01 here, as PM-00 directs:
    - R.Set's body is split into local prepare (find target, validate,
      refuse nowhere-to-store; answers a plan or nil, err, why) and small
      store / react / announceOne helpers. Set's observable order is
      unchanged: refuse, validate, store, react, announce.
    - New R.SetMany(entries, opts): phase 1 prepares every entry and
      answers false, err, why, i on the first refusal (unknown path or
      invalid value) with nothing stored; phase 2 stores and runs onChange,
      inside R.BulkRun when opts.act is set; then d.announceBatch once when
      the host has one, else d.announce per write.

    Left to PM-01 (it will find the above done): row.normalize in prepare,
    id forwarding on R.Get / R.ApplyDefault, the header comment naming
    SetMany and normalize, and the test cases (a)-(d) in tests/test_schema.lua.

    Deviation from PM-01's text: phase 2 runs every store and then every
    onChange (the live Schema.lua commitBatch order, so a reaction reading a
    sibling row sees the whole batch), rather than store+onChange per plan.
    The helper is named announceOne, not announce, because a file-level
    local announce already exists (lint W431 shadowing).

    Suite (all bounded): tests/run.lua 884 passed, 0 failed (the parity case
    green); lint 0 warnings / 0 errors in 60 files; the CCN 15 complexity
    run prints nothing (largest new function prepare, CCN 7); no authored
    .lua file over 1500 lines. No tests/perf.lua.

    Findings: none (the item resolves no finding ids).

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Ldej1stXpdhQLvEJxKqube

commit b26ab40f6c7c8a9ddbae381aa7504b9dd7ea18a6
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 24 04:40:51 2026 +0530

    RV-PM: Re-vendor LibKa0s v1.56.0 and record its delta bundle

    Replace libs/LibKa0s/ and tests/_kit/ whole from the local tag v1.56.0
    (tag 4622018 -> commit 514fc0a), extracted with git archive, and roll the
    CLAUDE.md provenance line v1.55.0 -> v1.56.0 in the same commit. Fifteen
    library files move a minor (Core 8, Lifecycle 2, Bus 2, Schema 2, Item 2,
    Media 4, Widgets 10, DebugLog 13, Slash 15, Launcher 2, Options 24,
    OptionsWidgets 31, OptionsTabs 4, OptionsScroll 4, Perf 13); the kit goes
    from revision 25 to 26 and gains asserts.lua, mock_events.lua and
    prose_lists.lua. Both payloads diff empty against the tag, with and
    without --strip-trailing-cr; the runner keeps mode 100755.

    Adds the frozen bundle docs/revendor/2026-09-23-v1.56.0/ (01_DELTA.md,
    05_SUMMARY.md), written by hand from the local wow-addon
    revendor-libka0s.md as amended by WA-01: base, per-file minors, both
    payload diffs, kit pairing 25 -> 26, the consumption map and the
    contract delta. No contract blocker. Adoption is left to the M3 items.

    Suite after the copy (all through ka0s-bounded):
    - tests/run.lua: 883 passed, 1 failed, 0 skipped, 884 total (baseline
      884/884). The one red is caused by the stricter kit/library, as the
      item permits:
        Parity: the Schema seam's degraded surface matches the live one, on
        both levels -- schema instance vs host stub: SetMany is missing
        (live: function)
      PM-01 clears it (the Schema stub gains SetMany).
    - luacheck: 0 warnings / 0 errors in 60 files.
    - lizard CCN 15 warning run: nothing above 15; largest authored file
      1476 lines.

    docs/test-cases.md and the README test badge are left stale on purpose
    (kit case names now carry the section sign); PM-DOCS regenerates them.
    The span back-fill of unrecorded tags is PM-18, not written here.

    Findings: none (the item resolves no finding ids).

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Ldej1stXpdhQLvEJxKqube

commit 7183100ee4f6ca8a2a9989119bdf342a3406b52e
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 23 20:50:41 2026 +0530

    Record the 2026-09-23 review and standards audit

    The frozen docs/reviews/2026-09-23/ and docs/audits/2026-09-23/ bundles
    from the collection-wide sweep. Findings are collated and planned in
    Ka0sAddonsCommonTasks/docs/2026-09-23-REVIEW_AND_STANDARDS_AUDIT_REMEDIATION/.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Ldej1stXpdhQLvEJxKqube

commit ce0b70501f420333d934e2ed150c01876ab046fc
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 23 19:09:11 2026 +0530

    Count Schema among the adopted LibKa0s majors in CLAUDE.md

    The v1.55.0 pass made LibKa0s-Schema-1.0 the settings runtime, but the
    agent brief still said eight of twelve majors were adopted. The vendored
    library ships fifteen, and nine are consumed here, which is what
    docs/module-map.md already says.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01TTuxA9sSHE1H7JLgJ4kYAx

commit ce0b70501f420333d934e2ed150c01876ab046fc
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 23 19:09:11 2026 +0530

    Count Schema among the adopted LibKa0s majors in CLAUDE.md

    The v1.55.0 pass made LibKa0s-Schema-1.0 the settings runtime, but the
    agent brief still said eight of twelve majors were adopted. The vendored
    library ships fifteen, and nine are consumed here, which is what
    docs/module-map.md already says.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01TTuxA9sSHE1H7JLgJ4kYAx

commit c595035cc0fb9dcde61ab8add3db43a6eebdc7ac
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 23 16:54:43 2026 +0530

    Pin the player's JC-5 path and name the walk case for what it asserts

    The case that drives the library's RestoreDefaults("general") walk still
    claimed the General page's Defaults closes the console; that button is the
    profile reset and never writes the row. Rename it, and add the path a player
    actually meets: /pm reset state.debugConsole through NS.Slash:OnSlash, which
    closes the console (the row and the window). Dropping
    defaults.debugConsole = false turns both red.

    Bring the v1.55.0 bundle's summary in line with its corrected in-game check,
    rewrap its long prose lines, and roll test-cases.md and the badge to 884.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01TTuxA9sSHE1H7JLgJ4kYAx

commit 9923388de7604c6ffe04f64d16da537c94ef4daa
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 23 16:51:17 2026 +0530

    Name the v1.55.0 re-vendor bundle for its tag

    audit-review-history requires a re-vendor bundle folder shaped
    <YYYY-MM-DD>-v<tag>. This run's bundle was written to a bare-dated
    folder because the sweep's brief named the wrong path. The folder is
    renamed to 2026-09-23-v1.55.0 and every reference follows it. The
    bundle's contents are unchanged.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01TTuxA9sSHE1H7JLgJ4kYAx

commit b473776a58fc083c599e7174095c4c29591f63a0
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 23 15:34:00 2026 +0530

    Correct the in-game check that expected Defaults to close the console

    The General page's Defaults button is the profile reset (P:RestoreDefaults
    through ConfirmResetAll to db:ResetProfile). It never writes the
    session-only state.debugConsole row, so an open console stays open, at
    b7edc9f and now. The check asked the owner to expect the opposite.

    JC-5 lives on the row reset instead: /pm reset state.debugConsole closes
    the console, and with defaults.debugConsole = false dropped it does not.
    The summary's check is split into that step and the minimap step that
    survives Reset all settings. The same claim is corrected in
    03_DECISIONS.md and in the settings/Schema.lua comment (comment only).

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01TTuxA9sSHE1H7JLgJ4kYAx

commit 46b86e2431c7bcbb84d3888096cc87d545ac646b
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 23 15:21:49 2026 +0530

    Record the v1.55.0 adoption pass, and roll the test inventory to 883

    docs/revendor/2026-09-23 gains 02_CANDIDATES through 05_SUMMARY. Schema
    was adopted (d830303, af8a935). The Bus Catalog was deferred as optional
    (#52, state:triaged) and Compat was declined as a structural misfit (#53,
    state:will-not-do). docs/test-cases.md is regenerated and the README
    badge follows it.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01TTuxA9sSHE1H7JLgJ4kYAx

commit af8a935830c8e2e5533c1fe81fea1ea83f390db4
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 23 15:19:44 2026 +0530

    Adopt LibKa0s-Schema-1.0 as the settings runtime, keeping every seam name

    settings/Schema.lua keeps its rows and builds one LibKa0s-Schema-1.0
    instance (NS.SchemaRuntime) for the path walk, the row index, the write
    seam, the bulk bracket and the boot shape check. NS.Schema:Set, :Get,
    :FindRow, :Default, :Register and S.BulkBegin/BulkEnd/BulkLine delegate
    to it, so no caller moved. The Options and Slash descriptors take the
    instance's members as values.

    - The minimap inversion leaves the seam and becomes the composed row's
      own get/set, so nothing sits in front of Set.
    - The composer's defaults gain debugConsole = false. The runtime reads a
      nil default as "no restore", and the General page's Defaults has
      always closed an open console.
    - The refusal texts stay "unknown path: <path>" and "invalid value",
      through a plain-table descriptor L.
    - Register is Validate with a global-aware defaults root. It now counts
      shape errors as well as unresolved paths.
    - The profile reset's snapshot count stays host-side, as the design
      allows.

    Without the library the seam falls back to hostSchemaStub, which is
    write-completing and log-silent and stands in for both the library and
    the instance. The parity suite pins both levels, and test_schema drives
    one degraded write per writer kind: /pm set and /pm disable, Reset All,
    the page Defaults and a Registry bulk act. The six contract cases from
    the previous commit pass unchanged. Two tests that appended a probe row
    by hand now go through AddRows and Reindex, and the bracket-depth checks
    read InBulk().

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01TTuxA9sSHE1H7JLgJ4kYAx

commit d8303035765ab9867b8920f277919ee6b6375e19
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 23 15:10:13 2026 +0530

    Pin the schema write seam's contract before the library takes it

    Six cases in tests/test_schema.lua, each green against the host's own
    S:Set / S:Get: the refusal texts and arity, a write answering exactly
    true, the [Set] line before onChange, a raising onChange propagating
    after the store, an interior-path read answering the stored table, and
    the General page's Defaults closing an open debug console (the row
    declares no default today).

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01TTuxA9sSHE1H7JLgJ4kYAx

commit b7edc9f663cf43ab15ebe46c65a3f73a23269690
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 23 14:55:43 2026 +0530

    Re-vendor LibKa0s v1.55.0, and hand the cap gate to the kit

    Both payloads copied whole from the v1.55.0 tag with the CLAUDE.md
    provenance line rolled in the same commit. No existing file's minor
    moves; Compat, Bus and Schema arrive as new majors and are not adopted
    here. Kit revision 25 ships the layout-1 cap gate, so the local
    tests/test_layout_cap.lua and its bare suite entry are retired in favor
    of the kit's pair-form declaration.

    The census is renamed to "Files over the 1500-line cap" and moved under
    Documented deviations, where the kit's gate reads it, stating that
    nothing is over the cap today. The 1000-1500 band leaves the hub for
    the release watch list, which already dispositions all four band files.
    The delta read is recorded in docs/revendor/2026-09-23/01_DELTA.md.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01TTuxA9sSHE1H7JLgJ4kYAx

commit eb4b4a84235253c2611a31854b757f65b18df4d5
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 23 11:33:56 2026 +0530

    Bring .gitattributes to the line-endings-§5 canonical body (standard v2.63.0)

    The client-bound body now carries the `*.py text eol=lf` carve-out and
    the shebang-file comment block that replaced the shell-only wording.
    The path-keyed appendix for tools/artwork/bin/realesrgan-ncnn-vulkan
    is kept unchanged below the body, so the file still diffs clean against
    the canonical text plus a conforming appendix.

    The four tracked .py files under tools/artwork and tools/sunn were
    already stored LF in the index; their CRLF working copies were
    re-checked-out so the tree agrees with the new pin. No content change,
    nothing renormalized in the index.

    The rest of the standards reference was already current: X-Standard,
    the bare README badge and the CLAUDE.md compliance block all match, and
    the retired-notation sweep finds no hits outside frozen bundles.

    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01TTuxA9sSHE1H7JLgJ4kYAx

commit e30e329557d7dee0e5af467927444042c21c2b3a
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Tue Sep 22 21:05:05 2026 +0530

    Adopt the kit's US-English gate, and delete the copy this repo was keeping

    LibKa0s v1.54.2 re-vendored, both payloads whole. The library bytes are identical to v1.53.0 --
    kit revision 24 changes no library file -- so what actually arrives here is tests/_kit/test_prose.lua
    and one line in tests/run.lua declaring it.

    WHAT CAME OUT IS THE POINT. localization-5 says wire the kit's gate or your own and never both,
    because two gates over one rule is two copies of a list each required to be carried WHOLE. So the
    hand-written one goes: seven repositories in this collection had written that gate themselves under
    three different filenames, which is why nothing could tell at a glance which repositories had one.

    COVERAGE WENT UP ON THE SWAP, which is why this is not a lateral move. The hand-written gates
    walked a glob of the addon's own source. The kit's reads the tracked set out of git, so the TOC,
    the docs, the locale files and .luacheckrc are held to the same rule -- and its exclusions are a
    named list rather than whatever a glob happened to miss. Everything the sweep corrects below was
    invisible to the gate that was here yesterday.

    WHERE A SPELLING IS NOT THIS REPO'S ENGLISH TO CORRECT it goes in tests/prose_waivers.lua, per FILE
    and per WORD, with the reason beside it -- never per file alone, which would hide every other
    British spelling in a file this repo edits often. A waiver is a debt where it stands in for work
    that is owed, and it says so.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YRNj7EQPJHjuxLUH6jv4xk

commit ff4bef0467b00a49d787180565adbbe8bf63836e
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Tue Sep 22 19:38:47 2026 +0530

    Close out the documentation drift the sync pass reported but could not act on

    The sync run surfaced every hit its own rules fenced it away from: comment citations, which need a
    named replacement rather than a guessed one; count claims it could see but not settle; residual
    British spellings; and one root doc that was genuinely owed. This is that list worked through, each
    item either corrected against evidence in the tree or left alone with the reason recorded.

    A comment naming a file that is gone is not automatically wrong. Most of them name the absent thing
    ON PURPOSE -- "it used to be ours", "which is why that file is gone rather than emptied", "has not
    existed since debug logging moved to LibKa0s" -- and correcting those would delete the explanation
    they exist to give. They were read individually and left. What was corrected is the other kind: a
    citation whose target moved, a count that no longer counts, a claim the cited line does not support.

    Nothing that runs was touched. No version string moved, no export was deleted, no generated doc was
    hand-edited, and the vendored payloads are untouched. Every correction was re-checked against the
    code by a pass that did not write it, and the green gate was re-run from scratch afterwards.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YRNj7EQPJHjuxLUH6jv4xk

commit 78f751587ba32aaccb08f09665b647dfa5e39121
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Tue Sep 22 18:06:29 2026 +0530

    Sync the docs to what the code actually does

    A /wow-addon:sync-docs pass over the whole collection, each repo's drift found against its own
    source and each correction carrying the evidence that settled it: a count re-counted, a file:line
    re-grepped, a load order read back off the TOC, a doc-map row checked against the directory in both
    directions.

    Documentation only. No version string moved, nothing under libs/ or tests/_kit/ was touched, and no
    comment was edited -- the comment-citation check ran and its hits are reported rather than applied,
    because that correction needs a named replacement and there was nobody to name one. Dead exports and
    missing Tier 1 docs are likewise surfaced, not acted on.

    Every claim added or changed here was re-verified against the code by a second pass that had not
    written it, and the green gate was re-run from scratch afterwards: several suites in this collection
    read the docs, so a documentation edit can and does turn them red.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YRNj7EQPJHjuxLUH6jv4xk

commit f2b08e28b01ad05523d9dd3ba06fe7e05c0b043c
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Tue Sep 22 17:12:17 2026 +0530

    Re-vendor LibKa0s v1.53.0

    OptionsWidgets minor 30 (LibKa0s-Options-1.0 23.30.3.7.3); every other file
    unchanged from v1.52.0, kit at revision 23. Payload taken from the v1.53.0 tag
    and verified identical, and the provenance line in CLAUDE.md moves with the
    bytes rather than after them.

    O.IdInput's Add button is now the height of the edit box beside it. It was
    never mis-anchored -- AceGUI's labeled EditBox publishes alignoffset = 30 and
    Flow honors it, so the two centers were one pixel apart. The button was 24 tall
    against InputBoxTemplate's 20-tall border art, so it overhung 2px at each end,
    and the overhangs do not read alike: the top one sits against the row's gold
    caption and the bottom against empty dark, which is what reads as "higher".

    Nothing to adopt: no new member, no new field.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YRNj7EQPJHjuxLUH6jv4xk

commit 9e024d559da5ecd7787b026489fbc58c3143925b
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Tue Sep 22 10:22:38 2026 +0530

    Re-vendor LibKa0s v1.52.0

    Both payloads copied whole from the v1.52.0 tag -- libs/LibKa0s/ and
    tests/_kit/ -- and the CLAUDE.md provenance line rolled in the same
    commit, from v1.51.0.

    Minor 29 is mostly a fix to the library's own v1.51.0: the O.IdList help
    mark reserved too little of the row for its absolute frame, so the column
    fit correctly collapsed every list that adopted `help` to one column.
    This addon adopts none of the help surface, so nothing here changes.

    Gate: lint 0 warnings / 0 errors in 61 files; 849 passed, 0 failed, 0 skipped, 849 total

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YRNj7EQPJHjuxLUH6jv4xk

commit c8d924f814818ddae500e95c0f97fe51109d19a2
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Tue Sep 22 02:25:12 2026 +0530

    Re-vendor LibKa0s v1.51.0

    Both payloads copied whole from the v1.51.0 tag -- libs/LibKa0s/ and
    tests/_kit/ -- and the CLAUDE.md provenance line rolled in the same
    commit, from v1.50.0.

    Minor 28 adds three OPTIONAL O.IdList spec fields (entry.help,
    spec.helpIcon, kind.suggestTag) which this addon does not use, and one
    behaviour change that arrives without being asked for: every id-list row
    lights under the cursor now, not only above one column.

    Gate: lint 0 warnings / 0 errors in 61 files; 849 passed, 0 failed, 0 skipped, 849 total

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YRNj7EQPJHjuxLUH6jv4xk

commit 10e66102a106f3106f67041f3ce380fd06fbc49f
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Mon Sep 21 14:56:04 2026 +0530

    Re-vendor LibKa0s v1.50.0

    Both payloads copied whole from the v1.50.0 tag -- libs/LibKa0s/ and
    tests/_kit/ -- and the CLAUDE.md provenance line rolled in the same
    commit, from v1.50.0.

    No surface this addon uses changed, so there is nothing to adopt:
    v1.50.0's member manifest is identical to OptionsWidgets minor 26's, and
    the four O.IdList follow-ups behind it are fixes rather than new surface.

    Gate: lint 0 warnings / 0 errors in 61 files; 849 passed, 0 failed, 0 skipped, 849 total

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YRNj7EQPJHjuxLUH6jv4xk

commit cdc13ffc25743a61b515861c570097cb764f6466
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Sep 20 19:56:23 2026 +0530

    Re-vendor LibKa0s v1.47.0

    OptionsWidgets minor 24: O.IdList takes a `columns` count, packing entries
    row-major (1 2 / 3 4) into a Flow row, clamped to ID_COLUMNS_MAX of 2. Default
    1 draws exactly what minor 23 drew, so a spec that never heard of the option is
    unchanged. An entry with a note still takes a full-width row of its own, and
    above one column an entry name no longer wraps -- it truncates from the tail,
    which is where the gray `(id)` sits.

    Not adopted, and there is nothing here to adopt it into: this addon builds no
    id list. The only mention of the surface in authored code is the inert stub in
    `settings/OptionsSetup.lua:92`, which exists for the surface-parity case -- its
    own comment says "No page in this addon builds one, so each is INERT". Panels
    are managed through the Panels editor and the registry, not through a typed-id
    list, so no call site exists to widen and no new test was warranted.

    OptionsWidgets.lua is the only payload file that moved; the kit stays at
    revision 23 and the runner keeps mode 100755. The CLAUDE.md provenance line
    moves in this commit with the bytes. No other file in the repo stamps the
    vendored version -- `docs/data-flow.md:193` names v1.46.1 as the release the
    combat lock shipped in, which is history and stays put.

    Battery: 849 passed, 0 failed, 0 skipped (vendor-sync compared against
    v1.47.0); lint 0/0 over 61 files; docs/test-cases.md regenerates byte-identical.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YRNj7EQPJHjuxLUH6jv4xk

commit cdc13ffc25743a61b515861c570097cb764f6466
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Sep 20 19:56:23 2026 +0530

    Re-vendor LibKa0s v1.47.0

    OptionsWidgets minor 24: O.IdList takes a `columns` count, packing entries
    row-major (1 2 / 3 4) into a Flow row, clamped to ID_COLUMNS_MAX of 2. Default
    1 draws exactly what minor 23 drew, so a spec that never heard of the option is
    unchanged. An entry with a note still takes a full-width row of its own, and
    above one column an entry name no longer wraps -- it truncates from the tail,
    which is where the gray `(id)` sits.

    Not adopted, and there is nothing here to adopt it into: this addon builds no
    id list. The only mention of the surface in authored code is the inert stub in
    `settings/OptionsSetup.lua:92`, which exists for the surface-parity case -- its
    own comment says "No page in this addon builds one, so each is INERT". Panels
    are managed through the Panels editor and the registry, not through a typed-id
    list, so no call site exists to widen and no new test was warranted.

    OptionsWidgets.lua is the only payload file that moved; the kit stays at
    revision 23 and the runner keeps mode 100755. The CLAUDE.md provenance line
    moves in this commit with the bytes. No other file in the repo stamps the
    vendored version -- `docs/data-flow.md:193` names v1.46.1 as the release the
    combat lock shipped in, which is history and stays put.

    Battery: 849 passed, 0 failed, 0 skipped (vendor-sync compared against
    v1.47.0); lint 0/0 over 61 files; docs/test-cases.md regenerates byte-identical.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01YRNj7EQPJHjuxLUH6jv4xk

commit 940bb11223943939d8de321d898c1d7a048543cd
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Sep 20 02:27:21 2026 +0530

    Align the version to the 1.1.1 tag; document the settings combat lock

    The published 1.1.1-release tag sits on a rebuild of 1.1.0 while the TOC
    and NS.version still read 1.1.0. Bump both (and the strings the smoke
    tests and a Database.lua comment quote) to 1.1.1, and record 1.1.1 in
    Version History as a re-triggered build with no functional changes. The
    unreleased work since the tag stays out of that row.

    The README Troubleshooting table and docs/smoke-tests.md had nothing on
    the LibKa0s v1.46.1 settings combat lock: add a Troubleshooting row and
    a combat-gating smoke step (§ 8 step 7).

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01WkU3isSkvWPZkWVr51uZKo

commit 47cda865b268965f83796c071fec098399e4a241
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sun Sep 20 02:13:02 2026 +0530

    Sync docs: options-page combat lock, Compat class color

    data-flow.md's combat-gating section described only the /pm config
    refusal; LibKa0s v1.46.1 (Options minor 22) now also covers a page that
    is on screen in combat and refuses writes until PLAYER_REGEN_ENABLED.
    The compat-layer row in ARCHITECTURE.md still listed class color as
    Compat's, which LibKa0s-Core minor 7 took over (core/Compat.lua:84-94).

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01WkU3isSkvWPZkWVr51uZKo

commit 11e3d562b24c05bd949476b7d5f3a59764426133
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 19 21:47:16 2026 +0530

    Re-vendor LibKa0s v1.46.1

    The combat lock (standard v2.60.0, options-ui-§2/§13): a settings page
    shown in combat is covered and refuses writes, Defaults and tab
    switches until combat ends; the library never closes Blizzard's
    settings window from addon code. v1.46.1 registers its combat events
    only while a page is on screen.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01WkU3isSkvWPZkWVr51uZKo

commit 11e3d562b24c05bd949476b7d5f3a59764426133
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 19 21:47:16 2026 +0530

    Re-vendor LibKa0s v1.46.1

    The combat lock (standard v2.60.0, options-ui-§2/§13): a settings page
    shown in combat is covered and refuses writes, Defaults and tab
    switches until combat ends; the library never closes Blizzard's
    settings window from addon code. v1.46.1 registers its combat events
    only while a page is on screen.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01WkU3isSkvWPZkWVr51uZKo

commit 47dd30555bf1ce9ef128b095880a2c21b17fb374
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 19 16:32:24 2026 +0530

    Re-vendor LibKa0s v1.45.0

    OptionsWidgets minor 22 (LibKa0s-Options-1.0 21.22.1.7.3): the opt-in row field shownWhen draws a
    row only while a selector path holds a given value, and re-renders the page once, on the next
    frame, when the selector changes. Absent, a render is unchanged; this addon does not use it (see the
    adoption sweep in Aura Master's docs/superpowers/plans/2026-09-19-smoke-feedback.md, Task 17).
    Every other payload file is byte-identical to v1.44.0; the kit stays at revision 23.

    Battery: 849 passed, 0 failed, 0 skipped (vendor-sync compared against v1.45.0); lint 0/0;
    complexity check no new warning; perf none.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_019uT32jXujZ279wBVAwHhEU

commit 47dd30555bf1ce9ef128b095880a2c21b17fb374
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 19 16:32:24 2026 +0530

    Re-vendor LibKa0s v1.45.0

    OptionsWidgets minor 22 (LibKa0s-Options-1.0 21.22.1.7.3): the opt-in row field shownWhen draws a
    row only while a selector path holds a given value, and re-renders the page once, on the next
    frame, when the selector changes. Absent, a render is unchanged; this addon does not use it (see the
    adoption sweep in Aura Master's docs/superpowers/plans/2026-09-19-smoke-feedback.md, Task 17).
    Every other payload file is byte-identical to v1.44.0; the kit stays at revision 23.

    Battery: 849 passed, 0 failed, 0 skipped (vendor-sync compared against v1.45.0); lint 0/0;
    complexity check no new warning; perf none.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_019uT32jXujZ279wBVAwHhEU

commit 82a7f8017ab4fd9f20c9e91e479e9ec7b4d5914d
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Sat Sep 19 09:58:46 2026 +0530

    Re-vendor LibKa0s v1.44.0

    OptionsWidgets minor 21 arrives (opt-in removeStyle = "icon" on O.IdList);
    every other major is byte-identical to v1.43.0. Test kit stays at revision
    23 (byte-identical, no changes).

    Battery: lua tests/run.lua 849 passed, 0 failed, 0 skipped (vendor-sync ran
    for real and passed); lint 0 warnings / 0 errors; complexity check clean,
    no new function above CCN 15; no tests/perf.lua in this repo.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_019uT32jXujZ279wBVAwHhEU

commit eaa7807510620a557e7879ada66ff6e872aba068
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 17 20:19:02 2026 +0530

    Re-vendor LibKa0s v1.43.0: kit revision 23 bounds every run and stops holding built instances

    The kit now re-launches each run under a depth limit, a systemd scope
    memory cap, ulimit -v and a timeout, and holds every case to a heap
    budget, a leak gate and a CPU ceiling. Its mock no longer keeps every
    instance a case built alive. The library payload is byte-identical.

    DEPENDENCIES.md re-points its tests/_kit/framework.lua line citations.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Qy4TpGt4ZzGBCHP5hejntU

commit d5ed125ea433b4d008597645192fe54b7577d053
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Thu Sep 17 18:33:44 2026 +0530

    Disabling the addon stands it down, and a perf run takes the same latch

    Adopts LibKa0s-Lifecycle-1.0 (vendored from LibKa0s v1.42.0) the way the rest
    of the collection already has: core/LifecycleSetup.lua owns the one latch with
    its two holds — the stored `disabled` state and a perf run — and a disabled
    addon registers nothing, runs no timer, draws nothing and writes nothing from a
    game event. The slash dispatcher and settings registration stay live, so every
    reserved verb, `config` and the schema CLI still answer while disabled
    (slash-commands-§2/§7 as of standard v2.58.0).

    tests/test_disabled.lua is the conformance suite, over the kit's new
    mock_record.lua recording registry. Suite 834 -> 849, badge and
    docs/test-cases.md with it.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01FBmHJjW22defmzscncENmu

commit 8181d1d767bea5ef55cb29d0b6b3b367bdbffbd3
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 19:45:46 2026 +0530

    Record the four-suite run of 2026-09-16

    The battery had not run since this morning, so the record lagged every commit of
    today's launcher cycle. This is that run: the frozen bundle, its ANALYSIS.md and
    the row prepended to RESULTS.md.

    Generated by tests/_kit/run-automated-tests.sh. The watch list's Disposition
    column is the only authored cell in the file (automated-tests-§4).

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_019r6eqKPKL93nb93aiiZwsh

commit 3c4005abd6ae7266f56c289b9f78b910b032665d
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 18:08:00 2026 +0530

    The Master controls comment counts its own rows correctly

    One comment block gave three different numbers for the same tab. It said the
    composer exists because addons "were about to hand-write the same eight rows",
    then said a library-less install loses "these six rows ... all six are the
    composer's". The tab holds SEVEN, pinned by tests/test_schema.lua:267 and stated
    correctly in docs/ARCHITECTURE.md -- so the prose disagreed with the test, the
    docs and itself.

    Both numbers were defensible once and neither is now. Eight is the canonical set
    at its fullest, and this addon takes seven of them: it is exempt from the Test
    mode row under options-ui-§15, unlocking being its preview. The comment now says
    both, in that order, so the next reader is not left deriving which number the
    sentence meant.

    Also: "Nine addons" is eleven.

    Comment only; no behaviour. 834 passing, lint 0/0 in 59 files.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_019r6eqKPKL93nb93aiiZwsh

commit b6d69abe9d7191fb634861270d75e4ee530d0394
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 17:55:55 2026 +0530

    Two documentation rows that had stopped describing the tree

    THE VERSION HISTORY'S 1.1.0 ROW WAS THE ODD ONE OUT. Every highlight in the
    1.0.0 row leads with a bullet; 1.1.0's five highlights were bare `<br>`-joined
    sentences, so the table rendered one release as a list and the other as a wall.
    Nothing about the entries changed -- the same five lines, punctuated the way the
    row above them already was. A reader comparing two releases should be comparing
    the releases, not parsing two different notations for the same thing.

    THE LAYOUT CENSUS NAMED THE WRONG RUNNER-UP. `## Files by the layout-§1 band`
    closes by saying which file is nearest the 1000-line band without being in the
    table, and it said `modules/Registry.lua` at 937, sixty-three lines off. It is
    not: `tests/test_libka0s.lua` is at 971 and `tests/test_sunnart.lua` at 955,
    both nearer, and the first is twenty-nine lines from earning a row. The census
    header is dated today, so a stale runner-up under a fresh date is worse than no
    sentence at all -- it reads as measured.

    WHY THIS ONE SLIPS AND KEEPS SLIPPING. `tests/test_layout_cap.lua` asserts the
    table's MEMBERSHIP in both directions and nothing else, deliberately: a figure
    in that column is a measurement, not a claim. The consequence is that the prose
    around the table has no gate at all, and the prose is the half that names a file
    the table does not contain. The `M4-18` note about Registry being trimmed under
    the trigger is kept -- it is still true and still the reason that file is worth
    mentioning -- but it is no longer doing duty as the nearest-file claim.

    834 headless cases, luacheck 0/0, both vendor diffs empty.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_019r6eqKPKL93nb93aiiZwsh

commit da7a902170e12b49047e7430479c10e682361c22
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 16:40:07 2026 +0530

    A disabled addon refuses its feature verbs, from one place

    slash-commands-§2 has carried a trailing SHOULD since it was written -- a
    disabled addon answers a feature verb by saying so and naming `enable`, rather
    than acting -- and no addon in the collection implemented it. Standard v2.54.0
    made it precise enough to implement and audit, and this addon takes it: eight of
    its nineteen verbs create, delete, rename, list, edit, unlock, lock or recover
    the panels it is currently standing down from drawing, and a silent no-op on any
    of them leaves the player with no clue why nothing happened.

    THE GATE IS ON THE VERB TABLE, NOT ON THE VERBS. A guard pasted into each handler
    is eight places to keep in step and a ninth to forget, and the next verb added
    forgets it BY DEFAULT -- the wrong default for a courtesy nobody will notice is
    missing. NS.COMMANDS is the one seam every verb passes through: the library's
    dispatcher reads entry[3] out of that very table, and so does the degraded arm's
    own run(). So settings/Slash.lua walks it ONCE, before either reader exists, and
    wraps every handler whose name is not in ALWAYS_LIVE. One place, both surfaces,
    and a verb added tomorrow is gated the day it lands.

    ALWAYS_LIVE IS THE STANDARD'S OWN SET, spelled as data rather than as a chain of
    conditions: help config version enable disable debug perf get set list reset
    resetall. The reasoning is the standard's -- a player must be able to read and
    repair settings and reach the panel while the addon is off, which is precisely
    when they are most likely to need to, and enable above all or the pair is one-way
    again. `perf` is listed although this addon registers no such verb: the set is the
    rule rather than an inventory of today's table.

    ONE TAGGED LINE, and it is the first string in this addon to route through NS.L.
    locales/enUS.lua declares the key, which is the English source string
    (localization-§1/§2), and the slash command is a `%s` rather than part of the key
    so a translator never retypes a command -- the placeholder is a contract, since a
    translation that drops it loses the one thing the line exists to name.

    FIVE CASES, and three of them read the WORLD rather than the chat, because a case
    that only checks the message passes over a verb that printed and then acted
    anyway. The refusal loop is derived from NS.COMMANDS rather than from a list
    written out beside it, so it covers the next verb too. The acting case drives
    new / panel / rename / unlock / delete while disabled and reads the registry and
    the unlock state back, then re-runs delete once enabled to prove the gate is a
    gate and not a removal. Mutating the wrapper to print-and-fall-through reddens
    two; widening ALWAYS_LIVE by one verb reddens two others.

    834 headless cases, luacheck 0/0.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_019r6eqKPKL93nb93aiiZwsh

This mod has no additional files