global setup and configuration.
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
# /unslop cleanup
|
||||
|
||||
Surface AI patterns as reviewable edits the user accepts or rejects, rather than
|
||||
a finished rewrite. Agent-invoked, never a background daemon. Route here on
|
||||
`/unslop cleanup` or when the user wants suggestions instead of a silent rewrite.
|
||||
Set `$INPUT` to the source.
|
||||
|
||||
## Report-only variant
|
||||
|
||||
When the user says "flag only", "just detect", "audit only", "don't change
|
||||
anything", or passes `--report`, change nothing. Scan and report:
|
||||
|
||||
```bash
|
||||
python3 scripts/banned_phrase_scan.py <<< "$INPUT"
|
||||
python3 scripts/structure_scan.py <<< "$INPUT"
|
||||
python3 scripts/silhouette_scan.py <<< "$INPUT"
|
||||
python3 scripts/readability_metrics.py <<< "$INPUT"
|
||||
```
|
||||
|
||||
Report each issue by span, category, severity, and why it reads as machine-
|
||||
written, separating clear problems from register-dependent judgment calls (the
|
||||
audit-only shape in SKILL.md **Output Format**). Re-read negations, scope, and
|
||||
certainty yourself; the scanners are necessary, not sufficient.
|
||||
|
||||
## Suggestion flow
|
||||
|
||||
```bash
|
||||
python3 scripts/suggest.py document.md # emit suggestions
|
||||
python3 scripts/suggest.py doc.md --apply-replacements repl.json # merge model replacements
|
||||
python3 scripts/check_suggestions.py suggestions.json # blocking contract gates
|
||||
```
|
||||
|
||||
- **Detection is cheap and deterministic.** `suggest.py` runs both scanners and
|
||||
emits LSP-style suggestions `{span, severity, category, rationale,
|
||||
suggested_replacement, phrased_as_question}`, ordered and non-overlapping.
|
||||
- **Replacement generation is delegated to a stronger model.** `suggest.py`
|
||||
leaves `suggested_replacement` null; the stronger model fills them, merged back
|
||||
via `--apply-replacements`.
|
||||
- **Hard findings** become direct replacements; **soft findings** are register-
|
||||
dependent, so their rationale is phrased as a question
|
||||
(`phrased_as_question: true`).
|
||||
- **Suggestions are surfaced to the user, never silently applied.**
|
||||
|
||||
## Contract gates
|
||||
|
||||
`check_suggestions.py` is the blocking contract. Every replacement clears all
|
||||
four gates or it is rejected:
|
||||
|
||||
- `span-minimality`: the edit changes only its span (a whole-sentence rewrite
|
||||
fails).
|
||||
- `replacement-scanner`: each replacement passes both scanners in isolation and
|
||||
adds no new violation in context.
|
||||
- `accept-all`: applying every suggestion yields a document that passes both
|
||||
scanners with `validate_preservation` exit 0 versus the original.
|
||||
- `span-overlap`: spans must not overlap.
|
||||
|
||||
Non-English input is declined the way the scanners decline it: `suggest.py`
|
||||
returns `non_english: true` with no suggestions. For a full rewrite instead of
|
||||
suggestions, route to `references/commands/rewrite.md`.
|
||||
@@ -0,0 +1,51 @@
|
||||
# /unslop contribute
|
||||
|
||||
Turn one AI-ism caught in the wild into a scanner contract example and a structured PR. Route
|
||||
here on "contribute a pattern", "add this tell", or "I found a new AI-ism".
|
||||
Everything stays offline until the user approves both publication and the final
|
||||
PR body. Read `references/contribute.md` for the precheck exit codes, redaction
|
||||
discipline, row-diff verification, and the non-maintainer fork path.
|
||||
|
||||
## Flow
|
||||
|
||||
1. **Precheck.** `python3 scripts/contribute.py precheck /abs/path/snippet.txt`.
|
||||
Stop if it exits 3. The tell is already covered, so add a REC row rather
|
||||
than opening a fresh false-negative row.
|
||||
|
||||
2. **User confirmation gate #1 — publication.** Show the exact snippet and ask
|
||||
whether it may go in a public repo. Offer redaction hints from
|
||||
`python3 scripts/extract_constraints.py < snippet.txt`. Redact only with
|
||||
explicit approval, and keep the tell byte-for-byte intact.
|
||||
|
||||
3. **Scaffold** the working bundle under `.unslop/contrib/<slug>/` (do not
|
||||
commit it):
|
||||
```bash
|
||||
python3 scripts/contribute.py scaffold --snippet /abs/path/snippet.txt \
|
||||
--tell "exact substring" --category significance_inflation \
|
||||
--pattern-name exact-substring-slug --redact "Alice=NAME"
|
||||
```
|
||||
|
||||
4. **Implement eval-first**, following `references/maintenance.md`: copy
|
||||
`row_fn.json` into `evals/fixtures/contracts/scanner-examples.json`, renumber from the live
|
||||
maxima, then set `exact_total` to the new `examples` length. Add the
|
||||
literal-use FP example (and a REC example if a word is gated
|
||||
behind a collocation). Confirm the FN example is **red** before you touch the
|
||||
scanner, then update `scripts/banned_phrase_scan.py` and
|
||||
`references/taboo-phrases.md` until it goes **green** while the FP example holds.
|
||||
|
||||
5. **Verify:** `python3 scripts/contribute.py verify --bundle .unslop/contrib/<slug>`.
|
||||
It refuses TODO markers, checks specimen fidelity, and captures the
|
||||
red-to-green transition.
|
||||
|
||||
6. **Full deterministic gate battery:** `python3 evals/check.py --full`.
|
||||
|
||||
7. **Render the PR body:**
|
||||
`python3 scripts/contribute.py report --bundle .unslop/contrib/<slug> > pr-body.md`.
|
||||
|
||||
8. **User confirmation gate #2 — publication of the PR.** Show the final PR
|
||||
body, get approval, then branch, `git add` the three changed files, commit,
|
||||
and use `gh pr create` (or the non-maintainer fork path in
|
||||
`references/contribute.md`). Network access belongs to the host agent.
|
||||
|
||||
The resulting branch contains the contract example, scanner change, and taboo-catalog
|
||||
entry.
|
||||
@@ -0,0 +1,66 @@
|
||||
# /unslop mimic
|
||||
|
||||
Single-pass voiced writing. Draft or rewrite in a taught voice, then clear the
|
||||
full gate battery. Route here on "write this like me", "match my voice", or
|
||||
"mimic this author" once a voice card exists. Read `references/mimic.md` for card
|
||||
anatomy, scoring, and failure modes.
|
||||
|
||||
## Flow
|
||||
|
||||
1. Load the situation sheet the task needs. Read `card.md` for the always-on core
|
||||
(rhythm, contraction habits, punctuation, openers, the Never list) and the
|
||||
one `card/<situation>.md` sheet that matches what you are writing. Load only
|
||||
what the task needs; the card is layered so generation stays cheap.
|
||||
2. Draft or rewrite in that voice. Follow the card's measured markers and
|
||||
verbatim snippets; do not invent a habit the samples cannot support.
|
||||
3. Run the output through **every** removal gate:
|
||||
```bash
|
||||
python3 scripts/banned_phrase_scan.py <<< "$OUTPUT"
|
||||
python3 scripts/structure_scan.py <<< "$OUTPUT"
|
||||
python3 scripts/readability_metrics.py <<< "$OUTPUT"
|
||||
python3 scripts/validate_preservation.py original.txt "$OUTPUT_FILE"
|
||||
python3 scripts/diff_check.py original.txt "$OUTPUT_FILE"
|
||||
```
|
||||
4. Score the voice:
|
||||
```bash
|
||||
python3 scripts/voice_score.py --profile profile.json "$OUTPUT_FILE"
|
||||
```
|
||||
|
||||
## The rule
|
||||
|
||||
A mimic that scores well on voice but trips a slop gate is **rejected**. Voice
|
||||
never buys an exemption from the constitution — the removal gates are hard, the
|
||||
voice score is a guide. Meaning preservation versus the original draft is its own
|
||||
hard gate, never blended into the voice score.
|
||||
|
||||
## Refine — when one pass is not enough
|
||||
|
||||
Most users teach once and mimic cheaply thereafter. When a single pass keeps
|
||||
scoring short of the target voice, hill-climb with the refine loop — worth the
|
||||
cost only then:
|
||||
|
||||
```bash
|
||||
python3 evals/run_mimic_refine.py --samples samples/ --draft draft.md --out OUT
|
||||
```
|
||||
|
||||
LIVE (default) calls `--generate-cmd` (default `claude -p`) once per beam per
|
||||
iteration; `--candidates-dir DIR` runs the loop logic with no model calls. Hard
|
||||
gates (banned-phrase, structure, draft→candidate preservation, copy-gate, 150-
|
||||
word floor) discard a candidate regardless of score; survivors are scored against
|
||||
a held-out DEV split with the full `voice_score` composite, and the best-so-far
|
||||
never regresses. The **divergence guard** halts and sets
|
||||
`reward_hacking_warning` when the A composite improves while DEV worsens for two
|
||||
iterations — the reward-hacking signature. Confirm a win only when
|
||||
`mimic_stats.py` shows the CI lower bound > 0 and p < 0.05. Internals, baselines,
|
||||
and the failure table are in `references/mimic.md`.
|
||||
|
||||
## Voice check
|
||||
|
||||
"Does this sound like me?" — score only, change nothing. Run
|
||||
`python3 scripts/voice_score.py --profile .unslop/voice/<name>/profile.json
|
||||
--impostors evals/fixtures/voice/impostors --seed 7 <draft>` and report the
|
||||
composite (lower is more them), the GI rank, and the two or three metric
|
||||
deltas that explain the score, in plain words ("your sentences run longer than
|
||||
usual; contractions match"). No rewrite unless asked. This is the cheapest
|
||||
voice interaction and the usual one after teach: check drafts often, commission
|
||||
rewrites rarely.
|
||||
@@ -0,0 +1,46 @@
|
||||
# /unslop rewrite
|
||||
|
||||
The default command. Read `references/core-contract.md`; it is authoritative.
|
||||
Use two passes: diagnose, then repair confirmed findings and validate.
|
||||
|
||||
Input arrives as an argument, a file path, or stdin. Set `$INPUT` to the source
|
||||
and `$OUTPUT` to your rewrite.
|
||||
|
||||
## Pass 1 — diagnose
|
||||
|
||||
1. Extract the facts and constraints that must survive:
|
||||
```bash
|
||||
python3 scripts/extract_constraints.py <<< "$INPUT"
|
||||
```
|
||||
2. Scan the source so the rewrite answers evidence, not a hunch:
|
||||
```bash
|
||||
python3 scripts/banned_phrase_scan.py <<< "$INPUT"
|
||||
python3 scripts/structure_scan.py <<< "$INPUT"
|
||||
python3 scripts/silhouette_scan.py <<< "$INPUT"
|
||||
python3 scripts/readability_metrics.py <<< "$INPUT"
|
||||
```
|
||||
Pass `--genre docs` or `--genre social` only when the input truly belongs to
|
||||
that genre. Add `banned_phrase_scan.py --include-quoted` only when the user
|
||||
wants quoted examples audited too.
|
||||
3. Read the selected preset only for voice. It cannot authorize a finding.
|
||||
4. Classify exact spans as confirmed findings or protected source. Do not
|
||||
fact-check, use the current date, or treat missing support as an AI tell.
|
||||
Scanner rows remain candidates until contextual review confirms a defect.
|
||||
|
||||
## Pass 2 — reconstruct
|
||||
|
||||
Apply the core contract. Edit only a sentence containing a confirmed finding,
|
||||
make the smallest repair, and copy all other sentences byte-for-byte. If there
|
||||
are no findings, return the source exactly. Undo any edit that changes a fact,
|
||||
meaning, register, attribution, or protected domain phrase.
|
||||
|
||||
## Validate
|
||||
|
||||
Run the gate battery and apply the blocking semantics in
|
||||
`references/core-contract.md` **Validation**.
|
||||
|
||||
Return the cleaned text only, unless the user asked for the strict analysis
|
||||
block in SKILL.md **Output Format**.
|
||||
|
||||
For multi-agent execution, use `references/pipeline.md`; for orchestrated
|
||||
detector packs, use `references/packs/`.
|
||||
@@ -0,0 +1,77 @@
|
||||
# /unslop teach
|
||||
|
||||
Build a reusable voice from a writer's samples. **Agent-driven end to end**: the
|
||||
user supplies only approvals and answers, never a directory or a command. Route
|
||||
here on "teach my voice", "learn how I write", or when the user offers samples to
|
||||
learn from. Any samples the user provides are fair game; there are no rights or
|
||||
attestation checks.
|
||||
|
||||
Read `references/mimic.md` for card anatomy, sample requirements, and scoring
|
||||
before you finish; this file is the flow.
|
||||
|
||||
## 1. Gather samples (harvest)
|
||||
|
||||
If the user offers none, default to bootstrapping. Harvest their transcripts and
|
||||
writing folders per `references/harvest.md`:
|
||||
|
||||
```bash
|
||||
python3 scripts/harvest_samples.py SOURCE [SOURCE...] -o candidates.json
|
||||
python3 scripts/harvest_classify.py --candidates candidates.json --mode heuristic
|
||||
```
|
||||
|
||||
Present the ranked candidates with their sources and flags; the user approves or
|
||||
rejects each. Treat `suspect_ai` candidates skeptically — that human review is
|
||||
the contamination defense, so never auto-approve a flagged paste. Copy only
|
||||
approved samples into `.unslop/voice/<name>/samples/`. The adapter internals,
|
||||
contamination tripwire, and privacy rules live in `references/harvest.md`.
|
||||
|
||||
## 2. Build the profile and card
|
||||
|
||||
Create `.unslop/voice/<name>/` yourself (it is gitignored) and run:
|
||||
|
||||
```bash
|
||||
python3 scripts/voice_profile.py samples/ -o profile.json
|
||||
python3 scripts/voice_card.py --profile profile.json --samples samples/ --out . --name <name> --provenance
|
||||
```
|
||||
|
||||
`voice_profile.py` is the machine fingerprint the scorer refers to.
|
||||
`voice_card.py` writes the layered card the generating model follows (`card.md`
|
||||
plus `card/<situation>.md` sheets) and, with `--provenance`, a `provenance.json`
|
||||
audit trail. Both scripts read only `.txt` and `.md` files; convert samples
|
||||
first. `voice_card.py` refuses (exit 2) when the profile does not describe the
|
||||
supplied samples, so a stale profile can never drive a card.
|
||||
|
||||
## 3. Surface confidence and gaps
|
||||
|
||||
Show the user `card.md`. If the profile is `low_confidence` (thin or cross-genre
|
||||
samples), say the voice is provisional and ask for more same-genre samples before
|
||||
trusting a mimic. For an **Uncovered** dimension the target writing will need,
|
||||
ask for one short sample that exercises it — and only those the task requires, not
|
||||
all ten. Prompt templates:
|
||||
|
||||
| Dimension | Prompt |
|
||||
|-----------|--------|
|
||||
| explaining-technical | "Share something you wrote explaining how a thing works." |
|
||||
| anecdote | "Share a few sentences telling a small story that happened to you." |
|
||||
| argument | "Share something where you defended a claim." |
|
||||
| disagreement | "Share something where you pushed back on an idea." |
|
||||
| praise | "Share something where you recommended something you liked." |
|
||||
| hedging-uncertainty | "Share something where you were unsure and said so." |
|
||||
| numbers-data | "Share something you wrote that works with quantities." |
|
||||
| addressing-reader | "Share a note or instructions written to a reader." |
|
||||
|
||||
`openings` and `closings` are structural and covered as soon as one document
|
||||
exists, so they need no prompt. The full canonical table lives in
|
||||
`references/mimic.md`.
|
||||
|
||||
When coverage or confidence stays thin and the user cannot supply more samples,
|
||||
offer the A/B calibration game (`references/calibrate.md`): it elicits voice
|
||||
preferences through reversible pair choices and feeds them to the card as
|
||||
`stated-preference` provenance, distinct from `measured-from-samples`.
|
||||
|
||||
## 4. Close with a scored demo
|
||||
|
||||
Prove the loop before the user trusts it: mimic one paragraph per
|
||||
`references/commands/mimic.md`, run `scripts/voice_score.py` and the scanners,
|
||||
and show the results. A voiced demo that trips a slop gate fails the loop; do not
|
||||
ship it with an excuse.
|
||||
Reference in New Issue
Block a user