diff --git a/TODOS.md b/TODOS.md new file mode 100644 index 0000000..63f2f2a --- /dev/null +++ b/TODOS.md @@ -0,0 +1,5 @@ +# TODOS + +gstack-extensions TODOs: grouped by plugin/component, `**Priority:**` P0-P4, completed items move to the bottom. + +## Completed diff --git a/qa/.claude-plugin/plugin.json b/qa/.claude-plugin/plugin.json index 156c5e9..d2417ef 100644 --- a/qa/.claude-plugin/plugin.json +++ b/qa/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "qa", - "version": "3.5.0", + "version": "3.6.0", "description": "QA Quincey, the manual-QA persona. Verifies one defined flow against the spec or mockup and records a QA posture. qa:browser drives the real running app through the user's persistent agent-browser session (click/pixel level), walks the spec, seeds and tears down tagged data via the repo's recipe, and ends with the QA_STATUS contract that satisfies the build-time Stop hook and the PR qa-gate CI. qa:headless does the same for backend features with no UI (capturing side effects). qa:qa-plan authors the two-phase QA plan and writes the approval stamp. The plugin also SHIPS Quincey's enforcement hooks (hooks/hooks.json): the QA-plan gates (presentation, build, PR) and the QA-status Stop gate, active in opted-in repos (.qa-plan-gate.json) under ~/dev. Skills: qa:browser, qa:headless, qa:qa-plan.", "author": { "name": "Mujtaba Badat", diff --git a/qa/skills/qa-plan/CHANGELOG.md b/qa/skills/qa-plan/CHANGELOG.md index e7f257b..498b381 100644 --- a/qa/skills/qa-plan/CHANGELOG.md +++ b/qa/skills/qa-plan/CHANGELOG.md @@ -1,5 +1,17 @@ # qa:plan CHANGELOG +## v2.2.0 + +Checkbox-free, skimmable companion artifact. + +- Template restructure (Mujtaba's 2026-07-22 feedback): terse "Story" / + "Solution" headings; the Solution and Production-artifacts blocks are bullet + lists, never paragraphs; the Story block ends with a muted "Linked issue:" + line (the GitHub issue when one exists, else "none" + provenance); and the + artifact carries NO checkboxes at all (no Dev-table column, plain-bullet + Definition of Done). Checkbox state lives only in the PR body's ## QA + section, which the merge gates read. Step 4b instructions updated to match. + ## v2.1.0 Story-first companion artifact. diff --git a/qa/skills/qa-plan/SKILL.md b/qa/skills/qa-plan/SKILL.md index 0628bbb..aae28f0 100644 --- a/qa/skills/qa-plan/SKILL.md +++ b/qa/skills/qa-plan/SKILL.md @@ -1,6 +1,6 @@ --- name: qa-plan -version: 2.1.0 +version: 2.2.0 description: | QA Quincey's planning skill: turn a change's success criteria into a two-phase QA plan written into the PR body, BEFORE the PR is reviewed or merged. Produces a @@ -162,12 +162,14 @@ Publish a rendered, always-linked view of the same plan as a Claude **artifact** 1. **Build the HTML.** Copy `references/artifact-template.html` (this skill's base directory) to the session scratchpad and swap the content between the `FILL:` markers: the **title**, the story-first **context blocks** (STORY / SOLUTION / PROOF, below), the **Development** ELI5 + rows, the **Production** ELI5 + rows, the **Production artifacts**, and the **Definition of Done**. The artifact is the leaner companion view: it deliberately drops the QA-driver line, the `Standard (all green)` line, and the QA-posture line (those live in the PR body, the source of truth). - **Story-first context blocks (required).** The page opens with three blocks ABOVE the Development section, so a reader gets what problem is being solved, what is being built, and how the plan proves it before any table: - - `FILL: STORY` - the change's user story in one sentence (`As , when , I want , so `), then the observed problem in a muted line (the incident, gap, or pain that motivated the change, with date/PR when one exists). Derive it from the same success criteria Step 2 pulled (spec, issue, mockup, or the user's own words); never invent it. - - `FILL: SOLUTION` - one paragraph naming what is being built to deliver that outcome, concrete enough that the QA rows below visibly test it. + **Story-first context blocks (required).** The page opens with three blocks ABOVE the Development section, headed tersely **"Story"**, **"Solution"**, and **"How this plan proves it"**, so a reader gets what problem is being solved, what is being built, and how the plan proves it before any table: + - `FILL: STORY` - the change's user story in one sentence (`As , when , I want , so `), then the observed problem in a muted line (the incident, gap, or pain that motivated the change, with date/PR when one exists), then a muted **`Linked issue:`** line: link the GitHub issue when one exists; otherwise write `none` plus where the change originated (e.g. "requested in-session, "). Derive it all from the same success criteria Step 2 pulled (spec, issue, mockup, or the user's own words); never invent it. + - `FILL: SOLUTION` - a short **bullet list** (2-5 bullets, `ul.proof` markup), never a paragraph, naming what is being built to deliver that outcome, concrete enough that the QA rows below visibly test it. - `FILL: PROOF` - 2-4 numbered bullets mapping the plan to the story: each states one thing the plan establishes and ends with a muted pointer to the rows that establish it (for example "(Dev rows 1-3.)", "(Prod row 2.)"). This is the bridge that lets the reader see the QA verifies the solution actually solves the story's problem. - The template is self-contained (inline CSS + data-URI images, theme-aware, no external assets, which the artifact CSP requires) and uses display checkbox glyphs (`โ˜` / `โ˜‘`), NEVER square-bracket checkboxes (the artifact is never gate-parsed, so glyphs are free here). + The **Production artifacts** block is likewise a **bullet list** (one bullet per artifact fact), never a paragraph. + + The template is self-contained (inline CSS + data-URI images, theme-aware, no external assets, which the artifact CSP requires) and carries **NO checkboxes of any kind**: no checkbox column in the Development table, plain bullets in the Definition of Done, and never square-bracket boxes. Checkbox state lives ONLY in the PR body's `## QA` section, the source of truth the merge gates read; the artifact is the readable view of the plan, not a tracker. **Driver avatars.** The `Tester` cell shows a logo-only avatar that carries the driver's identity for assistive tech via `role="img"` + `aria-label` (the `title` is the hover tooltip), with the decorative inner `.pic` marked `aria-hidden`: ``, where `` is a roster id with a built-in avatar (`claude` `mutwo` `muthree` `mufour` `mujtaba`). For any driver without one, use the initials fallback: ``. The template's header comment documents how to add a new avatar (inline its `github.com/.png` as a data URI in a new `.pic.` rule; `claude` is a hand-drawn inline-SVG burst on Anthropic clay). @@ -175,7 +177,7 @@ Publish a rendered, always-linked view of the same plan as a Claude **artifact** - **Re-run (URL already in the PR body):** read the existing `๐Ÿ“„ Plan view:` URL from the body and call `Artifact` with that same `file_path` AND `url: ` so it updates in place and the link never changes. - **First run (no URL yet):** call `Artifact` with the `file_path` (no `url`). Use a **stable** `title` and `favicon` (๐Ÿงช) so redeploys stay one artifact. Take the returned URL and write it into the `๐Ÿ“„ Plan view:` line of the PR body (re-edit the body via `gh pr edit`). If there is no PR yet, hold the URL and include the `๐Ÿ“„ Plan view:` line when `/ship` folds the section in (or hand the user the URL to paste). -3. **Tell the user it is private.** Artifacts are private by default. If a reviewer or teammate needs to open the plan view, the user shares it from the artifact page's share menu; the PR body link works for anyone who can see the PR regardless. Note that the artifact is a **snapshot at plan-authoring time** (boxes unchecked); the live checkbox state is in the PR body. Re-running `/qa:plan` refreshes the artifact. +3. **Tell the user it is private.** Artifacts are private by default. If a reviewer or teammate needs to open the plan view, the user shares it from the artifact page's share menu; the PR body link works for anyone who can see the PR regardless. Note that the artifact is a **snapshot at plan-authoring time** and deliberately carries no checkboxes; the live checkbox state is in the PR body's `## QA` section. Re-running `/qa:plan` refreshes the artifact. If the `Artifact` tool is unavailable (non-interactive / headless run), skip this step, keep the PR-body section (the source of truth) intact, and note that the companion artifact was not published. diff --git a/qa/skills/qa-plan/references/artifact-template.html b/qa/skills/qa-plan/references/artifact-template.html index a654cf8..f9eeda1 100644 --- a/qa/skills/qa-plan/references/artifact-template.html +++ b/qa/skills/qa-plan/references/artifact-template.html @@ -3,10 +3,18 @@ /qa:plan companion-artifact template. COMPANION view, never gate-parsed. Clone this file to the scratchpad and swap the content between the FILL markers: FILL: TITLE / STORY / SOLUTION / PROOF / DEV ELI5 / DEV ROWS / PROD ELI5 / PROD ROWS / ARTIFACTS / DOD + (DEV ROWS have NO checkbox cell; DOD is plain bullets; SOLUTION + ARTIFACTS are bullet lists.) The page is story-first: the reader gets the user story (problem + outcome), the - solution being built, and how the plan proves it BEFORE any QA table. + solution, and how the plan proves it BEFORE any QA table. Headings are terse: + "Story" / "Solution" / "How this plan proves it". The Story block ends with a + muted "Linked issue:" line pointing at the GitHub issue when one exists (write + "none" plus provenance when it does not). The Solution and Production-artifacts + blocks are BULLET LISTS (ul.proof), not paragraphs. The artifact carries NO + checkboxes of any kind (no column in the Dev table, no glyphs in the DoD); + checkbox state lives only in the PR body's ## QA section, which the gates read. Self-contained (inline CSS + data-URI images) so it satisfies the artifact CSP. Theme-aware (light + dark). The default content is a worked example so it renders standalone. + (Restructured 2026-07-22: terse headings, bulleted Solution/Artifacts, checkbox-free.) DRIVER AVATARS: the Tester column shows a logo-only avatar. It carries the driver's identity for assistive tech via role="img" + aria-label (title= is the hover tooltip); @@ -42,7 +50,7 @@ header.plan{margin-bottom:8px;} .eyebrow{font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--accent);font-weight:650;margin:0 0 10px;} h1.title{font-size:clamp(24px,3.4vw,34px);line-height:1.12;margin:0 0 8px;letter-spacing:-.02em;text-wrap:balance;font-weight:750;} - /* story-first context blocks (The story / The solution / How this plan proves it) */ + /* story-first context blocks (Story / Solution / How this plan proves it) */ .context{margin-top:22px;display:grid;gap:20px;} .block.story{border-left:3px solid var(--accent);} .block.solution{border-left:3px solid var(--live);} @@ -63,7 +71,6 @@ thead th{text-align:left;font-weight:650;font-size:12px;letter-spacing:.03em;text-transform:uppercase;color:var(--muted);padding:12px 16px;border-bottom:1px solid var(--hair-strong);white-space:nowrap;} tbody td{padding:13px 16px;border-bottom:1px solid var(--hair);vertical-align:top;} tbody tr:last-child td{border-bottom:none;} - td.check{width:34px;text-align:center;font-size:18px;color:var(--accent);line-height:1;} td.tester{white-space:nowrap;} td.expect{color:var(--muted);} td.notes{color:var(--muted);font-size:13px;} @@ -83,9 +90,6 @@ .block p{margin:0 0 9px;} .block p:last-child{margin-bottom:0;} .block .mono{font-size:13px;word-break:break-word;} - ul.dod{list-style:none;padding:0;margin:0;display:grid;gap:9px;} - ul.dod li{display:flex;gap:10px;align-items:flex-start;font-size:14px;} - ul.dod .box{color:var(--accent);font-size:17px;line-height:1.35;}
@@ -97,15 +101,20 @@

email-hero: LLM-failure health check

-

The story

- +

Story

+

As Mujtaba, when email-hero's LLM starts failing in production, I want the health check to notice and flag it, so silent LLM breakage surfaces in the mini's triage instead of going unnoticed for days.

Observed problem: LLM calls were failing quietly inside the daemon; email-hero health stayed green because nothing recorded the failures where it could see them.

+

Linked issue: none (change originated in-session).

-

The solution being built

- -

A per-failure sink records every LLM failure to llm-failures.jsonl, and email-hero health counts the failures inside its window, exiting non-zero past --llm-max-failures so mini check #8 turns red when the LLM is breaking.

+

Solution

+ +
    +
  • A per-failure sink records every LLM failure to llm-failures.jsonl.
  • +
  • email-hero health counts failures inside its window and exits non-zero past --llm-max-failures.
  • +
  • Mini check #8 turns red when the LLM is breaking, surfacing silent failures in triage.
  • +

How this plan proves it

@@ -124,18 +133,16 @@

How this plan proves it

On a throwaway copy we fake an LLM failure and check the health command notices and flags it, all before this can merge.

- + - + - - @@ -169,17 +176,20 @@

How this plan proves it

Production artifacts

- -

email-hero on mutwos-mac-mini at the merged main commit, exercised by email-hero health (check #8, every 600s) + the com.emailhero.watch daemon.

+ +
    +
  • email-hero on mutwos-mac-mini at the merged main commit.
  • +
  • Exercised by email-hero health (check #8, every 600s) + the com.emailhero.watch daemon.
  • +

Definition of Done

-
    - -
  • โ˜Tests written and green
  • -
  • โ˜Independent local review clear (/eng:cr) + CodeRabbit addressed
  • -
  • โ˜Docs updated where user-facing
  • -
  • โ˜where-things-run.json bumped if the deploy changed hosts
  • +
      + +
    • Tests written and green
    • +
    • Independent local review clear (/eng:cr) + CodeRabbit addressed
    • +
    • Docs updated where user-facing
    • +
    • where-things-run.json bumped if the deploy changed hosts
โœ“TesterCheckExpectNotes
TesterCheckExpectNotes
โ˜ Unit tests for llm_health Assertions pass; sink fires once per failure; fail-safes never raise in-window counting, torn-line skip, cap trim
โ˜ E2E on mini: force an LLM failure, run health --llm-max-failures 1 Row in llm-failures.jsonl; exits 1 at threshold 1, 0 at high