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
caseglob 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.sheval’scommands.test,commands.test_new, andcommands.coveragefrom 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
/csetupor 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:
/cautomay execute a custom PR creation command frompreferences.mdwhenpr_creation: customis 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/csetupand edited only by the project owner. The file is local and under the owner’s control.sensitive-file-guard.shguards against accidental/naive Edit/Write tool-path writes topreferences.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.mdis a DEFAULTS entry, so thecustom_patternsconfig-degradation does not drop its Edit/Write protection. Its highest-consequence value (pr_creation: custom→evalin/cautoStep 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 toworkflow-config.json→eval(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.mdis 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 —
/cautosweep 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 —/cspecreads aggregated historical findings (deferred findings, devadv themes, overrides, lens recommendations, debug investigations, phase effectiveness) during brainstorm as advisory context. The/ctddtest-audit fixture provenance check (check 11 inskills/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/ctddcheck-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 intests/test-cross-feature-intel.sh(anti-anchoring directive and calibration examples); check-11 treat-as-data clause pinned by R-003(l) intests/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
approvetohard_stop. Red Team and security-keyword review findings cannot receivereject— orchestrator overrides tohard_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:
/cautoStep 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, orrelease/*— 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.gitignoreis 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.contentin 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.contentfor 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
/cautoautonomous 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.shverbatim —<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
locationas a filesystem path or emits a codex id in Claude’sRS-namespace. - Acknowledged gap: external review is
/creview-spec-only; the TB-007/cautoautonomous “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.codexconfig 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 -aargv array and execs codex with noeval/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/viewJSON →/cchoresorchestration context → outwardgit push/gh pr create/gh issue comment. - Identity assertion: issue title/body/comments are attacker-controllable text.
/cchoresingests them only as DATA inside a per-invocation nonce-delimited fence (INV-009, reusingbuild-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),/cchoresacts 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-pinnedghallowlist makesgh pr merge/gh issue closeunreachable (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/gitcommand; 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.
/cchoresdoes 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/cwdmay 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
jqparse; 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_pathdeliberately dropped, RS-024b). - Invariant: parse via
jq(nevereval); construct any log line withjq -n --arg/--argjson(JSON-encoded, neverprintf/echostring interpolation — prevents record-forgery via embedded newlines/metacharacters); canonicalize any path field viacanonicalize_path(PAT-017) then prefix-check before use (AP-032); tolerate absent/malformed fields (fail-open, exit 0);set -f+LC_ALL=Cto 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 ofjq -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)