Skip to content

/spec-sanitization

Sanitizes analysis specs to remove implementation contamination while preserving provenance metadata. Run in SEPARATE SESSION after analysis, before implementation.

shell
$ npx -y skills add prime-radiant-inc/greenfield --skill spec-sanitization --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/spec-sanitization
How auto-invocation works

Context preview

The summary Claude sees to decide when to auto-load this skill.

Sanitizes analysis specs to remove implementation contamination while preserving provenance metadata. Run in SEPARATE SESSION after analysis, before implementation.

SKILL.md

spec-sanitization.SKILL.md
name: spec-sanitization
description: Sanitizes analysis specs to remove implementation contamination while preserving provenance metadata. Run in SEPARATE SESSION after analysis, before implementation.

Spec Sanitization

The sanitization pass turns raw analysis into specs an implementer can build from.

Why This Exists

Analysts read source code, binaries, and runtime behavior. Even with good intentions, they leak implementation details:

  • Function names from source (minified or not)
  • Variable and class names from source
  • Code structure ("function X calls Y which calls Z")
  • Line numbers and file locations
  • Raw file paths (`workspace/raw/source/analysis/chunk-42.md:67`)

**These have no place in the output specs.** Your job: READ each spec, UNDERSTAND the behavior, REWRITE without source references, TRANSFORM provenance citations.

The Rewrite Rule

**You must not copy text from raw specs into output specs.** Not sentences, not paragraphs, not sections. Read the raw specs to understand the behavior, then write a fresh output spec from your understanding.

Why? Raw specs have source code identifiers woven into every sentence — minified names (`k0`, `Wq`, `z1`), internal function signatures (`Pn(a, b, c)`), and numeric implementation constants. Find-and-replace cannot catch them all; many internal identifiers read like plain English (`shouldRetryOnTimeout`, `evict_stale_connections`). A paraphrase that preserves the original's structure is still leaking the original's design. The only reliable approach is to never copy the text at all.

**Process per file:** 1. Read the raw spec end-to-end 2. Close it (do not refer back to it while writing) 3. Write the output spec from your understanding of the behavior 4. Use only: behavioral descriptions, user-facing identifiers (env vars, CLI flags, config keys, protocol fields), and numeric constants (timeouts, limits, sizes) 5. For any concept you could not translate into behavioral language — because you don't understand what it does — add: `[UNCERTAINTY: U-{DOMAIN}-{NNN}] {what the raw spec said, in behavioral terms as best you can} — behavioral purpose could not be determined from available analysis.`

Never preserve implementation jargon in slightly-reworded form. "`validator.Exists()` is called" rewritten as "the exists check runs" is still jargon — neither you nor the implementer knows what it means. Either translate it to behavior ("verifies the value exists in the constrained list") or flag it as uncertain.

If you find yourself copying a sentence and then editing out identifiers — STOP. You are doing it wrong. Rewrite the sentence from scratch.

**Caveat on the "close the file" step:** this is a behavioral instruction, not an enforced mechanism. Closing a file does not evict its content from the agent's context window; the raw text remains readable until the session ends. The Layer 6 second-pass review, which runs in a fresh session with access only to `workspace/output/`, is the practical check on verbatim leakage. Treat this process as discipline, not guarantee.

The Core Principle

For every identifier in a spec, ask: **"Would an implementor encounter this exact string?"**

  • `DATABASE_URL` → YES: it's in official docs, users type it. **KEEP.**
  • `--format` → YES: it's in CLI help output. **KEEP.**
  • `plugins` → YES: it's a config file key users write. **KEEP.**
  • `Retry-After` → YES: it's an HTTP header defined by RFC 9110. **KEEP.**
  • `routeRequest` → NO: this is an internal function name the developer chose. A different developer would name it differently. **GENERALIZE** to "the request routing operation."
  • `ff_batch_commit_v2` → NO: this is an internal feature flag. No user ever types this. **GENERALIZE** to "the batch commit feature gate."
  • `q9` → NO: this is a minified identifier with zero semantic content. **REMOVE.**

**No set of regex patterns will catch every internal identifier** because many look like legitimate English (e.g., `shouldRetryOnTimeout`, `evict_stale_connections`). You must read every line and apply the principle above.

Implementation Detail vs. External Contract

Every identifier in a raw spec is either an **implementation detail** that must be abstracted or an **external contract** that must be preserved. This distinction is language-agnostic — it applies whether the source is TypeScript, Python, Rust, Go, Java, C++, or anything else.

Implementation Details (MUST be abstracted)

These are choices the original developers made that a reimplementor would reasonably make differently. Abstract them to behavioral descriptions or remove them entirely.

**Internal names** — function, method, class, module, and variable names chosen by the original developers:

  • Python: `_drain_write_queue()`, `RecordParser`, `should_retry_on_timeout`
  • Go: `routeRequest()`, `evictStaleConnections`, `indexBuilder`
  • Rust: `fn decode_packet()`, `struct ProtocolFrame`
  • Java: `parseRecord()`, `validateRecord()`, `AbstractMessageProcessor`
  • Any language: camelCase, snake_case, PascalCase internal identifiers

**Internal architecture** — how the codebase is organized into files, modules, packages, or namespaces:

  • "defined in the auth handler module"
  • "the session manager class calls the config loader"
  • "located in `pkg/internal/transport/`"

**Framework-specific patterns** — references to libraries, state management, UI frameworks, or runtime internals:

  • State stores: `useStore`, `getState()`, `@observable`, `store.get()`
  • UI frameworks: `className=`, `styled.`, `@Component`, `#[derive(Template)]`
  • ORM details: `Model.objects.filter()`, `has_many :sessions`, `@Entity`
  • DI containers: `@Inject`, `container.resolve()`, `wire.Build()`

**Build and deployment artifacts** — paths, chunk IDs, minified identifiers, line numbers:

  • Source paths: `src/`, `lib/`, `pkg/`, `internal/`, `dist/`, `target/`, `build/`
  • Source filenames: `auth-handler.ts`, `record_parser.py`, `transport.go`, `Main.java`
  • Minified/o
Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withgreenfield

Reverse engineer clean behavioral specs from any codebase. Greenfield reads source code, documentation, SDKs, runtime behavior, and binaries, then produces behavioral specifications, test vectors, acceptance criteria, and a full provenance trail.

Get the whole plugin, auto-invoked
Stats
239
Stars
0
Views
23
Forks
Active
Maintenance
Apache-2.0
License
19d ago
Last commit
3mo ago
Created

Repo: prime-radiant-inc/greenfield