Skip to content

feat(ui): the Character tab, with the picker, header and gear (M14-08) - #290

Merged
sandgraal merged 1 commit into
mainfrom
m14/08-character-tab
Oct 19, 2026
Merged

sandgraal merged 1 commit into
mainfrom
m14/08-character-tab

Conversation

@sandgraal

Copy link
Copy Markdown
Owner

Ticket

M14-08 — The Character tab: picker, header, gear.

Acceptance — with proof

All proofs are in lab/core/tests/test_ui_character.py (21 passed).

  • The tab appears: test_the_character_tab_is_the_fourth_and_starts_hidden passes.
  • The picker lists the fixture characters, latest-written first, with folder label and local time: test_the_picker_lists_the_characters_latest_written_first passes.
  • The gear rows match char gear --json for the picked one (all 19 slots in slot order; empty slots drawn "empty"; a second pick reads the other character): test_the_gear_rows_match_char_gear_for_the_picked_one passes. Header: test_the_header_carries_spec_averages_and_the_notes passes.
  • The detail row carries the raw link; Copy puts the exact raw link on the clipboard and makes no request; a second click closes it: test_the_detail_row_carries_the_raw_link_and_copies_it passes.
  • No request other than the two read commands (every control used; char list read once): test_the_tab_runs_only_char_list_and_char_gear passes.
  • A record with no gear shows the command's reason; a refusal and errors show the CLI's or server's text: four constructed tests pass. Hostile item text draws as inert text: test_hostile_item_text_draws_as_inert_text_constructed passes.
  • The grep test test_the_templates_hold_no_slot_name_and_no_colour_code passes: no slot name or colour code from gear_slots.toml in the templates, no quality word in page.js, no .colour- rule in page.css. The colour rules are generated from the shipped table and read on the gear backing: two tests pass.
  • make ci green (paste tail): ruff clean, mypy 42 files clean, 8579 passed, 208 skipped, serial 66, parser 1746 passed / 24 skipped, hooks 182 x2.
  • Ticket acceptance command(s) run: the 21 tests above.
  • luadata.py, guard.py or another parser changed? No.
  • New external-format parsing? No.
  • New runtime dependency? None.
  • User-facing surface (wiki page affected: wowlab ui):
    • wowlab ui gains a fourth tab, Character, after Commands.
    • A picker: folder label, ", written YYYY-MM-DD HH:MM:SS"; an unreadable row is disabled and marked ": not read".
    • A header: label, Character folder, Spec id or its absent reason, equipped and overall average item level, File, Written, and the report's notes.
    • A Gear table (Slot / Item / Item level). The item name is a button in its quality colour that opens a detail row: Item id, Quality word and code, Enchant, Gems, Bonus ids, Crafter when removed, Link with Copy.
    • A record with no gear, a refusal or an error shows the CLI's stderr or "Refused: ".
    • When char list exits 1 the status line shows its stderr and the readable characters are still listed.
    • The served page's <style> ends with the generated colour rules, under the CSP hash.
    • A comment added in gear_slots.toml.

Invariants (AGENTS.md)

  • L1 reads never write: the tab runs only the two read commands char list and char gear
  • L2 one write gate: no write site added
  • L3 no Lua execution: none added
  • L4 lossless: the raw item link is shown and copied unchanged
  • L5 game data keyed by build and never overwritten: n/a
  • L6 no flavor, product, interface or build constants in library code: slot names and colour codes come from the shipped table, none in the templates (grep test)
  • L7 nothing ADR-0023 excludes
  • L8 real fixtures; constructed inputs (four error/refusal tests, hostile item text) labelled constructed; no live calls

Judgment calls

Claims for the reviewers:

  • Colour rules .gear-name.colour-<code> { color: #rrggbb; } are appended by the server to the hashed <style> from the shipped table only (new gear.colour_class / gear.colour_rgb).
  • char gear --json is byte-identical; no new field.
  • A code only the player's override names draws plain. WoW Token has no rule.
  • The header shows all of the report's notes, the two char show ones first.
  • Quality is also given as a word (title, screen-reader span).
  • runJson gained partial; a shared copyButton().
  • test_ui_explorer.py::test_the_explorer_runs_only_listed_read_commands allowed set widened by the two leaves.
  • Untested: a late reply after a quick re-pick; the stand-in DOM does not read disabled.
  • Nobody has checked the tab in a real browser (the owner's end-to-end check).

Reviews

security-reviewer and code-reviewer: dispatched by the conductor; pending.


session: 284d1153-c891-4b84-8e47-150842fac4ba
🤖 Generated with Claude Code

A fourth tab drawn from char list --json and char gear --json. Item names
take their quality colour from rules the server makes from the shipped
gear_slots.toml (gear.colour_class, gear.colour_rgb); the templates hold no
slot name and no colour code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sandgraal
sandgraal marked this pull request as ready for review October 19, 2026 07:02
@sandgraal

Copy link
Copy Markdown
Owner Author

Reviewed at fc522f8. security-reviewer: CLEAN (no new write path, no new data-to-HTML sink, colour rules only from the shipped gear_slots.toml, CSP style hash covers them, clipboard gets the raw link only). code-reviewer: CLEAN (every acceptance item has a test that fails without the code; mutation probe caught all seven changes; widened explorer allowlist is exactly char list + char gear). Four uncounted notes go to the conductor's docs PR.

@sandgraal
sandgraal merged commit 9f47b7a into main Oct 19, 2026
10 of 12 checks passed
@sandgraal
sandgraal deleted the m14/08-character-tab branch October 19, 2026 07:03
@claude

claude Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Claude encountered an error after 0s —— View job


I'll analyze this and get back to you.

sandgraal added a commit that referenced this pull request Oct 19, 2026
…-72; M14-09 pointers (#293)

## What

Conductor docs lane (ADR-0013 amendment, 2026-10-17): `docs/BACKLOG.md`
only.

- Ticks M14-02 (#288), M14-05 (#286), M14-06 (#287), M14-08 (#290).
- M14-02: a dated note on the Windows stdin follow-up (#291, 826ce3d):
why `DEVNULL` made the child's `isatty()` True on Windows, what changed,
and that Windows on `main` at 826ce3d is green.
- M14-08: a dated note from the #290 reviews (shipped-table colours vs
the ticket's "from the model" wording, which is an owner item; the
`aria-live` region; the `page.css` exemption in the colour grep test).
- M14-09: pointers from the #290 code review (the `loadGear` refactor,
the intro paragraph and allowlist test that change, the default-flavor
question, the `aria-live` narrowing).
- New tickets: M13-71 (`guard_bash.py`: `--input` bodies and the
substring allowlist match, from the #289 review; conductor lane) and
M13-72 (`char list --json` carries every full record under the Character
tab, and the colour grep's `page.css` exemption; from the #290 code
review, off that branch).

## Proof

- `grep -c '^## \[' docs/BACKLOG.md` → 87 headings; the four ticks are
the only `[ ]` → `[x]` changes.
- Pre-commit hooks green on the commit (merge-conflict check,
end-of-file).
- Rebased on `main` at 7415e07 (#289); the one conflict (M13-70 and
M13-71 both appended after M13-69) was resolved by keeping both.

## Reviewed by

`code-reviewer` CLEAN at cec1ea3 (every claim checked against main and
the CI history; the one nit, a blank line before M13-72, fixed in the
follow-up commit).

session: 284d1153-c891-4b84-8e47-150842fac4ba

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant