@erclx/canon 5.40.0 → 5.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -17
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/api-design/references/adopted.md +34 -14
- package/claude/skills/auto-ship/REQUIREMENT.md +2 -0
- package/claude/skills/auto-ship/SKILL.md +28 -2
- package/claude/skills/auto-ship/references/draft-mark.md +32 -6
- package/claude/skills/auto-ship/references/failure-recovery.md +15 -13
- package/claude/skills/auto-ship/references/fan-in.md +59 -0
- package/claude/skills/auto-ship/references/tier-failures.md +31 -10
- package/claude/skills/auto-ship/references/ui-checklist.md +9 -4
- package/claude/skills/auto-ship/references/worktree-name.md +9 -3
- package/claude/skills/build-in-slices/references/adopted.md +35 -21
- package/claude/skills/canvas-board/references/canvas.md +17 -6
- package/claude/skills/canvas-board/references/design.md +26 -7
- package/claude/skills/code-craft/references/adopted.md +58 -20
- package/claude/skills/codebase-layout/references/adopted.md +49 -16
- package/claude/skills/codebase-layout/references/frontend.md +11 -4
- package/claude/skills/codebase-layout/references/tests.md +4 -2
- package/claude/skills/context-fold/references/classify.md +10 -15
- package/claude/skills/context-fold/references/completion-report.md +11 -9
- package/claude/skills/context-fold/references/context-refresh.md +26 -9
- package/claude/skills/context-fold/references/unusable-baseline.md +5 -3
- package/claude/skills/create-rule/REQUIREMENT.md +5 -0
- package/claude/skills/create-rule/SKILL.md +9 -1
- package/claude/skills/create-rule/references/checklist.md +26 -0
- package/claude/skills/create-rule/references/rule.md +98 -20
- package/claude/skills/create-skill/SKILL.md +1 -0
- package/claude/skills/create-skill/references/skill-disclosure.md +10 -2
- package/claude/skills/create-skill/references/skill-frontmatter.md +43 -0
- package/claude/skills/create-skill/references/skill-paths.md +7 -4
- package/claude/skills/create-skill/references/skill-practice.md +6 -3
- package/claude/skills/create-skill/references/skill-requirement.md +4 -2
- package/claude/skills/create-skill/references/skill.md +67 -44
- package/claude/skills/decision-escalate/REQUIREMENT.md +1 -1
- package/claude/skills/decision-escalate/SKILL.md +1 -2
- package/claude/skills/deploy-app/references/vercel.md +2 -1
- package/claude/skills/deprecation-migration/references/adopted.md +44 -25
- package/claude/skills/design-taste/references/adopted.md +9 -1
- package/claude/skills/design-taste/references/craft.md +3 -1
- package/claude/skills/design-taste/references/kinds.md +8 -7
- package/claude/skills/design-taste/references/preflight.md +12 -0
- package/claude/skills/design-taste/references/systems.md +7 -6
- package/claude/skills/design-taste/references/tells.md +24 -25
- package/claude/skills/design-taste/references/vocabulary.md +7 -5
- package/claude/skills/document-health/references/axes.md +54 -30
- package/claude/skills/draft-and-pick/references/live-arms.md +2 -2
- package/claude/skills/draft-doc/references/context.md +4 -3
- package/claude/skills/draft-doc/references/docs.md +6 -3
- package/claude/skills/draft-doc/references/readme/agent-facing.md +6 -0
- package/claude/skills/draft-doc/references/readme/application.md +8 -2
- package/claude/skills/draft-doc/references/readme/cli.md +5 -1
- package/claude/skills/draft-doc/references/readme/library.md +4 -0
- package/claude/skills/draft-doc/references/readme/plugin.md +9 -1
- package/claude/skills/draft-doc/references/readme.md +30 -13
- package/claude/skills/draft-doc/references/requirements.md +17 -4
- package/claude/skills/draft-doc/references/wiki-kind.md +20 -10
- package/claude/skills/draft-figure/references/architecture-set.md +7 -3
- package/claude/skills/draft-figure/references/figures.md +8 -6
- package/claude/skills/draft-figure/references/hand-drawn.md +3 -1
- package/claude/skills/draft-figure/references/mermaid-path.md +19 -9
- package/claude/skills/draft-figure/references/mermaid.md +10 -5
- package/claude/skills/draft-ready/references/ready.md +22 -15
- package/claude/skills/git-branch/REQUIREMENT.md +17 -6
- package/claude/skills/git-branch/SKILL.md +63 -7
- package/claude/skills/git-branch/references/branch.md +11 -1
- package/claude/skills/git-branch/references/slug.md +17 -5
- package/claude/skills/git-commit/references/commit.md +8 -0
- package/claude/skills/git-commit/references/versioning.md +23 -17
- package/claude/skills/git-followup/REQUIREMENT.md +1 -1
- package/claude/skills/git-followup/SKILL.md +5 -6
- package/claude/skills/git-issue/references/issue.md +29 -16
- package/claude/skills/git-pr/REQUIREMENT.md +1 -5
- package/claude/skills/git-pr/SKILL.md +11 -22
- package/claude/skills/git-pr/references/final-command.md +21 -8
- package/claude/skills/git-pr/references/labels.md +45 -28
- package/claude/skills/git-pr/references/pr.md +28 -9
- package/claude/skills/git-pr/references/publish.md +42 -28
- package/claude/skills/git-pr/references/task-number.md +20 -8
- package/claude/skills/git-ship/SKILL.md +1 -1
- package/claude/skills/plan-feature/references/batches.md +48 -1
- package/claude/skills/plan-feature/references/plan-lifecycle.md +10 -3
- package/claude/skills/plan-feature/references/plan.md +59 -20
- package/claude/skills/plan-groundwork/references/groundwork-spikes.md +4 -1
- package/claude/skills/plan-groundwork/references/groundwork.md +14 -16
- package/claude/skills/plan-intake/references/intake.md +29 -24
- package/claude/skills/plan-intake-answer/REQUIREMENT.md +1 -1
- package/claude/skills/plan-intake-answer/SKILL.md +1 -2
- package/claude/skills/pr-evidence/REQUIREMENT.md +40 -0
- package/claude/skills/pr-evidence/SKILL.md +53 -0
- package/claude/skills/pr-evidence/references/evidence.md +150 -0
- package/claude/skills/review-address/references/post-review-findings.md +10 -3
- package/claude/skills/review-address/references/rebase-conflicts.md +22 -7
- package/claude/skills/review-address/references/rest-reads.md +3 -1
- package/claude/skills/review-craft/references/adopted.md +35 -18
- package/claude/skills/review-craft/references/security.md +42 -7
- package/claude/skills/review-craft/references/ui.md +23 -8
- package/claude/skills/review-pr/SKILL.md +6 -6
- package/claude/skills/review-pr/references/body-variants.md +29 -9
- package/claude/skills/review-pr/references/close-out.md +20 -5
- package/claude/skills/review-pr/references/key-changes.md +27 -3
- package/claude/skills/review-pr/references/post.md +83 -31
- package/claude/skills/review-pr/references/scope.md +54 -19
- package/claude/skills/review-ui/SKILL.md +2 -0
- package/claude/skills/review-ui/references/close-out.md +49 -0
- package/claude/skills/review-ui/references/driving.md +24 -4
- package/claude/skills/review-ui/references/post.md +43 -13
- package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +67 -17
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +81 -40
- package/claude/skills/role-orchestrator/references/orchestrator-handback.md +52 -15
- package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +48 -26
- package/claude/skills/role-orchestrator/references/orchestrator-inbound.md +12 -13
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +72 -36
- package/claude/skills/role-orchestrator/references/orchestrator-output.md +12 -4
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +64 -24
- package/claude/skills/role-orchestrator/references/orchestrator-poll.md +80 -26
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +41 -18
- package/claude/skills/role-orchestrator/references/orchestrator-resume.md +19 -7
- package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +22 -12
- package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +15 -6
- package/claude/skills/role-orchestrator/references/orchestrator-sweep.md +25 -7
- package/claude/skills/role-orchestrator/references/orchestrator-watch.md +34 -8
- package/claude/skills/role-orchestrator/scripts/poll.ts +16 -24
- package/claude/skills/role-worker/REQUIREMENT.md +2 -0
- package/claude/skills/role-worker/SKILL.md +17 -0
- package/claude/skills/search-craft/references/adopted.md +18 -6
- package/claude/skills/session-map/references/session.md +26 -7
- package/claude/skills/session-worktree/references/main-root-writes.md +25 -8
- package/claude/skills/systematic-debugging/references/adopted.md +30 -16
- package/claude/skills/target-check/references/domains.md +39 -11
- package/claude/skills/target-setup/references/detect.md +80 -65
- package/claude/skills/target-setup/references/indexes.md +8 -6
- package/claude/skills/task-board/references/board.md +86 -30
- package/claude/skills/task-board/references/decline.md +29 -13
- package/claude/skills/task-board/references/tasks-decline.md +12 -5
- package/claude/skills/task-board/references/tasks.md +65 -33
- package/claude/skills/task-complete/references/archive.md +41 -17
- package/claude/skills/task-complete/references/receipt-sweep.md +23 -9
- package/claude/skills/task-complete/references/unusable-baseline.md +10 -3
- package/claude/skills/teach-workspace/REQUIREMENT.md +1 -1
- package/claude/skills/teach-workspace/SKILL.md +1 -2
- package/claude/skills/teach-workspace/references/glossary.md +6 -2
- package/claude/skills/teach-workspace/references/lesson-build.md +44 -16
- package/claude/skills/teach-workspace/references/lesson-craft.md +12 -7
- package/claude/skills/teach-workspace/references/pedagogy.md +6 -3
- package/claude/skills/teach-workspace/references/promotion-fold.md +17 -11
- package/claude/skills/teach-workspace/references/promotion.md +31 -8
- package/claude/skills/teach-workspace/references/revisit.md +8 -2
- package/claude/skills/teach-workspace/references/teach.md +17 -9
- package/claude/skills/test-craft/references/adopted.md +48 -14
- package/claude/skills/test-craft/references/component.md +7 -4
- package/claude/skills/test-craft/references/e2e.md +25 -7
- package/claude/skills/test-craft/references/unit.md +3 -1
- package/claude/skills/test-first/references/adopted.md +12 -4
- package/claude/skills/ui-checklist/REQUIREMENT.md +1 -1
- package/claude/skills/ui-checklist/SKILL.md +1 -1
- package/claude/skills/video-craft/references/adopted.md +62 -18
- package/claude/skills/write-human/references/adopted.md +21 -8
- package/docs/workflow/parallel-features.md +2 -1
- package/docs/workflow/skill-map.md +2 -1
- package/package.json +1 -1
- package/src/claude/cases/git.ts +4 -0
- package/src/claude/cases/workflow.ts +5 -0
- package/src/commands/pr.ts +174 -37
- package/src/commands/records.ts +11 -3
- package/src/context/shape-gated.ts +1 -0
- package/src/markdown/scope.ts +150 -2
- package/src/pr/frames.ts +53 -9
- package/src/pr/lift.ts +6 -3
- package/src/pr/review-state.ts +182 -0
- package/src/records/validate.ts +1 -0
- package/src/tasks/answers.ts +79 -2
- package/src/tasks/fan-in.ts +176 -0
- package/src/tasks/stack.ts +1 -1
- package/tooling/astro/reference.md +80 -39
- package/tooling/base/reference.md +63 -32
- package/tooling/base/seeds/canon/context/ci.md +7 -15
- package/tooling/base/seeds/canon/context/development.md +14 -14
- package/tooling/claude/reference.md +40 -22
- package/tooling/cloudflare/reference.md +31 -12
- package/tooling/go/reference.md +47 -23
- package/tooling/nextjs/reference.md +52 -19
- package/tooling/php/reference.md +35 -16
- package/tooling/python/reference.md +47 -30
- package/tooling/shell/reference.md +6 -5
- package/tooling/vite-react/reference.md +49 -21
- package/tooling/web/reference.md +130 -70
- package/claude/skills/git-pr/references/evidence.md +0 -124
package/tooling/web/reference.md
CHANGED
|
@@ -4,128 +4,188 @@
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
The web layer covers
|
|
7
|
+
The web layer covers the tooling shared across Vite + React, Astro, and any future web stack. It ships golden configs for oxlint, Vitest, Playwright, Tailwind v4, screenshots, VS Code integration, and CI. Framework wiring (Vite plugins, Astro islands, Next.js config) lives in per-stack adapter folders that extend this layer.
|
|
8
8
|
|
|
9
9
|
## What ships as golden configs
|
|
10
10
|
|
|
11
|
-
Golden
|
|
11
|
+
Golden configs live in `tooling/web/configs/`. `canon tooling sync web . --write` copies them into the target and replaces whatever sits at those paths. They are the source of truth, so this reference covers rationale and the configs show the setup.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- `
|
|
18
|
-
- `
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
### Lint and test setup
|
|
14
|
+
|
|
15
|
+
Two configs carry the lint and unit-test baseline.
|
|
16
|
+
|
|
17
|
+
- `.oxlintrc.json` is migrated from the ESLint config it replaced. It runs the recommended, React, and test-scoped vitest rules, with `check-file` and `simple-import-sort` as JS plugins.
|
|
18
|
+
- `src/test/setup.ts` imports `@testing-library/jest-dom/vitest` and runs `cleanup` after each test.
|
|
19
|
+
|
|
20
|
+
### Screenshot cases
|
|
21
|
+
|
|
22
|
+
`e2e/screenshot.ts` is the capture template. One `CASES` record carries an entry per output file, each naming a section, a theme, and a route, and per-project cases extend it.
|
|
23
|
+
|
|
24
|
+
- The loop crosses every case with `VIEWPORTS` and writes `screenshots/<hostname>/<section>/<width>--<theme>.png`. The hostname of `SCREENSHOT_BASE_URL` keeps a local run and a deployed run apart.
|
|
25
|
+
- `VIEWPORTS` holds 320, 768, 1280, and 1536. Width 320 is the base a page has to hold without wrapping or clipping.
|
|
26
|
+
- `excludeViewports` skips a width, for a route whose long-form prose reflows at 320 instead of breaking.
|
|
27
|
+
- `evidence: true` also writes `evidence/<section>/<width>--<theme>.png` at 320 and 1280 alone, keeping the tracked set at twice the sections rather than four times.
|
|
28
|
+
|
|
29
|
+
### Sections and masks
|
|
30
|
+
|
|
31
|
+
A case may name `sections`, one `{ name, selector }` per addressable part of the route. Each writes its own frame beside the whole-page one.
|
|
32
|
+
|
|
33
|
+
- A section frame lands at `screenshots/<hostname>/<section>/<name>/<width>--<theme>.png`, plus the same path under `evidence/` where the case and width are flagged.
|
|
34
|
+
- A selector matching nothing is reported and skipped, since a target syncing the template before editing its list would otherwise capture nothing.
|
|
35
|
+
- Testing that every section resolves belongs to the project owning the selectors.
|
|
36
|
+
- `mask` lists selectors painted over in every frame, for a value that moves with no code change, so a double capture compares the rest.
|
|
37
|
+
|
|
38
|
+
### Settling before a shot
|
|
39
|
+
|
|
40
|
+
Every case settles before anything is shot.
|
|
41
|
+
|
|
42
|
+
- The context uses `reducedMotion: 'reduce'`, and each named section scrolls into view so an `IntersectionObserver` fires and `loading="lazy"` frames load. The page then returns to the top.
|
|
43
|
+
- Fonts, images, and same-origin frames are waited out on a bounded condition. A second `networkidle` does not re-arm for a load a scroll started.
|
|
44
|
+
- A section frame drops floating chrome (`position: sticky` or `fixed`), which would otherwise ride the scroll into the frame. The whole-page frame is shot first and keeps its chrome.
|
|
45
|
+
|
|
46
|
+
### Run flags
|
|
47
|
+
|
|
48
|
+
Three controls narrow or harden a run.
|
|
49
|
+
|
|
50
|
+
- `SCREENSHOT_FILTER` keeps cases whose `<section>/<width>--<theme>` label contains a comma-separated term. It exits 1 and lists the labels on no match.
|
|
51
|
+
- `--check-console-clean` exits 1 with the list if any `console` error fired, turning the capture into a smoke check.
|
|
52
|
+
- `--require-base-url` exits 1 before launching a browser when `SCREENSHOT_BASE_URL` is unset, so a deployment script cannot capture `localhost`.
|
|
53
|
+
- With a base URL, it skips every flagged case so a production smoke run writes nothing to the committed path, and exits 1 when zero cases run.
|
|
54
|
+
|
|
55
|
+
### Scripts and workflows
|
|
56
|
+
|
|
57
|
+
The wrappers around the capture and the verify run. `governance/rules/tooling/ci-workflow.md` states when a workflow's commit-back is right and when a report is.
|
|
58
|
+
|
|
59
|
+
- `scripts/screenshot.sh` sources `scripts/lib/preview-server.sh`, never executed itself. It builds, serves on `PREVIEW_PORT`, waits for the port, and traps the whole process group on exit.
|
|
60
|
+
- `scripts/readme-screenshot.sh` captures one case under `SCREENSHOT_FILTER` into `assets/evidence/readme/`. `README_FILTER` ships empty, so it exits 1 until a project fills it.
|
|
61
|
+
- `.github/workflows/readme-screenshot.yml` ships its path list as `REPLACE_WITH_PROJECT_PATHS`, and its first step exits 1 while that stays.
|
|
62
|
+
- `.github/workflows/verify.yml` runs `static-checks`, `unit-tests`, `build-verify`, and `e2e-tests`.
|
|
23
63
|
|
|
24
64
|
## What stays in per-stack adapters
|
|
25
65
|
|
|
26
|
-
Framework glue lives in `tooling/vite-react/configs/` or `tooling/astro/configs
|
|
66
|
+
Framework glue lives in `tooling/vite-react/configs/` or `tooling/astro/configs/`, because merge helpers and config shapes differ.
|
|
27
67
|
|
|
28
|
-
- `vite.config.ts` or `astro.config.mjs
|
|
29
|
-
- `vitest.config.ts
|
|
30
|
-
- `playwright.config.ts
|
|
31
|
-
- `tsconfig.json
|
|
68
|
+
- `vite.config.ts` or `astro.config.mjs` holds the framework's config.
|
|
69
|
+
- `vitest.config.ts` uses `mergeConfig` in Vite stacks and `getViteConfig` from `astro/config` in Astro.
|
|
70
|
+
- `playwright.config.ts` differs in its `webServer` command.
|
|
71
|
+
- `tsconfig.json` differs in its `extends` target. Astro uses `astro/tsconfigs/strict` and Vite projects use scaffold defaults.
|
|
32
72
|
|
|
33
73
|
## File layout
|
|
34
74
|
|
|
35
|
-
- `src/`
|
|
75
|
+
- `src/` holds app code, `e2e/` Playwright, `scripts/` shell, and `src/test/setup.ts` the Vitest globals.
|
|
36
76
|
- Path alias `@` maps to `./src` in both tsconfig and the framework's build config.
|
|
37
|
-
- Tsconfig
|
|
77
|
+
- Tsconfig sits at root with `noEmit: true` in Vite stacks. Astro keeps the scaffold default from `@astrojs/check`.
|
|
38
78
|
|
|
39
79
|
## Ports
|
|
40
80
|
|
|
41
81
|
Two worktrees of one repository run the same stack, so a fixed port makes the second one attach to the first.
|
|
42
82
|
|
|
83
|
+
### Deriving the port
|
|
84
|
+
|
|
85
|
+
The helper owns the offset, and a config only adds it.
|
|
86
|
+
|
|
43
87
|
- Derive every served port from `scripts/worktree-port.sh`. Never write a port literal into a script string.
|
|
44
|
-
- Read `WORKTREE_PORT_OFFSET` in a config and add it to the stack's default port. Unset yields the default, so a plain clone keeps
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
88
|
+
- Read `WORKTREE_PORT_OFFSET` in a config and add it to the stack's default port. Unset yields the default, so a plain clone keeps its port.
|
|
89
|
+
- The offset comes from a band of 50 hashed from the worktree folder name. Two worktrees can collide, so set `WORKTREE_PORT_OFFSET` by hand to break a tie.
|
|
90
|
+
- Force-replace `dev` and `preview` through `[scripts.override]`, since a plain `[scripts]` entry never replaces a key the scaffold wrote.
|
|
91
|
+
- Set `strictPort` on every dev and preview server, and Playwright `reuseExistingServer: false`. A server that walks to another port, or a reused one, passes against the wrong code silently.
|
|
92
|
+
|
|
93
|
+
### Calling the helper
|
|
94
|
+
|
|
95
|
+
Call it as `VAR=$(bash scripts/worktree-port.sh) && export VAR && <server>`, never as `VAR=$(bash scripts/worktree-port.sh) <server>`. An assignment prefix discards the exit status of its own substitution. The shorter form starts the server with `VAR` empty, which every config reads as offset zero.
|
|
96
|
+
|
|
97
|
+
### Refusal in a removed worktree
|
|
98
|
+
|
|
99
|
+
Expect a non-zero exit and no port from a folder left under `.claude/worktrees/` once its worktree is gone. Git reports the parent repository from inside one, so every base served would land on the main checkout's port.
|
|
100
|
+
|
|
101
|
+
- A folder whose own `.git` was deleted refuses only under that directory, since location alone separates it from an ordinary subdirectory.
|
|
102
|
+
- A folder whose `.git` names a pruned administrative directory refuses wherever it sits.
|
|
103
|
+
- Set `WORKTREE_PORT_OFFSET` by hand to serve from such a folder anyway. It is the one override and is checked before any directory test.
|
|
52
104
|
|
|
53
105
|
## Anti-patterns
|
|
54
106
|
|
|
55
|
-
|
|
107
|
+
Negative knowledge that costs a failed run to relearn.
|
|
56
108
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
109
|
+
| Do NOT | Why and what to do |
|
|
110
|
+
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
111
|
+
| Use `exclude: ["e2e"]` | Bare-folder globs miss. Use `"e2e/**/*"`. |
|
|
112
|
+
| Put Playwright `trace` at the top of the config | It lives under `use`. |
|
|
113
|
+
| Ship Vitest failing on no tests | Fresh scaffolds have none. Use `passWithNoTests: true` until one exists. |
|
|
114
|
+
| Skip `skipLibCheck: true` in Vite + React | `@testing-library/jest-dom` and Vite's `module-runner` conflict otherwise. |
|
|
115
|
+
| Use `tsc -b` in a Vite project | Composite mode emits `.js` next to `.ts` and the linter lints it. Use `tsc --noEmit`. |
|
|
116
|
+
| Trust `vite-react`'s scaffolded `lint` script | Its bare `oxlint` exits 0 on warnings. `[scripts.override]` forces `--max-warnings 0` over it. |
|
|
117
|
+
| Run `bunx shadcn@latest init` over `global.css` | It silently overwrites `src/styles/global.css`. Back up first, and pass `-t -b -p -y` to skip prompts. |
|
|
64
118
|
|
|
65
119
|
## Tool pairing
|
|
66
120
|
|
|
67
|
-
- Unit tests
|
|
68
|
-
- E2E
|
|
69
|
-
- Tailwind
|
|
70
|
-
- Lint
|
|
121
|
+
- Unit tests use Vitest with jsdom, globals on, `src/test/setup.ts`, `@testing-library/react`, and `@testing-library/user-event`.
|
|
122
|
+
- E2E uses Playwright in `e2e/`, Chromium only for Chrome extensions and all browsers for web apps.
|
|
123
|
+
- Tailwind is v4 through `@tailwindcss/vite`, never the v3 integration.
|
|
124
|
+
- Lint is oxlint at an exact pin, since its JS plugin host is alpha and a minor release could break `check-file` or `simple-import-sort`. Astro keeps ESLint, which its own reference covers.
|
|
71
125
|
|
|
72
126
|
## oxlint
|
|
73
127
|
|
|
74
|
-
- Set `lint` and `lint:fix` through `[scripts.override]`, so
|
|
75
|
-
-
|
|
76
|
-
- Keep import sorting on `simple-import-sort
|
|
128
|
+
- Set `lint` and `lint:fix` through `[scripts.override]`, so a synced target stops running ESLint on its next sync.
|
|
129
|
+
- After that sync, delete a leftover `eslint.config.js` or `eslint.config.mjs` and `bun remove` the ESLint packages by hand. Sync deletes nothing a stack stopped shipping.
|
|
130
|
+
- Keep import sorting on `simple-import-sort`, because oxfmt's built-in sort orders differently and would rewrite every import block.
|
|
77
131
|
|
|
78
132
|
## lint-staged (extend)
|
|
79
133
|
|
|
80
|
-
- Add `**/*.{js,jsx,ts,tsx}`
|
|
81
|
-
- Extend the oxfmt glob to include `css
|
|
134
|
+
- Add `**/*.{js,jsx,ts,tsx}` running `oxlint --fix --max-warnings 0` and `oxfmt --no-error-on-unmatched-pattern`.
|
|
135
|
+
- Extend the oxfmt glob to include `css`, giving `**/*.{json,css,md}`.
|
|
82
136
|
|
|
83
137
|
## CI docs (extend)
|
|
84
138
|
|
|
85
139
|
Extend `canon/context/development/ci.md` so the `## Checks` table reflects the web jobs. <!-- audit-ignore-citations: canon/context/development/ci.md -->
|
|
86
140
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
| Typecheck | `bun run typecheck`
|
|
90
|
-
| Lint
|
|
91
|
-
| Tests
|
|
92
|
-
| Build
|
|
93
|
-
| E2E
|
|
141
|
+
| Check | Command | What it asserts |
|
|
142
|
+
| --------- | ----------------------- | ------------------------------------------- |
|
|
143
|
+
| Typecheck | `bun run typecheck` | framework-specific typecheck passes |
|
|
144
|
+
| Lint | `bun run lint` | oxlint passes with zero warnings |
|
|
145
|
+
| Tests | `bun run test:coverage` | Vitest passes with coverage thresholds |
|
|
146
|
+
| Build | `bun run build` | Production build succeeds |
|
|
147
|
+
| E2E | `bun run test:e2e` | Playwright passes against the built preview |
|
|
94
148
|
|
|
95
149
|
Under `## Running CI locally`, document that `bun run check:full` runs verify plus `test:e2e`.
|
|
96
150
|
|
|
97
151
|
## Development docs (extend)
|
|
98
152
|
|
|
99
|
-
Extend the `development` context entry under `canon/context/` so the `## Scripts` table lists every web script. Stack adapters add their `dev`, `build`, `preview`, `typecheck` rows.
|
|
100
|
-
|
|
101
|
-
Append rows:
|
|
153
|
+
Extend the `development` context entry under `canon/context/` so the `## Scripts` table lists every web script. Stack adapters add their `dev`, `build`, `preview`, and `typecheck` rows.
|
|
102
154
|
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
| `bun run
|
|
106
|
-
| `bun run
|
|
107
|
-
| `bun run test
|
|
108
|
-
| `bun run test:
|
|
109
|
-
| `bun run test:
|
|
110
|
-
| `bun run
|
|
111
|
-
| `bun run
|
|
112
|
-
| `bun run
|
|
155
|
+
| Command | Purpose |
|
|
156
|
+
| --------------------------- | --------------------------------------- |
|
|
157
|
+
| `bun run lint` | Run oxlint, no warnings allowed. |
|
|
158
|
+
| `bun run lint:fix` | Auto-fix oxlint issues. |
|
|
159
|
+
| `bun run test` | Run Vitest in watch mode. |
|
|
160
|
+
| `bun run test:run` | Run Vitest once, verbose. |
|
|
161
|
+
| `bun run test:coverage` | Run Vitest with coverage. |
|
|
162
|
+
| `bun run test:e2e` | Run Playwright E2E tests. |
|
|
163
|
+
| `bun run test:e2e:changed` | Run specs the diff's import graph hits. |
|
|
164
|
+
| `bun run screenshot` | Build, preview, capture screenshots. |
|
|
165
|
+
| `bun run readme-screenshot` | Capture the README frame. |
|
|
166
|
+
| `bun run smoke:prod` | Capture against a required base URL. |
|
|
113
167
|
|
|
114
|
-
|
|
168
|
+
### Screenshot contract
|
|
115
169
|
|
|
116
|
-
`
|
|
170
|
+
`canon tooling verify <stack>` is the only automated caller of `bun run screenshot`. It runs the script for any stack whose `package.json` declares it and asserts that PNG files land under `screenshots/`.
|
|
117
171
|
|
|
118
|
-
The
|
|
172
|
+
- The count is a recursive find with no depth limit, so the seed's section folders satisfy it. Do not flatten the layout to protect that check.
|
|
173
|
+
- `governance/rules/ui/surface-capture.md` asks a session to run the capture after a surface changes, component files included, with an exemption for a component the production build strips out.
|
|
174
|
+
- The sweep under `screenshots/` is ignored and only a flagged case's `evidence/` output tracks, so a target's first capture is the baseline it commits.
|
|
175
|
+
- A case naming sections commits a folder per section, so size the list against the frames each later change regenerates.
|
|
119
176
|
|
|
120
177
|
## Gitignore (extend)
|
|
121
178
|
|
|
122
|
-
`[gitignore]` groups
|
|
179
|
+
These `[gitignore]` groups mirror the manifest.
|
|
123
180
|
|
|
124
181
|
- `"# Playwright" = ["test-results/", "playwright-report/", "blob-report/", "playwright/.cache/"]`
|
|
125
182
|
- `"# Screenshots" = ["screenshots/"]`
|
|
126
183
|
|
|
127
184
|
## Verify script
|
|
128
185
|
|
|
129
|
-
The web layer's `scripts/verify.json` requires `typecheck`, `lint`, `test:run`, and `build
|
|
186
|
+
The web layer's `scripts/verify.json` requires `typecheck`, `lint`, `test:run`, and `build`. Base's `scripts/verify.ts` runs them in its fixed order, being typecheck, lint, format, shell where the `shell` stack declares it, unit tests, build, markdown bans, then the card exclusion check where installed.
|
|
130
187
|
|
|
131
|
-
|
|
188
|
+
- Astro, vite-react, and nextjs inherit the list, since the nearest stack's copy wins. An adapter whose phases differ ships its own `verify.json` rather than a script.
|
|
189
|
+
- The card stage runs `scripts/check-card-exclusion.sh` whenever that file is installed, keeping the social card route's build exclusion on the default path rather than behind a flag.
|
|
190
|
+
- It tests for the script rather than the stack, so a project with no card route runs one less stage with no override.
|
|
191
|
+
- The stack shipping a card route owns what the check reads, being the build the stage before it produced. The astro reference carries the route itself.
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Rendered-surface evidence
|
|
3
|
-
description: How git-pr finds the UI checklist and the local server, posts the evidence comparison or the checklist alone as the fallback for a git refusal, and adds the preview address, for a change that touches a rendered surface
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Rendered-surface evidence
|
|
7
|
-
|
|
8
|
-
The rendered-surface step of `git-pr`, reached after the final command printed the pull request number. The step runs on every pull request, with no test on the diff ahead of it. `no-evidence` is the silent branch, so a pull request that changes no rendered surface posts nothing.
|
|
9
|
-
|
|
10
|
-
## Contents
|
|
11
|
-
|
|
12
|
-
- [Find the UI checklist](#find-the-ui-checklist)
|
|
13
|
-
- [Find the local server](#find-the-local-server)
|
|
14
|
-
- [Post the evidence comparison](#post-the-evidence-comparison)
|
|
15
|
-
- [Post the UI checklist alone](#post-the-ui-checklist-alone)
|
|
16
|
-
- [Post the preview address](#post-the-preview-address)
|
|
17
|
-
|
|
18
|
-
## Find the UI checklist
|
|
19
|
-
|
|
20
|
-
`ui-checklist` writes a visual checklist to `.canon/tmp/handoff/ui-checklist/<slug>.md` at the main worktree root when a change needs visual verification, with `<slug>` derived per `${CLAUDE_SKILL_DIR}/../git-branch/references/slug.md`. This skill is the file's sole consumer. Resolve the main root the way `session-worktree` does (`git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`) and check for the file there. A missing file means no checklist was produced, and the two steps below each skip their checklist half.
|
|
21
|
-
|
|
22
|
-
When it exists, scan it against `${CLAUDE_SKILL_DIR}/references/publish.md` before either step posts it, the same as the pull request body in the skill's pre-publish scan.
|
|
23
|
-
|
|
24
|
-
Where it lands is decided by the evidence step below rather than here, since a checklist reads next to the screenshots it annotates and posting it on its own is the fallback for a refused render.
|
|
25
|
-
|
|
26
|
-
## Find the local server
|
|
27
|
-
|
|
28
|
-
A reviewer on the operator's machine can open the branch's running dev server, which screenshots and a checklist cannot stand in for. Ask the verb for the server this worktree is running before the evidence step, so the first evidence comment already carries the link:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
canon pr local --json
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
The verb reads the listening sockets on this machine, keeps those whose process runs inside this worktree, and reports the lowest port serving an HTML page. A server in another worktree or in the main checkout is never reported, since it shows a different branch. `canon pr local --help` states the contract. Read `reason` on the record rather than the exit code.
|
|
35
|
-
|
|
36
|
-
- `ok`: hold the record's `url` for the evidence step below.
|
|
37
|
-
- `no-server` or `no-listener-reader`: hold the reason for the closing report, pass no link, and move on. Do not start a server here, since one started inside the ship chain has no owner to stop it.
|
|
38
|
-
- Anything else, including no record at all: move on silently. An installed binary older than the verb answers with an unknown-subcommand error, which is a skip rather than a stop.
|
|
39
|
-
|
|
40
|
-
Pass `--local` to the evidence step only on an `ok` here. The binary answering `ok` is the one carrying the flag, so a binary lacking the verb never meets a flag it would reject.
|
|
41
|
-
|
|
42
|
-
With a checklist, a diff carrying no evidence image still renders `ok`, and a local link rides in the same comment on the address line under `## Evidence`, above the checklist, so a reviewer gets both in one place. A local link with neither an evidence image nor a checklist still reports `no-evidence`, which keeps a branch that changed no rendered surface from getting a comment holding a link and nothing else.
|
|
43
|
-
|
|
44
|
-
A seeded workflow drops the whole address line once the pull request closes, hosted and local segments together and with no note in their place, so neither link outlives the branch it points at.
|
|
45
|
-
|
|
46
|
-
## Post the evidence comparison
|
|
47
|
-
|
|
48
|
-
Run the verb once against the number the skill's final command printed. Pass `--checklist` when the checklist step found a file, and `--local` when the step above returned `ok`. Leave each flag off otherwise:
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
canon pr evidence <number> --checklist <main-root>/.canon/tmp/handoff/ui-checklist/<slug>.md --local <url> --json
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
One call answers both questions because a checklist decides `no-evidence`. The verb renders `ok` on a diff carrying a checklist and no evidence image, with a marked body holding the checklist, so the checklist always lands in the one comment a later call finds and edits. Without a checklist, a diff carrying no evidence image reports `no-evidence`.
|
|
55
|
-
|
|
56
|
-
Pass `--checklist` only for a file that exists. The verb refuses as `unreadable-checklist` on a path it cannot read or one holding nothing, which is a caller bug rather than a transient failure, so stop and repair the path rather than posting a body with the checklist silently dropped.
|
|
57
|
-
|
|
58
|
-
Read `reason` on the record rather than the exit code.
|
|
59
|
-
|
|
60
|
-
- `no-evidence`: nothing changed under an `evidence/` segment and no checklist was passed, so no body was rendered. Say nothing about the evidence and move on.
|
|
61
|
-
- `ok`: write `body` to `.canon/tmp/pr/evidence/body-<number>.md` at the main worktree root (resolved the way `session-worktree` does), then post or update the comment:
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
gh api -X POST repos/{owner}/{repo}/issues/<number>/comments -F body=@<main-root>/.canon/tmp/pr/evidence/body-<number>.md --silent
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Both posts in this file go through the REST issue-comments endpoint, since the `gh pr` subcommands run on GraphQL and a cloud session's GitHub proxy refuses it. `git-followup` mints a preview through this file, so a GraphQL post here would break the cloud review-address leg.
|
|
68
|
-
|
|
69
|
-
When the record carries a `commentId`, edit that comment in place instead of posting a second one, reading the body field from the tmp file with `@`, which needs the typed-field flag `-F` because the raw-string flag `-f` posts the path itself as the body:
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
gh api -X PATCH repos/{owner}/{repo}/issues/comments/<commentId> -F body=@<main-root>/.canon/tmp/pr/evidence/body-<number>.md
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Delete the handoff file once that call reports success, per the cleanup below, since the checklist now lives on the pull request. Clean up the tmp body file the same way.
|
|
76
|
-
|
|
77
|
-
Any other `reason` is one of the mirrored git refusals (`gh-missing`, `gh-failed`, `no-base`, `unreadable-changes`, `would-empty`). Report it and move on without stopping the chain: a branch that carries no evidence images most of the time should not fail here on a transient git or `gh` read. Fall through to the checklist step, which posts the checklist alone rather than losing it to a transient read.
|
|
78
|
-
|
|
79
|
-
## Post the UI checklist alone
|
|
80
|
-
|
|
81
|
-
Run this step only as the fallback, when the evidence step above reported one of the git refusals and a checklist file exists, since every other branch with a checklist rendered `ok` and carried it. The comment this posts carries no marker, so a later `canon pr evidence` call reports no `checklist` for it. Post it as its own comment on `<number>`:
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
gh api -X POST repos/{owner}/{repo}/issues/<number>/comments -F body=@<main-root>/.canon/tmp/handoff/ui-checklist/<slug>.md --silent
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Run the cleanup below only once the call that carried the checklist reports success, whichever of the two steps that was. On a failure, stop and leave the file in place: a retry needs the checklist to still be there, and deleting it on a failed post loses the only copy with nothing landed on the pull request.
|
|
88
|
-
|
|
89
|
-
The cleanup is a main-root delete, so it goes out as a plain `rm` and then a plain `rmdir`, the file and then the folder, routed the way `session-worktree` states:
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
rm <main-root>/.canon/tmp/handoff/ui-checklist/<slug>.md
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
rmdir <main-root>/.canon/tmp/handoff/ui-checklist 2>/dev/null || true
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
The `rmdir` is a no-op when another branch's pending checklist still sits in the folder, which keeps this step from deleting a handoff that is not its own.
|
|
100
|
-
|
|
101
|
-
Deleting the file is what makes the later re-render safe. `git-followup` re-runs `canon pr evidence` with no `--checklist`, and the verb carries the checklist forward out of the comment it is editing, so the checklist survives the push. A tick survives a render at the head its stamp names and is cleared by one at a newer head, which leaves the next UI pass to earn it again.
|
|
102
|
-
|
|
103
|
-
## Post the preview address
|
|
104
|
-
|
|
105
|
-
Run this step when the evidence step above returned `ok`, a checklist was posted by the fallback, or `canon pr evidence <number> --check --json` lists `preview` in `owed`. The first two mean the pull request changes a rendered surface, and a reviewer holding a checklist with no screenshots needs the live page most. The third is how `git-ship` reaches this step alone when an earlier run's deploy timed out, so no evidence step ran in the current one. Otherwise skip it silently.
|
|
106
|
-
|
|
107
|
-
The evidence comment is already posted, so the reviewer has the screenshots while the deploy runs. Mint the preview against the same `<number>`:
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
canon pr preview <number> --json
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
The verb dispatches the project's Pages deploy on the pull request's branch and waits on the run for up to 15 minutes. It refuses before dispatching anything when the deploy command passes no `--branch`, since that deploy would publish the branch to production, and when the workflow's own push path filter matches no path the pull request changed, since a dispatch ignores that filter and the site it published would show none of the change. `canon pr preview --help` states the contract. Read `reason` on the record rather than the exit code.
|
|
114
|
-
|
|
115
|
-
- `ok`: re-render the evidence body with the address on the line under `## Evidence`, then post or update it exactly as the evidence step does, through the same tmp file and the `commentId` the record carries:
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
canon pr evidence <number> --preview <url> --json
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
The hosted address opens the address line and a local link already on the comment follows it on the same line, carried forward with no flag.
|
|
122
|
-
|
|
123
|
-
- `no-deploy` or `unserved`: the project deploys nothing a dispatch can start, or nothing this branch changed is something its site builds from. Say nothing and move on.
|
|
124
|
-
- Any other `reason`, being `unfenced`, `no-alias`, `run-failed`, `timeout`, or a mirrored `gh` refusal: report it with the record's `message` and move on without stopping the chain. A missing link costs the reviewer a click, and a held ship costs the whole chain.
|