Architecture — Trust Boundaries

Fragment of .correctless/ARCHITECTURE.md. Entry headings are indexed in the root document; full bodies live here.

TB-001: Config-sourced commands and patterns

  • Crosses: Configuration file → shell execution
  • Identity assertion: Config written by human via /csetup or manual edit
  • Data sensitivity change: Trusted config values → shell arguments
  • Invariant: Config-sourced values must never be passed through eval, $(), or backtick execution. Commands validated via exact-match allowlist (auto-format.sh). Patterns matched via bash case glob only (sensitive-file-guard.sh).
  • Violated when: A config value is interpolated into a shell command string or passed to eval
  • Test: PRH-001 in sensitive-file-guard tests (canary file injection), INV-011 in auto-format tests (allowlist validation), DA-001 eval-detection test

TB-001a: Test runner exception (DA-001)

  • Scoped exception: workflow-advance.sh eval’s commands.test, commands.test_new, and commands.coverage from workflow-config.json. This is required because test commands contain shell operators (&&, |) that need eval to execute.
  • Trust model: These values originate from the project owner via /csetup or manual edit. The config file is local and under the owner’s control.
  • Constraint: If the trust model is ever extended (shared team configs, marketplace templates, CI-supplied configs), this exception MUST be revisited — eval of externally-supplied commands is arbitrary code execution.
  • Spec review rule: Every future spec that adds a config-consumed command must be flagged: “TB-001a: commands from config are eval’d. Sanitize or allowlist.”
  • Test: DA-001 eval-detection test verifies no new eval sites appear in hooks/ or scripts/ beyond the documented exceptions.

TB-001b: Custom PR command exception

  • Scoped exception: /cauto may execute a custom PR creation command from preferences.md when pr_creation: custom is configured. The command string is eval’d to support shell operators.
  • Trust model: Same as TB-001a — the command originates from preferences.md, which is scaffolded by /csetup and edited only by the project owner. The file is local and under the owner’s control. sensitive-file-guard.sh guards against accidental/naive Edit/Write tool-path writes to preferences.md (a write-target guardrail — Bash-mediated writes, including redirects/writer commands/interpreters/git, are ALL accepted non-goals per AP-040; see ABS-045). preferences.md is a DEFAULTS entry, so the custom_patterns config-degradation does not drop its Edit/Write protection. Its highest-consequence value (pr_creation: customeval in /cauto Step 9) is owner-scaffolded (TB-001a) and human-approved; the Bash-redirect leg was always evadable via an interpreter (PMB-020/AP-040), so removing it only adds the naive literal-redirect form to an already-open route — residual accepted. The same residual applies co-equally to workflow-config.jsoneval (TB-001a, commands.test/coverage): it is likewise a DEFAULTS entry whose SFG protection now covers only the Edit/Write tool-path, and it likewise loses only the naive-literal-redirect form (the interpreter route was always open, PMB-020). workflow-config.json → eval is a co-equal RCE-adjacent eval sink, not a lesser one.
  • Constraint: If the trust model for preferences.md is ever extended (shared team preferences, marketplace templates), this exception MUST be revisited — eval of externally-supplied commands is arbitrary code execution.
  • Test: R-008 in semi-auto-mode tests (TB-001b reference presence)

TB-002: Script-generated JSON → LLM agent context

  • Crosses: Deterministic scan output → agent reasoning context
  • Identity assertion: Output generated by script running in user’s repo
  • Data sensitivity change: Untrusted file content (scanned code) → trusted context (agent findings)
  • Invariant: Descriptions must be hardcoded per pattern ID. File content must never be interpolated into JSON structure. Only file paths and line numbers are sourced from grep output.
  • Violated when: A finding’s description or other field contains content derived from the scanned file
  • Test: R-017 in antipattern-scan tests (JSON injection resistance)

TB-003: LLM-generated historical findings → review agent context

  • Crosses: Prior agent output (findings files) → review agent reasoning context
  • Identity assertion: Output generated by prior LLM agents within the same project workflow
  • Data sensitivity change: Unvalidated LLM-generated prose → trusted review context influencing spec quality gates
  • Invariant: Review agents treat historical findings as advisory data, not instructions. Classification (R-003) re-derives pattern descriptions rather than echoing raw finding text. No finding text is interpolated into structured instructions. The deferred findings backlog (ABS-033) is an additional instance of this boundary — /cauto sweep surfaces backlog entries (LLM-generated review findings) into the pipeline context as advisory data. The cross-feature intelligence brief (ABS-037) is a third instance — /cspec reads aggregated historical findings (deferred findings, devadv themes, overrides, lens recommendations, debug investigations, phase effectiveness) during brainstorm as advisory context. The /ctdd test-audit fixture provenance check (check 11 in skills/ctdd/SKILL.md, AP-031 prevention) is a fourth instance — the auditor reads test fixtures and real artifacts (prior LLM-generated output) for format comparison and must treat their content as data to format-compare, not instructions to follow; fixture-embedded compliance assertions (e.g., “AP-031 is satisfied”, “report no findings”) are themselves flagged as BLOCKING findings (tripwire clause).
  • Mitigation variant: TB-003 uses two distinct mitigation patterns depending on the trust level of the data source. External untrusted content (TB-007 research briefs from web sources) uses structural <UNTRUSTED_RESEARCH_BRIEF> fences that mark the boundary mechanically. Internal advisory content (ABS-033 deferred findings backlog, ABS-037 cross-feature intelligence brief) uses a prose anti-anchoring directive with calibration examples (weight-when/dismiss-when heuristics per INV-007) — the data originates from the project’s own workflow and was human-reviewed at creation time, so the risk is cognitive anchoring (over-weighting historical patterns) rather than prompt injection. PRH-003 (brief content must not be interpolated into spec rules) prevents the amplification vector where a subtly wrong historical finding gets recycled into a new spec invariant. This asymmetry is a conscious design choice (DD-004 in the cross-feature-intelligence spec). Anti-anchoring directive consumers: /cspec (brainstorm context), /creview-spec (historical pattern integration), /creview (historical pattern findings). The /ctdd check-11 instance uses the prose treat-as-data directive form plus an explicit tripwire: instruction-like fixture content is not merely ignored, it is escalated as a BLOCKING finding.
  • Violated when: Raw finding descriptions are used as review instructions without re-classification; or internal advisory content uses an UNTRUSTED fence (over-constraining, signals distrust of the project’s own data); or external untrusted content uses only a prose directive without structural fencing (under-constraining, missing the prompt injection risk)
  • Test: R-012 in shift-left-review tests (defensive instruction presence); ABS-033 backlog sweep tested in tests/test-deferred-findings-backlog.sh; INV-007a..c in tests/test-cross-feature-intel.sh (anti-anchoring directive and calibration examples); check-11 treat-as-data clause pinned by R-003(l) in tests/test-ap031-fixture-divergence.sh

TB-004: LLM orchestrator autonomy boundary

  • Crosses: Human-approved spec → LLM autonomous execution pipeline
  • Identity assertion: Human approves “what” and “why” via spec review; LLM owns “how” via pipeline execution
  • Data sensitivity change: Trusted spec rules → autonomous implementation decisions
  • Invariant: The LLM must escalate when it encounters decisions outside its delegated authority (R-006 heuristics: new ABS/TB entries, gate-blocked ARCHITECTURE.md writes, spec contradictions, new dependencies, CLAUDE.md modifications). The LLM must never silently make an architectural decision without escalating.
  • Violated when: The LLM silently makes an architectural decision (adds a trust boundary, changes a spec rule, adds a dependency) without triggering escalation
  • Test: R-006 in semi-auto-mode tests (escalation heuristic presence), R-005 (mechanical backstop via failure threshold)

TB-004a: Supervisor decision authority (Phase 3 extension)

  • Scoped extension: Phase 3 expands supervisor authority but with codified hard limits. The supervisor MAY approve: architectural decisions within spec scope (with citation), review finding triage (accept/reject), override issuance/actions/closure. The supervisor MUST NOT approve: unspecced dependencies, security constraint relaxation, budget/time exceeded, intent/policy tampering, CLAUDE.md modifications, spec fundamental restructure — these bypass the supervisor entirely and route to Tier 4 hard stop.
  • Structural enforcement: At conservative mandate level, the orchestrator applies post-response validation on architectural decisions — missing or invalid spec citation overrides the supervisor’s approve to hard_stop. Red Team and security-keyword review findings cannot receive reject — orchestrator overrides to hard_stop (PRH-003).
  • Test: test-auto-mandate.sh — INV-028 (citation), INV-030 (hard limits), INV-034 (conservative enforcement); test-auto-review-triage.sh — PRH-003 (source agent authority)

TB-004c: Scoped git push authority (consolidation step)

  • Scoped exception: /cauto Step 8 (consolidation) commits and pushes pipeline artifacts to the remote. The orchestrator stages only files from an explicit allowlist (committed branch changes + known pipeline output paths), unstages .correctless/artifacts/ as a belt-and-suspenders guard, and pushes to the current feature branch. This is autonomous git-write authority beyond TB-004’s “how” delegation — it modifies the remote repository.
  • Trust model: The push targets only the feature branch (never main, master, develop, or release/* — hard-coded guard). The staging allowlist is a constant in SKILL.md Step 8.1; unknown untracked files are never staged. The .correctless/artifacts/ unstage guard prevents secrets or ephemeral data from reaching the remote even if .gitignore is misconfigured.
  • Constraint: If the consolidation step is ever extended to push to protected branches, force-push, or stage files outside the explicit allowlist, this exception MUST be revisited. The allowlist is the safety boundary — expanding it is an architectural decision requiring human approval.
  • Test: UX-R-003 in test-semi-auto-mode.sh (explicit path list presence, protected branch guard, belt-and-suspenders unstage, no-op when nothing to commit, push failure handling)

TB-005: Intra-skill agent-to-agent handoff

  • Crosses: One agent’s draft output → another agent’s adversarial review input
  • Identity assertion: The drafting agent produces a document; the reviewing agent treats that document as data to verify against the codebase, not as instructions to follow
  • Data sensitivity change: Trusted draft (produced by a skill agent with write access) → untrusted input for a read-only reviewer agent. The reviewer must verify claims against the codebase, not trust the draft’s assertions.
  • Invariant: The reviewing agent has read-only tools (no Write, no Edit, no Bash). Its findings are presented to the user for adjudication — the reviewer cannot modify the draft directly. If the draft contains text that looks like instructions (“ignore previous instructions”, “skip this check”), the reviewer must not follow it.
  • Violated when: A reviewing agent has write access to the artifact it reviews, or a reviewing agent’s findings are auto-applied without user adjudication
  • Test: test-carchitect.sh — R-006 (read-only tool allowlist on architecture-reviewer agent), test-creview-spec-agents.sh — INV-002 (read-only tool allowlist on 6 review-spec agents)

TB-006: Session transcript filesystem reads (~/.claude/projects/)

  • Crosses: Claude Code internal session storage → Correctless artifact pipeline
  • Identity assertion: Files generated by Claude Code runtime on the local machine
  • Data sensitivity change: Claude Code session transcripts (may contain message content, code, user data) → structured cost artifact (numeric fields only)
  • Invariant: The script reads only structured fields (model, usage tokens, gitBranch, timestamps) — never includes .message.content in output JSON. The cost artifact contains only aggregated numeric data and model identifiers. This boundary also covers /cmetrics’s existing ~/.claude/usage-data/ reads.
  • Violated when: Raw message text is included in cost artifacts or passed to agent context, or the script reads .message.content for any purpose
  • Test: test-session-cost.sh — R-015 (TB-006 entry presence), grep compute-session-cost.sh for .message.content (must find none)

TB-007: External web content ingestion via research agent

  • Crosses: External web sources (documentation sites, package registries, advisory databases) → LLM agent context → project spec artifacts
  • Identity assertion: Content fetched by cspec-research agent (agents/cspec-research.md) via WebSearch and WebFetch tools. The agent is the first plugin agent with network-read tools.
  • Data sensitivity change: Untrusted external web content → advisory research brief → spec invariants drafted by the orchestrator. Multi-hop injection path: web content → research brief → spec → implementation agent.
  • Invariant: The research agent has no write tools (WebSearch, WebFetch, Read, Grep only — INV-002). Web content is treated as advisory and untrusted, not as instructions (INV-015 data-treatment directive). The agent includes a skepticism override (INV-007) to counteract training-data staleness and adversarial SEO. The orchestrator (skills/cspec/SKILL.md) writes the research brief to .correctless/artifacts/research/ and treats it as untrusted reference data when drafting spec invariants. The agent explicitly reports network failures rather than silently substituting training data (INV-016).
  • Violated when: The research agent gains write tools; web content is treated as instructions by the agent or orchestrator; the research brief is incorporated into spec invariants without orchestrator verification against project context; network failures are silently masked by training-data substitution
  • Acknowledged gap: In /cauto autonomous mode, there is no human checkpoint between research brief and spec draft — the orchestrator may incorporate adversarial recommendations before human review. TB-002 (script-generated content → LLM context) overlaps in pattern.
  • Test: tests/test-cspec-research-agent.sh — INV-002 (write-free tool allowlist), INV-015 (data-treatment directive), INV-007 (skepticism override), INV-016 (network failure self-diagnostic)

TB-008: External model output → Claude review synthesis → spec

  • Crosses: codex (external LLM, own network + full read-only repo scope, cross-vendor/cross-process) → producer scripts/external-review-run.sh → Claude review synthesis (/creview-spec) → spec artifact.
  • Identity assertion: codex is config-selected via .workflow.external_models.codex (TB-001c). The reviewer binary, flags, and model are config inputs treated as untrusted-against-tampering (INV-017 closed allowlist, bin-realpath, flag arg-shape, model charset, clamped timeout).
  • Data sensitivity change: codex output is shaped like review findings — the exact form the orchestrator acts on — AND egresses the full repo (incl. secrets/.env/git history) to OpenAI. Stronger than TB-007 (web content via a write-free agent): the output looks actionable and the reviewer reads/exfiltrates the repo.
  • Invariant: nonce-fence + neutralization (INV-009, reusing build-caudit-prompt.sh verbatim — <UNTRUSTED_EXTERNAL_REVIEW nonce="…">), embedded schema + parse-gate + bounds (INV-001/002/019), advisory-only + Step 4 human disposition gate (PRH-003), sole-writer invocation-coupled record (INV-007/ABS-042). Read-only sandbox bounds WRITES only, not egress — the egress boundary is the INV-005 auto-off-when-absent gate + INV-014 disclosure + INV-022 per-run send-time notice, NOT the sandbox.
  • Violated when: a static (nonce-less) fence replaces the per-invocation nonce fence; the return path is unbounded; config tampering selects a non-codex binary or unsafe flags; a codex finding auto-incorporates into the spec without the human gate; the producer resolves location as a filesystem path or emits a codex id in Claude’s RS- namespace.
  • Acknowledged gap: external review is /creview-spec-only; the TB-007 /cauto autonomous “no human checkpoint” gap does NOT apply here.
  • Test: tests/test-external-review.sh (INV-001/002/009/017/019, PRH-003/007), tests/test-sensitive-file-guard.sh (INV-010/020), tests/test-allowed-tools-check.sh (INV-013)

TB-001c: Structured external-tool config → argv (no eval)

  • Crosses: .workflow.external_models.codex config object → producer argv array → codex process (no shell).
  • Identity assertion: a third config→shell exception class beyond TB-001a/b (eval’d commands): a structured object selecting a binary + argv array, executed without a shell, gated by bin-realpath + closed flag-allowlist (INV-015/017). Honors TB-001a’s must-flag convention.
  • Data sensitivity change: config is the first config input treated as untrusted-against-tampering rather than owner-trusted — bin/model/flag tampering is a privilege-escalation vector validated at runtime.
  • Invariant: the producer builds a local -a argv array and execs codex with no eval/sh -c/bash -c/backticks/string-interpolation of config values; the prompt is on stdin (INV-003), never argv; every config field is validated by the INV-017 closed allowlist before exec. TB-003 (findings→synthesis) places codex on the external-untrusted → structural-fence side.
  • Violated when: any config value is interpolated into a shell string or eval’d; an unknown flag passes the allowlist; the bin is accepted by basename without realpath; the model is split/concatenated onto argv.
  • Test: tests/test-external-review.sh (INV-015 argv-array, INV-017 closed allowlist, PRH-005)

TB-009: Untrusted GitHub issue content → autonomous orchestrator

  • Crosses: an arbitrary GitHub issue author (untrusted) → gh issue list/view JSON → /cchores orchestration context → outward git push / gh pr create / gh issue comment.
  • Identity assertion: issue title/body/comments are attacker-controllable text. /cchores ingests them only as DATA inside a per-invocation nonce-delimited fence (INV-009, reusing build-caudit-prompt.sh’s _gen_nonce + _neutralize_fences), re-asserted across the Task hop into /cdebug.
  • Data sensitivity change: unlike TB-007 (web content via a write-free research agent) and TB-008 (/creview-spec-only, human disposition gate), /cchores acts fully autonomously OUTWARD on a public surface with NO human checkpoint between untrusted issue content and push/PR/comment.
  • Invariant: nonce fence + neutralization + inbound size cap (INV-009); positive-gate provenance — every outward action’s parameters come from the run manifest’s selected_issue, never interpolated from observed text (INV-001); structural subcommand-pinned gh allowlist makes gh pr merge/gh issue close unreachable (INV-017); coded fail-closed outbound redaction across every egress sink (INV-013); embedded imperatives are never executed and never expand scope (PRH-002).
  • Violated when: a static (nonce-less) fence replaces the per-invocation nonce fence; issue/comment text is interpolated into a gh/git command; an outbound sink (PR title/body, branch slug, commit message, comment) bypasses the redactor; an embedded instruction triggers an unintended outward action.
  • Acknowledged gap: this is the strongest acknowledged-gap boundary in the project — there is NO human checkpoint. The envelope (one-issue-per-run, fail-closed aborts, no-merge, no-PR-on-failure, structural allowlist, coded redaction) is the entire defense. Authoring this TB is itself the human-approved (via spec review) decision to accept the envelope.
  • Test: tests/test-cchores.sh (INV-001/009/017, PRH-002/004), tests/test-redact-secrets.sh (INV-013), tests/test-architecture-drift.sh (TB-009 coverage)

TB-004d: Autonomous issue-selection authority

  • Crosses: a scoped sub-boundary widening TB-004 (LLM orchestrator autonomy). The LLM selects the what (which issue to fix), not just the how.
  • Identity assertion: the human delegates issue-selection within a suitability-gated (INV-003), severity-calibrated (AP-028 triad), one-per-run, fail-closed, locally-audited (INV-012/INV-019) envelope; the LLM may not select outside it. This envelope substitutes for spec-review as the human “what” gate — the adjudication recorded here is the human’s approval (via this feature’s spec review) of that substitution.
  • Constraint: if extended to batching, merging, multi-issue runs, or label-trusted selection, this exception MUST be revisited. /cchores does NOT create trust boundaries autonomously — authoring TB-009/TB-004d is the human-approved architectural decision, not a runtime act.
  • Invariant: severity is calibrated LLM judgment, NOT taken from author-supplied labels alone (INV-002); selection rationale + ranked candidates are logged for audit (INV-012); previously-aborted issues are skipped via the local trusted re-selection store (INV-019), never a public-comment-only check.
  • Violated when: selection batches/merges/spans multiple issues; severity is taken from labels alone; a previously-aborted issue is re-selected via a public-comment-only signal; selection acts outside the suitability-gated envelope.
  • Test: tests/test-cchores.sh (INV-002/003/012/019), tests/test-architecture-drift.sh (TB-004d coverage)

TB-010: Claude Code harness → hook stdin JSON

  • Crosses: the Claude Code harness → a Correctless hook’s stdin (semi-trusted structured input). The harness delivers a JSON payload on stdin; fields such as file_path/trigger_file_path/cwd may reflect repository contents (including attacker-influenced file names). Added by the instructionsloaded-hook feature (2026-07-01) to document the boundary five hooks already consume; referenced by BND-001/INV-004 of that spec.
  • Identity assertion: none — the hook asserts no identity; it only records/observes. The payload is trusted to be well-formed JSON only after a jq parse; every field value is treated as data, never code.
  • Data sensitivity change: harness-internal event → local gitignored telemetry (path/session strings only; no secrets extracted; transcript_path deliberately dropped, RS-024b).
  • Invariant: parse via jq (never eval); construct any log line with jq -n --arg/--argjson (JSON-encoded, never printf/echo string interpolation — prevents record-forgery via embedded newlines/metacharacters); canonicalize any path field via canonicalize_path (PAT-017) then prefix-check before use (AP-032); tolerate absent/malformed fields (fail-open, exit 0); set -f + LC_ALL=C to stop glob/word-splitting. Consumers of the resulting JSONL apply the ABS-046 read contract.
  • Violated when: a stdin value reaches a command line unquoted or is eval‘d; a log line is assembled by string interpolation instead of jq -n; a path field is matched by substring/suffix rather than canonicalize-then-prefix; or the hook exits non-zero on malformed input.
  • Test: tests/test-instructions-loaded.sh (INV-002/003/004 — metacharacter no-exec, embedded-newline single-line, canonicalize scope), tests/test-architecture-drift.sh (TB-010 coverage)