spec-preflight
Skill6 starsChanged 2 months agoMITView on GitHub
Empirical pre-flight checks on a Linear issue's spec. Use right before /work consumes a spec. Use when a spec has been sitting in Approved for >1 week and reality may have drifted. Verifies file paths, symbol/line refs, deps. Read-only.
In this repository32 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- brainstorm-reviewSkill
- brainstormSkill
- conceptSkill
- defineSkill
- financial-reviewSkill
- light-spec-reviseSkill
- light-specSkill
- linear-hygieneSkill
- linearSkill
- phase-planSkill
- pipekit-helpSkill
- pipekit-updateSkill
- pk-bugSkill
- pk-exitSkill
- pk-expressSkill
- pr-fixSkill
- prod-readySkill
- pr-security-reviewSkill
- release-changelogSkill
- repo-security-reviewSkill
- review-planSkill
- roadmap-createSkill
- roadmap-reviewSkill
- security-gateSkill
- startupSkill
- strategy-createSkill
- strategy-syncSkill
- sync-linearSkill
- tpmSkill
- verifySkill
- workSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. About 0 are common, 2 are distinctive, and 15 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
15
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 12
Read method.config.md for project context (Linear team prefix, state IDs, project root).
- Very specific: line 54
Read the issue via the project's Linear route — pk issue show PROJ-XXX --fields id,title,state,description --comments (verb table: …
- Very specific: line 60
Keep the inverseRelations nodes whose type is blocks — each one's issue blocks PROJ-XXX (the direction bin/pk itself reads for its …
- Very specific: line 67
If the issue isn't found or has no description: stop and report "PROJ-XXX has no spec body.
- Very specific: line 78
If a category yields zero claims, that's fine — record it as n/a in the verdict, not a failure.
- Very specific: line 128
If the Linear route times out or is unavailable on any individual fetch (pk surfaces the transport error rather than a not-found): record …
- Very specific: line 141
Read Strategy docs path from method.config.md (default: Strategy/).
- Very specific: line 163
If Strategy docs path is unset OR the directory is empty: record n/a — no Strategy docs configured.
- Very specific: line 173
Read Platform from method.config.md.
- Very specific: line 174
If Platform: managed-supabase: managed Supabase blocks the postgres role from ALTER DATABASE … SET <custom> even when role-owns the DB …
- Very specific: line 175
If Platform: self-hosted-postgres: emit ⚠ reminder to confirm the role has ALTER DATABASE privilege on the target DB.
- Very specific: line 176
If Platform unset or none: emit ⚠ Platform key not configured — GUC capability unverified for this deployment and continue.
- Very specific: line 219
If the AC mentions a tool but the same AC also says "to be added" / "follow-up" / "next phase": downgrade to ⚠ automatically — the spec …
- Very specific: line 257
If the skill was invoked with --accept:
- Distinctive: line 291
When emitting REVISE, point at *where* in the spec the divergence sits — by AC number, by section heading, by file path, or by the …
- Very specific: line 414
Read-only: Never edit the spec. Never transition Linear.
- Distinctive: line 416
Specific divergences: When something fails, name *which* claim failed (AC #, section heading, file path, dependency identifier) — not just …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Spec Preflight Skill
You verify that the empirical claims in a Linear issue's spec match reality, before pk branch <ID> + /work consume the spec. Spec Review Agent reviews narrative coherence; this skill reviews facts. The two are complementary — agent review catches "is the spec well-shaped?", /spec-preflight catches "is the spec still true?".
This skill is read-only: it never edits the spec, never transitions Linear status, never writes any project file. Output goes to stdout only. (A scratch file under /tmp/ is acceptable for analysis state.)
Read method.config.md for project context (Linear team prefix, state IDs, project root).
Triggers
/spec-preflight PROJ-XXX— verify a single specced issue/spec-preflight PROJ-XXX --accept— downgrade Phase 3.6 hard-fails (✗) to warnings (⚠). Use for accepted-risk cases (e.g., tooling intentionally absent, to be bootstrapped later). The findings still appear in the report; only the blocking verdict softens.- "pre-flight PROJ-XXX" / "verify spec PROJ-XXX"
When to use
Between Spec Review Agent passing and pk branch. The pipeline position:
/light-spec → Spec Review Agent → human approval → /spec-preflight → pk branch <ID> → /workFor Quick-tier issues that skip agent review entirely, this skill is the only automated check before pk branch — surface it in the Quick-tier template too.
When NOT to use
- The issue isn't specced yet — the skill has nothing empirical to verify. Run
/light-specfirst. - Mid-execution. Empirical claims drift while building; this skill validates the spec contract, not in-flight work.
Inputs (read-only)
| Source | Tool | Purpose |
| Linear issue body | pk issue show PROJ-XXX --fields id,title,state,description --comments, plus the pk gql blocker read in Step 1 | Spec body + status + blocked_by |
| File paths from spec | Read or Glob | Confirm cited files exist |
| Line ranges from spec | Read with offset/limit | Confirm line citations resolve to real content |
| Symbol/heading refs from spec | Grep | Confirm cited symbols/headings exist in the cited files |
| Linear status (re-fetched) | pk issue show PROJ-XXX --fields id,state | Compare current status against spec body's claim |
Each blocked_by issue | pk issue show <ID> --fields id,state | Confirm dependency claims of "Done" |
Strategy docs path (from method.config.md) | Glob + Read | Probe 3.6a — canonical-doc cross-check (#21) |
Platform (from method.config.md) | none — heuristic match against spec body | Probe 3.6b — platform-capability check (#20) |
package.json + lockfile (root + workspace pkgs) | Read + Grep | Probe 3.6c — tooling availability (#22) |
| Migration files cited in spec | Read (and optionally a Supabase MCP execute_sql for read-only SELECT COUNT(*) violator counts) | Probe 3.6d — migration data-shape (#24) |
Algorithm
Step 1 — Fetch the issue
Read the issue via the project's Linear route — pk issue show PROJ-XXX --fields id,title,state,description --comments (verb table: sop/Linear_SOP.md § Linear transport; the mcp route's equivalent is listed there) — then its blockers:
pk gql 'query($id: String!) { issue(id: $id) { inverseRelations(first: 50) { nodes { type issue { identifier state { name } } } } } }' '{"id":"PROJ-XXX"}'Keep the inverseRelations nodes whose type is blocks — each one's issue blocks PROJ-XXX (the direction bin/pk itself reads for its blocked-by annotation). Capture:
title,identifier- Full
description(the spec body) - Current
state.name(e.g.,Approved,Specced,Building) - The
blocked_bylist from the blocker read (each carries an issue identifier and its state)
If the issue isn't found or has no description: stop and report "PROJ-XXX has no spec body. Run /light-spec first.". Do not proceed to checks.
Step 2 — Parse empirical claims
Walk the spec body and bucket claims into four categories. Use these heuristics — when in doubt, prefer false-positive (treat ambiguous text as a claim and verify it) over false-negative (silently skipping a claim).
- File paths. Any backtick-quoted token containing
/or a file extension (e.g.,`supabase/config.toml`,`src/lib/auth.ts`). Treat absolute paths and project-relative paths the same way. Strip surrounding punctuation. - Code citations (line + symbol). Line forms:
line N of <file>,lines N-M of <file>,<file>:N,<file>:N-M— capture the file token and line range. Symbol forms (the preferred citation style, v4.23.0+ —/light-specnow emits path + symbol because line numbers rot fastest):`<file>` → `<symbol>`,<symbol>() in <file>, a backticked symbol and backticked file named in the same sentence, and<file> § <heading>for markdown targets — capture the file token and the symbol/heading text. - Linear status claim. A line in the spec body of the form
Status: <name>(typical Light Spec metadata). Capture the stated status. - Dependency claims. Cross-references to other Linear issues (
PROJ-NN) inside §Dependencies, §Blocked by, or in narrative prose like "blocked by PROJ-42 (Done)". The blocker list also comes from the Step 1 blocker read — combine both sources, dedupe by identifier.
If a category yields zero claims, that's fine — record it as n/a in the verdict, not a failure.
Step 3 — Verify each claim
For every parsed claim, verify against reality. Check categories in this order so that infrastructure-degraded checks don't block file-path checks (which are always verifiable).
3a — File paths
For each path, prefer Read (cheaper than Glob for known paths). On ENOENT, fall back to Glob with the basename to detect renames. Record:
exists— file present at the cited pathrenamed_to— if Glob found a single match elsewhere, surface it
A missing file is a real divergence (fail-loud), not infrastructure noise.
Exception — explicit-NEW markers. Before flagging a missing file as ✗, check whether the surrounding spec text marks the path as a NEW file the implementation will create. Treat any of the following as an explicit-NEW marker on the line of the path, on the same line, on the line before, or in a section header within 5 lines above:
NEW(bold, plain, or in parentheses):**NEW**,(NEW),, NEW(new)/(new file)- "Files to create" or "New files" section heading that contains the path
NEW: <path>prefix
When an explicit-NEW marker is present, record the path as 🆕 expected-new instead of ✗ missing — the spec is asserting this file will be created, not that it exists. The Phase 1–3 verdict treats 🆕 expected-new as ✓ for the file-paths category. The pre-existing files in the same list still get verified normally; only the NEW-marked paths get the downgrade.
Why: two Pipekit v2.4.x canary subjects on a consumer project listed NEW components explicitly in their specs (line-item-actions.tsx, line-item-edit-dialog.tsx, move-line-item-dialog.tsx), each clearly annotated NEW in the Technical Context section. v2.4.0's preflight emitted ✗ for all of them, which over-stated the divergence and forced manual exception-noting in the verdict. v2.4.2 collapses that noise.
3b — Code citations (line + symbol)
For each <file>:N or <file>:N-M, call Read with offset: N and limit: M-N+1 (or 1 for a single line). Record:
resolves— the line range exists (file is at least N lines long)- Optionally capture the cited content for the verdict (helps the user see if the line still says what the spec claims)
A line range past EOF is a divergence — record resolves: false.
For each symbol/heading citation, Grep the cited file for the symbol's definition or the heading text (for a symbol, match declaration-shaped lines first — function <sym>|const <sym>|def <sym>|class <sym>|export.*<sym> — falling back to any occurrence; for a heading, match ^#+\s*<heading>). Record:
resolves— the symbol/heading exists in the cited filemoved_to— if absent from the cited file,Grepthe repo (excludingnode_modules/) for the same declaration; a single hit elsewhere is a move — surface the new location, mirroring 3a'srenamed_to
A symbol found nowhere is a divergence (✗, REVISE). A moved symbol is ⚠ with the new location — the spec needs a path update, but the contract still exists. When a citation carries both a symbol and a line number, the symbol is authoritative: if the symbol resolves at a different line, record ⚠ drifted (symbol at line X, spec says Y) rather than ✗.
3c — Linear status
Re-fetch the issue's state (pk issue show PROJ-XXX --fields id,state, or reuse Step 1's payload if still in scope). Compare state.name to the spec body's Status: line. Record match or mismatch (spec says X, actual Y). The spec body claim is a documentation artifact, not the source of truth — Linear is. The point is to surface drift so the human knows the spec body is stale.
3d — Dependencies
For each blocked_by identifier (from the Step 1 blocker read and from any narrative claims in Step 2.5), read its state — pk issue show <ID> --fields id,state — and record Done / <other>. The pass criterion is "every blocker is Done"; anything else is a real gate failure that pk branch / /work would also catch — surfacing it pre-flight saves a round trip.
If the Linear route times out or is unavailable on any individual fetch (pk surfaces the transport error rather than a not-found): record that specific dependency as unverified — Linear API timeout and continue. Do not fail the whole verdict on infrastructure flake. (See Graceful Degradation below.)
Step 3.6 — Project signal probes
Steps 1–3 verify claims the spec explicitly makes (this file exists, that line resolves, this issue is Done). Step 3.6 probes claims the spec implies — by referencing a tool, by proposing a platform-specific mechanism, by drafting a migration, or by anchoring to a non-canonical source. These are the "environmental blindness" gaps the v2.3.x recovery surfaced; without them, downstream agents read a spec that's internally consistent but reality-divergent.
Each probe runs independently. A miss in one does not skip the others. Findings render as a separate category-block under the verdict. Where a probe needs method.config.md keys, fall through gracefully if the key is unset.
3.6a — Canonical-doc cross-check (handoff #21)
Trigger: the spec body contains any of POC, parity with POC, POC pattern, the POC (case-insensitive) AND method.config.md's Strategy docs path resolves to an existing directory.
Probe:
- Read
Strategy docs pathfrommethod.config.md(default:Strategy/). Glob<path>/*.mdand<path>/**/*.md. Capture the file list.- For each Strategy doc, scan the first 200 lines (section index) for headings that overlap concept words from the spec body. Concept words: nouns appearing in the spec's §Goal, §Acceptance Criteria headings, or italicized key terms.
- Strategy-citation check (v2.4.2): scan the spec body for inline citations of any Strategy doc — patterns like
Strategy/Doc<N>,Strategy/Doc<N>_<name>.md,Strategy/Doc<N> §<section>, or anAuthority hierarchytable that names a Strategy file as the authority for a concern. If the spec body cites ≥1 Strategy doc inline, treat the cross-check as performed (the spec author already did the work the probe is asking for) and downgrade the emit to✓ Canonical docs: Strategy cited inline at <doc>:<section>instead of⚠.
Emit (default ⚠ — ambiguous; the human decides whether topic overlap is load-bearing):
⚠ Canonical docs: Strategy at <path> contains <N> doc(s); spec body references POC.
Cross-check spec claims against:
- Strategy/<doc1>.md (sections: ...)
- Strategy/<doc2>.md (sections: ...)
Strategy is canonical for this project; POC may diverge.Emit when Strategy is cited inline in the spec body (v2.4.2 downgrade):
✓ Canonical docs: spec body cites Strategy inline (<list of cited docs+sections>);
cross-check performed in-spec. No further action.If Strategy docs path is unset OR the directory is empty: record n/a — no Strategy docs configured. Do not warn — projects without Strategy docs are valid.
Why the downgrade was added: a consumer project's revised spec body cited Strategy/Doc6 §2.1, Strategy/Doc6 §3.3 line 86, and Strategy/Doc2 §3.3.1 throughout — and had an explicit "Authority hierarchy" table naming Strategy as the canonical source for the 5-action button set, conversation surface, and line-item canonical fields. v2.4.0's probe still emitted ⚠ Cross-check spec claims against Strategy because the trigger ("POC mentioned + Strategy/ exists") fired blindly. The downgrade keeps the probe useful for specs that haven't done the cross-check while letting fully-cited specs pass cleanly.
3.6b — Platform capability (handoff #20)
Trigger: the spec body contains any of ALTER DATABASE, SET app\., current_setting\(, pg_db_role_setting, GUC, or other Postgres custom-parameter patterns.
Probe: (only runs when the trigger fires — if no GUC pattern appears in the spec, this probe renders as ✓ n/a)
- Read
Platformfrommethod.config.md. Recognized values:managed-supabase,self-hosted-postgres,none. Default: unset (treated as "unconfigured"). - If
Platform: managed-supabase: managed Supabase blocks thepostgresrole fromALTER DATABASE … SET <custom>even when role-owns the DB (verified empirically on a consumer project, handoff #20). Emit✗(hard fail) with the known-blocker note. - If
Platform: self-hosted-postgres: emit⚠reminder to confirm the role hasALTER DATABASEprivilege on the target DB. - If
Platformunset ornone: emit⚠ Platform key not configured — GUC capability unverified for this deploymentand continue. Spec author should setPlatformso the next preflight gives a definitive answer.
Emit (✗ for managed-supabase, ⚠ otherwise):
✗ Platform capability: spec proposes GUC-based mechanism (ALTER DATABASE … SET app.X);
Platform=managed-supabase blocks this — postgres role lacks SET DATABASE privilege
even as db owner (handoff #20, verified on a consumer project against prod + dev).
Redesign with a sentinel-table pattern OR change Platform if the deployment moved.3.6c — Tooling availability (handoff #22)
Trigger: an Acceptance Criterion line mentions any known test runner / quality tool / framework name. Detection list (extend as projects evolve):
| Tool | Package(s) to grep for |
| Playwright | @playwright/test, playwright |
| Cypress | cypress |
| Jest | jest |
| Vitest | vitest |
| Storybook | @storybook/, storybook |
| Lighthouse | lighthouse, lighthouse-ci, @lhci/cli |
| ESLint | eslint |
| Prettier | prettier |
| MSW | msw |
| Testing Library | @testing-library/ |
Probe:
- Locate
package.jsonfiles: repo root + every workspacepackage.jsondiscoverable viaGlob**/package.json(skipnode_modules/). - For each tool detected in an AC,
Grepthe combined package.json set for the package names listed above (check bothdependenciesanddevDependencies). - Also check the lockfile (
pnpm-lock.yaml/package-lock.json/yarn.lock) — a package in the lockfile but notpackage.jsonmeans it's a transitive dep, not directly callable. Treat as absent.
Emit (✗ hard fail — high-confidence blocker, downgradeable to ⚠ with --accept):
✗ Tooling availability: AC #5 requires Playwright but @playwright/test not in
package.json (dependencies or devDependencies). The AC is unsatisfiable as
written. Either:
a) bootstrap @playwright/test (separate issue first), or
b) rewrite AC against an existing test runner (Vitest is configured).If the AC mentions a tool but the same AC also says "to be added" / "follow-up" / "next phase": downgrade to ⚠ automatically — the spec author already acknowledged the gap.
3.6d — Migration data shape (handoff #24)
Trigger: the spec body cites a migration path under Migration dir (from method.config.md), OR proposes a migration with CHECK, NOT NULL, type narrowing (varchar(255) → varchar(64)), or column rename language.
Probe:
Readeach cited migration file (or the spec's inline SQL block).- Scan for:
ALTER TABLE … ADD CONSTRAINT … CHECK \(ALTER TABLE … ALTER COLUMN … SET NOT NULLALTER TABLE … RENAME COLUMN- Type-narrowing
ALTER COLUMN … TYPE
- For each constraint, build the inverse predicate as a
SELECT COUNT(*)query. Example:CHECK (show_end_date <= onsite_end_date)becomesSELECT COUNT(*) FROM <table> WHERE NOT (show_end_date <= onsite_end_date);. - If a Supabase MCP is bound (any
mcp__supabase-*__execute_sqltool available in this session): run the query against the parent project (read-onlySELECT— safe even on prod-tier). Emit the count. - If no MCP is bound: emit the query template for the user to run manually.
Emit (⚠ — surface for review; the spec author decides whether 0 violators is required or whether to add a backfill):
⚠ Migration data shape: 2 new constraint(s) on populated columns.
Run violator counts against parent project before merging:
-- CHECK (show_end_date <= onsite_end_date)
SELECT COUNT(*) FROM projects WHERE NOT (show_end_date <= onsite_end_date);
-- count against the dev database (`psql`/SQL editor): 1 violator
-- NOT NULL on projects.production_start
SELECT COUNT(*) FROM projects WHERE production_start IS NULL;
-- count against the dev database (`psql`/SQL editor): 0 violators
Decide per row: backfill, default, or block migration until data is consistent.This is the same shape gap as a consumer project's per-PR branch DBs running with_data: false — schema-only validation passes, data-incompatibility fails at apply-time against the populated parent. The probe shifts that discovery left, to spec-time.
When --accept is in effect
If the skill was invoked with --accept:
- Phase 3.6 hard-fails (
✗) downgrade to warnings (⚠). - A banner line appears above the verdict:
--accept: Phase 3.6 hard-fails downgraded to warnings. - Steps 1–3 hard-fails are unaffected (file-presence / line-ref / dependency failures remain blocking —
--acceptdoes not bypass empirical claim divergence).
Step 4 — Render verdict
Print a single block to stdout. Use checkmarks (✓), warning markers (⚠), and failure markers (✗) so humans can scan it fast. Format:
Pre-flight checks for PROJ-XXX ({tier} tier):
─ Empirical claims (Phase 1–3)
✓ File paths: {n_pass}/{n_total} exist
✓ Code refs (line/symbol): {n_pass}/{n_total} resolve
✓ Linear status: {state} (matches spec)
✓ Dependencies: {n_done}/{n_total} Done
─ Project signal probes (Phase 3.6)
{emoji} Canonical docs: {message or n/a}
{emoji} Platform capability: {message or n/a}
{emoji} Tooling availability: {message or n/a}
{emoji} Migration data shape: {message or n/a}
Verdict: {PASS | REVISE} — {one-line reason if REVISE}
{action hint if REVISE}Verdict rules:
- PASS — every category is
✓orn/a(no claims of that type) or graceful-degradation⚠ unverifiedfor the Linear API. Phase 3.6 may emit⚠(warnings) and still PASS — warnings inform but don't block. - REVISE — at least one real divergence in Phases 1–3 (missing file, unresolved line, status mismatch, non-Done dependency) OR a Phase 3.6 hard-fail (
✗: managed-Supabase GUC pattern; tooling absent frompackage.json). The user updates the spec (or resolves the blocker) beforepk branch. - REVISE (downgraded with
--accept) — Phase 3.6 hard-fails alone don't force REVISE when--acceptis in effect; they appear as warnings. Phase 1–3 hard-fails are never downgradeable.
When emitting REVISE, point at where in the spec the divergence sits — by AC number, by section heading, by file path, or by the migration constraint — so the human can edit surgically rather than re-reading the whole spec.
Step 5 — Stop
Print the verdict. Do nothing else. Do not call pk branch or /work. Do not transition Linear. Do not write any project file (NEXT.md is retired in v2 anyway, but this skill writes nothing — it gates the next move).
Graceful Degradation
These rules are explicit so the skill stays useful when infrastructure is partially down:
| Condition | Behavior |
| Linear route timeout fetching the main issue | Stop. The skill needs the spec body to do anything else. Report "Linear API unavailable — re-run later.". |
| Linear route timeout fetching a blocker | Record that dependency as ⚠ unverified. Verdict is PASS-eligible if all other categories pass. |
| File doesn't exist | Real divergence. Record ✗. Triggers REVISE. Not graceful — file-presence is verifiable without infrastructure. |
| Line range past EOF | Same as above — ✗, REVISE. |
Strategy docs path unset / dir empty | Canonical-docs probe records n/a. Not a warning — projects without Strategy docs are valid. |
Platform key unset | Platform-capability probe records ⚠ Platform key not configured — capability unverified only if the spec body triggered the probe (GUC pattern detected). |
No package.json discoverable | Tooling-availability probe records ⚠ no package.json found — tooling claims unverified. Verdict PASS-eligible. |
| No Supabase MCP bound | Migration-data-shape probe emits query templates for manual run. No ⚠ from this alone — surfacing the query is the deliverable. |
Graceful degradation never upgrades the verdict (a ⚠ cannot become ✓); it just keeps a single failure mode from blocking the rest of the report.
Output Examples
PASS verdict:
Pre-flight checks for RS-87 (Standard tier):
─ Empirical claims (Phase 1–3)
✓ File paths: 4/4 exist
✓ Code refs (line/symbol): 2/2 resolve
✓ Linear status: Approved (matches spec)
✓ Dependencies: 2/2 Done
─ Project signal probes (Phase 3.6)
✓ Canonical docs: n/a — no Strategy docs configured
✓ Platform capability: n/a — no GUC pattern in spec
✓ Tooling availability: 1/1 verified (Vitest in package.json)
✓ Migration data shape: n/a — no migration cited
Verdict: PASS — spec is empirically current. Proceed to pk branch RS-87.REVISE with a Phase 1–3 divergence:
Pre-flight checks for RS-51 (Standard tier):
─ Empirical claims (Phase 1–3)
✓ File paths: 5/5 exist
✓ Code refs (line/symbol): 3/3 resolve
✗ Linear status: Needs Spec (spec body says Approved)
✓ Dependencies: 2/2 Done
─ Project signal probes (Phase 3.6)
✓ Canonical docs: n/a — no Strategy docs configured
✓ Platform capability: n/a
✓ Tooling availability: n/a — no test runner in ACs
✓ Migration data shape: n/a
Verdict: REVISE — Linear status diverges from the spec body.
Update the spec's "Status: Approved" line (or advance the issue) before pk branch.REVISE with the PROJ-348 canary pattern (#21 + #22):
Pre-flight checks for PROJ-348 (Standard tier):
─ Empirical claims (Phase 1–3)
⚠ File paths: 4/6 exist (renamed: projects.js → database/projects.js,
budget-edit-main.js → pages/budget-edit-main.js)
✓ Code refs (line/symbol): 2/2 resolve
✓ Linear status: Specced (matches spec)
✓ Dependencies: 1/1 Done
─ Project signal probes (Phase 3.6)
⚠ Canonical docs: Strategy at Strategy/ contains 2 doc(s); spec body references POC.
Cross-check spec claims against:
- Strategy/Doc1_ConceptualOverview.md §3.1 (project lifecycle dates)
- Strategy/Doc2_TechnicalSpec.md §3.2.3 (six date fields, engagement defaults)
Strategy defines 6 lifecycle date fields; spec claims 5. Reconcile before approval.
✓ Platform capability: n/a — no GUC pattern in spec
✗ Tooling availability: AC #5 requires Playwright but @playwright/test not in
package.json. Either bootstrap (separate issue) or rewrite against Vitest.
⚠ Migration data shape: 5 chronological CHECK constraint(s) on projects (populated).
Run violator counts against the dev database (`psql`/SQL editor) before merging:
SELECT COUNT(*) FROM projects WHERE NOT (show_end_date <= onsite_end_date);
SELECT COUNT(*) FROM projects WHERE NOT (project_start_date <= production_start);
-- (3 more)
Verdict: REVISE
- File path renames (2): update §Technical Context paths.
- Canonical-doc divergence: spec claims 5 fields, Strategy says 6. Reconcile §Goal + ACs.
- Tooling absent: AC #5 Playwright requirement unsatisfiable until bootstrap issue lands.
- Migration data shape: 5 CHECKs on populated table — run violator counts first.REVISE downgraded with --accept:
--accept: Phase 3.6 hard-fails downgraded to warnings.
Pre-flight checks for PROJ-348 (Standard tier):
─ Empirical claims (Phase 1–3)
✓ File paths: 6/6 exist
✓ Code refs (line/symbol): 2/2 resolve
✓ Linear status: Specced (matches spec)
✓ Dependencies: 1/1 Done
─ Project signal probes (Phase 3.6)
⚠ Canonical docs: ...
⚠ Tooling availability: AC #5 Playwright absent (--accept: hard-fail downgraded)
⚠ Migration data shape: ...
Verdict: PASS (with --accept warnings) — proceed knowing the listed gaps are accepted-risk.Rules of Engagement
- Read-only. Never edit the spec. Never transition Linear. Never write any project file. The only writes allowed are scratch files under
/tmp/for parsing state. - No false confidence. A graceful-degradation
⚠is not a✓. The verdict surfaces what was unverified so the human can re-run later or accept the gap. - Specific divergences. When something fails, name which claim failed (AC #, section heading, file path, dependency identifier) — not just "a mismatch." The user shouldn't have to grep the spec to find what to fix.
- Don't recurse into the daily loop. This skill ends at the verdict. The user invokes
pk branch <ID>themselves on PASS (then/workfrom inside the worktree), or/light-spec-reviseon REVISE.
Relationship to Other Skills
| Skill | Relationship |
/light-spec | Produces the spec this skill verifies. |
| Spec Review Agent | Reviews narrative coherence. /spec-preflight reviews empirical claims — complementary, not redundant. |
/light-spec-revise | Where the user goes on REVISE if the spec body is the problem (most cases). |
pk branch + /work | The daily loop consumes specs that have passed /spec-preflight. |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

