Merged
bvandeusen
merged 4 commits from 2026-08-27 21:28:48 -04:00
dev into main
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ce1376edc9 |
refactor(ui): the badge layer gets one owner per shape (#3132 items 1-3)
CI & Build / Python lint (push) Successful in 5s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 33s
CI & Build / TypeScript typecheck (push) Successful in 40s
CI & Build / Python tests (push) Successful in 1m6s
CI & Build / Build & push image (push) Successful in 39s
ITEM 1 — the dead canon. StatusBadge is recorded canon (#2960) and its only consumer, TaskCard, has been unreachable since 2026-04-08, when TasksListView was deleted in favour of the Knowledge view. Four and a half months of a canon that rendered nowhere, which is worse than no canon: a session pulls #2960, builds from it, and matches a component nobody has seen. TaskCard is deleted (rule 22), and the canon is made real by adoption rather than by being left as a museum piece. ITEM 2 — MY OWN ISSUE OVERSTATED THIS, and the correction is the finding. "Three scoped re-spellings" assumed one shape spelled thrice. Reading them: KnowledgeView a task-status chip, just smaller -> a real duplicate WorkspaceTaskPanel a CLICKABLE cycler: pointer, outlined, transparent background -> a control, not a chip ProjectView PROJECT lifecycle (active/paused/ completed/archived) -> a different vocabulary Only the first was ever a duplicate. The others shared a class NAME and nothing else — which is exactly what would make a future consolidation merge three unrelated things. So: KnowledgeView adopts StatusBadge/PriorityBadge via the `compact` variant the canon already anticipated ("interactive/compact re-spellings are variants of it"); the cycler becomes `.status-cycler`; and project status becomes its own vocabulary. And there was a FOURTH, in ProjectListView — the genuine duplicate of ProjectView's project pill, differing by the amounts two hands differ by: 0.68rem vs 0.7rem, a 14% tint vs 15%, one bordered and one not. Both now use one ProjectStatusBadge. `statusLabel` went with its only caller. ITEM 3 — weight. StatusBadge and PriorityBadge used font-weight 600; the house style allows 400 and 500 only. Also "In Progress" -> "In progress", which was invisible under `text-transform: uppercase` and becomes visible the moment the compact variant turns that off. THE GUARD MISSED FOUR LIVE SITES, which is the part worth keeping. The project pills painted a hue on an inline `color-mix` tint of itself — measured 1.61-2.39:1 — and the checker only knew the `--fs-X-bg` token form. Widened, it finds 48 across the app, 26 of them --fs-accent. That backlog is not this task, so the check now splits: it GATES the token form, which is clean, and REPORTS the inline form with a count and its worst offenders. A gate nobody can satisfy today gets switched off, and then it guards nothing. Gate re-verified by reintroducing a defect — exit 1 with it, exit 0 without. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
0c74dc8275 |
fix(design): badge text clears AA — the ladder was painting a hue on a tint of itself (#3132)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 29s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 1m4s
CI & Build / Build & push image (push) Successful in 36s
Every status and priority badge used its raw hue as TEXT on a 12% tint of that same hue. Measured on the dark palette, all six pairs failed the kit's own AA floor: todo 1.60:1, in-progress 1.97:1, done 2.06:1, low 2.02:1, high 2.92:1, medium 2.97:1, against 4.5. Four also failed in light mode. The cause is structural, not a bad colour pick. A 12% tint sits near the surface it composites over, so the hue as text on it has almost nowhere to go. Strengthening the tint was measured and REJECTED: on a dark palette a heavier tint moves the chip toward the light text and makes it worse. 12% was already optimal. So each pair gains a `-fg` sibling: the hue mixed toward --fs-text-primary until it clears 4.5:1 worst-case over surface-raised AND surface-hover in BOTH modes. Mixing toward that token rather than a literal is what makes one declaration cover both — it inverts by mode, so the text follows. Recorded in the DESIGN SYSTEM, not hand-written into theme.css: seven tokens on design system 2, each carrying its measurement and its reasoning, then the sheet regenerated. theme.css says not to hand-edit the --fs-* block and it is right — a hand-edit would be silently reverted by the next regeneration. The ladder keeps its shape. High priority still holds 52% saturation and medium 31% — the rungs that need to shout still shout. Low, todo and done wash toward neutral, which is what their own rationales ask for: status-todo is derived from the border colour precisely so not-yet-started recedes. Receding and illegible are different things and the old value was the second. --fs-status-cancelled-fg was found by measuring, not by reasoning. Cancelled derives from --fs-text-tertiary, which looks like the obviously-correct "quiet" choice and is a HINT colour tuned for plain surfaces — 2.63:1 on a badge tint in light mode. StatusBadge additionally dropped a `color-mix(..., #000 15%)` that darkened the hue: a light-mode instinct that made these worse on a near-black surface, and a literal besides. THE GUARD IS THE POINT. check_design_tokens.py now FAILS on any rule that paints text with a token on a tint of that same token, and names the -fg sibling as the fix. Verified by reintroducing the defect: exit 1 with it, exit 0 without. Unlike a raw literal there is nothing to weigh up, so it gates rather than reports. Two `border-top-color` uses keep the raw hue, correctly — a border is a non-text graphic and needs 3:1, which is what the hue is for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
a0b54ff6a3 |
feat(ui): task rows show their kind — a badge for issue and spike (#3124)
CI & Build / integration (push) Successful in 29s
CI & Build / Python tests (push) Successful in 1m3s
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / TypeScript typecheck (push) Successful in 10s
CI & Build / Build & push image (push) Successful in 32s
task_kind was only visible inside the task editor's Kind select, so every list surface rendered work, issue and spike identically and a list of tasks hid the fact that three different things were in it. ONE component, not a fifth spelling. The badge layer had already drifted — StatusBadge.vue is the recorded canon (#2960) but WorkspaceTaskPanel, ProjectView and KnowledgeView each carry their own scoped `.status-badge`. KindBadge is modelled on PriorityBadge, its closest sibling, which already does the thing that matters here: the DEFAULT value renders nothing. `work` is most tasks, so badging it would put a chip on nearly every row and say nothing — the same reason RuleListPane marks only `conditional`. COLOUR BY TEMPERATURE, measured rather than eyeballed. Issue and spike are opposite in character — corrective vs exploratory — so they split warm (warning) against cool (info), which survives being small and stays distinguishable without reading the word. Neither uses the accent; kind is not one of the places it is allowed. The raw semantic colour FAILS the contrast floor on the dark palette: warning on its own 12% tint measures 2.97:1 against AA's 4.5. So the text is the hue mixed toward --fs-text-primary, which passes and, because that token inverts by mode, follows light/dark for free. Measured both ways — issue 5.23:1 dark / 6.68:1 light, spike 5.33:1 / 9.26:1. `plan` renders hue-free and italic: retired since 0066, so a legacy row should read as archival rather than as a fourth kind competing for attention. In KnowledgeView it is passed as null instead, because the type badge beside it already says "Plan" and two chips reading the same word would look like two facts. Weight is 500, not the 600 the two older badges use — the house style allows 400 and 500 only, and copying 600 would spread it. SERVER FIX, without which this was decorative: dashboard's `_task_row` omitted task_kind entirely. The badge would have rendered nothing there while working everywhere else, which reads as "this list has no issues" rather than as a missing field. The guard is on the payload, where the omission was. Surfaces: ProjectView's three status columns, WorkspaceTaskPanel's two task lists, DashboardView's milestone and no-milestone rows, KnowledgeView's result rows. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
16805ca22c |
docs(mcp): every create_* tool says what it is NOT for (#3123)
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 28s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 1m6s
CI & Build / Build & push image (push) Successful in 23s
Scribe's record kinds get reached for interchangeably, and the moment of
choice is the only moment a correction is cheap. Rule 119 puts product
guidance in the instruction surfaces, so the docstring is where this
belongs — but a docstring that only documents parameters answers "how do I
call this" and leaves "should I be calling this at all" unasked.
The gap was lopsided. create_rule and start_planning already carried real
disambiguators; create_note — far and away the highest-volume surface —
carried none at all. The guidance sat in the rarest tool and was missing
from the most common one.
Each surface now opens with ONE deciding question in its own terms rather
than a pasted block:
create_note WHAT ELSE COULD HOLD THIS? note is right when nothing
is owed and nothing enforces
create_task IS ANYTHING ACTUALLY OWED? nothing owed -> note;
an arc -> start_planning
create_snippet SHAPE, OR ADVICE? a snippet is code with a
LOCATION
create_process FOLLOWED, OR READ? applies uninvoked -> rule
create_project_rule now points at the entity check too; it had only ever
covered rule-vs-rule scope.
The guard asserts STRUCTURE, never wording: each surface must name at least
two siblings. Pinning phrasing would make every improvement a test failure,
and a test that punishes editing is a test that gets deleted. Its second
half asserts the Args: block survives — the first check is satisfiable by
turning a docstring into an essay about the other tools, which would be a
worse contract than the one being fixed.
The guard caught two gaps on its first run, one of them its own: "design
system" is hard-wrapped across a line break in create_rule, so matching the
raw docstring reported it absent. _doc() now flattens whitespace. It also
caught start_planning naming only one alternative, which was true and is
now fixed.
Deliberately NOT built: an intent-router tool. It has a bootstrapping
problem — it is itself a tool that must be reached for — and MCP clients
already list every tool's description. Recorded in #3123; build it only if
wrong-surface reaches survive this.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|