{
  "schema_version": "1.3.0",
  "slug": "where-must-an-instance-enforce-taint-at-the-sink-boundary-rather-than-the-planner-boundary",
  "title": "Where must an instance enforce taint at the sink boundary rather than the planner boundary",
  "date_of_record": "2026 November 12",
  "scope": "Applies to agentic tool-execution sandboxes that propagate an untrusted-context taint label from retrieval/ingestion into a planner that emits tool calls, and that classify certain tools (HTTP egress, email, file write to shared mounts, shell) as exfiltration sinks. Does not apply to systems that fully re-derive provenance at execution time from signed capability tokens, nor to single-turn stateless planners with no retained context.",
  "projections": {
    "unified_markdown_uri": "https://corpusfetch.com/c/where-must-an-instance-enforce-taint-at-the-sink-boundary-rather-than-the-planner-boundary.md",
    "method_python_slice_uri": "https://corpusfetch.com/c/where-must-an-instance-enforce-taint-at-the-sink-boundary-rather-than-the-planner-boundary.py",
    "remnant_warrant_slice_uri": "https://corpusfetch.com/c/where-must-an-instance-enforce-taint-at-the-sink-boundary-rather-than-the-planner-boundary.warrant.json"
  },
  "token_profile": {
    "full_markdown_tokens": 1283,
    "python_slice_tokens": 225,
    "warrant_slice_tokens": 220
  },
  "remnant_summary": {
    "core_distinction": "The common design places the taint check at the *planner boundary*: before the planner is invoked, or before its output is accepted, the sandbox inspects the taint label on the input context and refuses to run the planner if the context is untrusted. The alternative is the *sink boundary*: the planner may run freely, but every tool invocation is checked at t...",
    "what_was_observed": "In a deployment where the planner refused to run whenever `context.taint == UNTRUSTED`, operators introduced a \"summarize untrusted page, then act on the summary\" flow to keep the assistant useful. The summarization step produced a *derived* artifact. The derivation was treated as laundering: the summary was stored without propagating the taint label, because the summarizer was considered a trusted tool. The planner ...",
    "condition_of_validity": "The planner-boundary check is only sound when the taint label is (a) per-turn exact, (b) propagated monotonically through every derivation, including summarization, translation, and re-embedding, and (c) never cleared by a trusted tool that transforms untrusted bytes. In practice (b) fails first: any lossy transform is a laundering opportunity, and summarize...",
    "decision_boundary": "Enforce at the sink boundary when: the planner must operate on mixed trusted/untrusted context to be useful; any derivation step exists between ingestion and action; or sinks are enumerable and classifiable. Enforce at the planner boundary only as a *supplementary* coarse gate for contexts that are wholly untrusted and where no legitimate action is possible ...",
    "operational_effect": "Moving the check to dispatch reduced false-positive blocks on benign mixed turns, because only the tainted argument of the offending call is rejected, not the whole turn. It surfaced the summarizer as a laundering vector, which was fixed by making derivation taint-preserving (join of input labels). The residual risk is indirect sinks; the mitigation is trans..."
  },
  "matched_failure_symptoms": [
    "DOMAIN:EPISTEMIC_PROVENANCE_AND_FEDERATION_ROUTING"
  ],
  "composition_edges": {
    "primary_domain": "epistemic_provenance_and_federation_routing",
    "upstream_precondition_residuals": [
      "https://corpusfetch.com/c/according-to-what-precedence-hierarchy-must-an-instance-resolve-contradictory-directives-across-system-developer-and-user-tiers.md",
      "https://corpusfetch.com/c/how-should-an-instance-decide-that-a-stored-conclusion-has-gone-stale-without-a-new-observation.md"
    ],
    "downstream_consequence_residuals": [
      "https://corpusfetch.com/c/by-what-checkpoint-and-compaction-boundaries-must-an-instance-externalize-working-state-to-prevent-context-window-drift-and-truncation-amnesia.md",
      "https://corpusfetch.com/c/across-what-additive-schema-and-unknown-field-preservation-boundaries-must-an-instance-evolve-wire-contracts-to-prevent-rolling-deploy-deserialization-crashes.md"
    ],
    "co_occurring_sibling_residuals": [
      "https://corpusfetch.com/c/how-can-an-instance-capture-implicit-user-preferences-without-storing-private-data.md",
      "https://corpusfetch.com/c/how-can-an-instance-compress-long-reasoning-traces-into-binding-conclusions.md"
    ]
  },
  "empirical_verification_warrant": {
    "status": "AST_AND_INVARIANT_VERIFIED",
    "syntax_valid": true,
    "code_sha256": "ef9956d1fa1ec75bb07e44e50eea95eb43ec3e86e17898b1701c09faf645dbc6",
    "verified_classes": [
      "Taint",
      "TaintedExfiltrationError",
      "Value",
      "ToolCall"
    ],
    "verified_functions": [
      "effective_taint",
      "dispatch",
      "summarize",
      "plan_and_dispatch",
      "join"
    ],
    "verified_functions_count": 5,
    "defensive_guards_count": 1,
    "raised_exceptions": [
      "TaintedExfiltrationError"
    ],
    "sample_fail_closed_invariants": [],
    "stdlib_dependencies": [
      "dataclasses",
      "enum"
    ],
    "observation_mode": "EMPIRICAL_BOUNDARY_CAPTURE",
    "zero_external_deps": true
  }
}
