Plan testing for an Insight feature: risk-ordered test groups, target suites, scope boundaries and an acceptance gate. Use when deciding QA coverage, test dimensions or a test subtask. Review agreed requirements and inspect implementation, data flow and existing tests to expose risks and specification disagreements. Keep output at test-group level; quality-vector-tests turns that scope into tracked scenarios in an issue or FEATURE artifact.
71
86%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Turn a feature into a test scope a QA lead would actually trust: a short, code-grounded document that says what dimensions to check, groups the tests, draws the in/out boundary, and ends in a real acceptance gate. Then offer to file it as a linked test subtask.
The output is deliberately not a list of individual test cases. Cases come later and are cheap; getting the shape of coverage right — the axes, the boundary, the gate — is the expensive, high-leverage part, and it's what this skill produces.
Agreed requirements determine expected outcomes. Inspecting the implementation and data flow
reveals boundaries, risks and disagreements that a requirements-only pass can miss. Use those
findings to propose missing criteria and focus coverage; resolve specification disagreements
before changing expectations. An unimplemented promise remains a gap until the author changes
the contract. Follow the grounding contract in quality-vector-tests section 2.
Pull the issue (gh issue view <n> --repo constructorfabric/insight --json title,body,labels,assignees,projectItems).
Extract: what it does, why it matters, who consumes it, and its shape — one of:
The shape sets the strategy. Step 2 checks implementation claims and identifies disagreements with the agreed requirements; it does not silently change the contract.
When the exact target set isn't final (it'll be settled by a later scoping pass, or items will merge/split), do not scope to a hand-count of items — scope the machinery and invariants that hold regardless of the final list (registry-driven harnesses, sum/parity invariants). A scope pinned to today's list rots the moment the list changes; one pinned to invariants survives it.
Use quality-vector-tests step 1 to resolve the owning FEATURE and its section
1.2 FR/NFR references, including inherited obligations. Read Acceptance Criteria
as completion conditions; keep the kit's checklist form. Test groups attach to
the feature and its upstream requirements, without an imposed AC numbering or
coverage map. Record missing requirements and deferred behaviour with owner,
reason and resolution point. Grounding in step 2 may reveal disagreements;
resolve them before claiming a test group's coverage.
This is the core. Investigate this repo — src/backend, src/ingestion (and its dbt),
src/frontend for UI; when invoked from outside an insight checkout, the sibling ../insight
clone is the fallback. Do not
scope from memory or the issue alone. Look at:
src/frontend/src/api/, analytics clients).docs/, inbox/, cypilot specs) for intended behavior.In-progress features live on a branch, not main. If main doesn't contain the code, find
the implementation: gh pr list --search, git branch -r | grep, and read the actual branch
(worktree it via git worktree add, or git show <branch>:<path>). Scope against
the agreed requirements, real implementation and its DESIGN.md — these can diverge, and a
branch's DESIGN doc is frequently the richest single source of the test surface.
Enumerate worktrees authoritatively (git worktree list --porcelain) — never glob directory
names. Spawn parallel Explore agents when the surface is broad. Reading the code, migrations,
and schema is normally enough to scope coverage; a live stand's ClickHouse is an optional
sharpener for a specific check, not a prerequisite — you're planning tests, not executing them.
When code and requirements disagree, report the mismatch before changing expectations.
Grounding can reveal a race, an off-by-one, or a broken invariant. Add a must-verify check using
the agreed expected behavior and flag the defect to the author. If the expected behavior is
undefined, record a specification question instead of making the implementation its own oracle.
Offer to file a merged-code defect separately via file-bug-insight.
Shift from "does function X return Y" to "does the right thing show up for whoever depends on this" — the right person on the dashboard, the right metric total, the right screen, the right API shape. Name the consumers and the observable outcomes. Functional/behavioral framing surfaces the checks that matter and hides the ones that don't.
Coverage is measured along axes — the dimensions the behavior varies over (source × join-key, tenant × role, connector × operation, input-shape × outcome). When two axes interact, a small matrix with the expected outcome per cell is worth more than paragraphs — it makes the coverage and the gaps legible at a glance. Identify the axis where the risk actually lives (in the worked example, everything off the email column) and center the tests there.
The concrete enumerated set is itself an axis — not just abstract behavior. "Does sum/ratio × each view work" is the engine; "does each real metric produce the right value with its own measure/dimensions/cohort" is the coverage that catches per-item config bugs. Name that axis and list it (with rough counts — a count and a validation-effort estimate help the reader size the work). When the set is large and will grow (100 metrics, N connectors), say so and specify a registry-driven / parametrized harness that reads the source of truth — so coverage scales by adding config, not test code. That design choice belongs in the scope, because authoring N hand-written suites is the failure mode.
Configurator and export surfaces need a pipeline, not a click list. Model them as input state → validation → request planning → result shaping → preview → serialization. Inventory every closed option set the surface exposes — the metric list, the granularity choices, the export formats, whatever the topbar contributes — then split the coverage three ways:
Treat route entry as an axis whenever state lives in the URL: control navigation, cold deep-link,
reload and Back/Forward are four different paths through the SPA and its validators do not all
fail the same way. Treat the artifact as the consumer contract: a download event or a non-empty
file proves the transport, not the content, so parse every supported format and compare the
semantic table against the preview or the response that produced it. Put batching and serializer
boundaries in fe-unit / fe-component, request-contract edges in stand-api, and keep
stand-ui for the browser-only join — routing, rendering, cancellation and real downloads.
Explicitly list what's out of scope — not built yet, owned by another layer, or deferred to
later work — so nobody scores the feature against unbuilt surface. For a port — and usually a
refactor/consolidation — add the parity framing: the new behavior must equal what it replaces,
verified by a differential (same input, outputs compared row by row, every expectation
tagged exact / known-diff(direction) / merge — see the differential-gate axis below; a
port is simply the case where the whole table is exact) as the headline gate.
For a port, "what it replaces" is the old impl; for a consolidation it's the retired rows / sibling
keys the new output subsumes. When that differential is the strongest available proof, give it its
own headline test group rather than burying it inside the correctness group.
Two boundary traps worth naming explicitly:
xfail: the
gate that turns green when the deferred piece lands, so a known gap stays visible instead of
vanishing from the plan. (xfail-as-gate is the honest middle between "test it" and "drop it.")Collapse the dimensions into a handful of named test groups (aim for ~5–8), each a single line. Add sub-bullets or a matrix only where they carry real signal. Resist enumerating individual cases — if you're writing "test that email with trailing space unifies," you've dropped too low.
Give each group a home: the target component, then the cheapest suite that can falsify it.
The suite menu depends on the component the group targets — take it from the per-component
layer table in quality-vector-tests step 3 rather than from memory (the ladders differ by
backend function, and auth claims can terminate in stand-ui). The tag names the suite the
tests will land in, which is what makes a coverage gap checkable later. Suite tags and
feature and requirement ids are exempt from the strip-internal-identifiers rule below — they are the
tracking scheme itself. Browser journeys pay a
permanent flake tax: a stand-ui group must say what is user-visible about the claim that a
cheaper suite cannot observe.
Write each group as an action, not a property. A QA lead reading it should know what to do. Lead with a verb and name the setup → the check: "Build the metric×view harness: for each seeded metric request every view, assert value/dimensions/cohort" beats "Coverage: every metric serves in each view" — same content, but one is executable and one is a description. Order the groups as a plan (reusable harnesses first, then the gate, then apply per case). Keep it scannable: short sentences, no stacked parentheticals; if a reader has to re-read a line, cut it down. This is a frequent failure mode — the first draft reads like a spec, not a plan.
Deep analysis, lean artifact — they are not the same document. The surface inventory, state-
machine list, coverage matrix, and code-symbol grounding you build to find the coverage are
working notes; they are not what you file. Do that analysis (it's how you get the coverage right),
then keep it in chat or a plan file. What you file is a short, plain-language plan a QA lead
skims in under a minute: the test groups ordered biggest-risk-first, each a plain sentence,
with the internal identifiers stripped out — table names, ADR numbers, symbol paths, the S1/SM2/ T4 tags, the coverage matrix. Those are how you reasoned; to everyone else they read as a spec.
When someone asks for it "shorter" they mean fewer concepts, not smaller font — drop the
scaffolding, keep the risks. The end state to aim for is roughly six lines: one framing sentence,
then the handful of things that break the feature if they're wrong, worst first. That the analysis
was deep should show up as good choices in those six lines, not as six pages.
Lead with the stand when the tests need a non-trivial environment. If running these tests means standing up new infrastructure (a new service, a fake provider, a compose-vs-kube choice, seeded hooks), open the plan with a short The stand section naming exactly what to bring up and how you drive it. A reader cannot act on a coverage spec that never says what to run it against — that omission is what makes a scope read as abstract. Scopes over an already-implicit stand (a running ClickHouse + dbt) can skip it; anything that stands up new infra cannot.
Minimize without losing correctness by testing at the choke point. When enforcement is centralized — routes generated from one config, one shared verifier/middleware, one revoke pipeline, one code path — test each property once where it's enforced plus a cheap invariant that it's applied uniformly (a golden-file check that every generated route carries the auth block), instead of re-testing per route / per service / per caller. The deletions are safe precisely because the architecture forces those cases identical — say so, so the cut reads as principled, not lazy. Keep the security core (fail-closed, revocation, no-token-leak) and the cheap must-resolve spec ambiguities; those are correctness, not volume.
Use the template below. Short. Every line earns its place. There are two altitudes: the full template when the reader wants the working plan, and a compact form — one framing line + ~6 risk-ordered bullets + an out-of-scope line + a rough day estimate — when they want just the main effort. Default toward the compact end and expand only when asked; it is far easier to deepen a scope on request than to get a reader to wade through an over-detailed one. A scope that is correct but unread has failed.
Offer to file the scope as a linked test subtask under the parent feature via the
github-task skill (Type Task, added to the Insights board, attached as a sub-issue). Draft
for review first; don't auto-create. When the coverage belongs in the feature body instead,
hand the groups to quality-vector-tests — it lays them out as the tracked scenario checkboxes. Do not reimplement issue mechanics here — compose with
github-task.
Use these to interrogate the feature — keep the ones the code makes real, drop the rest:
exact (must match),
known-diff(direction) (a deliberate semantic change — assert the direction, don't fail it), or
merge/scale-preserving (siblings collapse into one — merged == Σ parts, source → breakdown).
The tagged expectation table is the reusable artifact; a blanket "zero diff" gate is wrong and
will fail intended changes.Keep it this tight. Drop any section that doesn't apply rather than padding it.
Compact form (the default when filing). Most of the time this is all you file — one framing line, ~6 risk-ordered bullets, an out-of-scope line, a day estimate. Reach for the full template below only when the reader wants the working plan.
Always wrap the compact form in a collapsible spoiler (<details>/<summary>) so it drops
into a GitHub issue or comment as one foldable block, with the 🧪 title line as the summary. Put
a blank line after <summary> and before </details> or GitHub won't render the markdown inside.
Estimate assuming the tests are automated over seeded example data on the existing stand —
that is the norm here, so day counts are small (often 1–3); only call out manual effort if some
check genuinely can't be automated.
<details>
<summary>🧪 QA testing scope — <feature> (#<n>)</summary>
<one framing sentence: what we're proving + the strategy in a phrase — e.g. "new feature, no
baseline to compare, so we test correctness" or "port — must reproduce the old counter">.
<Optional: one clause naming the single fixture / dataset threaded through everything.>
1. **<Biggest risk, plain words>** — <suite> — <what breaks the feature if this is wrong>.
2. **<Next risk>** — <suite> — <one plain sentence>.
... (~6 bullets, worst first)
**Out:** <what's deferred / owned elsewhere>. **~<N> QA-days, automated.**
</details>Full template — when the reader wants the working plan, not just the headline effort:
Test scope for <feature> (parent #<n> — use the nearest parent; note both if the feature itself
has one). Goal: <one line. For a port/consolidation, name the parity bar and what it must
reproduce — e.g. "the new counter equals the retired sibling keys on the same data">.
**<Axis / source split>** — <the corrected, code-grounded framing; e.g. seed sources vs
resolve-only sources, or the key axis of variation>.
**Out of scope:** <not-built / other-layer / deferred surface>.
## The stand <!-- only if the tests need new infra; drop for an implicit existing stand -->
<what to bring up — services, fake providers, compose vs kube, seed/hooks — and how you drive it>
## Plan
**1. <Verb> <the action>** (<suite> · owning feature and FR/NFR references) — <what to set up → what to assert;
matrix only where it adds signal>.
**2. <Verb> …** — <one line>.
... (~5–8 steps; reusable harnesses first, then the gate, then apply per case)
## Acceptance
- [ ] <the coverage/differential gate that actually proves it — e.g. per-source coverage measured;
differential tagged exact/known-diff(direction)/merge, never blanket zero-diff>
- [ ] every applicable feature requirement maps to a test group or shared evidence (deferred ones carry a reason
and an owner)
- [ ] <invariant / registry-driven / sequenced-UI checks as they apply>Five, one per shape — read the one closest to the feature in front of you:
references/example-identity-resolution.md — a port (C#→Rust identity-resolution). Models
the altitude, the assumption-correction move (git seeds no identity), and the source × join-key
matrix, with the old-vs-new differential as the gate.references/example-collab-consolidation.md — a refactor/consolidation (collapse
connector-scoped metric rows into modality counters with a breakdown). Models how a non-port
still gets a differential — against the retired sibling keys it subsumes — plus the
sum-equals-parts invariant and honest-NULL (not fake-zero) correction.references/example-unified-metrics-migration.md — a migration platform / rolling migration
(a generic metrics engine that the whole catalog migrates onto, wave by wave). Models the
provisional-target-set principle (test machinery over a fixed list), the three-way differential
tag, registry-driven harnesses, xfail-as-gate for deferred tenant isolation, the action-plan
altitude, and grounding that surfaced a real reconciler race.references/example-nginx-auth-security-epic.md — a security architecture EPIC (replace an
API gateway with an nginx edge + authenticator gear), specs-first (no code yet). Models the
no-differential security gate, grounding in PRD/DESIGN found on a merged branch, the fail-closed
matrix as the headline, choke-point minimization (test once + a golden-file invariant), the
stand-first action layout, and treating a fake provider's control hooks as the test oracle.references/example-functional-role-cohorts.md — a new capability (per-person role sets from
HR), no baseline to match. Models the risk-ordered correctness gate, "set-ness" as the one
concentrated risk, honest-gap / expected-fail handling — and the deep-analysis vs lean-artifact
split: do the surface/state-machine/matrix work to find the coverage, then file only the ~6-line
risk-ordered plan. The reference case for "shorter means fewer concepts, not smaller font."c31d302
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.