From 051688e1964fae11c888f0cf16d86bcf05c39a91 Mon Sep 17 00:00:00 2001 From: Malin Date: Sat, 15 Aug 2026 14:28:54 +0200 Subject: [PATCH] feat: 10 new skills scouted from spec-kit and deepseek-harness Sourced via Codex scan of github/spec-kit and deepseek-ai/deepseek-harness (scan reports in granja/_temp/codex-logs/), then authored by Codex against this repo's exact SKILL.md format/density, calibrated against bastille-jail-provisioning/writing-implementation-plans/tdd. Spot-checked two directly (write-feature-specification, harden-async-lifecycle-code) -- concrete, code-example-backed procedures, not generic advice. From spec-kit: write-feature-specification, clarify-feature-specification, audit-requirements-quality, analyze-spec-plan-task-consistency, converge-implementation-to-spec. From deepseek-harness: harden-async-lifecycle-code, test-real-entry-paths, snapshot-agent-behavior, maintain-decision-records, remove-reasoning-transcript-prose. Co-Authored-By: Claude Sonnet 5 --- .../SKILL.md | 137 +++++++++++++++ skills/audit-requirements-quality/SKILL.md | 151 ++++++++++++++++ skills/clarify-feature-specification/SKILL.md | 129 ++++++++++++++ .../converge-implementation-to-spec/SKILL.md | 113 ++++++++++++ skills/harden-async-lifecycle-code/SKILL.md | 159 +++++++++++++++++ skills/maintain-decision-records/SKILL.md | 150 ++++++++++++++++ .../SKILL.md | 137 +++++++++++++++ skills/snapshot-agent-behavior/SKILL.md | 151 ++++++++++++++++ skills/test-real-entry-paths/SKILL.md | 120 +++++++++++++ skills/write-feature-specification/SKILL.md | 163 ++++++++++++++++++ 10 files changed, 1410 insertions(+) create mode 100644 skills/analyze-spec-plan-task-consistency/SKILL.md create mode 100644 skills/audit-requirements-quality/SKILL.md create mode 100644 skills/clarify-feature-specification/SKILL.md create mode 100644 skills/converge-implementation-to-spec/SKILL.md create mode 100644 skills/harden-async-lifecycle-code/SKILL.md create mode 100644 skills/maintain-decision-records/SKILL.md create mode 100644 skills/remove-reasoning-transcript-prose/SKILL.md create mode 100644 skills/snapshot-agent-behavior/SKILL.md create mode 100644 skills/test-real-entry-paths/SKILL.md create mode 100644 skills/write-feature-specification/SKILL.md diff --git a/skills/analyze-spec-plan-task-consistency/SKILL.md b/skills/analyze-spec-plan-task-consistency/SKILL.md new file mode 100644 index 0000000..f83f7fa --- /dev/null +++ b/skills/analyze-spec-plan-task-consistency/SKILL.md @@ -0,0 +1,137 @@ +--- +name: analyze-spec-plan-task-consistency +description: Use when a feature specification, technical plan, task list, and project principles exist and need a read-only semantic audit for conflicts, ambiguity, duplication, underspecification, traceability, and coverage gaps before implementation. +--- + +# Analyze Spec, Plan, and Task Consistency + +Perform a read-only audit. Do not edit the artifacts, generate replacement tasks, or resolve policy conflicts silently. The output is a traceable findings report that lets the owner decide what to change. + +## 1. Require a complete artifact set + +Locate and read: + +- feature specification; +- technical plan; +- implementation task list; +- project principles, constitution, ADRs, or mandatory policy, when present. + +Stop if spec, plan, or tasks are missing. Partial analysis produces misleading coverage numbers. Treat an unfilled policy template as absent and say so. + +## 2. Build normalized inventories + +Extract only normative or buildable content. + +From the spec: + +- functional requirements and stable IDs; +- user journeys and acceptance scenarios; +- edge cases; +- buildable success criteria, excluding post-launch business KPIs; +- assumptions and exclusions. + +From the plan: + +- architecture and stack decisions; +- data model and contracts; +- named components and file touch-points; +- technical constraints, migration, and verification strategy. + +From tasks: + +- task IDs, phase, dependencies, and parallel markers; +- action, file path, and claimed requirement/story association. + +From principles: + +- every `MUST`, `MUST NOT`, and materially relevant `SHOULD`. + +Normalize equivalent phrases to one concept key such as `account-recovery` or `retention-window`, while preserving original IDs for citations. + +## 3. Run six detection passes + +### Duplication + +Find requirements or tasks that express the same obligation with different IDs. Distinguish harmless local restatement from two authorities that can drift. Flag duplicates when ownership, criteria, or wording differ materially. + +### Ambiguity + +Find vague adjectives, unresolved placeholders, undefined actors, unclear pronouns, missing quantities, or terms used with multiple meanings. Quote the shortest relevant phrase and state what decision cannot be derived. + +### Underspecification + +Find journeys without acceptance scenarios, requirements without observable outcomes, plan choices without failure/compatibility treatment, and tasks without files or verifiable completion conditions. + +### Conflict + +Compare: + +- requirement against requirement; +- requirement against plan decision; +- task against requirement or plan; +- every artifact against mandatory principles. + +A stricter plan is not automatically a conflict; it is a conflict when it changes stated behavior, excludes required scope, or violates an authority. + +### Coverage + +Build both directions: + +```text +requirement/criterion → plan decision(s) → task(s) +task → originating requirement, plan decision, or principle +``` + +Flag requirements with no task, tasks with no source, acceptance scenarios with no implementation path, and principle obligations with no enforcement or verification work. + +### Ordering and feasibility + +Find tasks that consume artifacts before they are created, claim unsafe parallelism on the same file/shared state, omit migrations or wiring, or schedule integration proof before a runnable composition exists. + +## 4. Assign severity + +Use: + +- **CRITICAL:** violates a mandatory principle, creates a security/privacy breach, or makes P1 behavior impossible. +- **HIGH:** uncovered core requirement, direct spec/plan conflict, or task set cannot deliver an acceptance scenario. +- **MEDIUM:** meaningful ambiguity, secondary coverage gap, unsupported task, or ordering risk. +- **LOW:** localized duplication, terminology drift, or polish-level traceability weakness. + +Do not inflate severity because an item is easy to notice. When uncertain between two levels, choose the lower and state the uncertainty. + +## 5. Report findings with evidence + +Use stable IDs such as `A001` and order by severity, then by artifact order. + +```markdown +| ID | Category | Severity | Locations | Finding | Recommendation | +|----|----------|----------|-----------|---------|----------------| +| A001 | Coverage | HIGH | FR-008; tasks.md | No task implements or verifies revocation of active challenges. | Add a vertical task covering state change and acceptance proof. | +``` + +Every finding must cite at least two locations for a conflict/duplication, or one location plus an explicit missing mapping for a gap. Recommendations name the artifact that owns the correction; they do not draft the correction. + +## 6. Provide coverage metrics + +Report: + +```text +Requirements mapped to ≥1 task: 18/20 (90%) +Acceptance scenarios mapped: 7/9 (78%) +Tasks with an authoritative source: 24/26 (92%) +Mandatory principles represented: 4/5 (80%) +``` + +Counts are navigation aids, not proof of quality. One task mentioning an ID does not count as coverage unless its action could satisfy the obligation. One task may cover several requirements, and one requirement may need several tasks. + +## 7. Self-check and handoff + +- no artifact was modified; +- every finding is evidence-backed and non-duplicative; +- all mandatory principles were inspected; +- both requirement-to-task and task-to-intent mappings were checked; +- severity follows impact rather than wording; +- recommendations preserve artifact ownership; +- a zero-finding report includes inventory and coverage counts. + +End with the top three remediation priorities and state whether implementation should pause. Any CRITICAL finding or unresolved HIGH conflict means pause; ordinary MEDIUM gaps may be corrected before or during planning at the owner’s discretion. diff --git a/skills/audit-requirements-quality/SKILL.md b/skills/audit-requirements-quality/SKILL.md new file mode 100644 index 0000000..d2197e6 --- /dev/null +++ b/skills/audit-requirements-quality/SKILL.md @@ -0,0 +1,151 @@ +--- +name: audit-requirements-quality +description: Use when reviewing a specification, PRD, or requirements document for completeness, clarity, consistency, measurability, traceability, and scenario coverage without testing implementation behavior. +--- + +# Audit Requirements Quality + +Create “unit tests for English.” The checklist asks whether the requirements are written well enough to build and test. It never asks whether the product currently behaves correctly. + +## The decisive distinction + +Bad item — implementation test: + +```markdown +- [ ] Verify the page displays three featured cards. +``` + +Good item — requirements-quality test: + +```markdown +- [ ] CHK001 Are the number, ordering, and selection rules for featured cards explicitly specified? [Completeness, Spec §FR-004] +``` + +The bad item belongs in a test plan. The good item can fail while no code exists, because it evaluates the words. + +## 1. Choose audit depth and focus + +Read the authoritative requirements and any linked plan or principles needed to interpret them. State the requested focus, such as security, API, accessibility, migration, performance, or general readiness. + +Use one of three depths: + +- light: 10–15 highest-risk items; +- standard: 20–30 items across all applicable dimensions; +- deep: up to 40 items, including cross-section consistency and exception coverage. + +Use a soft cap of 40. Merge near-duplicates and consolidate low-impact edge cases rather than producing checkbox noise. + +## 2. Inventory the requirement surfaces + +Collect stable requirement IDs, user journeys, acceptance criteria, success criteria, assumptions, dependencies, entities, and explicit exclusions. If IDs do not exist, cite headings and flag traceability as a gap. + +Classify scenarios: + +- primary; +- alternate; +- exception/error; +- recovery/rollback; +- non-functional; +- boundary and empty state. + +Do not infer that an implementation probably handles a missing scenario. Absence in the requirements is the finding. + +## 3. Generate quality questions + +Group items under applicable dimensions: + +- Requirement Completeness +- Requirement Clarity +- Requirement Consistency +- Acceptance Criteria Quality +- Scenario Coverage +- Edge Case Coverage +- Non-Functional Requirements +- Dependencies and Assumptions +- Ambiguities and Conflicts +- Traceability + +Use these forms: + +```markdown +- [ ] CHK001 Are failure outcomes defined for every external dependency? [Completeness, Gap] +- [ ] CHK002 Is “fast” quantified from the user’s perspective? [Clarity, Spec §NFR-002] +- [ ] CHK003 Are retention obligations consistent between FR-008 and the privacy section? [Consistency, Spec §FR-008] +- [ ] CHK004 Can the success threshold in SC-003 be measured objectively? [Measurability, Spec §SC-003] +- [ ] CHK005 Are rollback requirements defined for interruption after partial migration? [Coverage, Gap] +``` + +At least 80% of items must contain a direct section/ID reference or one of `[Gap]`, `[Ambiguity]`, `[Conflict]`, `[Assumption]`, or `[Dependency]`. + +## 4. Cover domain-relevant failure classes + +Ask whether requirements exist and are precise for: + +- actor permissions and ownership boundaries; +- empty, loading, stale, duplicate, and partial data; +- invalid input and dependency failures; +- concurrency, conflict resolution, retries, and idempotency; +- security failures, abuse limits, and sensitive-data handling; +- accessibility and localization; +- capacity, latency, degradation, and recovery targets; +- deletion, retention, rollback, and irreversible operations; +- compatibility, versioning, and migration. + +Only include a class when it could plausibly affect the feature. A generic security checklist pasted onto a static copy edit is not a quality audit. + +## 5. Apply the wording gate + +Reject any item that: + +- starts with “Verify,” “Test,” “Confirm,” or “Check” and then describes product behavior; +- tells a user to click, navigate, render, execute, or load something; +- says “works correctly,” “functions as expected,” or “displays properly”; +- names code, framework internals, algorithms, or test procedures; +- merely restates a requirement as a behavior assertion. + +Require items to ask one of: + +- Are requirements for X defined/documented? +- Is vague term X quantified or clarified? +- Are A and B consistent? +- Can criterion X be objectively measured? +- Are scenarios or edge cases X covered? +- Does the document define missing aspect X? + +## 6. Write a reviewer-owned artifact + +Use globally increasing IDs and leave new items unchecked: + +```markdown +# Requirements Checklist: + +**Purpose:** Evaluate the quality of written requirements for . +**Source:** + +**Marker semantics:** `[x]` means a reviewer found the requirements-quality criterion satisfied. It does not mean implementation is complete. + +## Requirement Clarity + +- [ ] CHK001 ... + +## Notes + +- Record the requirement edit or decision beside any resolved item. +``` + +When appending to an existing checklist, continue from its maximum ID. Never delete, renumber, mark as passed, or overwrite reviewer-owned items during generation. + +## 7. Self-audit the audit + +Before handoff: + +- every item tests prose quality, not runtime behavior; +- categories reflect actual feature risk; +- scenario classes are represented or intentionally excluded; +- near-duplicates are merged; +- at least 80% of items are traceable; +- each item contains one answerable quality proposition; +- new markers remain unchecked; +- the list is within the selected depth cap. + +Report item count, focus, depth, source documents, and the most material uncovered requirement areas. Do not claim the underlying requirements pass until a reviewer evaluates the checklist. diff --git a/skills/clarify-feature-specification/SKILL.md b/skills/clarify-feature-specification/SKILL.md new file mode 100644 index 0000000..f949106 --- /dev/null +++ b/skills/clarify-feature-specification/SKILL.md @@ -0,0 +1,129 @@ +--- +name: clarify-feature-specification +description: Use when an existing feature specification is materially ambiguous or incomplete and its highest-impact decisions must be resolved before technical planning without expanding scope. +--- + +# Clarify a Feature Specification + +Clarification tightens an existing intent artifact. It does not create a new feature, choose an implementation, or turn optional ideas into scope. + +## 1. Establish the authority and boundary + +Read the entire current specification plus any project principles it claims to follow. If no specification exists, stop and request one; do not silently author a replacement. + +Record the current in-scope and out-of-scope statements. Treat them as a fence. A proposed answer that adds a new actor, journey, business outcome, or integration is a scope change and requires explicit approval outside this workflow. + +## 2. Build an ambiguity map + +Mark each category `Clear`, `Partial`, or `Missing`: + +- functional goals, boundaries, actors, and permissions; +- entity identity, relationships, lifecycle, and scale assumptions; +- primary, alternate, empty, error, and recovery flows; +- performance, reliability, availability, and observability outcomes; +- security, privacy, retention, and compliance obligations; +- external dependencies, formats, compatibility, and failure modes; +- conflicts, concurrency, throttling, and negative scenarios; +- terminology and canonical names; +- acceptance scenarios and measurable completion signals; +- placeholders and vague adjectives. + +Create a candidate question only if its answer would materially alter architecture, data modeling, task decomposition, test design, user-visible behavior, operational readiness, or compliance validation. Exclude stylistic preferences, already answered points, and choices properly owned by the technical plan. + +## 3. Prioritize a small batch + +Score each candidate using: + +```text +priority = impact × uncertainty × irreversibility +``` + +Use High/Medium/Low values rather than fake numeric precision. Prefer one scope or security question over several polish questions. Cap a clarification session at five accepted questions; use three when that resolves the material uncertainty. + +Questions must be answerable as either: + +- 2–5 mutually exclusive choices with consequences; or +- a short phrase explicitly limited to five words. + +Ask one question at a time so later questions can be dropped or rewritten after each decision. Do not expose the whole internal queue. + +## 4. Ask answerable questions + +Use this form: + +```markdown +**Question:** Who may approve a refund above the ordinary limit? + +This determines the permission boundary and the acceptance scenarios for high-value refunds. + +**Recommended:** Option B — requiring a second approver limits unilateral high-value changes while preserving a defined path. + +| Option | Answer | Consequence | +|--------|--------|-------------| +| A | Any refund operator | Simplest flow; broadest authority | +| B | Two refund operators | Adds dual control and an intermediate state | +| C | Finance administrator only | Narrowest authority; may delay completion | + +Reply with A, B, C, “recommended,” or a short alternative. +``` + +The question must be a complete interrogative, not a topic label such as “Refund permissions.” Explain why it matters before listing options. Recommend only when the existing context supports a best default; otherwise state the trade-off neutrally. + +Validate the reply. If it does not map to an option or is too vague, ask a disambiguation without counting a new question. Accept “recommended” only when a recommendation was shown. + +Stop when critical ambiguity is resolved, the user says to stop, or five answers have been accepted. Report high-impact deferred questions rather than exceeding the cap. + +## 5. Integrate each answer immediately + +After every accepted answer: + +1. add one audit bullet under `## Clarifications` and a dated session heading; +2. edit the authoritative section where the decision belongs; +3. remove or replace the now-invalid ambiguous wording; +4. save the file before asking the next question. + +```markdown +## Clarifications + +### Session 2026-08-15 + +- Q: Who may approve a refund above the ordinary limit? → A: Two refund operators. +``` + +Route the decision by kind: + +- functional answer → functional requirement; +- actor or sequence answer → journey and acceptance scenarios; +- entity answer → entity identity, relationship, or lifecycle; +- quality answer → measurable success criterion; +- failure answer → edge case or exception scenario; +- terminology answer → normalize the canonical term throughout. + +Write the smallest testable change. Do not append a clarification while leaving contradictory alternatives elsewhere. If the answer changes settled scope, pause and label it a scope amendment rather than integrating it as routine clarification. + +## 6. Validate after each edit + +Check: + +- exactly one clarification bullet exists per accepted answer; +- the answer appears in the normative section, not only the audit log; +- the triggering placeholder or vague phrase is gone; +- no earlier statement asserts a rejected alternative; +- IDs, heading hierarchy, and unrelated ordering are preserved; +- canonical terminology is consistent; +- no new actor, journey, or requirement slipped in without being implied by the answer. + +If a requirements-quality checklist exists, re-evaluate it against the edited spec. Toggle only checklist state that the clarified text actually changes; preserve all other wording and formatting. + +## 7. Report the result + +Report: + +- number of questions accepted; +- specification path; +- sections changed; +- categories resolved, clear, deferred, and still outstanding; +- any checklist items that changed state; +- whether planning can safely begin. + +If no candidate meets the materiality threshold, say that no critical ambiguity warrants formal clarification. Do not invent questions to fill a quota. diff --git a/skills/converge-implementation-to-spec/SKILL.md b/skills/converge-implementation-to-spec/SKILL.md new file mode 100644 index 0000000..9ca183c --- /dev/null +++ b/skills/converge-implementation-to-spec/SKILL.md @@ -0,0 +1,113 @@ +--- +name: converge-implementation-to-spec +description: Use when implementation exists and must be compared against its specification, plan, and task ledger to classify remaining intent gaps and append remediation work. Pairs with verification-before-completion but does not replace or duplicate its independent evidence checks. +--- + +# Converge Implementation to Specification + +Convergence answers “what specified intent is still not represented correctly in the codebase?” It is not a generic final verification pass. Use `verification-before-completion` separately to independently prove completion claims and test results after convergence work is implemented. + +## 1. Establish authoritative scope + +Read the complete specification, technical plan, current task ledger, and mandatory project principles. Refuse to infer a larger feature from nearby code or conversation history. + +Extract named file/component touch-points from the plan and tasks. Expand scope only through repository searches for the exact domain concepts and public interfaces named by the artifacts. Record why each additional file belongs. + +If code is sparse or absent, continue: specified obligations are `missing`, not an analysis failure. + +## 2. Build an intent inventory + +Create one row per: + +- functional requirement; +- buildable success criterion; +- user-story acceptance scenario; +- binding plan decision; +- mandatory project principle relevant to this feature; +- existing task whose unchecked intent is not fully represented elsewhere. + +```text +Intent key | Source | Obligation | Expected code surface | Evidence sought +FR-008 | spec | revoke active challenge | recovery service + public entry | state guard and observable outcome +US1/AC2 | spec | expired challenge cannot mutate credentials | validation path | negative path before mutation +``` + +Do not count a task checkbox as evidence. The ledger records intent and work history; code and observable tests show realization. + +## 3. Inspect implementation by intent + +For every row: + +1. locate the public entry path and relevant internal owner; +2. read implementation, tests, migrations/configuration, and wiring; +3. compare observable behavior and constraints with the source wording; +4. record concrete evidence by file and symbol or section; +5. create a finding only when intent is not fully represented. + +Classify each gap: + +- **missing:** no implementation exists; +- **partial:** some path or case exists but the obligation is incomplete; +- **incorrect:** implementation contradicts the intended behavior, constraint, or principle; +- **obsolete:** code or a task represents intent that has been removed or superseded. + +Use `obsolete` for awareness and remediation, not as authorization to delete. First determine whether compatibility, migration, or historical data still depends on it. + +## 4. Assign severity + +- **CRITICAL:** violates a mandatory principle or makes baseline P1 behavior unsafe or impossible. +- **HIGH:** missing/incorrect core requirement or acceptance scenario. +- **MEDIUM:** partial secondary behavior, plan drift with material maintenance cost, or obsolete work of unclear consequence. +- **LOW:** bounded polish gap or low-risk stale surface. + +Severity measures consequence, not estimated effort. + +## 5. Present findings before writing + +```markdown +| ID | Gap | Severity | Source | Evidence | Remediation | +|----|-----|----------|--------|----------|-------------| +| F001 | partial | HIGH | US1/AC2 | `src/recovery.ts` rejects expiry after credential mutation | Move expiry guard before mutation and add a public-path regression test. | +``` + +Include counts of requirements, acceptance scenarios, plan decisions, and principles inspected, plus findings by gap and severity. Distinguish “no evidence found” from “evidence disproves intent.” + +## 6. Append concrete remediation tasks + +Do not rewrite settled spec/plan text and do not renumber or edit prior tasks. Append a new `Convergence` phase only when actionable findings exist. + +1. find the largest existing task number and phase number; +2. create the next phase at the end; +3. order CRITICAL, HIGH, MEDIUM, LOW; +4. emit one independently completable task per finding; +5. cite the source and gap class; +6. name exact files/symbols when known and observable acceptance evidence. + +```markdown +## Phase 7: Convergence + +- [ ] T042 **CRITICAL** Enforce the project isolation principle in `src/jobs/dispatch.ts` and cover the public submission path; reject cross-tenant job IDs without reading their payload. (Principle II; incorrect) +- [ ] T043 Move the expiry guard before credential mutation in `src/recovery.ts` and add a real-entry regression test for US1/AC2. (US1/AC2; partial) +``` + +For an obsolete surface, phrase the task as “review and justify, migrate, or remove,” with explicit compatibility checks. Do not prejudge deletion. + +Never add an empty convergence phase. If a prior convergence phase exists, append a newly numbered phase; its old checkboxes are history, not scratch space. + +## 7. Repeat until genuinely converged + +After remediation is implemented, rebuild the inventory from current artifacts and inspect again. Do not merely check whether appended tasks are marked done. A follow-up may expose a deeper partial or an obsolete workaround. + +Stop only when: + +- every inventory row has concrete implementation evidence; +- no missing, partial, incorrect, or actionable obsolete finding remains; +- no new out-of-scope behavior requires owner review; +- task ledger has no unchecked convergence work; +- mandatory principles are represented in code and appropriate tests. + +Then leave the ledger unchanged and report the counts inspected. Phrase the result as convergence against the defined artifact scope, not proof that the whole product is bug-free. + +## 8. Hand off to independent verification + +Run the repository’s relevant checks and actual entry paths under `verification-before-completion`. That skill owns the rule that test claims and delegate reports must be independently rechecked. This skill owns intent enumeration, semantic code comparison, gap classification, and remediation-ledger maintenance; do not duplicate generic “run tests and trust the output” guidance here. diff --git a/skills/harden-async-lifecycle-code/SKILL.md b/skills/harden-async-lifecycle-code/SKILL.md new file mode 100644 index 0000000..a22b3d2 --- /dev/null +++ b/skills/harden-async-lifecycle-code/SKILL.md @@ -0,0 +1,159 @@ +--- +name: harden-async-lifecycle-code +description: Use when implementing or reviewing asynchronous lifecycle, callback dispatch, subprocess, cancellation, temporary spill, or teardown code where races, orphaned work, exception leakage, secret exposure, or unsafe link cleanup are possible. +--- + +# Harden Async Lifecycle Code + +Treat lifecycle correctness as a set of independently observable contracts. Each rule below prevents a distinct shipped failure class; do not collapse them into a single success boolean or a generic cleanup block. + +## 1. Draw the lifecycle before editing + +For every owned resource, record: + +```text +resource | creator | start signal | completion signal | cancellation request | quiescence signal | disposer +``` + +Include processes, streams, readers, timers, callbacks, registries, temp files, and background promises. Mark shared signals versus per-operation signals. If ownership or quiescence cannot be named, the design is not ready. + +Model states explicitly, for example: + +```text +created → starting → running → stopping → quiescent → disposed + ↘ failed ─────────────↗ +``` + +Define legal repeated calls. Usually cancellation and disposal are idempotent; starting twice is rejected. + +## 2. Report orthogonal outcomes independently + +A process may time out and later exit zero because it handled the termination signal. A request may be aborted and also produce a provider error. Do not nest one fact beneath another: + +```ts +type Outcome = { + timedOut: boolean + aborted: boolean + exitCode: number | null + signal: string | null + error: Error | null +} +``` + +Bad: + +```ts +if (exitCode !== 0) return { timedOut } +return { ok: true } // loses the fact that the deadline cut the run short +``` + +This rule prevents cut-short work from being reported as a clean success. Define precedence only for a final display label; preserve every underlying fact. + +## 3. Normalize public async contracts + +Inventory every way an implementation can signal termination: throw, reject, terminal event, EOF, abort event, or status field. Choose one public contract and normalize at the boundary. + +Example: provider failures may arrive as throws or error-finish events, while consumer callback defects should remain thrown. Convert only provider-originated forms to the documented terminal result; do not swallow middleware or caller bugs into the same bucket. + +Test each source form through a real consumer. This prevents callers from guessing whether a caught exception came from the provider, a wrapper, logging, or their own assembly. + +## 4. Do not mistake shared state for operation completion + +Global `idle`, `running`, reader `close`, or queue-empty signals may cover several operations. They cannot prove which message completed, whether it started, or which output belongs to it. + +For an owned operation, define an interval with durable boundaries, such as: + +```text +operation receipt persisted → all work attributable to the owned run settled → system quiescent +``` + +If the API lacks per-operation completion, describe captured output as interval-wide, not causally attributed. Handle the “nothing started, therefore no transition will occur” branch explicitly or the wait can hang forever. + +This prevents wrapper jobs from reporting completion merely because background work was started or a shared agent later became idle. + +## 5. Dispose to quiescence + +Disposal means work has stopped, not that a stop request was issued. + +Use this order unless resource dependencies require a documented variation: + +1. mark the owner as disposing so no new work is accepted; +2. close callback/listener/notification registries; +3. request cancellation or send termination to children; +4. await every child’s definitive completion signal; +5. escalate termination after a bounded grace period when appropriate; +6. await exit after escalation; +7. close streams, handles, and files; +8. remove owned temporary paths; +9. mark disposed. + +```ts +async function dispose(): Promise { + if (disposePromise) return disposePromise + disposePromise = (async () => { + accepting = false + listeners.clear() + child.kill('SIGTERM') + await withTimeout(childDone, graceMs, () => child.kill('SIGKILL')) + await childDone + await removeOwnedTemp() + })() + return disposePromise +} +``` + +Returning after `kill()` creates orphaned processes and late callbacks into torn-down state. + +## 6. Isolate callback failures + +Take a stable snapshot if listeners may add/remove listeners during dispatch. Catch per listener so one bad subscriber cannot reject the lifecycle promise or starve later subscribers: + +```ts +for (const listener of [...listeners]) { + try { + await listener(event) + } catch (error) { + logger.error({ error }, 'listener failed') + } +} +``` + +Define whether dispatch is sequential or concurrent. Sequential preserves order; concurrent must collect all settlements. Never leave floating promises. + +## 7. Scrub child environments + +Do not pass the ambient environment to an untrusted command or tool output. Build an allowlist where feasible. Otherwise clone and delete keys whose case-insensitive names contain `KEY`, `SECRET`, `TOKEN`, `PASSWORD`, `CREDENTIAL`, or project-specific secret names. + +Preserve only variables required for execution, such as a controlled `PATH`, locale, and explicitly approved runtime settings. Test that canary secrets are absent from child `env` output and spill artifacts. This prevents harness or CI credentials from leaking through subprocess output. + +## 8. Create private unpredictable spill paths + +Create a random private directory with mode `0700`, then files with exclusive creation and mode `0600`: + +```ts +const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'worker-')) +await fs.chmod(dir, 0o700) +const handle = await fs.open(path.join(dir, randomUUID()), 'wx', 0o600) +``` + +Never use a predictable shared filename, open without exclusivity, or depend on a permissive default umask. Those allow pre-created symlink races and cross-user disclosure. + +## 9. Unlink link-shaped paths safely + +For a path that may be a symlink or Windows junction, inspect with `lstat`, not `stat`. If it is link-shaped, call `unlink`; do not recursively remove it. `unlink` deletes the link and refuses a real directory. Recursive removal may follow a junction or otherwise endanger its target. + +Reserve recursive deletion for a path proven to be a real directory created and owned by this operation. Validate the resolved target remains inside the owned private parent before deletion. + +## 10. Test the failure classes + +- timeout plus zero exit preserves both facts; +- cancellation before start does not hang; +- disposal awaits real process exit and emits no late callback; +- one throwing listener does not block the next; +- repeated disposal returns the same settlement; +- child environment omits canary secrets; +- spill creation rejects a pre-existing name; +- cleanup unlinks a symlink/junction without touching its target; +- provider errors normalize while consumer defects still throw. + +Use fake clocks only for time nondeterminism; keep the real queue, dispatcher, process wrapper, and cleanup owner whenever possible. diff --git a/skills/maintain-decision-records/SKILL.md b/skills/maintain-decision-records/SKILL.md new file mode 100644 index 0000000..1d24703 --- /dev/null +++ b/skills/maintain-decision-records/SKILL.md @@ -0,0 +1,150 @@ +--- +name: maintain-decision-records +description: Use when creating, accepting, evolving, superseding, rejecting, auditing, or archiving durable engineering decision records while preserving rationale, alternatives, consequences, accurate lifecycle status, and valid links. +--- + +# Maintain Decision Records + +A decision record preserves why a durable choice exists and what it gave up. Code and current docs own present mechanics; the record owns decision rationale, alternatives, consequences, and conditions that prevent re-litigation. + +## 1. Find the owner before creating a record + +Search existing active and rejected records by concept, affected interface, and alternative. Update the existing owner when the decision is unchanged. Do not create one record per PR or duplicate the same rationale under a new title. + +Create a record when a change alters behavior, architecture, a shared contract, process, testing strategy, durable/wire/config format, security boundary, or another choice a maintainer may reasonably revisit. Skip purely mechanical local edits. + +Use a stable path convention if the project has none: + +```text +decisions//YYYY-MM-DD-.md +``` + +Use relative Markdown links between records so moves can be checked mechanically. + +## 2. Choose the truthful lifecycle + +- **proposed:** decision is under review or only partly implemented; +- **accepted:** decision is current and shipped; +- **rejected:** proposal was considered and declined; +- **superseded:** a newer decision replaces all or part of it; +- **archived:** frozen historical snapshot with low current decision value. + +Status is truth, not workflow aspiration. Never leave “accepted” on an unshipped proposal. Never edit an accepted record into the opposite decision. + +## 3. Write the appropriate skeleton + +Proposed: + +```markdown +# Decision: + +Status: proposed + +## Problem +## Proposal +## Alternatives considered +## Acceptance criteria +## Risks +``` + +Accepted: + +```markdown +# Decision: <title> + +Status: accepted + +## Problem +## Decision +## Alternatives considered +## Consequences +## Verification +``` + +Rejected: + +```markdown +# Decision: <title> + +Status: rejected — <one-line verdict> + +## Problem +## Proposal +## Alternatives considered +## Rejection rationale +``` + +Every record starts with the problem independently of its preferred solution. Record genuine alternatives and why each lost; do not invent straw alternatives after the fact. + +## 4. Move a proposal to accepted + +In the same change that ships it: + +1. move/update status to `accepted`; +2. rewrite future-tense `Proposal` as present-tense `Decision`; +3. replace plans with what actually shipped; +4. convert acceptance criteria into evidence under `Verification`; +5. fold realized risks and trade-offs into `Consequences`; +6. update paths, symbols, defaults, formats, and links; +7. preserve alternatives and rationale. + +An accepted record must describe shipped reality, not its implementation checklist. + +## 5. Keep current facts accurate without rewriting history + +When the same decision moves files, renames symbols, or changes a realization detail, update those facts in the accepted record. Do not append a chronological changelog. + +When the decision or rationale reverses, create a new record. Add reciprocal links: + +```markdown +Status: superseded by [Use append-only events](../accepted/2026-08-15-append-only-events.md) +``` + +The new record explains what it supersedes and why. For partial supersession, keep both active and state which scope each owns. + +Delete a fully superseded record only when the current owner preserves every unique rationale, alternative, consequence, verification obligation, and named gap, and every inbound link is repaired. Git history is not the only acceptable copy. + +## 6. Handle rejected records deliberately + +Keep a rejected record only when the losing idea remains tempting and its rationale prevents a meaningful mistake. Freeze the proposal and make the verdict prominent. Delete it when the premise is obsolete, the idea is no longer plausible, or a newer record fully owns the warning. Repair inbound links when deleting. + +Do not relabel a rejected proposal as accepted by rewriting it in place; create or revive the correct decision history explicitly. + +## 7. Distinguish four storage roles + +- **Active rationale:** accepted record whose trade-offs, ownership boundary, negative guarantee, or reintroduction condition still guides work. Keep current. +- **Current-state decision:** concise accepted record that owns a live rule even if implementation detail lives elsewhere. Keep current. +- **Rejected fallacy prevention:** rejected record that blocks a plausible bad choice. Keep readable but stable. +- **Frozen archive:** low-future-value implemented history retained for provenance, not current authority. Freeze it. + +Age and word count do not decide archival. Archive only accepted records whose rationale is unlikely to guide future changes. Never archive a proposal; reject it or continue review. + +## 8. Archive safely + +Before archiving: + +1. confirm current docs/code own the present behavior; +2. inspect inbound links; +3. redirect active guidance to current authority; +4. move the record to the archive without modernizing its body; +5. add only archive metadata required by the repository; +6. freeze it against future edits. + +Active prose may cite an archived record as intentional history, but not as current operational authority. Do not repair outbound links inside a sealed archive if the project treats archives as frozen. + +## 9. Mechanical audit + +Check: + +- path lifecycle agrees with `Status`; +- required headings match lifecycle; +- accepted decisions use present tense; +- proposed-only plans are absent from accepted records; +- alternatives exist and are real; +- consequences include both benefits and costs; +- supersession links are reciprocal and resolve; +- every relative link resolves after moves; +- no duplicate active owner exists; +- archive files are unchanged except the authorized archival move/metadata. + +Report records created, updated, accepted, superseded, rejected, deleted, archived, and deliberately kept, including borderline calls and their governing rationale. diff --git a/skills/remove-reasoning-transcript-prose/SKILL.md b/skills/remove-reasoning-transcript-prose/SKILL.md new file mode 100644 index 0000000..46f2bcd --- /dev/null +++ b/skills/remove-reasoning-transcript-prose/SKILL.md @@ -0,0 +1,137 @@ +--- +name: remove-reasoning-transcript-prose +description: Use when durable documentation or comments contain design-session narration, PR-stack references, reviewer commentary, change narration, dead draft citations, conversational control flow, or other prose that cannot be resolved and verified from the repository at HEAD. +--- + +# Remove Reasoning-Transcript Prose + +Durable prose must speak from the repository’s current, verifiable vantage. Remove the authoring-session transcript while preserving every factual clause a maintainer still needs. + +## The core test + +For each passage ask: + +> Can a reader at HEAD resolve and verify every reference and claim without seeing the authoring session, PR thread, review conversation, or uncommitted draft? + +If no, enumerate the passage’s facts, restate the surviving facts from HEAD’s vantage, and delete the transcript framing. If the passage contains no durable fact, delete it outright. + +## 1. Set scope and exclusions + +Require an explicit file/directory/diff scope. Read applicable repository instructions. Exclude vendored sources, generated artifacts whose owner is elsewhere, recorded model fixtures, and frozen archives unless the user explicitly requests those artifacts and they are editable. + +For generated prose, edit the owning source or template and regenerate. Treat model-visible strings as behavior: require the appropriate snapshot or behavior test before changing them. + +## 2. Audit read-only first + +Use searches as recall probes, then read dense prose semantically: + +```bash +rg -n --hidden -g '*.md' -g '*.{ts,tsx,js,jsx,py,go,rs,java}' \ + '(decision [A-Z0-9]+|audit [A-Z0-9]+|design §|plan §|this PR|this commit|later PR|previous commit|rejected in review|reviewer|used to|no longer|for now|should be enough|first we|then we)' <scope> +``` + +Also inspect module docs, JSDoc, comments around surprising invariants, READMEs, and decision records without a search pattern in mind. Patterns miss paraphrases and produce legitimate hits. + +## 3. Classify each suspect passage + +### Dead session citations + +Examples: `(decision 7)`, `audit C2`, `design §4.7`, task-wave labels, “the design ledger.” Replace with a named committed link when one owns the fact; otherwise remove the citation and make the factual clause stand alone. + +### PR/stack vantage + +Examples: “this PR adds,” “a later PR in the stack,” “the previous commit.” State the current mechanism. Put real deferred work in a resolvable issue or `TODO(owner):` marker. + +### Change narration + +Examples: “used to,” “no longer,” “the old implementation,” “in this cut,” “now” as a release contrast. In current-state docs, state present behavior. Preserve a useful regression reason as a counterfactual: + +```text +Before: We used to delete the directory recursively, but now unlink junctions. +After: Unlink junctions; recursive removal can descend into the junction target. +``` + +### Review choreography + +Examples: “rejected in review,” “the reviewer confirmed,” “version 5 addresses feedback.” Keep the decision and rationale; remove who said it and in which round. + +### Reviewer-addressed justification + +Examples: “this cast is safe because…” or “this is correct because…” State the invariant that makes it safe, or delete the comment when the code already makes it obvious. + +### Conversational control flow + +Examples: “first we considered X, then we realized Y,” walkthroughs of obvious branches, or narration of how the author reasoned. Replace with the resulting contract, invariant, or consequence. + +### Hedges and planning residue + +Examples: “probably fine for now,” “should be enough,” or an unowned deferral. Replace with the actual bound or a mechanically resolvable TODO/issue; otherwise delete. + +## 4. Preserve complete propositions + +Before editing, list internally every proposition: + +- actor and action; +- condition, timing, and order; +- `must`, `may`, `never`, or other modality; +- negative guarantee and exception; +- ownership and side effect; +- failure mode and consequence; +- evidence or provenance that remains verifiable. + +Rewrite only after every relevant proposition has a destination. Never delete a factual clause merely because it shares a sentence with transcript framing. + +Worked example: + +```text +Original: Reviewer B confirmed in round 3 that we now close listeners before killing the child, because otherwise callbacks from the old implementation raced teardown. + +Facts: +- listeners close before child termination; +- late callbacks can race teardown if listeners remain open. + +Rewrite: Close listener registries before terminating the child so late completion callbacks cannot enter teardown state. +``` + +## 5. Preserve legitimate history and references + +Do not remove: + +- issue references and owned TODOs that resolve at HEAD; +- external standards citations; +- committed decision-record links; +- PR/issue evidence inside sanctioned postmortems or decision-history sections; +- suppression and empty-catch justifications; +- measured bounds with meaningful provenance; +- counterfactual-present regression warnings (“without X, Y occurs”); +- runtime old/new states (“the old connection drains before the new one accepts”); +- genuine alternatives-considered sections. + +Resolvable history may still be misplaced in a current-state README; move unique causal history to a decision record or postmortem and keep the present contract locally. + +## 6. Edit owner-first + +For each candidate choose one outcome: keep, restate, delete, move, or defer. + +- generated catalog → edit source documentation, regenerate; +- duplicated explanation → keep one authoritative home, retain essential local contract; +- current-state doc → present behavior and consequence; +- decision record → preserve unique rationale and alternatives; +- postmortem → preserve incident sequence, evidence, and causal chain; +- comment → retain only non-obvious invariant, ownership, failure, or rationale. + +Do not optimize for word-count reduction. A shorter sentence that drops a precondition or negative guarantee is worse. + +## 7. Verify the rewrite + +Re-run the recall searches and inspect remaining hits. For each keep, explain why it is resolvable and appropriate to that document genre. Then check: + +- every internal reference resolves at HEAD; +- no factual proposition disappeared in the diff; +- modal force and exceptions are unchanged; +- no hypothetical became a claim of shipped behavior; +- current-state docs no longer narrate PR/review chronology; +- generated or paired artifacts were updated through their owner; +- relevant link, docs, lint, and snapshot checks pass. + +Report scope inspected, passages restated, passages deleted as fact-free narration, deliberate keeps, and any deferred model-visible or frozen artifact. diff --git a/skills/snapshot-agent-behavior/SKILL.md b/skills/snapshot-agent-behavior/SKILL.md new file mode 100644 index 0000000..67da62b --- /dev/null +++ b/skills/snapshot-agent-behavior/SKILL.md @@ -0,0 +1,151 @@ +--- +name: snapshot-agent-behavior +description: Use when an agent or API-driven application needs deterministic, keyless regression snapshots despite nondeterministic LLM or remote-service calls, including transport, model-visible context, tool schemas, persistence, and presentation. +--- + +# Snapshot Agent Behavior + +Record a real interaction once, then replay the assembled application without credentials. Snapshot boundaries should expose product regressions while normalizing only values that are truly volatile. + +## 1. Define the surfaces and scenario + +Choose one named user journey with deterministic inputs. Inventory separately: + +- transport requests/responses or CLI frames; +- model-visible messages and request headers; +- system instructions; +- tool schemas; +- tool calls and results; +- durable session/event log; +- user-visible terminal, web, or protocol output. + +Do not collapse these into one opaque blob. A failure should reveal which surface changed. + +Use a real application composition and runtime entry. Replace only the live LLM/API provider during replay. + +## 2. Define a portable fixture schema + +Keep an explicit scenario directory: + +```text +snapshots/<scenario>/ +├── input.jsonl # user/protocol inputs and control events +├── provider-replay.jsonl # recorded provider stream/events +├── output.expected.jsonl # normalized external output +├── session.expected.jsonl # normalized re-persisted durable log +├── system-prompt.expected.md # only for a header-pinning scenario +└── tool-schemas.expected.json # only for a header-pinning scenario +``` + +Each JSONL file starts with a versioned header identifying fixture type, scenario, and schema version. Preserve event order and deterministic sequence numbers. + +Example records: + +```json +{"type":"fixture","schema":1,"scenario":"create-report"} +{"type":"input","text":"Create report.txt containing ready"} +{"type":"provider_chunk","delta":{"tool_call":{"name":"write_file","arguments":{"path":"report.txt","content":"ready"}}}} +{"type":"provider_finish","kind":"stop"} +``` + +Do not store live credentials, authorization headers, or unrelated environment values. + +## 3. Record once through the live boundary + +With explicit authorization and credentials available: + +1. create a fresh isolated workspace and session; +2. boot the real assembled application; +3. send the scenario inputs; +4. capture provider requests and streamed events losslessly; +5. capture external output and the final durable session log; +6. independently verify the world state; +7. convert captures into fixture roles above; +8. remove secrets before writing any fixture. + +Recording is a deliberate mode, never the CI default. Fail if recording would overwrite a fixture without an explicit flag. + +## 4. Normalize only true volatility + +Maintain named, pure normalizers. Typical volatility: + +- wall-clock timestamps → `0` or relative offsets; +- request/session/message IDs → stable first-seen tokens when identity is not semantic; +- generated workspace root → `{{cwd}}`; +- random temp basenames → role tokens; +- nondeterministic hook durations → `0`. + +Preserve: + +- event order and deterministic sequence numbers; +- finish/error kinds; +- tool names, arguments, and results; +- user/model text; +- permissions and policy outcomes; +- config selections; +- durable relationships between correlated IDs. + +Before normalizing a field, prove that changing it cannot alter behavior under review. “The diff is noisy” is not proof of volatility. Structurally rewrite known ID fields; do not global-replace arbitrary UUID-shaped strings that may be user content. + +## 5. Pin one full header fixture + +System prompts and tool schemas are large and repeat across scenarios. Select one representative scenario per distinct header class to store their full bytes. In every other scenario, replace the repeated bulk with tokens such as `{{system}}` and `{{tools}}` while retaining header structure, configuration, reason, and model-visible prefixes. + +Guards must reject: + +- no pin or multiple pins for one header class; +- a tokenized scenario whose generated header differs from its pin; +- duplicate full sidecars; +- unscrubbed bulk where a token is required. + +This makes a header edit churn one reviewable fixture instead of dozens without weakening coverage. + +## 6. Replay keylessly + +In replay mode: + +1. boot the same application composition with only the provider swapped for a replay adapter; +2. feed committed input/control events; +3. require provider requests to match the recorded semantic request before releasing recorded chunks; +4. capture external output; +5. let the real persistence layer write a new session log; +6. normalize both captures; +7. compare them byte-for-byte with expected fixtures; +8. inspect external world state independently. + +Reject missing, extra, reordered, or unconsumed provider events. Replay must fail without live credentials present, proving it is actually keyless. + +## 7. Assert re-persistence + +Do not compare only stdout or UI output. Read the session/event log produced by the replay run, normalize it, and compare it to `session.expected.jsonl`. This catches assembly, persistence, event-ordering, and recovery drift invisible in presentation. + +Where the format packs repeated chunks, compare logical decoded events or canonicalize packing before byte comparison. Keep the header/version contract explicit. + +## 8. Refresh versus re-record + +- **Refresh:** replay inputs are still semantically valid; regenerate expected external and persistence outputs keylessly. +- **Re-record:** provider interaction itself must change; call the live service and replace provider fixtures intentionally. + +Never use re-record to make an unexplained failure green. Review every fixture diff like source code: + +- Which semantic behavior changed? +- Which changes are normalization-only? +- Did a new field appear or disappear? +- Did event order, tool schema, prompt, finish kind, or durable state change? +- Does the full header pin carry the expected edit? + +CI runs replay read-only and fails if the working tree changes. + +## 9. Fixture integrity checks + +- all scenario directories are declared and no declared fixture is missing; +- schema headers and JSONL parse correctly; +- no secret/canary value exists; +- tokens resolve to exactly one runtime value; +- each header class has one full pin; +- replay consumes every recorded provider event; +- external output and re-persisted log match; +- a semantic fixture mutation makes the test fail; +- record/refresh modes are impossible in CI. + +Report which surfaces are pinned, which fields are normalized and why, and whether the run was live record, keyless refresh, or read-only replay. diff --git a/skills/test-real-entry-paths/SKILL.md b/skills/test-real-entry-paths/SKILL.md new file mode 100644 index 0000000..2973238 --- /dev/null +++ b/skills/test-real-entry-paths/SKILL.md @@ -0,0 +1,120 @@ +--- +name: test-real-entry-paths +description: Use when designing integration, end-to-end, release, or regression tests that must prove shipped behavior through the project's actual composition and published runtime entry point rather than a hand-assembled test path. +--- + +# Test Real Entry Paths + +A green unit suite can coexist with a completely broken product when tests bypass loading, composition, packaging, or the external world. Identify the path users actually execute for this project and test that path. + +## 1. Name the shipped path before choosing a test + +Ask: + +```text +What exact artifact and entry point does a user, editor, server, job runner, package consumer, or operating system invoke after release? +``` + +Examples include a built CLI executable, published package export, application bootstrap, plugin/config loader, worker entry, installed extension, container command, HTTP route through production middleware, or migration binary. Do not assume source imports or a specific stack. + +Write the chain: + +```text +published artifact → loader/configuration → composition/DI → public action → external state +``` + +The test must traverse every link implicated by the change. + +## 2. Identify bypasses in existing tests + +Flag tests that: + +- import an internal function instead of the published entry; +- mount a component manually instead of using the shipping loader; +- run source through a development transpiler while users execute built output; +- replace real downstream tools with hand-written stand-ins; +- assert only a returned message or agent self-report; +- never exercise module exports, configuration resolution, registration, or process exit. + +These tests may remain useful unit tests. They do not satisfy real-entry coverage. + +## 3. Mock only true nondeterminism + +Keep real: + +- application composition and dependency registration; +- loaders and configuration parsing; +- the tool/executor under test; +- persistence and serialization; +- public transport and protocol assembly; +- built artifact and process boundary where shipped. + +Mock only a genuinely nondeterministic, costly, or unavailable boundary: LLM response, remote network, wall clock, random source, or third-party outage. Put the mock at that outer boundary, not between internal components. + +Bad: replace the filesystem tool with `{ success: true }`. + +Good: script the model’s tool call, run the real filesystem tool in a temporary workspace, then inspect the file externally. + +## 4. Assert the world, not the actor’s story + +If the action should create a file, read it from a separate handle. If it should run a command, execute or inspect the resulting process state. If it should publish a record, query through an independent consumer. If it should leave unrelated files untouched, compare them byte-for-byte. + +```text +Weak: output contains “created report.txt” +Strong: report.txt exists, has exact expected bytes, and sibling.txt is unchanged +``` + +Agent/model output is untrusted evidence. Logs and exit codes are supporting evidence, not substitutes for world state when the world is observable. + +## 5. Exercise built and non-index entries + +Build the product using the release build. Invoke the built entry under the same runtime users receive, without source-only path maps, hot reloaders, or test transpilers. + +Include non-index runtime siblings when they ship independently: workers, subprocess helpers, migration binaries, generated clients, or singleton-bearing modules used across bundles. Test missing configuration and load failures produce a non-zero exit or documented error rather than being swallowed. + +This catches module-resolution, export-shape, duplicated-singleton, settle-race, and packaging omissions that source tests mask. + +## 6. Own resources and teardown + +Each test creates its own workspace, server, process, credentials fixture, and application instance. Register cleanup immediately in `afterEach`/`finally`, not after the first successful action. Await quiescent disposal so retries and failures do not leak processes or ports. + +Shared helpers belong in non-test modules; importing one test file from another can register its suite twice. + +## 7. Prove the regression guard goes red + +For every regression test: + +1. run it against the fixed code; observe green; +2. locally restore the exact defective condition or equivalent mutation; +3. run the focused test; observe the intended assertion fail for the intended reason; +4. reapply the fix; +5. run the focused test again; observe green; +6. run the broader relevant suite. + +If the test remains green under the regression, it is not a guard. Strengthen its entry path or assertion. Do not commit the deliberate regression. + +## 8. Layer evidence deliberately + +Use the smallest set that covers distinct risks: + +- unit test: branch and contract detail; +- real-composition test: loader, configuration, registration, and collaboration; +- built-artifact smoke: packaging and runtime entry; +- external-world assertion: actual effect; +- live-service smoke: provider compatibility when a key/service is available. + +Line coverage proves execution, not shipped behavior. A real-service test does not replace deterministic keyless coverage; each answers a different question. + +## 9. Handoff checklist + +- actual published/runtime entry point is named; +- test crosses the real loader/composition path; +- only nondeterministic outer boundaries are mocked; +- assertion observes independent external state; +- built artifact is exercised where release changes can matter; +- failure/missing-config behavior is asserted; +- resources are disposed even on timeout or retry; +- deliberate regression makes the guard red; +- fix restored and focused plus broader checks are green. + +Report the exact entry chain, mocked boundaries, external observations, and red-capability evidence. diff --git a/skills/write-feature-specification/SKILL.md b/skills/write-feature-specification/SKILL.md new file mode 100644 index 0000000..db475b7 --- /dev/null +++ b/skills/write-feature-specification/SKILL.md @@ -0,0 +1,163 @@ +--- +name: write-feature-specification +description: Use when turning a feature request into a bounded, technology-independent specification before technical planning or implementation begins. +--- + +# Write a Feature Specification + +Write the contract for **what users need and why**, not how engineers will build it. The result must let a product reviewer judge scope and let a tester derive acceptance tests without choosing a language, framework, database, API shape, or module layout. + +## 1. Extract the request + +Read the request and any governing project principles. Write down, internally: + +- actors and their goals; +- actions and observable outcomes; +- information created, read, changed, or deleted; +- explicit constraints and exclusions; +- dependencies and stated business outcomes. + +If no actor, goal, or observable journey can be recovered, stop and ask for the missing feature intent. Do not manufacture a specification from a technology request alone. + +Separate intent from implementation. Preserve domain terms such as OAuth or PDF when they are part of the user-visible requirement, but replace implementation prescriptions with outcomes unless the prescription is itself a binding external constraint. + +## 2. Bound uncertainty + +Fill ordinary gaps with reasonable defaults and record each one under `Assumptions`. Ask only when all three are true: + +1. the answer materially changes scope, security/privacy, user experience, or acceptance; +2. at least two reasonable answers have different consequences; +3. no safe, conventional default follows from the request or project context. + +Keep at most three unresolved clarification markers in a first draft. Prioritize scope, then security/privacy, then user experience; defer technical choices to planning. Use this exact form: + +```markdown +[NEEDS CLARIFICATION: Which account roles may approve a refund?] +``` + +Do not ask about routine error messages, conventional accessibility, or a particular integration style when a documented assumption can bound them. + +## 3. Write prioritized, independent journeys + +Order journeys P1, P2, P3 by delivered user value, not implementation order. Each journey must remain a viable demonstrable slice if later journeys do not exist. + +```markdown +### User Journey 1 — Recover access (Priority: P1) + +A registered user who cannot sign in can regain access without support staff. + +**Why this priority:** Locked-out users cannot use any other account feature. + +**Independent test:** Starting from a recoverable account, the user regains access and can sign in without any P2 capability. + +**Acceptance scenarios:** + +1. **Given** a recoverable account, **When** the user completes the recovery challenge, **Then** the user can set new credentials. +2. **Given** an expired challenge, **When** it is submitted, **Then** access is not changed and the user is told how to request a new challenge. +``` + +Reject journeys that are layers (“build database”), components (“create settings page”), or dependencies (“add API”). Split journeys by independently valuable outcomes. For each journey include the priority rationale, an independent-test statement, and Given/When/Then acceptance scenarios. + +## 4. Enumerate edge cases + +Cover only relevant classes, but scan all of them: + +- empty, first-use, and no-results states; +- minimum/maximum values and volume limits; +- invalid, stale, duplicate, or partial input; +- authorization and ownership boundaries; +- concurrent or conflicting changes; +- dependency failure, timeout, and recovery; +- interruption after partial state mutation; +- accessibility, locale, and time-zone boundaries; +- deletion, retention, and irreversible actions. + +State the required outcome, not “handle gracefully.” If the outcome is intentionally undefined or out of scope, say so explicitly. + +## 5. Write testable requirements + +Give each requirement a stable ID and one obligation: + +```markdown +- **FR-001:** The system MUST allow an account owner to revoke any active recovery challenge. +- **FR-002:** A revoked or expired challenge MUST NOT change account credentials. +``` + +Use `MUST`, `MUST NOT`, or `MAY` deliberately. A requirement is testable only if two reviewers can agree whether an observed outcome satisfies it. Replace vague words such as “fast,” “secure,” “easy,” “appropriate,” and “robust” with a defined outcome, metric, or named governing standard. + +Keep these separate: + +- requirements describe mandatory behavior; +- acceptance scenarios demonstrate journeys; +- success criteria measure whether the feature achieves its outcome; +- assumptions disclose defaults chosen because the request was silent. + +Do not bury new requirements inside prose or edge-case questions. + +## 6. Define entities without designing storage + +When the feature manages information, describe domain entities, their identity, essential attributes, relationships, ownership, and lifecycle. Do not name tables, classes, serialization formats, or databases. + +```markdown +- **Recovery challenge:** A time-bounded proof associated with one account; has an issued, used, revoked, or expired state. Only one successful use is permitted. +``` + +Omit the section when the feature introduces no meaningful data concept. + +## 7. Define measurable success + +Include a balanced set of user, scale/performance, quality, and business outcomes where relevant. Criteria must be measurable, verifiable without knowing the implementation, and phrased from the user or business perspective. + +Good: + +```markdown +- **SC-001:** At least 90% of test participants complete account recovery on the first attempt. +- **SC-002:** A recovery attempt produces its next user-visible response within 2 seconds for 95% of attempts under the agreed peak load. +``` + +Bad: “the API responds in 200 ms,” “use a cache,” or “React renders efficiently.” Those prescribe or measure internals. + +## 8. Use this artifact shape + +```markdown +# Feature Specification: <name> + +## Context and Scope +### In Scope +### Out of Scope + +## User Journeys +### User Journey 1 — <title> (Priority: P1) + +## Edge Cases + +## Requirements +### Functional Requirements +### Key Entities + +## Success Criteria +### Measurable Outcomes + +## Assumptions and Dependencies +## Clarifications +``` + +Remove an optional section rather than leaving placeholders or `N/A`. + +## 9. Self-check before handoff + +Review, revise, and repeat up to three passes: + +- no implementation details unless explicitly binding; +- every mandatory section contains concrete content; +- every journey is prioritized and independently testable; +- every requirement is atomic, unambiguous, and traceable by ID; +- acceptance scenarios cover primary and failure outcomes; +- relevant edge cases are explicit; +- scope, dependencies, and assumptions are bounded; +- entities use domain language rather than storage design; +- success criteria are measurable and technology-independent; +- no contradiction, placeholder, or undefined synonym remains; +- no more than three critical clarification markers remain. + +If failures remain after three revision passes, list the exact failed checks beside the draft. Do not call the spec ready for planning while a scope-, security-, or acceptance-changing clarification remains unresolved.