Incogni: provider-declared attribution markers — one ScrubPatterns declaration feeding hook AND body sanitizer, unioned across providers #75

Closed
opened 2026-07-09 21:15:25 +02:00 by dominik.polakovics · 2 comments

Context

Two incogni enforcement points exist for AI-attribution markers, but only one is provider-declared (ADR-0012, ADR-0026 / issue #51 decision 8):

  • The pre-push hook is rendered from SeedMeta.ScrubPatterns (internal/seeder/hook.go) — already generalized.
  • The agent-API body sanitizer (sanitizeBodyattributionLine, internal/agentapi/handlers.go:929) still hardcodes Claude shapes: a co-authored-by: trailer starting with claude or containing anthropic.com, claude-session:, generated with…claude.

Under a Codex provider (#2), a Co-authored-by: ChatGPT <…@openai.com> footer in a PR/issue/comment body would pass straight to the tracker on an incogni repo. #2's acceptance requires incogni parity and a grep-clean core, so this is a precursor — the same role #6 played for the DeepLinker seam.

A second, related hole: incogniSeedMeta (internal/reposvc/reposvc.go) renders the hook from the repo's resolved default provider only. With three-level provider selection (ADR-0030), a per-session provider override can push commits screened by the wrong provider's markers.

Design

One declaration, two enforcement points, unioned.

  1. Widen SeedMeta.ScrubPatterns's contract: consumed by BOTH the pre-push hook (grep -i BRE in sh, as today) and the body sanitizer (compiled as case-insensitive Go regexps, applied per line). Patterns must stay in the BRE∩RE2 common dialect — claude-code's four already do ([[:space:]], [^>]* are valid in both). A test pins that every registered provider's patterns compile as Go regexps; the existing hook golden pins the sh side.
  2. sanitizeBody keeps core's line-walk + seam-repair mechanism (stripAttribution — blank-collapse at removal seams, edge trims, code-fence blank runs untouched, non-incogni bodies byte-identical, runs after ensureCloses). Only the per-line predicate changes: a line is dropped when it matches ANY registered provider's compiled patterns. attributionLine's hardcoded logic is deleted.
  3. incogniSeedMeta returns the union of all registered providers' ScrubPatterns (and keeps SeededPathPatterns per the same union or repo default — decide in implementation; over-matching is safe for the message scan, path patterns may stay per-provider if union would over-reject). The hook install/reconcile paths pick this up unchanged.
  4. Re-point the existing sanitizer tests at the declared claude patterns so any coverage change is deliberate (e.g. today's sanitizer matches a bare anthropic.com after the trailer prefix; the hook pattern requires the bracketed email — reconcile the pattern set explicitly).

Non-goals: no new interface method — a provider declares markers, core owns both mechanisms (seam-v2 idiom). If a future provider's attribution is not line-shaped, an optional capability (ADR-0017 pattern) can override the declarative path then; not built speculatively.

Acceptance

  • sanitizeBody strips markers of EVERY registered provider on incogni repos; provider fakes prove it with a non-claude pattern set (no Codex account needed).
  • Pre-push hook on an incogni repo rejects commits carrying ANY registered provider's markers regardless of which provider the pushing session ran.
  • Core stays grep-clean of claude-specific attribution literals outside internal/provider/claudecode (test-fixture literals exempt).
  • Existing invariants hold and stay tested: non-incogni byte-identity, Closes #N untouched, code-fence blank runs untouched, claude hook golden byte-identical (or deliberately re-pinned if the pattern set is reconciled).
  • ADR documenting the widened ScrubPatterns contract and the union decision.
## Context Two incogni enforcement points exist for AI-attribution markers, but only one is provider-declared (ADR-0012, ADR-0026 / issue #51 decision 8): - The **pre-push hook** is rendered from `SeedMeta.ScrubPatterns` (`internal/seeder/hook.go`) — already generalized. - The **agent-API body sanitizer** (`sanitizeBody` → `attributionLine`, `internal/agentapi/handlers.go:929`) still hardcodes Claude shapes: a `co-authored-by:` trailer starting with `claude` or containing `anthropic.com`, `claude-session:`, `generated with…claude`. Under a Codex provider (#2), a `Co-authored-by: ChatGPT <…@openai.com>` footer in a PR/issue/comment body would pass straight to the tracker on an incogni repo. #2's acceptance requires incogni parity and a grep-clean core, so this is a precursor — the same role #6 played for the DeepLinker seam. A second, related hole: `incogniSeedMeta` (`internal/reposvc/reposvc.go`) renders the hook from the repo's **resolved default** provider only. With three-level provider selection (ADR-0030), a per-session provider override can push commits screened by the wrong provider's markers. ## Design **One declaration, two enforcement points, unioned.** 1. Widen `SeedMeta.ScrubPatterns`'s contract: consumed by BOTH the pre-push hook (`grep -i` BRE in sh, as today) and the body sanitizer (compiled as case-insensitive Go regexps, applied per line). Patterns must stay in the BRE∩RE2 common dialect — claude-code's four already do (`[[:space:]]`, `[^>]*` are valid in both). A test pins that every registered provider's patterns compile as Go regexps; the existing hook golden pins the sh side. 2. `sanitizeBody` keeps core's line-walk + seam-repair mechanism (`stripAttribution` — blank-collapse at removal seams, edge trims, code-fence blank runs untouched, non-incogni bodies byte-identical, runs after `ensureCloses`). Only the per-line predicate changes: a line is dropped when it matches ANY registered provider's compiled patterns. `attributionLine`'s hardcoded logic is deleted. 3. `incogniSeedMeta` returns the **union of all registered providers'** ScrubPatterns (and keeps SeededPathPatterns per the same union or repo default — decide in implementation; over-matching is safe for the message scan, path patterns may stay per-provider if union would over-reject). The hook install/reconcile paths pick this up unchanged. 4. Re-point the existing sanitizer tests at the declared claude patterns so any coverage change is deliberate (e.g. today's sanitizer matches a bare `anthropic.com` after the trailer prefix; the hook pattern requires the bracketed email — reconcile the pattern set explicitly). **Non-goals:** no new interface method — a provider *declares* markers, core owns both mechanisms (seam-v2 idiom). If a future provider's attribution is not line-shaped, an optional capability (ADR-0017 pattern) can override the declarative path then; not built speculatively. ## Acceptance - `sanitizeBody` strips markers of EVERY registered provider on incogni repos; provider fakes prove it with a non-claude pattern set (no Codex account needed). - Pre-push hook on an incogni repo rejects commits carrying ANY registered provider's markers regardless of which provider the pushing session ran. - Core stays grep-clean of claude-specific attribution literals outside `internal/provider/claudecode` (test-fixture literals exempt). - Existing invariants hold and stay tested: non-incogni byte-identity, `Closes #N` untouched, code-fence blank runs untouched, claude hook golden byte-identical (or deliberately re-pinned if the pattern set is reconciled). - ADR documenting the widened ScrubPatterns contract and the union decision.
Author
Owner

Design resolution from the provider-seam grill (2026-07-09), settling the question this issue left open: SeededPathPatterns are unioned across all registered providers too, same as ScrubPatterns — not kept per-provider.

Rationale: with per-session provider override (ADR-0030), a Codex session on a claude-default repo seeds that provider's files; a hook carrying only the repo-default provider's path patterns wouldn't block them if committed. False-reject risk is negligible because context-file names must be lab-owned/never-tracked by hard rule (#79). One symmetric rule, no per-repo conditionals, no hook reinstall on session-level override.

Design resolution from the provider-seam grill (2026-07-09), settling the question this issue left open: **SeededPathPatterns are unioned across all registered providers too**, same as ScrubPatterns — not kept per-provider. Rationale: with per-session provider override (ADR-0030), a Codex session on a claude-default repo seeds that provider's files; a hook carrying only the repo-default provider's path patterns wouldn't block them if committed. False-reject risk is negligible because context-file names must be lab-owned/never-tracked by hard rule (#79). One symmetric rule, no per-repo conditionals, no hook reinstall on session-level override.
Author
Owner

This was generated by AI while landing a PR.

PR #81 validation — verdict: PASS

Ran the /land-pr flow against PR #81 (afk/75, feat(incogni): provider-declared attribution markers unioned across providers).

Verification signal relied on: Forgejo CI combined status = success on head 43ad7d8 — required check ci / native green (runs go test -tags ui ./..., SPA lint/format/test/build, golangci-lint). The ci-nix hermetic gate was correctly not triggered: it is path-gated to **/*.nix/flake.lock/go.mod/go.sum, and this diff touches none of them, so the native gate fully covers the diff's reach. Did not re-run — CI already vouches.

Conventions: Conventional Commits title ✓. AFK contract ✓ — Closes #75 present and valid on branch afk/75.

Diff review (23 files, +1120/-134) against issue #75 intent:

  • One ScrubPatterns declaration → two enforcement points, unioned across all registered providers. NewRegistry precomputes UnionScrubPatterns/UnionSeededPathPatterns/ScrubRegexps and validates every provider's patterns compile as RE2 at boot (unenforceable marker set fails fast). ✓
  • sanitizeBody now drops any line matching the compiled union; hardcoded attributionLine deleted; agentapi.New takes the compiled set, wired from providerReg.ScrubRegexps(). Seam-repair mechanics unchanged. ✓
  • reposvc.incogniPatterns() screens the union (scrub + seeded-path) regardless of the session's provider — closes the ADR-0030 per-spawn-override hole. Per the 2026-07-09 grill comment, SeededPathPatterns are unioned too. ✓
  • Empty/nil registry → content-inert pass-through, matching the hook's empty-registry behavior. ✓
  • Deliberate pattern reconciliation: co-authored-by:.*<[^>]*@anthropic\.com> requires the bracketed email (narrows the old bare anthropic.com match); claudecode patterns unchanged vs main, so the pre-push hook golden stays byte-identical. Pinned by a new sanitize test case. ✓
  • New arch test TestCoreAttributionNeutrality (Go twin of the SPA neutrality test) scans core string literals for attribution tokens outside claudecode/providertest. ✓

Mergeability: merges cleanly into origin/main (abed41d) — no conflicts.

No blockers. Awaiting free-text merge confirmation.

> *This was generated by AI while landing a PR.* **PR #81 validation — verdict: PASS** Ran the `/land-pr` flow against PR #81 (`afk/75`, `feat(incogni): provider-declared attribution markers unioned across providers`). **Verification signal relied on:** Forgejo CI combined status = **success** on head `43ad7d8` — required check `ci / native` green (runs `go test -tags ui ./...`, SPA lint/format/test/build, golangci-lint). The `ci-nix` hermetic gate was correctly *not* triggered: it is path-gated to `**/*.nix`/`flake.lock`/`go.mod`/`go.sum`, and this diff touches none of them, so the native gate fully covers the diff's reach. Did not re-run — CI already vouches. **Conventions:** Conventional Commits title ✓. AFK contract ✓ — `Closes #75` present and valid on branch `afk/75`. **Diff review (23 files, +1120/-134) against issue #75 intent:** - One `ScrubPatterns` declaration → two enforcement points, unioned across all registered providers. `NewRegistry` precomputes `UnionScrubPatterns`/`UnionSeededPathPatterns`/`ScrubRegexps` and validates every provider's patterns compile as RE2 at boot (unenforceable marker set fails fast). ✓ - `sanitizeBody` now drops any line matching the compiled union; hardcoded `attributionLine` deleted; `agentapi.New` takes the compiled set, wired from `providerReg.ScrubRegexps()`. Seam-repair mechanics unchanged. ✓ - `reposvc.incogniPatterns()` screens the union (scrub + seeded-path) regardless of the session's provider — closes the ADR-0030 per-spawn-override hole. Per the 2026-07-09 grill comment, SeededPathPatterns are unioned too. ✓ - Empty/nil registry → content-inert pass-through, matching the hook's empty-registry behavior. ✓ - Deliberate pattern reconciliation: `co-authored-by:.*<[^>]*@anthropic\.com>` requires the bracketed email (narrows the old bare `anthropic.com` match); claudecode patterns unchanged vs `main`, so the pre-push hook golden stays byte-identical. Pinned by a new sanitize test case. ✓ - New arch test `TestCoreAttributionNeutrality` (Go twin of the SPA neutrality test) scans core string literals for attribution tokens outside `claudecode`/`providertest`. ✓ **Mergeability:** merges cleanly into `origin/main` (`abed41d`) — no conflicts. No blockers. Awaiting free-text merge confirmation.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/coding-lab#75
No description provided.