chore: address Copilot review round 4

- verify:skills:cli — the authoritative validator is now a GUARANTEED step in
  `local:gate` and CI, not a best-effort hand-off. It resolves the CLI itself
  (an installed one at 2.1.233+, else a pinned `npx -y`), so both tiers run the
  same script and cannot drift. `verify:skills` keeps skipping when the CLI is
  absent, which is right for `validate`: fast, offline, no Claude Code required.
- skill-manifest: the 1,536-char listing-entry cap covers `description` +
  `when_to_use` together; checking the description alone passed an over-cap
  entry. `when_to_use` is now parsed, validated and counted, with boundary tests
  at 1,536/1,537.
- verify-skills: report the budget as *this repo's contribution*. The real
  listing budget is shared with bundled skills and the contributor's own
  ~/.claude/skills, none of which is visible from here, so the number was
  claiming more than it measured.
- skill-eval: a negative case now means "no skill OF THIS REPO'S fired". It
  failed on any Skill invocation, so a contributor with an unrelated global
  skill got a false failure about their environment rather than these skills.
- docs/architecture + local-dev: the Node backend runner gets its
  `@inspector/core` alias from `clients/web/tsup.runner.config.ts`, not from
  Vite. The old text sent runner work to the wrong config.
- local-dev: the tarball does not ship "only each client's build/" — the
  allowlist also carries `clients/web/dist`, `clients/web/static` and the
  install helper. States the invariant that actually matters instead.
- issue-triage: the test for needing triage is "no board card". Adding "and no
  milestone" would skip the approved-but-unboarded case the same section then
  handles. Also corrected the `$M` note: the lookup is `--state all`, so closed
  issues DO have entries — `isopen` is about the invariants, not the lookup.
- issue-create: replaced "all five" with a per-version table. Steps 3 and 6
  (milestone, Priority) do not exist for v1, so the old list opened with a rule
  the same skill later tells you to violate.

Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-29 01:47:43 -04:00
commit d05e76d470
4 changed files with 330 additions and 51 deletions

View file

@ -6,16 +6,22 @@ disable-model-invocation: true
# Creating an issue
An issue **you** create is not "created" until all five of these are true. A
label is a repo tag, the milestone is a release bucket, and the board is a
separate org project — `--label v2` does **not** add a board card, and adding a
card does **not** set a Status or a Priority.
An issue **you** create is not "created" until every step below that applies to
its version is done. A label is a repo tag, the milestone is a release bucket,
and the board is a separate org project — `--label v2` does **not** add a board
card, and adding a card does **not** set a Status or a Priority.
1. **Version label** — exactly one of `v1` / `v2`
2. **Type label** — exactly one of `bug` / `enhancement` / `documentation` / `chore` / `question`
3. **Milestone**
4. **A card on the board for that version** — `v2` → #28, `v1` → #11
5. **Status _and_ Priority set on that card** (Priority is v2-only)
| # | Step | v2 | v1 |
| --- | --- | --- | --- |
| 1 | **Version label** — exactly one of `v1` / `v2` | ✅ | ✅ |
| 2 | **Type label** — exactly one of `bug` / `enhancement` / `documentation` / `chore` / `question` | ✅ | ✅ |
| 3 | **Milestone** | ✅ | ❌ — every milestone is a v2 release bucket, so there is none to take |
| 4 | **A card on the board for that version** — `v2` → #28, `v1` → #11 | ✅ | ✅ |
| 5 | **Status** on that card | ✅ | ✅ |
| 6 | **Priority** on that card | ✅ | ❌ — board #11 has no such field |
The two ❌ rows are not oversights to fix later: the field does not exist for
that line, and `AGENTS.md` states both exceptions (Copilot).
Set the labels and milestone at **create time**, never by backfilling: an
unlabeled issue belongs to no version line and appears in no version-filtered

View file

@ -6,9 +6,11 @@ disable-model-invocation: true
# Triaging issues
**An issue needs triage when it arrives with no board card and no milestone —
regardless of who filed it.** That is the whole test, and it is deliberately
about *state*, not authorship. An outside reporter has no board access, so their
**An issue needs triage when it has no board card — regardless of who filed
it.** That is the whole test, and it is deliberately about *state*, not
authorship. The milestone is not part of the test; it decides *where the card
lands* (milestoned → **Todo**, unmilestoned → **Incoming**), so an
approved-but-unboarded issue is still swept in rather than skipped (Copilot). An outside reporter has no board access, so their
issue necessarily lands this way — but so does a maintainer's, whenever they
open one by hand instead of through the `/issue-create` flow. Write access makes
the board *reachable*, not automatic. What puts an issue in Todo is somebody
@ -276,9 +278,12 @@ Two things the queries must account for, both learned the hard way:
and that check then reports `0` while the invariant it states (no drafts) is
being violated (Copilot). The filter admits an item with no repository and
excludes only cards that name a *different* one.
- **Only open issues have a `$I` entry.** A closed issue still has a card
(correctly, in `Done`), so a check that treats "no milestone found" as a
violation must gate on `isopen(.n)` or it flags every closed card.
- **`$M` holds closed issues too** — the lookup is built from
`gh issue list --state all`, which it has to be, because the last check reads
closed issues' state reasons. So `isopen` is not there to cope with a missing
entry; it is there because the *invariants* are about open work. A closed
issue legitimately sits in `Done` with whatever milestone it had, and a check
that did not gate on `isopen` would report every one of them (Copilot).
**Do not "fix" a `Done` card that is missing a milestone.** Cards predating a
rule are not defects to backfill in bulk — the audit exists to stop *new* drift,

View file

@ -29,8 +29,11 @@ need: the root `postinstall` (`scripts/install-clients.mjs`) cascades
the root to re-sync every client.
The cascade is dev-only — it exits early when the package is installed under
`node_modules`, and the published tarball ships only each client's `build/`. Set
`INSPECTOR_SKIP_CLIENT_INSTALL=1` to skip it.
`node_modules`, and a consumer never needs it because the tarball ships
**prebuilt** artifacts (each client's `build/`, plus `clients/web/dist` and
`clients/web/static`) rather than sources to compile. Set
`INSPECTOR_SKIP_CLIENT_INSTALL=1` to skip it. The `files` allowlist itself is
[`docs/publishing.md`](../../../docs/publishing.md).
⚠️ **In a git worktree, do a real `npm install`.** A symlinked `node_modules`
passes lint, tests and coverage, then fails every Storybook story file on Vite's
@ -70,8 +73,11 @@ build-time alias:
- **CLI / TUI** — `esbuildOptions.alias` in `tsup.config.ts` maps
`@inspector/core` → the repo `core/` directory, with
`noExternal: [/^@inspector\/core/]` inlining it.
- **Web** — the same alias in `clients/web/vite.config.ts`, for both the browser
app and the Node backend runner.
- **Web** — **two** configs, because the client is two builds:
`clients/web/vite.config.ts` for the browser app, and
`clients/web/tsup.runner.config.ts` for the Node backend runner, which
defines the alias itself. Dependency or debugging work on the runner belongs
in the tsup config, not the Vite one (Copilot).
## Where a dependency goes

View file

@ -23,7 +23,7 @@ npm run format # auto-fix: core/, scripts/, the shared surface, every clien
npm run local:gate # several minutes
```
`local:gate` is `validate` → `coverage` → `verify:build-gate` →
`local:gate` is `validate` → `verify:skills:cli` → `coverage` → `verify:build-gate` →
`verify:bundle-externals` → `smoke` → `smoke:web:firefox` → `local:storybook`.
It is a **strict superset** of GitHub CI (which additionally runs `npm install`,
@ -62,6 +62,13 @@ A tracked `.ts`/`.tsx`/`.mts`/`.cts` lands in no tsconfig project. Usually a new
top-level file in a client whose build config roots at `./src`; add it to that
client's `tsconfig.test.json` (or the src config's `include`).
### `verify:skills` / `verify:skills:cli`
A `.claude/skills` manifest does not parse, declares no invocation mode, or a
model-invoked skill is missing its eval cases. `verify:skills:cli` is the
authoritative validator and fetches a pinned CLI over the network if you have
none installed — so it is also the one stage that will fail offline.
### `verify:dep-lockstep`
A dependency reaching one `tsc` program from two installs resolves to two