mirror of https://github.com/garrytan/gstack.git
feat: add evidence-driven bug report skill
This commit is contained in:
parent
7c9df1c568
commit
e9e32c3cad
|
|
@ -30,6 +30,7 @@ Invoke them by name (e.g., `/office-hours`).
|
|||
| `/review` | Pre-landing PR review. Finds bugs that pass CI but break in prod. |
|
||||
| `/codex` | Second opinion via OpenAI Codex. Review, challenge, or consult modes. |
|
||||
| `/investigate` | Systematic root-cause debugging. No fixes without investigation. |
|
||||
| `/bug-report` | Reconstruct what happened, capture safe diagnostics, and draft an exact maintainer-ready issue plus PR guidance. |
|
||||
| `/design-review` | Live-site visual audit + fix loop with atomic commits. |
|
||||
| `/design-shotgun` | Generate multiple AI design variants, comparison board, iterate. |
|
||||
| `/design-html` | Generate production-quality Pretext-native HTML/CSS. |
|
||||
|
|
|
|||
5
SKILL.md
5
SKILL.md
|
|
@ -564,9 +564,10 @@ quality gates that produce better results than answering inline.
|
|||
- User asks to review design of a plan → invoke `/plan-design-review`
|
||||
- User asks about developer experience of a plan, API/CLI/SDK design → invoke `/plan-devex-review`
|
||||
- User wants all reviews done automatically, "review everything" → invoke `/autoplan`
|
||||
- User reports a bug, error, broken behavior, "why is this broken", "this doesn't work", "wtf", "something's wrong" → invoke `/investigate`
|
||||
- User reports a bug, error, broken behavior, "why is this broken", "this doesn't work", "wtf", or "something's wrong" → invoke `/investigate`
|
||||
- Explicit precedence exception: when the user asks to document, reconstruct, capture, file, or draft a report for an already-observed failure → invoke `/bug-report`
|
||||
- User asks to test the site, find bugs, QA, "does this work", "check the deploy" → invoke `/qa`
|
||||
- User asks to just report bugs without fixing → invoke `/qa-only`
|
||||
- User asks to explore a web app for bugs without fixing → invoke `/qa-only`
|
||||
- User asks to review code, check the diff, pre-landing review, "look at my changes" → invoke `/review`
|
||||
- User asks about visual polish, design audit of a live site, "this looks off" → invoke `/design-review`
|
||||
- User asks to audit the live developer experience, time-to-hello-world → invoke `/devex-review`
|
||||
|
|
|
|||
|
|
@ -53,9 +53,10 @@ quality gates that produce better results than answering inline.
|
|||
- User asks to review design of a plan → invoke `/plan-design-review`
|
||||
- User asks about developer experience of a plan, API/CLI/SDK design → invoke `/plan-devex-review`
|
||||
- User wants all reviews done automatically, "review everything" → invoke `/autoplan`
|
||||
- User reports a bug, error, broken behavior, "why is this broken", "this doesn't work", "wtf", "something's wrong" → invoke `/investigate`
|
||||
- User reports a bug, error, broken behavior, "why is this broken", "this doesn't work", "wtf", or "something's wrong" → invoke `/investigate`
|
||||
- Explicit precedence exception: when the user asks to document, reconstruct, capture, file, or draft a report for an already-observed failure → invoke `/bug-report`
|
||||
- User asks to test the site, find bugs, QA, "does this work", "check the deploy" → invoke `/qa`
|
||||
- User asks to just report bugs without fixing → invoke `/qa-only`
|
||||
- User asks to explore a web app for bugs without fixing → invoke `/qa-only`
|
||||
- User asks to review code, check the diff, pre-landing review, "look at my changes" → invoke `/review`
|
||||
- User asks about visual polish, design audit of a live site, "this looks off" → invoke `/design-review`
|
||||
- User asks to audit the live developer experience, time-to-hello-world → invoke `/devex-review`
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,335 @@
|
|||
---
|
||||
name: bug-report
|
||||
preamble-tier: 2
|
||||
version: 1.0.0
|
||||
description: |
|
||||
Evidence-driven bug report authoring. Reconstructs what the user did from the
|
||||
conversation, repository state, recent changes, and safe diagnostic logs;
|
||||
reproduces the failure when possible; and drafts a maintainer-ready report
|
||||
with exact steps, expected/actual behavior, environment, evidence, and a
|
||||
bounded root-cause assessment. Use when asked to "write a bug report",
|
||||
"report this issue", "document what just broke", "capture this bug",
|
||||
"draft an issue for maintainers", or "bugreport". This is report-only: it
|
||||
does not fix code or publish the report without explicit approval. (gstack)
|
||||
voice-triggers:
|
||||
- "write a bug report"
|
||||
- "report this issue"
|
||||
- "document what just broke"
|
||||
- "bugreport"
|
||||
allowed-tools:
|
||||
- Bash
|
||||
- Read
|
||||
- Write
|
||||
- Grep
|
||||
- Glob
|
||||
- AskUserQuestion
|
||||
- WebSearch
|
||||
triggers:
|
||||
- write a bug report
|
||||
- report this issue
|
||||
- capture this bug
|
||||
- draft an issue
|
||||
- bugreport
|
||||
---
|
||||
|
||||
{{PREAMBLE}}
|
||||
|
||||
# /bug-report: Evidence-Driven Bug Reports
|
||||
|
||||
Turn a rough description such as "it failed after I upgraded" into a report an
|
||||
unfamiliar maintainer can reproduce. Gather evidence; do not invent certainty.
|
||||
|
||||
## Iron Laws
|
||||
|
||||
1. **REPORT, DO NOT FIX.** Do not edit product code, dependencies, configuration,
|
||||
or tests. If the user wants a fix, finish the report first, then recommend
|
||||
`/investigate` in a separate turn.
|
||||
2. **OBSERVED IS NOT INFERRED.** Label every material claim as observed,
|
||||
user-reported, inferred, or unknown. Never present a hypothesis as root cause.
|
||||
3. **NO SECRET HARVESTING.** Never dump the full environment, credential stores,
|
||||
cookies, auth headers, shell history, or unrelated logs. Collect the minimum
|
||||
relevant slice and redact before writing or publishing it.
|
||||
4. **NO SURPRISE PUBLICATION.** The default deliverable is a local draft. Never
|
||||
run `gh issue create`, `glab issue create`, create a PR/MR, post a comment, or
|
||||
upload an attachment unless the user explicitly asks after seeing the draft.
|
||||
5. **SAFE REPRODUCTION ONLY.** Do not reproduce against production, mutate shared
|
||||
data, send messages, spend money, or run destructive commands without explicit
|
||||
approval. Prefer a local, sandboxed, read-only reproduction.
|
||||
|
||||
## Inputs and defaults
|
||||
|
||||
Parse the request for:
|
||||
|
||||
| Input | Default |
|
||||
|-------|---------|
|
||||
| Scope | Current repository and conversation |
|
||||
| Output | `.gstack/bug-reports/{YYYY-MM-DD}-{slug}.md` |
|
||||
| Reproduction | Safe local attempt |
|
||||
| Publication | Draft only |
|
||||
| History inspection | Current conversation and Git metadata only |
|
||||
|
||||
Ask at most one blocking question at a time. Read available context before
|
||||
asking. A vague initial symptom is enough to begin evidence collection.
|
||||
|
||||
## Phase 1: Preserve the initial account
|
||||
|
||||
Restate the report in one paragraph without "cleaning up" meaningful details:
|
||||
|
||||
- what the user was trying to do;
|
||||
- what happened and any exact error text already supplied;
|
||||
- what they expected;
|
||||
- when it last worked, if known;
|
||||
- impact and frequency, if known.
|
||||
|
||||
Record missing facts as `Unknown`; do not force the user through a questionnaire.
|
||||
|
||||
## Phase 2: Reconstruct the timeline
|
||||
|
||||
Build a chronological table with `time/order`, `action`, `result`, and `source`.
|
||||
Use sources in this order:
|
||||
|
||||
1. The current conversation and commands already run in it.
|
||||
2. Current repository evidence:
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
git branch --show-current
|
||||
git log -10 --date=iso --pretty='%h %ad %s'
|
||||
git diff --stat
|
||||
git diff --cached --stat
|
||||
```
|
||||
|
||||
3. Project-local logs clearly connected to the failure. Search filenames first;
|
||||
read only a narrow tail or time window. Do not recursively ingest every log.
|
||||
4. Tool-specific diagnostic state that is both local and relevant (versions,
|
||||
lockfile diff, failed test output, browser console/network evidence).
|
||||
|
||||
Treat `git reflog`, IDE histories, browser histories, and shell history as
|
||||
sensitive activity records. Inspect them only when the user explicitly approves
|
||||
the named source and scope. Never read an entire history file; use a narrow time
|
||||
or count bound. Do not inspect histories from other repositories or applications.
|
||||
|
||||
When evidence conflicts with the user's memory, preserve both accounts and say
|
||||
which evidence creates the discrepancy.
|
||||
|
||||
## Phase 3: Capture the environment safely
|
||||
|
||||
Collect only fields that can affect reproduction:
|
||||
|
||||
- OS name/version and architecture;
|
||||
- runtime/compiler/package-manager versions;
|
||||
- application/package version or commit SHA;
|
||||
- relevant dependency versions;
|
||||
- relevant feature flags or configuration **names and sanitized states**;
|
||||
- clean/dirty worktree state;
|
||||
- local, staging, or production context (never include private hostnames).
|
||||
|
||||
Never run bare `env`, `printenv`, `set`, or commands that dump all configuration.
|
||||
Query allowlisted names individually and render secrets as `[REDACTED]`. Replace
|
||||
usernames in filesystem paths with `<user>`.
|
||||
|
||||
## Phase 4: Reproduce and log
|
||||
|
||||
Derive the smallest credible reproduction from the timeline. Before running it:
|
||||
|
||||
1. State the exact command or interaction and expected side effects.
|
||||
2. Confirm it stays local/read-only. Ask before any meaningful mutation.
|
||||
3. Prefer an existing test, fixture, dry-run flag, disposable temp directory, or
|
||||
isolated browser session.
|
||||
|
||||
Capture a timestamped transcript with:
|
||||
|
||||
- exact sanitized command or UI action;
|
||||
- exit code and duration;
|
||||
- relevant stdout/stderr excerpt with 20 lines of context around the failure;
|
||||
- structured application logs in the matching time window;
|
||||
- stack trace with the first application-owned frame called out;
|
||||
- screenshots or request/response metadata when the issue is visual or networked.
|
||||
|
||||
Screenshots and other binary evidence require a separate visual privacy gate:
|
||||
inspect every visible region, run OCR when available and scan the extracted text,
|
||||
crop or redact private UI, and strip EXIF/metadata before persistence. A clean
|
||||
text-byte scan does not prove pixels are safe. If visual review or metadata
|
||||
stripping is unavailable, describe the screenshot without saving or publishing
|
||||
it. Never upload raw captures.
|
||||
|
||||
Enable verbose/debug logging only for the single reproduction attempt and only
|
||||
when it will not expose credentials or payloads. Do not leave persistent logging
|
||||
enabled. Store raw diagnostic artifacts in a collision-safe temporary directory
|
||||
outside the repository. Store only sanitized evidence under
|
||||
`.gstack/bug-reports/evidence/{report-slug}/`; exclude irrelevant output and note
|
||||
every omitted or redacted field. Never commit raw logs.
|
||||
|
||||
After extracting sanitized evidence, delete the raw temporary directory in a
|
||||
finally-style cleanup step. If cleanup fails, warn with the exact path and stop
|
||||
before publication. Retain raw evidence only when the user explicitly approves
|
||||
the path and retention period after being warned it may contain secrets.
|
||||
|
||||
Never copy an entire tool home, user profile, browser profile, application-state
|
||||
directory, or credential directory into evidence, even temporarily. Create
|
||||
disposable runtime homes outside the report tree and delete them after extracting
|
||||
the minimum sanitized text evidence. Auth files, config databases, SQLite state,
|
||||
cookies, and telemetry stores never belong under `.gstack/bug-reports/`.
|
||||
|
||||
Treat every evidence file as its own persistence sink. Compose each sanitized
|
||||
artifact in a temporary file outside the repository, run the same exact-byte
|
||||
redaction procedure used for the report, and only then move the scanned bytes
|
||||
into `.gstack/bug-reports/evidence/`. A HIGH finding blocks persistence; MEDIUM
|
||||
requires the same confirmation/redaction flow. Never copy raw evidence into the
|
||||
report tree first and promise to clean it later.
|
||||
|
||||
Classify reproduction honestly:
|
||||
|
||||
- `Reproduced` — exact symptom observed;
|
||||
- `Partially reproduced` — related failure observed, with the difference stated;
|
||||
- `Not reproduced` — attempt completed without the symptom;
|
||||
- `Not attempted` — unsafe, unavailable, or missing prerequisite, with the reason.
|
||||
|
||||
Never loop indefinitely. Stop after three materially different attempts and list
|
||||
what changed between them.
|
||||
|
||||
## Phase 5: Analyze without overclaiming
|
||||
|
||||
Trace enough code and recent changes to help maintainers choose where to start.
|
||||
Do not edit anything. Separate:
|
||||
|
||||
- **Confirmed facts:** directly supported by an artifact or reproduction.
|
||||
- **Likely trigger:** the action or change immediately preceding the failure.
|
||||
- **Root-cause hypothesis:** a specific, falsifiable explanation, with supporting
|
||||
and contradicting evidence.
|
||||
- **Suspected area:** files/modules/owners worth inspecting.
|
||||
- **Unknowns:** facts still required to confirm the cause.
|
||||
|
||||
Use `git blame` and commit history only for technical provenance. Do not assign
|
||||
fault to an individual. If evidence is insufficient, write "Root cause unknown."
|
||||
|
||||
## Phase 6: Draft the maintainer-ready report and PR guidance
|
||||
|
||||
Write the local report using this exact structure:
|
||||
|
||||
```markdown
|
||||
# <concise symptom-oriented title>
|
||||
|
||||
## Summary
|
||||
<what failed, for whom, impact, frequency>
|
||||
|
||||
## Reproduction status
|
||||
<Reproduced | Partially reproduced | Not reproduced | Not attempted>
|
||||
|
||||
## Steps to reproduce
|
||||
### Prerequisites
|
||||
1. <versions/config/data setup>
|
||||
### Steps
|
||||
1. <one action per step>
|
||||
### Minimal reproduction
|
||||
<smallest command, fixture, or interaction; omit if unavailable>
|
||||
|
||||
## Expected behavior
|
||||
<observable expected result>
|
||||
|
||||
## Actual behavior
|
||||
<observable actual result, exact sanitized error>
|
||||
|
||||
## Timeline reconstructed
|
||||
| Order/time | Action | Result | Source |
|
||||
|---|---|---|---|
|
||||
|
||||
## Environment
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
|
||||
## Evidence
|
||||
<sanitized log excerpts and relative artifact paths>
|
||||
|
||||
## Technical assessment
|
||||
### Confirmed facts
|
||||
### Likely trigger
|
||||
### Root-cause hypothesis
|
||||
### Suspected area
|
||||
### Unknowns
|
||||
|
||||
## Regression range
|
||||
<last known good / first known bad / unknown>
|
||||
|
||||
## Workarounds
|
||||
<verified workarounds only; otherwise "None known">
|
||||
|
||||
## Maintainer verification checklist
|
||||
- [ ] Run the minimal reproduction on the reported version
|
||||
- [ ] Confirm the stated actual result
|
||||
- [ ] Test the root-cause hypothesis
|
||||
- [ ] Add a regression test before closing
|
||||
|
||||
## Privacy and redaction notes
|
||||
<what was omitted, anonymized, or unavailable>
|
||||
```
|
||||
|
||||
Every reproduction step must be executable by someone without conversation
|
||||
context. Pin versions and include setup details that materially affect the bug.
|
||||
Link evidence by relative path; do not paste megabytes of logs into the report.
|
||||
|
||||
Also write `.gstack/bug-reports/{YYYY-MM-DD}-{slug}-pr-body.md`. This is a draft
|
||||
PR description and maintainer handoff, not a claim that a fix exists. Include:
|
||||
|
||||
- the linked issue draft or issue URL, when available;
|
||||
- `Problem reproduced by` with the minimal sequence;
|
||||
- `Evidence of failure` with the stable error and control comparison;
|
||||
- `Proposed change: Not implemented in this report-only run` unless an already
|
||||
authorized, verified change exists on the branch;
|
||||
- exact `How maintainers can verify` commands and before/after pass criteria;
|
||||
- the smallest regression test that should fail before a fix and pass afterward;
|
||||
- verified risks, hypotheses, and unknowns in separate lists.
|
||||
|
||||
Do not use `git diff --exit-code` where legitimate generated changes make a diff
|
||||
expected. Verify generator idempotency by snapshotting after the first generation,
|
||||
running it again, and confirming the second run produces no further changes.
|
||||
|
||||
Do not add a deliberately failing test to a shared branch. Do not manufacture an
|
||||
empty commit or empty PR merely to obtain a PR number.
|
||||
|
||||
Before writing the report, scan the exact report bytes:
|
||||
|
||||
{{REDACT_INVOCATION_BLOCK:pre-issue:retain}}
|
||||
|
||||
Create the destination only after the scan passes. Use a collision-safe slug; do
|
||||
not overwrite an existing report. Pass the same scanned bytes to the file write.
|
||||
|
||||
Before writing or returning the companion PR body, independently scan its exact
|
||||
bytes and pass the same scanned file to the destination write:
|
||||
|
||||
{{REDACT_INVOCATION_BLOCK:pre-pr-body:brief:retain}}
|
||||
|
||||
The issue draft, each evidence artifact, and the PR-body draft are separate sinks;
|
||||
a clean scan for one never authorizes another. Rerun the PR-body scan again before
|
||||
any later remote publication because user edits may have changed its bytes.
|
||||
|
||||
## Phase 7: User review and optional handoff
|
||||
|
||||
Show the title, reproduction status, strongest evidence, root-cause confidence,
|
||||
and local report path. Ask: **"Does this accurately capture what happened?"**
|
||||
Revise the draft until confirmed.
|
||||
|
||||
After confirmation:
|
||||
|
||||
- If the user asked only for a draft, stop.
|
||||
- If they explicitly ask to file it, rerun the same redaction scan on the final
|
||||
issue bytes and every attachment, show the destination repository and visibility, request confirmation,
|
||||
then use `gh issue create --body-file` (or the equivalent tracker command).
|
||||
- If they ask for a PR draft, return the PR-body draft even when no fix exists.
|
||||
- Open a remote draft PR only when the branch already contains a meaningful,
|
||||
explicitly authorized artifact or verified code change. Rerun the PR-body scan
|
||||
immediately before publication. Otherwise explain what
|
||||
is missing (normally a regression test or fix), and offer `/investigate` next.
|
||||
|
||||
Final output:
|
||||
|
||||
```text
|
||||
BUG REPORT DRAFT
|
||||
Title: <title>
|
||||
Reproduction: <status>
|
||||
Evidence: <strongest artifact>
|
||||
Root cause: <confirmed | hypothesis at confidence | unknown>
|
||||
Issue draft: <path>
|
||||
PR draft: <path or reason a remote PR cannot yet be opened>
|
||||
Published: no
|
||||
```
|
||||
|
|
@ -12,6 +12,7 @@ Detailed guides for every gstack skill — philosophy, workflow, and examples.
|
|||
| [`/design-consultation`](#design-consultation) | **Design Partner** | Build a complete design system from scratch. Knows the landscape, proposes creative risks, generates realistic product mockups. Design at the heart of all other phases. |
|
||||
| [`/review`](#review) | **Staff Engineer** | Find the bugs that pass CI but blow up in production. Auto-fixes the obvious ones. Flags completeness gaps. |
|
||||
| [`/investigate`](#investigate) | **Debugger** | Systematic root-cause debugging. Iron Law: no fixes without investigation. Traces data flow, tests hypotheses, stops after 3 failed fixes. |
|
||||
| [`/bug-report`](#bug-report) | **Incident Reporter** | Reconstruct what happened from conversation, Git, and safe diagnostic logs; reproduce when possible; draft an exact maintainer-ready issue and PR handoff without publishing it. |
|
||||
| [`/design-review`](#design-review) | **Designer Who Codes** | Live-site visual audit + fix loop. 80-item audit, then fixes what it finds. Atomic commits, before/after screenshots. |
|
||||
| [`/design-shotgun`](#design-shotgun) | **Design Explorer** | Generate multiple AI design variants, open a comparison board in your browser, and iterate until you approve a direction. Taste memory biases toward your preferences. |
|
||||
| [`/design-html`](#design-html) | **Design Engineer** | Generates production-quality Pretext-native HTML. Works with approved mockups, CEO plans, design reviews, or from scratch. Text reflows on resize, heights adjust to content. Smart API routing per design type. Framework detection for React/Svelte/Vue. |
|
||||
|
|
@ -595,6 +596,14 @@ Instead of guessing and patching, it traces data flow, matches against known bug
|
|||
|
||||
---
|
||||
|
||||
## `/bug-report`
|
||||
|
||||
Use `/bug-report` when the failure already happened and the priority is preserving evidence for a maintainer. It reconstructs the timeline from the conversation, repository state, recent changes, and narrowly scoped logs; captures the relevant environment; attempts a safe local reproduction; and separates confirmed facts from hypotheses.
|
||||
|
||||
The output is a redacted local issue draft plus PR-body handoff with exact prerequisites, one-action-per-step reproduction instructions, expected and actual behavior, evidence links, regression range, and a maintainer verification checklist. It never fixes code, trawls sensitive histories without permission, or publishes without explicit approval. If the report reveals a credible fix path, hand it to `/investigate` next.
|
||||
|
||||
---
|
||||
|
||||
## `/qa`
|
||||
|
||||
This is my **QA lead mode**.
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ Conventions:
|
|||
- [/benchmark](benchmark/SKILL.md): Performance regression detection using the browse daemon.
|
||||
- [/benchmark-models](benchmark-models/SKILL.md): Cross-model benchmark for gstack skills.
|
||||
- [/browse](browse/SKILL.md): Fast headless browser for QA testing and site dogfooding.
|
||||
- [/bug-report](bug-report/SKILL.md): Evidence-driven bug report authoring.
|
||||
- [/canary](canary/SKILL.md): Post-deploy canary monitoring.
|
||||
- [/careful](careful/SKILL.md): Safety guardrails for destructive commands.
|
||||
- [/claude](claude/SKILL.md): Claude Code CLI wrapper for non-Claude hosts - three modes.
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@
|
|||
"routing": "Navigate any URL, interact with\nelements, verify page state, diff before/after actions, take annotated screenshots, check\nresponsive layouts, test forms and uploads, handle dialogs, and assert element states.\n~100ms per command. Use when you need to test a feature, verify a deployment, dogfood a\nuser flow, or file a bug with evidence. Use when asked to \"open in browser\", \"test the\nsite\", \"take a screenshot\", or \"dogfood this\".",
|
||||
"voice_line": null
|
||||
},
|
||||
"bug-report": {
|
||||
"lead": "Evidence-driven bug report authoring.",
|
||||
"routing": "Reconstructs what the user did from the\nconversation, repository state, recent changes, and safe diagnostic logs;\nreproduces the failure when possible; and drafts a maintainer-ready report\nwith exact steps, expected/actual behavior, environment, evidence, and a\nbounded root-cause assessment. Use when asked to \"write a bug report\",\n\"report this issue\", \"document what just broke\", \"capture this bug\",\n\"draft an issue for maintainers\", or \"bugreport\". This is report-only: it\ndoes not fix code or publish the report without explicit approval.",
|
||||
"voice_line": "Voice triggers (speech-to-text aliases): \"write a bug report\", \"report this issue\", \"document what just broke\", \"bugreport\"."
|
||||
},
|
||||
"canary": {
|
||||
"lead": "Post-deploy canary monitoring.",
|
||||
"routing": "Watches the live app for console errors,\nperformance regressions, and page failures using the browse daemon. Takes\nperiodic screenshots, compares against pre-deploy baselines, and alerts\non anomalies. Use when: \"monitor deploy\", \"canary\", \"post-deploy check\",\n\"watch production\", \"verify deploy\".",
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ const SINKS: Record<string, SinkSpec> = {
|
|||
export function generateRedactInvocationBlock(ctx: TemplateContext, args?: string[]): string {
|
||||
const sinkLabel = args?.[0] ?? 'pre-issue';
|
||||
const brief = args?.[1] === 'brief';
|
||||
const retain = args?.includes('retain') ?? false;
|
||||
const sink = SINKS[sinkLabel] ?? SINKS['pre-issue'];
|
||||
const bin = `${ctx.paths.binDir}/gstack-redact`;
|
||||
|
||||
|
|
@ -132,7 +133,9 @@ Run the SAME scan-at-sink procedure shown above (resolve \`$REDACT_VIS\` once an
|
|||
reuse it; write the exact bytes to \`$REDACT_FILE\`; \`${bin} --from-file "$REDACT_FILE"
|
||||
--repo-visibility "$REDACT_VIS" --json\`), now on ${sink.noun}. Apply the same
|
||||
exit-3/2/0 handling. On exit 3, do NOT ${sink.blockVerb}; HIGH has no skip. Pass the
|
||||
same \`$REDACT_FILE\` downstream so the bytes scanned are the bytes sent.`;
|
||||
same \`$REDACT_FILE\` downstream so the bytes scanned are the bytes sent.${retain ? `
|
||||
Retain \`$REDACT_FILE\` until the destination write succeeds, then remove it in a
|
||||
finally-style cleanup. Never delete or reconstruct it before the write.` : ''}`;
|
||||
}
|
||||
|
||||
return `#### Redaction scan — ${sinkLabel} (${sink.noun})
|
||||
|
|
@ -169,9 +172,11 @@ Branch on \`$REDACT_CODE\`:
|
|||
3. **Exit 0 (clean)** — proceed; surface \`WARN\` (tool-fence degrades) + \`LOW\` as a
|
||||
one-line FYI (never blocks).
|
||||
|
||||
\`\`\`bash
|
||||
${retain ? `Retain \`$REDACT_FILE\` for the immediate destination write. Write or send
|
||||
that exact file first, then run \`rm -f "$REDACT_FILE"\` in finally-style cleanup.
|
||||
Never delete or reconstruct it before the write.` : `\`\`\`bash
|
||||
rm -f "$REDACT_FILE"
|
||||
\`\`\`
|
||||
\`\`\``}
|
||||
|
||||
Guardrail, not airtight enforcement — direct \`gh\`/\`git\` bypass it; it catches accidents.`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
import { describe, expect, test } from 'bun:test';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const ROOT = path.resolve(import.meta.dir, '..');
|
||||
|
||||
function read(relativePath: string): string {
|
||||
return fs.readFileSync(path.join(ROOT, relativePath), 'utf8');
|
||||
}
|
||||
|
||||
describe('/bug-report skill', () => {
|
||||
test('is report-only and requires explicit approval before publication', () => {
|
||||
const template = read('bug-report/SKILL.md.tmpl');
|
||||
|
||||
expect(template).toContain('REPORT, DO NOT FIX');
|
||||
expect(template).toContain('NO SURPRISE PUBLICATION');
|
||||
expect(template).toContain('does not fix code or publish the report without explicit approval');
|
||||
expect(template).not.toMatch(/allowed-tools:[\s\S]*?\n - Edit\n/);
|
||||
});
|
||||
|
||||
test('requires reproducible evidence and distinguishes fact from hypothesis', () => {
|
||||
const template = read('bug-report/SKILL.md.tmpl');
|
||||
|
||||
expect(template).toContain('## Steps to reproduce');
|
||||
expect(template).toContain('## Evidence');
|
||||
expect(template).toContain('### Confirmed facts');
|
||||
expect(template).toContain('### Root-cause hypothesis');
|
||||
expect(template).toContain('Not reproduced');
|
||||
});
|
||||
|
||||
test('protects sensitive histories and scans the report at the sink', () => {
|
||||
const template = read('bug-report/SKILL.md.tmpl');
|
||||
|
||||
expect(template).toMatch(/shell history as\s+sensitive activity records/);
|
||||
expect(template).toContain('{{REDACT_INVOCATION_BLOCK:pre-issue:retain}}');
|
||||
expect(template).toContain('{{REDACT_INVOCATION_BLOCK:pre-pr-body:brief:retain}}');
|
||||
expect(template).toContain('Never run bare `env`, `printenv`, `set`');
|
||||
expect(template).toContain('Never copy an entire tool home');
|
||||
expect(template).toContain('SQLite state');
|
||||
expect(template).toContain('Treat every evidence file as its own persistence sink');
|
||||
expect(template).toContain('separate sinks');
|
||||
expect(template).toContain('finally-style cleanup step');
|
||||
expect(template).toContain('Rerun the PR-body scan');
|
||||
expect(template).toContain('Screenshots and other binary evidence require a separate visual privacy gate');
|
||||
expect(template).toContain('Never upload raw captures');
|
||||
});
|
||||
|
||||
test('generated workflow retains scanned bytes until persistence succeeds', () => {
|
||||
const generated = read('bug-report/SKILL.md');
|
||||
expect(generated).toContain('Retain `$REDACT_FILE` for the immediate destination write');
|
||||
expect(generated).toContain('Never delete or reconstruct it before the write');
|
||||
expect(generated).toContain('Retain `$REDACT_FILE` until the destination write succeeds');
|
||||
|
||||
const reportScan = generated.slice(
|
||||
generated.indexOf('#### Redaction scan — pre-issue'),
|
||||
generated.indexOf('Before writing or returning the companion PR body'),
|
||||
);
|
||||
const writeIndex = reportScan.indexOf('Write or send');
|
||||
const cleanupIndex = reportScan.indexOf('rm -f "$REDACT_FILE"');
|
||||
expect(writeIndex).toBeGreaterThan(-1);
|
||||
expect(cleanupIndex).toBeGreaterThan(writeIndex);
|
||||
});
|
||||
|
||||
test('drafts honest maintainer guidance without pretending a fix exists', () => {
|
||||
const template = read('bug-report/SKILL.md.tmpl');
|
||||
|
||||
expect(template).toContain('{YYYY-MM-DD}-{slug}-pr-body.md');
|
||||
expect(template).toContain('Not implemented in this report-only run');
|
||||
expect(template).toContain('Verify generator idempotency by snapshotting');
|
||||
});
|
||||
|
||||
test('is included in the router and documentation inventories', () => {
|
||||
const router = read('SKILL.md.tmpl');
|
||||
expect(router).toContain('"this doesn\'t work"');
|
||||
expect(router).toMatch(/"this doesn't work"[^\n]+invoke `\/investigate`/);
|
||||
expect(router).toMatch(/Explicit precedence exception:[^\n]+invoke `\/bug-report`/);
|
||||
expect(read('AGENTS.md')).toContain('`/bug-report`');
|
||||
expect(read('docs/skills.md')).toContain('## `/bug-report`');
|
||||
});
|
||||
|
||||
test('produces PR guidance without manufacturing an empty PR', () => {
|
||||
const template = read('bug-report/SKILL.md.tmpl');
|
||||
expect(template).toContain('-pr-body.md');
|
||||
expect(template).toContain('How maintainers can verify');
|
||||
expect(template).toContain('Do not manufacture an');
|
||||
expect(template).toContain('Open a remote draft PR only when');
|
||||
});
|
||||
|
||||
test('generated catalogs include the skill', () => {
|
||||
expect(read('gstack/llms.txt')).toContain('[/bug-report](bug-report/SKILL.md)');
|
||||
expect(read('scripts/proactive-suggestions.json')).toContain('"bug-report"');
|
||||
});
|
||||
});
|
||||
|
|
@ -93,4 +93,12 @@ describe("REDACT_INVOCATION_BLOCK", () => {
|
|||
test("unknown sink label falls back without throwing", () => {
|
||||
expect(() => generateRedactInvocationBlock(ctx, ["bogus-sink"])).not.toThrow();
|
||||
});
|
||||
|
||||
test("retain mode keeps exact scanned bytes until after the destination write", () => {
|
||||
const full = generateRedactInvocationBlock(ctx, ["pre-issue", "retain"]);
|
||||
const brief = generateRedactInvocationBlock(ctx, ["pre-pr-body", "brief", "retain"]);
|
||||
expect(full).toContain("Retain `$REDACT_FILE` for the immediate destination write");
|
||||
expect(full).toContain("Never delete or reconstruct it before the write");
|
||||
expect(brief).toContain("Retain `$REDACT_FILE` until the destination write succeeds");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -59,6 +59,11 @@ export const SKILL_COVERAGE: Record<string, SkillCoverage> = {
|
|||
gate: ['test/skill-coverage-floor.test.ts'],
|
||||
periodic: [],
|
||||
},
|
||||
'bug-report': {
|
||||
gate: ['test/bug-report-skill.test.ts', 'test/skill-coverage-floor.test.ts'],
|
||||
periodic: [],
|
||||
rationale: 'Deterministic invariants pin evidence labeling, privacy gates, reproduction, and PR-draft behavior.',
|
||||
},
|
||||
browse: {
|
||||
gate: ['test/skill-coverage-floor.test.ts'],
|
||||
periodic: [],
|
||||
|
|
|
|||
Loading…
Reference in New Issue