wirescreen

package
v0.44.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package wirescreen — ROADMAP for the "local model on the wire" proposer spine.

This doc.go is the extension contract. The spine is the witnessed-lossy-proposer PATTERN plus the abi.SemanticScreen seam (internal/abi/semscreen.go); each rung below is a sibling proposer added without changing the spine. The full rationale and the when-it-makes-sense decision framework live in docs/notes/RESEARCH-local-model-on-the-wire-2026-06-23.md.

THE PATTERN (every rung obeys it):

A small LOCAL model is a LOSSY PROPOSER, never the load-bearing answer; it emits a routing bit / rank / digest, not a decision the system trusts. It is bounded by a WITNESS: the original bytes stay pinned in the CAS and a gated PageIn (after a witness Clear) restores them byte-exact, so a wrong proposal costs one demand-page fault, never a lost fact. It is strictly ADDITIVE and one-sided: a proposer may only make the system MORE careful (quarantine, demote, redact), never weaker than a deterministic floor. It is DEFAULT-INERT and gated (build tag or env), because the real model needs weights and a measured latency number before it can default on, so the pure-Go binary is unchanged until an operator opts in. The local-triage ENVELOPE on this box is the native CPU Q8/Q4_K path in internal/model (cmd/fakchat -gguf), 1-3B sweet spot; the compute HAL is f32-only (a dead end for quant) and the RX 7600 is slower than CPU at this size, so measure end-to-end latency before defaulting any rung on.

RUNG 1 — SEMANTIC POISON SCREEN (this package; SHIPPED as the spine). Seam: abi.SemanticScreen, consulted by ctxmmu.MMU.Admit AFTER ScreenBytes; a hit routes through ctxmmu.quarantineResult and inherits the CAS-pin + PageIn witness. A registered Screener flags injection-shaped results the literal-marker regex floor misses. Reference impl: heuristicScreener (deterministic). NEXT: a model-backed Screener registered under "model" via cmd/fakchat's native CPU path, gated behind a build tag, with the end-to-end admit-latency measurement that lets it default on. Honest scope: on the flagship `fak guard -- claude` passthrough the byte-rewrite is dead (the model reads req.Raw verbatim); the live value is taint-gate hardening (a quarantine raises the IFC high-water mark adjudicateProposed reads). It removes bytes only on the non-passthrough re-marshal wire.

RUNG 2 — USEFUL PAGE-OUT (digest; SHIPPED as the reference floor — issue #570). Seam: ScreenDigest in ScreenAdvice (wired in the interface) plus ctxmmu's oversize Transform branch (digestToPointer, mmu.go). Today an oversize-benign result pages out to an OPAQUE {_paged,ref,len} pointer; when a Digester (digester.go, selected by FAK_WIRE_SCREEN) authors a ~200-token digest, the stub carries the digest instead and the original is pinned in CAS under the held ledger so a witness Clear + PageIn restores it byte-exact. The reference heuristicDigester is the zero-model floor; the model-backed Digester is the gated follow-on (needs weights + a measured digest latency before default-on). It only reaches the wire on the non-passthrough re-marshal path; on the passthrough it is dead until #555 lands (see the outbound blocker below).

RUNG 3 — MULTI-MODAL SCREENSHOT TRIAGE. Seam: the same ctxmmu Transform branch, but the body is a base64 image block. Reversible collapses: perceptual-hash dedup of an unchanged frame (ZERO model, buildable now), OCR/VLM collapse-to-text, crop-to-ROI. BLOCKER: no vision/OCR path exists (internal/model is text-only, no vision encoder), so only the phash arm is buildable on this stack today. The phash arm SHIPPED (issue #571): phash.go is a pure-Go DCT perceptual-hash Digester that dedups a re-sent frame to an "unchanged, see frame#k" pointer, selected by FAK_WIRE_SCREEN=phash (or PhashScreen), reusing rung 2's ScreenDigest -> digestToPointer reversible witness (the original pixels page into the CAS and a Clear + PageIn restores them byte-exact). The vision arms (OCR/ VLM, crop-to-ROI) wait on an encoder.

RUNG 4 — MODEL-AUTHORED RELEVANCE FORECAST. Seam: ctxplan.Forecast.Intents (internal/ctxplan/forecast.go), a DIFFERENT call site (the context planner, not the MMU). A small model authors the predicted reference strings the next turns will touch; the planner keeps the right cold spans resident and demotes the rest, and a miss costs one demand-page fault. This is ctxplan #556. BLOCKER: needs the outbound transform seam below to affect the flagship wire.

RUNG 5 — PRE-SEND PII/SECRET REDACTION (SHIPPED + WIRED on the non-passthrough re-marshal path; issue #572). Seam: this leaf's Redactor proposer + Apply/Restore (redactor.go), the redaction peer of rung 1's Screener, plus the agent wire point agent.RedactOutboundMessages (internal/agent/transcript.go) called from prepareUpstream (internal/agent/stream.go) on the NON-passthrough re-marshal hop. A Redactor proposes [start,end) byte spans to redact; Apply replaces each with a "[REDACTED:<kind>]" placeholder and pins the UNREDACTED original in the shared CAS so an authorized Restore returns it byte-exact (the same pageOut + PinResolved witness the MMU's quarantine uses). The reference piiRedactor is a zero-model, high-precision regex + Luhn compliance floor (credit cards, SSNs, AWS/GitHub/Slack/Stripe/Google keys, emails, bearer tokens, PEM private keys). It is DEFAULT-INERT (FAK_WIRE_REDACT) and touches no ABI seam.

Honest scope — this is a compliance floor, NOT a token saver. It is WIRED only where it can reach the wire today: the non-passthrough re-marshal path (OpenAI/xAI proxy, mock, local serve), where prepareUpstream runs RedactOutboundMessages over the outbound messages before adapter.MarshalRequest. The flagship `fak guard -- claude` Anthropic passthrough still sends req.Raw VERBATIM, so the redaction cannot reach the model there until the cache-prefix-preserving req.Raw transform (#555, ctxplan-owned) lands — that flagship wiring is the named, #555-gated follow-on, deferred in code + here. The model-backed Redactor is the further gated follow-on (needs weights + a measured span latency before default-on). This is the floor for the outbound surface, not a duplicate of ctxmmu's inbound ScreenBytes quarantine (which removes a whole secret-bearing RESULT).

MEASURED pre-send latency (the "measure before you default it on" gate): end-to-end Apply on a ~480 B body carrying every pattern shape + ordinary prose is ~54 µs/op (classify ~52 µs + ~2 µs CAS witness pin; BenchmarkApply/BenchmarkPropose, redactor_bench_test.go) — orders of magnitude under a turn, so the deterministic floor clears the TTFB bar comfortably. The gated model arm's NER-classify latency is UNMEASURED until weights land and is the number that decides its default-on. Witness: go test ./internal/agent ./internal/wirescreen (TestRedactOutbound_*, TestApply_RedactsSpansAndPinsOriginal, TestApply_NoSpansIsNoOp).

THE OUTBOUND BLOCKER (gates rungs 2/4/5 on the flagship route): on the `fak guard -- claude` Anthropic passthrough the upstream gets req.Raw VERBATIM (gateway messages.go, WithRawRequestBody, to preserve the cache_control prefix). The kernel's inbound rewrite targets req.Messages, which the passthrough never serializes, so any "shrink/rewrite the outbound prompt" rung changes nothing the model reads on the live route. Building a req.Raw transform that preserves the cache-prefix is the single seam that unblocks the digest (rung 2), the forecaster (rung 4/#556), and the redactor (rung 5/#572) on the flagship wire. Until it lands those rungs are non-passthrough-only (rung 5's deterministic floor is WIRED on the non-passthrough re-marshal path via agent.RedactOutboundMessages; only its flagship-passthrough arm waits on #555). This is the same blocker the ctxwin program hit (ctxplan #555).

Package wirescreen is rung 1 of the "local model on the wire" proposer spine: a small LOCAL model (or any cheap predicate) wired as an ADDITIVE, witnessed screen behind the context-MMU's deterministic regex floor. It is the first concrete member of the witnessed-lossy-proposer family designed in docs/notes/RESEARCH-local-model-on-the-wire-2026-06-23.md. See doc.go for the family roadmap (the digest, multi-modal, forecaster, and redactor siblings).

What it does: when FAK_WIRE_SCREEN selects a Screener, this leaf registers an abi.SemanticScreen adapter that the context-MMU consults AFTER ScreenBytes. A Screener may only ASK to quarantine a result the regex floor already admitted (an injection-shaped payload with no literal marker). The hit flows through the MMU's existing CAS-pin + PageIn-after-Clear path, so the held bytes are recoverable and a miss degrades to floor-only behaviour.

Default-inert: with FAK_WIRE_SCREEN unset, this leaf registers NOTHING with the ABI, so abi.SemanticScreens() stays empty and the MMU is exactly the v0.1 regex floor at zero added cost. The leaf is safe to blank-import in the defconfig for that reason.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Dedups added in v0.33.0

func Dedups() int64

Dedups reports how many frames this leaf has collapsed to a dedup pointer over its lifetime — the phash peer of Digests() (the digester), Flags() (the screener), and ctxmmu.MMU.Digested() (the page-outs the MMU actually used).

func Digests added in v0.33.0

func Digests() int64

Digests reports how many digests this leaf has authored over its lifetime — the digest peer of Flags() (the screener), Redactions() (the redactor), and ctxmmu.MMU.Digested() (the page-outs the MMU actually used).

func Flags

func Flags() int64

Flags reports how many results this leaf has flagged over its lifetime — the leaf's own observability peer of ctxmmu.MMU.Screened().

func PhashScreen added in v0.33.0

func PhashScreen() abi.SemanticScreen

PhashScreen returns an abi.SemanticScreen that advises a dedup pointer for a redundant screenshot frame via the perceptual-hash arm (issue #571). It is the PROGRAMMATIC opt-in peer of the FAK_WIRE_SCREEN=phash env gate: a host that wants phash dedup without the init-time env may register this directly. Default-inert either way — registering it (or setting the env) is the operator's explicit choice; otherwise nothing fires and the MMU is the bare regex floor.

func Redactions added in v0.33.0

func Redactions() int64

Redactions reports how many spans this leaf has redacted over its lifetime — the redaction peer of Flags() (the screener) and ctxmmu.MMU.Screened().

func Register

func Register(name string, s Screener)

Register adds a named Screener to the catalog. A leaf — the heuristic reference here, or a model-backed screener in a follow-on — registers itself from init(); the operator selects one with FAK_WIRE_SCREEN=<name>. Registering twice under one name replaces the prior entry (last wins), matching the abi RegionBackend idiom.

func RegisterDigester added in v0.33.0

func RegisterDigester(name string, d Digester)

RegisterDigester adds a named Digester to the catalog. A leaf — the heuristic reference here, or a model-backed digester in a follow-on — registers itself from init(); the operator selects one with FAK_WIRE_SCREEN=<name> (the SAME gate as the Screener, so one opt-in activates both rungs). Last-write-wins per name, matching the Screener / Redactor / RegionBackend idiom.

func RegisterRedactor added in v0.33.0

func RegisterRedactor(name string, r Redactor)

RegisterRedactor adds a named Redactor to the catalog. A leaf — the pii reference here, or a model-backed redactor in a follow-on — registers itself from init(); the operator selects one with FAK_WIRE_REDACT=<name>. Last-write-wins per name, matching the Screener / RegionBackend idiom.

func Restore added in v0.33.0

func Restore(ctx context.Context, handle abi.Ref) ([]byte, error)

Restore returns the UNREDACTED original for a handle Apply returned, byte-exact. It is the witness-layer reversal: the caller that holds the handle (an operator / audit path) decides authorization, exactly as the MMU's gated PageIn requires a witness Clear() before it resolves a quarantined result. The redactor provides the MECHANISM; the caller provides the POLICY.

func SetActiveRedactorForTest added in v0.35.0

func SetActiveRedactorForTest(name string) (restore func())

SetActiveRedactorForTest forces the FAK_WIRE_REDACT selection to the named registered redactor ("" resolves to inert/nil), bypassing the one-shot env resolution, and returns a restore func that puts the prior selection back. It lets a cross-package test (e.g. the agent outbound-wire path) exercise the active-redactor branch deterministically without depending on FAK_WIRE_REDACT or on init-resolution order. Test-support only — production code selects via ActiveRedactor; the package's own tests poke ractive/ractiveResolved directly.

Types

type Digester added in v0.33.0

type Digester interface {
	// Name identifies the digester for audit (it rides the same FAK_WIRE_SCREEN gate as
	// the Screener, so the adapter composes the audit trail from both).
	Name() string
	// Summarize authors a short (~200-token) digest of body (which SURVIVED the regex
	// floor and was NOT flagged for quarantine). tool is the producing tool name (may be
	// empty). ok is false (and digest empty) when the digester declines (e.g. an empty
	// body, or a model digester that is not confident enough to summarize).
	Summarize(ctx context.Context, body []byte, tool string) (digest string, ok bool)
}

Digester is the extension point a concrete digest proposer implements. It is a LOSSY proposer bounded by the witness the context-MMU enforces (the original is pinned in CAS and PageIn-after-Clear restores it byte-exact): it proposes a summary, never a decision the system trusts. A Digester is NEVER trusted to be correct — a wrong summary is recoverable (the operator pages the original back in) and a miss degrades to the opaque oversize pointer. It is strictly one-sided: it may only ADD information to the stub (a digest), never weaken or drop the CAS ref the witness needs.

func ActiveDigester added in v0.33.0

func ActiveDigester() Digester

ActiveDigester returns the Digester selected by FAK_WIRE_SCREEN, or nil when unset/unknown (the inert default). It shares the Screener's selection env so a single opt-in (e.g. FAK_WIRE_SCREEN=heuristic) activates both the rung-1 semantic screen and the rung-3 useful-page-out digest. Resolution is lazy and once-only so selection is robust to init() ordering across files — the same fence Active() uses.

type JSONHit added in v0.38.0

type JSONHit struct {
	Pointer string `json:"pointer"`
	Kind    string `json:"kind"`
}

JSONHit is one redaction the leaf-aware pass applied, addressed by an RFC-6901 JSON Pointer to the leaf (not a byte offset — the flat body's offsets are meaningless once the tree is re-marshalled) plus the Span kind that matched.

type JSONRedaction added in v0.38.0

type JSONRedaction struct {
	Redacted []byte    `json:"-"`
	Hits     []JSONHit `json:"hits,omitempty"`
}

JSONRedaction is the result of RedactJSONLeaves: the re-marshalled body with each matched leaf span replaced by a placeholder, and the pointer-addressed audit of what was redacted. Redacted equals the input body verbatim when ok is false.

func RedactJSONLeaves added in v0.38.0

func RedactJSONLeaves(ctx context.Context, r Redactor, body []byte, tool string) (JSONRedaction, bool)

RedactJSONLeaves runs r over the string leaves of a JSON body and returns the re-marshalled body with each proposed span redacted in place. It returns ok=false (and Redacted == body) when r is nil, the body is empty, the body is not a JSON object/array/string, or nothing was redacted — every case in which the caller should fall back to the flat path unchanged.

type Redaction added in v0.33.0

type Redaction struct {
	Redacted []byte  // body with each proposed span replaced by "[REDACTED:<kind>]"
	Original abi.Ref // CAS handle to the UNREDACTED original (Restore returns it byte-exact)
	Spans    []Span  // the disjoint spans that were redacted (audit)
	By       string  // the redactor name
}

Redaction is the result of Apply: the redacted body, a CAS handle to the unredacted original (byte-exact restore via Restore), the spans that were redacted, and the redactor that proposed them.

func Apply added in v0.33.0

func Apply(ctx context.Context, r Redactor, body []byte, tool string) (Redaction, bool)

Apply runs a proposed redaction in place. It asks r for spans, and if r proposes any it (1) pins the UNREDACTED original in the shared CAS so an authorized Restore returns it byte-exact, then (2) replaces each span with a "[REDACTED:<kind>]" placeholder. It is strictly one-sided: it only REMOVES bytes (a span -> a short placeholder), never injects or rewrites anything outside the proposed spans, so the witness invariant holds — a wrong proposal costs one demand-page fault, never a lost fact.

ok is false (and Redaction.Redacted == body, Original empty) when r proposed no spans OR when no CAS page-out backend is registered to witness the original: the spine's founding contract is that redaction MUST be reversible, so Apply refuses to redact when it cannot pin the original rather than silently dropping bytes. An operator who opted in (FAK_WIRE_REDACT) links the full defconfig, which registers the "blob" CAS backend, so the witness is present whenever a redactor is active.

type Redactor added in v0.33.0

type Redactor interface {
	// Name identifies the redactor for FAK_WIRE_REDACT selection and audit.
	Name() string
	// Propose returns the disjoint [Start,End) byte spans in body that should be
	// redacted before bytes leave the box. tool is the producing tool / message
	// role context (may be empty). The spans MUST be within bounds; Apply coalesces
	// them to be disjoint. A redactor that finds nothing returns nil.
	Propose(ctx context.Context, body []byte, tool string) []Span
}

Redactor is the extension point a concrete redaction proposer implements. It is a LOSSY proposer bounded by a witness (Apply pins the original in CAS): it proposes spans to redact, never a decision the system trusts. A Redactor is NEVER trusted to be correct — a false positive is recoverable (Restore returns the exact bytes) and a false negative degrades to the unredacted body. It is strictly one-sided: the spans it proposes may only cause bytes to be REMOVED (replaced with a placeholder), never injected, reordered, or weakened.

func ActiveRedactor added in v0.33.0

func ActiveRedactor() Redactor

ActiveRedactor returns the Redactor selected by FAK_WIRE_REDACT, or nil when unset/unknown (the inert default). Resolution is lazy and once-only so selection is robust to init() ordering across files. This is the redaction peer of Active() (the screener).

func PIIRedactor added in v0.33.0

func PIIRedactor() Redactor

PIIRedactor returns the deterministic reference redactor (the zero-model floor), independent of the FAK_WIRE_REDACT selection. It lets a caller apply the floor directly — e.g. a non-passthrough re-marshal path that wants compliance hygiene without opting the whole spine in — and gives tests a handle without env coupling.

type Screener

type Screener interface {
	// Name identifies the screener for FAK_WIRE_SCREEN selection and audit.
	Name() string
	// Flag reports whether body (which SURVIVED the regex floor) is injection-shaped.
	// tool is the producing tool name (may be empty). why is a short human reason for
	// the audit trail. A screener that cannot decide returns (false, "").
	Flag(ctx context.Context, body []byte, tool string) (flagged bool, why string)
}

Screener is the extension point a concrete proposer implements. It is a LOSSY proposer bounded by a witness: it proposes that a result the regex floor admitted is injection-shaped, and the MMU enforces the recoverable quarantine. A Screener is NEVER trusted to be correct — a false positive is recoverable (operator Clear + PageIn restores the exact bytes) and a false negative degrades to the regex floor.

The reference heuristicScreener here is a deterministic, dependency-free stand-in used to prove the wiring. The real value is a small (1-3B) local model registered under "model" in a gated follow-on (the build needs the model package + weights + a measured latency number before it can default on) — see doc.go.

func Active

func Active() Screener

Active returns the Screener selected by FAK_WIRE_SCREEN, or nil when unset/unknown (the inert default). Resolution is lazy and once-only: it runs on the first call, by which time every leaf's init() has registered its screener, so selection is robust to init() ordering across files.

type Span added in v0.33.0

type Span struct {
	Start int    `json:"start"`
	End   int    `json:"end"`
	Kind  string `json:"kind"`
}

Span is one proposed redaction: a half-open byte range [Start,End) plus a short audit Kind ("credit_card", "us_ssn", "api_key", ...).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL