Files
theclaymethod__unslop/docs/DECISIONS.md
Clayton Kim 4cd3ea0a1e Make the adversarial-refresh promise operational
Plan 013: the Growth promise in docs/PRODUCT.md relied on someone
remembering to run wiki_sync, re-run the parity bench, and funnel misses
through contribute. This lands the three missing pieces:

- references/refresh.md: the agent-runnable refresh procedure — staleness
  check, wiki-sync flow, parity-bench flow with the eval-gating rule,
  every-miss-becomes-a-row routing through contribute, and result-recording
  conventions (pipeline.md tables, TUNE-RESULTS.md style).
- scripts/refresh_status.py: stdlib, network-free staleness reporter.
  JSON with wiki_sync / parity_bench / newest_pattern_row, each carrying
  last/days/stale. Sources: .wiki_sync_state.json (last_timestamp, mtime
  fallback), the "Live matrix recorded **YYYY-MM-DD**" line in
  references/pipeline.md, and git log -1 --format=%cs on
  evals/adversarial-evals.json (argv list, no shell). Thresholds (90/180/60
  days) are commented guidance; always exits 0 — reporter, not gate.
- docs/DECISIONS.md: durable home for decided tradeoffs, each entry with
  Decision / Why / Revisit-when / Source. Seeds the PRODUCT.md decisions
  (agent-invoked only, English-only, no packaging, no rights checks,
  removal-dominant axis) plus the commit-message-only ones: WP8 fixture
  word-floor/length-balance queue (05f2363), voice impostor/background
  calibration queue (41b60d1), protects-grain + build_report deferrals
  (d6f6321), and FP-06 as the single intentional xfail (efd7e0e,
  evals/CRITIQUE.md).
- One-line pointers to references/refresh.md from references/maintenance.md
  and docs/PRODUCT.md (Growth).

All four touched/new docs pass banned_phrase_scan and
structure_scan --genre docs. Suite: 439 PASS / 1 XFAIL (FP-06) / 0 FAIL.

New decisions go in DECISIONS.md at decision time; the reporter is the
building block if the operator ever wants scheduled refresh outside this
repo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K6CYksdLbXbTAxcAQjvHz5
2026-07-07 06:37:22 -07:00

6.6 KiB

Decisions

Durable record of tradeoffs the product has already made, so the reasoning does not live only in a commit message someone has to go dig up. Each entry is dated to when the decision was made (not when it was copied here), and cites the doc or commit that carries it. New decisions get a new entry at decision time; nothing here is retroactively rewritten.

2026-07-06 — Agent-invoked only, no daemons or hooks

Decision: Linting and refresh run when a host agent invokes them. Nothing in this repo runs as a cron job, a pre-commit hook, or an editor extension.

Why: The host agent is the runtime. A background scheduler would be a second execution path with its own failure modes, and the repo ships as plain scripts specifically so any host agent can run them directly.

Revisit-when: An operator needs scheduled refresh outside an agent session. scripts/refresh_status.py is built as the reporter half of that path on purpose (see references/refresh.md), so a future scheduler only has to call it, not invent staleness detection.

Source: docs/PRODUCT.md (Identity and shape).

2026-07-06 — English-only, with a graceful decline

Decision: Non-English input gets a cheap detection and a clear decline rather than an attempt at cross-language scanning.

Why: The scanner catalog is built from English-language AI-writing tells; running it against other languages would produce noise, not signal.

Revisit-when: Demand for another language's AI-isms catalog appears and someone proposes a scanner strategy for it.

Source: docs/PRODUCT.md (Bounds).

2026-07-06 — No packaging

Decision: The repo is the artifact. There is no published package, and none is planned unless distribution genuinely requires it.

Why: Entry points are plain scripts under scripts/, runnable by any host agent without an install step.

Revisit-when: A hosting environment appears that cannot run the scripts directly and needs a packaged distribution to reach them.

Source: docs/PRODUCT.md (Identity and shape).

2026-07-06 — No rights or attestation checks on mimicry samples

Decision: Mimicry accepts any writing style the user supplies samples for. There is no rights-verification or attestation machinery; the sheet of samples is the only credential.

Why: The product treats consent to publish as the user's problem to manage, not one the tool can verify from the sample text itself.

Revisit-when: Mimicry usage grows past individual or team use in a way that makes provenance disputes likely.

Source: docs/PRODUCT.md (Bounds).

2026-07-06 — Removal-dominant balance on the product axis

Decision: Product weight sits roughly 70/30 toward removal (detect and strip AI-writing patterns) over reconstruction (write in a specific human's voice).

Why: Removal is deterministic, cheap, and objectively benchmarkable — the trust asset the rest of the product stands on. Reconstruction is generative and register-sensitive, and it only ships under removal's gates.

Revisit-when: Measured mimic/rewrite usage or quality data shifts the axis's practical value away from removal.

Source: docs/PRODUCT.md (The axis).

2026-07-06 — WP8 pair fixtures: word floors and length balance queued, not enforced

Decision: The minimal-pair fixtures under evals/fixtures/pairs/ shipped without raising every fixture to the review's spec word floors, without a corpus-level length-balance check, and without the vague_attribution pair's single-difference rework. check_pairs.py does not yet enforce these.

Why: The reviewed fixtures already passed pair-hygiene checks (existence, word-delta, clean-without, with-target); the remaining polish was accepted as a queued follow-up rather than a blocker for landing the pair infrastructure.

Revisit-when: A new pair addition re-exposes the with-twin length skew (+2.4 words at commit time), or check_pairs.py gains fixture-floor enforcement.

Source: commit 05f2363.

2026-07-06 — Voice impostor pool and background calibration queued

Decision: The deterministic voice scorer shipped with a synthetic impostor pool and no real --background calibration for delta z-scores, rather than a same-genre impostor pool and measured background calibration.

Why: The shipped scorer already passed its adversarial checks (mechanical attacks lose by 0.85+ composite, separation diagonal wins at five seeds); the follow-ups were approved-with-fixes and queued rather than blocking.

Revisit-when: voice_score.py's impostor pool or --background calibration path is reworked, or a same-genre impostor scenario produces a measurable gap the synthetic pool misses.

Source: commit 41b60d1.

2026-07-06 — Per-category protects-grain redesign deferred

Decision: check_pattern_coverage.py's per-category protects field keeps its current grain (one FP row can claim an entire category) rather than a finer-grained redesign.

Why: Explicitly deferred as out of scope for a contract-safe consolidation pass — the existing grain still made every category claimable, and a redesign risked changing pinned CLI/JSON behavior in the same change.

Revisit-when: A future refactor specifically touches check_pattern_coverage.py's protects handling.

Source: commit d6f6321.

2026-07-06 — run_mimic_refine.py's build_report() left as one function

Decision: build_report() in evals/run_mimic_refine.py was not decomposed during the internals-consolidation pass that touched most of its neighbors.

Why: Explicitly deferred as out of scope for the same contract-safe pass as the protects-grain redesign above — decomposing it risked behavior drift in a change meant to be a pure refactor.

Revisit-when: build_report() needs new report fields, or a bug traces back into it.

Source: commit d6f6321.

2026-07-04 — FP-06 (literal "delve into a place") is the one intentional XFAIL

Decision: evals/run_adversarial.py pins exactly one expected XFAIL, FP-06: the scanner still flags the literal sense of "delve into a place" even though only the figurative "delve into a topic" is the intended AI-ism.

Why: Distinguishing the literal and figurative senses is beyond a pattern scanner, and dropping the delve into pattern to fix the false positive would cost more recall on the real AI-ism than the rare false positive is worth.

Revisit-when: The scanner gains sense disambiguation beyond pattern matching, or a cheap-enough contextual rule is found that separates the two senses without dropping recall.

Source: evals/CRITIQUE.md (Status section); EXPECTED_XFAIL pinned in commit efd7e0e.