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
This commit is contained in:
parent
a9e0031721
commit
d74bb3852a
2 changed files with 264 additions and 0 deletions
220
docs/agent-judge-architecture.md
Normal file
220
docs/agent-judge-architecture.md
Normal file
|
|
@ -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)
|
||||
44
docs/agent-judge-rules.md
Normal file
44
docs/agent-judge-rules.md
Normal file
|
|
@ -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?
|
||||
Loading…
Add table
Add a link
Reference in a new issue