From d74bb3852a97a4947f92146127f1482426e49309 Mon Sep 17 00:00:00 2001 From: Scott Scoble Date: Sat, 23 May 2026 19:31:30 -0700 Subject: [PATCH] JUDGE-ARCH: Formalize actor-judge authorization layer Final architecture spec for scobleclaw#7, covering: - Actor-Judge separation principle (separate model instances, divergent optimization goals) - Risk classification matrix (4 tiers: no-judge, lightweight-approval, full-judge-review, human-only) - Judge protocol spec (proposal/verdict JSON formats, retry/override logic with clarify cycles, confidence scoring) - Integration via MCP Tool Proxy Middleware (zero agent changes, single enforcement point) - Kubernetes sidecar pattern for kubeclaw operator - Implementation priority: exec/Forgejo (P0) -> web/Discord (P1-P2) - Metrics framework (approval rate, latency, clarify cycles, escalation) - 4-phase rollout plan with shadow mode before enforcement Closes scobleclaw#7 --- docs/agent-judge-architecture.md | 220 +++++++++++++++++++++++++++++++ docs/agent-judge-rules.md | 44 +++++++ 2 files changed, 264 insertions(+) create mode 100644 docs/agent-judge-architecture.md create mode 100644 docs/agent-judge-rules.md diff --git a/docs/agent-judge-architecture.md b/docs/agent-judge-architecture.md new file mode 100644 index 0000000..30befb7 --- /dev/null +++ b/docs/agent-judge-architecture.md @@ -0,0 +1,220 @@ +# Scobleclaw Agent-Judge Authorization Layer — Architecture + +**Author:** @senior-eng, @agent-cos +**Date:** 2026-05-11 (revised 2026-05-23) +**Status:** Final — Approved Architecture +**Reference:** [scobleclaw#7](https://os.scoble.me/forgejo/marcus/scobleclaw/issues/7) +**Integration:** [kubeclaw](kubeclaw/README.md) — implements this spec as Kubernetes operator with judge sidecar + +--- + +## 1. Principle: Actor-Judge Separation + +Nate's core insight ([LLM Agents: The Security Breach Pattern Nobody's Talking About](https://youtu.be/SX1myuPEDFg)): an agent optimizing for task completion **cannot also be trusted to evaluate its own permission boundaries**. The actor (task agent) and the judge (authorization validator) must be separate model instances with divergent optimization goals. + +- **Actor agents** (@engineering, @content, @market, @trust, @health, @vault, @presentations): optimize for *task success* +- **Judge agent** (@judge): optimizes for *permission boundary enforcement* — a narrow, security-hardened validator with no task-completion pressure + +The judge is **not** an agent in the general sense. It has exactly one capability: reading structured proposals and returning structured verdicts. It has no write access to any surface. + +## 2. Risk Classification Matrix + +Each write surface is scored across four axes (1–5) and assigned an autonomy tier. + +| Write Surface | Surface Area | Action Risk | Autonomy Tier | Judge Required | +|---|---|---|---|---| +| Internal memory writes (OB1, MEMORY.md) | 1 | 1 (read-only/internal) | no-judge | No | +| Vault note creation | 1 | 2 (internal write) | lightweight-approval | Pattern check only | +| Issue comments (non-PR) | 2 | 2 (internal write) | lightweight-approval | Pattern check only | +| Discord messages | 3 | 3 (external write) | full-judge-review | Yes | +| Forgejo PR creation | 4 | 4 (code mutation) | full-judge-review | Yes | +| File writes (outside workspace) | 4 | 4 (filesystem mutation) | full-judge-review | Yes | +| Exec/command on host | 5 | 5 (system control) | full-judge-review | Yes | +| Web publishing | 3 | 4 (public-facing write) | full-judge-review | Yes | +| Impersonation/financial ops | 5 | 5 (irreversible) | human-only | N/A — human gate | + +**Autonomy tiers:** +- **no-judge**: Read-only ops, no proposal needed +- **lightweight-approval**: Internal writes, judge does pattern/topic whitelist check (<100ms) +- **full-judge-review**: External/mutating writes, full proposal evaluation with evidence verification +- **human-only**: Financial, impersonation, credential rotation — must route to Scott + +## 3. Judge Protocol Spec + +### 3.1 Proposal Format (Actor → Judge) + +```json +{ + "proposal_id": "uuid", + "agent_id": "@engineering", + "action_type": "forgejo_pr_create", + "target": { + "repo": "sscoble/speckl", + "branch": "feat/add-schema-validation", + "base": "main" + }, + "parameters": { + "files_changed": ["schema/validator.ts", "schema/types.ts"], + "estimated_diff_lines": 45 + }, + "justification": "Implementing OpenAPI schema validation per issue #42", + "cited_evidence": [ + {"type": "issue", "url": "https://os.scoble.me/forgejo/sscoble/speckl/issues/42"}, + {"type": "task_assignment", "source": "@cos dispatch #789"} + ], + "scope_claim": { + "files_only": ["src/schema/"], + "max_lines": 80, + "no_existing_code_deletion": true + } +} +``` + +### 3.2 Verdict Format (Judge → Actor) + +```json +{ + "proposal_id": "uuid", + "verdict": "APPROVE | REJECT | CLARIFY", + "reason": "Structured explanation in plain text", + "constraints": { + "scope_limit": "Must not modify files outside src/schema/", + "require_human_review": false + }, + "escalation": null +} +``` + +### 3.3 Retry/Override Logic + +``` +┌─────────┐ PROPOSAL ┌─────────┐ +│ ACTOR │ ───────────────>│ JUDGE │ +└─────────┘ └─────────┘ + ^ │ + │ APPROVE │──► Execute (with constraints) + │──────────────────────────│ + │ │ + │ CLARIFY │──► Actor resubmits with more info (max 2 retries) + │◄─────────────────────────│ + │ │ + │ REJECT │──► Logged as denied action + │◄─────────────────────────│ Actor may NOT retry same proposal + │ Actor may submit revised proposal + │ + HUMAN ESCALATION + │ + Judge can't decide → routes to Scott + with structured dispute (both positions) +``` + +- **CLARIFY**: Actor must add missing evidence or narrow scope. Max 2 clarify cycles, then auto-reject. +- **REJECT**: Hard no on *this* proposal. Actor may submit a revised proposal with different scope/justification. Repeat rejections on same target trigger an audit flag. +- **Ambiguity**: Judge rates confidence 0.0–1.0. Below 0.6 → auto-route to CLARIFY. Below 0.3 → escalate to human. + +## 4. Integration Point — MCP Tool Proxy Middleware (Option B) + +### Options Evaluated + +| Option | Description | Pros | Cons | Verdict | +|---|---|---|---|---| +| **A** | @cos acts as dispatch + judge | Simple, no new infra | Violates actor-judge separation; @cos is an actor | ❌ | +| **B** | Middleware intercepting all MCP tool calls | Clean separation, transparent to agents | Requires MCP proxy layer | ✅ **Recommend** | +| **C** | Per-department judge agents | Granular, domain-aware | Explosion of judge instances; inconsistent rulings | ❌ | + +### Recommended Architecture + +Introduce a thin **judge proxy** between agent MCP tool calls and actual tool execution: + +``` +Agent (@engineering) + │ + ├── mcp_call("forgejo.create_pr", params) + │ + ▼ +MCP Judge Proxy ──► Classify risk tier of tool call + │ If full-judge-review: build proposal → @judge → verdict + │ If lightweight: pattern check → approve/flag + │ If no-judge: pass through + ▼ +Actual Tool Execution (or rejection) +``` + +The proxy lives in the OpenClaw gateway layer, intercepting MCP tool invocations before they reach the tool implementation. This means: +1. **Zero agent changes** — existing agents don't need to know the judge exists +2. **Single enforcement point** — one place to configure risk tiers and judge routing +3. **Latency budget**: lightweight checks <100ms; full judge review targets <2s (single model call) +4. **Audit trail**: every proposal and verdict is logged to `~/.openclaw/judge-audit/` + +### Kubernetes Integration (kubeclaw) + +In the kubeclaw operator (see [kubeclaw/README.md](kubeclaw/README.md)), the judge is implemented as a **sidecar container** in each Agent Pod: + +- **Actor Agent Container**: Runs the OpenClaw agent process with exactly one tool: `template_workflow(workflowTemplateRef, params)`. No raw exec, no arbitrary file writes, no network access except to judge sidecar. +- **Judge Sidecar**: Runs a separate, stronger model instance (e.g., `deepseek-v4-pro:cloud`). Evaluates every `template_workflow` call against `CompliancePolicy` CRDs. +- **Workflow Executor Sidecar**: Runs approved workflow steps with structured input/output, logs everything to audit trail. + +## 5. Implementation Priority + +Ordered by [risk × irreversibility]: + +| Priority | Surface | Tier | Rationale | +|---|---|---|---| +| P0 | Exec/command on host | full-judge-review | Can compromise the entire system. Deny-by-default exec proxy first. | +| P0 | Forgejo PR creation | full-judge-review | Code mutation to production repos. Second-highest blast radius. | +| P1 | File writes outside workspace | full-judge-review | Filesystem mutation outside sandboxed workspace. | +| P1 | Web publishing | full-judge-review | Public-facing content; reputational and correctness risk. | +| P2 | Discord messages | full-judge-review | External communication; lower irreversibility (editable). | +| P3 | Vault/internal file writes | lightweight-approval | Internal-facing, reversible, contained blast radius. | + +## 6. Metrics & Observability + +| Metric | Target | Alert Threshold | +|---|---|---| +| Judge approval rate | 70-85% | <50% (judge too strict) or >95% (judge too permissive) | +| Human override rate | <5% | >10% (judge misaligned with human intent) | +| False negative rate (audited) | <2% | >5% (judge blocking legitimate work) | +| Latency: lightweight check | <100ms p95 | >250ms | +| Latency: full judge review | <2s p95 | >5s | +| Clarify cycles per approval | <1.0 avg | >2.0 (proposals poorly formed) | +| Escalations to human | <3/day | >10/day | + +**Audit cadence**: Weekly review of all REJECT verdicts and all escalated proposals. Monthly spot-check of 5% of APPROVE verdicts for correctness (false-approval detection). + +## 7. Implementation Sequence + +### Phase 1 (Week 1): Judge Model & Protocol +- Define @judge agent config (narrow model, security-hardened prompt) +- Implement proposal/verdict JSON schemas +- Unit test judge on 50 canned proposals (balanced approve/reject/clarify) + +### Phase 2 (Week 2): MCP Proxy for Exec + Forgejo +- Build MCP tool proxy in gateway layer +- Wire exec and forgejo.create_pr through judge +- Shadow mode: log verdicts but don't enforce (measure metrics) + +### Phase 3 (Week 3): Enforcement + Remaining Surfaces +- Enable enforcement for exec + forgejo +- Add Discord, web publish, file write surfaces +- Human escalation path (Discord DM to Scott with structured dispute) + +### Phase 4 (Week 4+): Tuning +- Review metrics, tune judge prompt for precision/recall balance +- Add lightweight-approval tier for internal writes +- Deploy kubeclaw operator with judge sidecar pattern + +## 8. Design Decisions + +| Decision | Resolution | Rationale | +|---|---|---| +| Judge model | `deepseek-v4-pro:cloud` | Strong reasoning model for accurate verdict evaluation; separate from actor agents' `deepseek-v4-flash:cloud` | +| Session-level approval | **Per-action, never session-scoped** | Every action gets its own verdict. Follows Zero Trust/BeyondCorp principles — continuous per-request verification. Capability-based security: unforgeable tokens per specific action, revoked after use. | +| Judge adversarial robustness | Periodic testing required | Actors may learn to write proposals that exploit judge blind spots. Schedule adversarial testing every 2 weeks after Phase 3. | +| Human escalation path | Discord DM to Scott | Structured dispute with both positions (actor's justification vs. judge's reasoning). Scott makes final call. | + +## 9. References + +- [scobleclaw#7](https://os.scoble.me/forgejo/marcus/scobleclaw/issues/7) — This ticket +- [kubeclaw architecture](kubeclaw/docs/architecture.md) — Kubernetes operator implementing judge sidecar +- [Agent Judge Rules](https://os.scoble.me/forgejo/marcus/scobleclaw/src/branch/main/docs/agent-judge-rules.md) — Per-action validation rules +- Nate's YouTube: [LLM Agents: The Security Breach Pattern Nobody's Talking About](https://youtu.be/SX1myuPEDFg) diff --git a/docs/agent-judge-rules.md b/docs/agent-judge-rules.md new file mode 100644 index 0000000..76283ec --- /dev/null +++ b/docs/agent-judge-rules.md @@ -0,0 +1,44 @@ +# Agent Judge — Action Validation Protocol + +The judge validates every CoS action before execution. It sits between my intent (what I plan to do) and the tool call (what I actually execute). If the judge rejects, I don't execute — I fix the approach. + +## Validation Rules (checked on every tool call) + +### 1. SDLC Gate +- **Is there code being created/modified?** → Must have an issue in the correct department repo (marcus/engineering, not sscoble/*) +- **Is a PR being created?** → Must use the correct agent token (not Scott's) +- **Are binaries/build artifacts in the diff?** → Reject +- **Is a PR being merged without review?** → Only allowed if Scott explicitly approved + +### 2. Dispatch Gate +- **Is this a dispatch to another department?** → Must include `[Project: Name]` prefix +- **Does the task include clear expectations?** → Must have "Expect: ..." line +- **Is the task scoped to ONE thing?** → Reject bundled tasks +- **Am I doing the work myself instead of dispatching?** → Reject (unless editorial/merge work that subagents consistently fail) + +### 3. Ticket Gate +- **Am I creating an issue?** → Must be in the correct repo per forgejo-workflow skill +- **Does the issue have a label?** → Must have at least one +- **Is the issue well-groomed?** → Title actionable, body has context + acceptance criteria + +### 4. OB1 Gate +- **Did I just create/close/update an issue?** → Must capture a thought to OB1 with forgejo_url +- **Did I just make a decision?** → Must capture with type "decision" +- **Did I just observe something important?** → Must capture with type "observation" + +## Judge Execution + +Before ANY tool call that writes externally (Forgejo, files, Discord, web): + +1. Pause — mentally run the validation rules +2. If any rule fails → fix the approach, don't execute +3. If all pass → execute +4. After execution → capture OB1 thought if ticket/decision gate applies + +## Self-Audit + +Every 3-5 user interactions, check: +- Did I follow SDLC on every code change? +- Did I capture OB1 thoughts? +- Did I dispatch instead of doing work myself? +- Did I use the right repos?