feat(cli): watermark-naturalization program — sanitize, naturalize, metadata forensics - #293
Merged
Conversation
… + agon naturalize (Phase 2) Phase 1 (sanitize): deterministic invisible-watermark forensics, no AI. Detects/cleans zero-width chars, bidi overrides, tag chars, homoglyph substitution, whitespace stego. --detect is report-only (exit 1 on actionable findings). Honesty contract: clean = no actionable findings; variation selectors/homoglyph words report-only; keyed statistical watermarks always listed as not assessable. Phase 2 (naturalize): sanitize → ONE non-author engine rewrites (writer ≠ rewriter, enforced) under a meaning-preservation brief → mandatory re-scan with refusal-to-emit on dirty output → word-level diff report. Live-verified: AI tells rewritten, facts/structure intact, 51% lexical change, re-scan exit 0. Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
…rk-naturalization program
Wire the program into the interactive surface (previously CLI + `agon call` only):
- intent.kern: /sanitize and /naturalize join SLASH_COMMANDS with usage
hints; parseSlashCommand maps them to { type, input } intents, leaving
flag parsing (--detect/--metadata/--strip/--out/--in-place and
--engine/--author/--min-change/--max-attempts) to the handlers.
- intent-orchestration.kern: /sanitize runs inline (deterministic, no
engine dispatch); /naturalize runs as a background job like /forge.
- handlers/naturalize.kern (new): handleSanitize renders scan/strip
results as native TUI tables + headers; handleNaturalize runs the full
sanitize → non-author rewrite → re-scan pipeline via runNaturalize with
spinner, word-diff summary, and the honesty contract intact (residual
statistical watermarks always reported not-assessable).
- handlers/index.ts: barrel export.
- self-coverage baseline bumped to actuals (+1 blocked handler from the
new kern file).
Gates: build (202/202 kern compile + tsc -b --force), kern:coverage
206/206, kern:self-coverage green, test:ts green.
Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
…watermark modes - Fix kern-guard kern-duplicate-symbol: readStdin was defined in both sanitize.kern and naturalize.kern; moved to a single source of truth in packages/cli/src/kern/blocks/stdin.kern, imported by both commands. - README: add sanitize/naturalize rows to the mode-picker table and a "Sanitize & Naturalize (watermark removal)" section under Core Modes. Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Ships the watermark-naturalization program in three phases (two commits):
Phase 1 —
agon sanitize(deterministic forensics)Phase 2 —
agon naturalize(sanitize → rewrite → re-scan)--min-changelexical-overlap threshold with retry (up to--max-attempts) as a heuristic against Anthropic's announced statistical/lexical watermarkPhase 3 — binary provenance metadata
agon sanitize --filescans PNG (tEXt/zTXt/iTXt), JPEG (EXIF/COM/XMP), and SVG for metadata channels--stripremoves them; report notes that metadata stripping doesn't address pixel-space watermarksReview
Six-engine review (agy, claude, codex, minimax, kimi, zai) on the uncommitted diff — blocking findings (duplicate test block, CLI flag parsing for
--min-change/--max-attempts, append-only bypass of the change threshold) were fixed in commit 2 before landing.Verification
npm run build✓npm run kern:coverage✓npm run kern:self-coverage✓ (baselines bumped to new actuals)npm run test:ts✓ (incl. newtests/unit/text-forensics.test.ts+tests/unit/naturalize.test.ts)Notes
mainafter PR feat(cesar): permission modes at Claude Code parity with a destructiv… #292 merged — contains only the watermark work.--min-changeis a divergence heuristic, not a guarantee.