feat(orchestrator): caveman-style output contracts for critic/adversary/governor/cartographer#199
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ry/governor/cartographer Closes #174. Adds cmd/sin-code/internal/orchestrator/output_contract.go: * Finding struct + 5 closed tags (delete, simplify, rebuild, risk, verify) parallel to JuliusBrussee/ponytail's ponytail-tag convention. * byte-stable Render() — same Finding struct produces identical bytes every run (prerequisite for issue #168 ledger hashing). * strict ParseFinding/ParseFindings (em-dash U+2014 separator, no prose, no hedging). * VerifyFindings rejects empty Path, unknown Tag, hedging phrases (closed set of 12, case-folded: 'you might', 'perhaps', 'could consider', 'maybe', 'i think', 'i would', 'sort of', 'kind of', 'tends to', 'should probably', 'i'd suggest', 'we should'), >240-char Hint, and trailing punctuation. Wired into the four sub-agents: * CriticResult.Findings — parsed from the last attempt's prose; CriticResult.ParseErrors carries per-line rejection trace (mirrors verify.fail flow). * AdversaryResult.Findings — derived from each Attack (landed -> risk, cleared -> verify). * GovernorResult.Findings — one risk Finding per Escalation, anchored at task://<ID>. * Cartographer.Findings(k) — top-k PageRank-sorted symbols as verify Findings (opt-in: k <= 0 yields empty). Byte-stable golden tests in output_contract_test.go (Find + Render + Verify) and output_contract_integration_test.go (one fixture per agent). Existing TestCritic*, TestAdversary*, TestGovernor*, and TestCartographer* unchanged and green. Verified: gofmt -l cmd/sin-code/internal/orchestrator/ (output_contract*.go clean; pre-existing stcov_test.go drift is a coverage-tag-only file, not my change) go build ./... (clean) go vet ./cmd/sin-code/... (clean) go test -race -count=1 ./cmd/sin-code/internal/orchestrator/ (PASS) golangci-lint run ./cmd/sin-code/internal/orchestrator/ (0 issues) govulncheck ./cmd/sin-code/internal/orchestrator/... (no vulns) gosec ./cmd/sin-code/internal/orchestrator/ (SARIF clean) python3 scripts/validate_skill.py --all-bundled --strict (34/34 OK)
|
Deployment failed with the following error: Learn More: https://vercel.com/cristianoronalodbau-9053s-projects?upgradeToPro=build-rate-limit |
|
Deployment failed with the following error: Learn More: https://vercel.com/ronaldokrause-9559s-projects?upgradeToPro=build-rate-limit |
|
Deployment failed with the following error: Learn More: https://vercel.com/mariobatrhs-9606s-projects?upgradeToPro=build-rate-limit |
|
Deployment failed with the following error: Learn More: https://vercel.com/aragonheld-7756s-projects?upgradeToPro=build-rate-limit |
|
Deployment failed with the following error: Learn More: https://vercel.com/einskarst-2238s-projects?upgradeToPro=build-rate-limit |
|
Deployment failed with the following error: Learn More: https://vercel.com/spriterfrau-5830s-projects?upgradeToPro=build-rate-limit |
|
Deployment failed with the following error: Learn More: https://vercel.com/manheiler-8784s-projects?upgradeToPro=build-rate-limit |
🏆 CEO Audit — A+ (100.0/100)
📥 Download full report (Markdown)
|
🏆 CEO Audit — A+ (100.0/100)
📥 Download full report (Markdown) Run ID:
|
What ships:
- cmd/sin-code/internal/sandbox/seatbelt.go (new, 171 LoC):
- SeatbeltPolicy typed field set (ReadWrite / ReadOnly /
Deny / AllowNetwork) so the policy struct is introspectable
and the byte-output is byte-stable for golden testing.
- DefaultSeatbeltPolicy(workdir, tmp, allowNet) returns the
project-wide convention: RW=workdir+tmp; RO=/usr/lib,
/usr/share, /System/Library; deny=~/.ssh, ~/.aws,
~/.gnupg, ~/.netrc. Network is opt-in via flag.
- Policy.Profile() returns the SBPL string. Construction is
deterministic: header always emitted first, deny paths
sorted lexicographically, RO/RW paths sorted, read rules
emitted before write rules per path.
- SeatbeltBackend.Exec(ctx, *exec.Cmd, workdir) wraps any
subprocess invocation with `sandbox-exec -p <profile>`.
Exit code 71 or stderr substring "deny" surfaces as the
typed ErrSeatbeltDenied so callers can retry or abort.
Stderr is teed to both the caller's writer and a local
buffer for the deny-detection heuristic.
- sandbox-exec PATH absence (Linux runners, CI) returns a
clear "sandbox-exec not on PATH" wrapper so callers can
fall back to Landlock or bubblewrap.
- cmd/sin-code/internal/sandbox/seatbelt_test.go (new, 133 LoC):
- 6 race-clean tests: byte-stable profile (golden constant
pinned), network allow toggling, sorted-deny emission,
binary-lookup behaviour (skips the actual exec call),
sentinel error typing, deterministic-for-equal-input.
- Total runtime ~1s under `go test -race -count=1`.
- cmd/sin-code/chat_cmd.go (+11 LoC):
- New --sandbox <backend> flag accepting
`landlock|seatbelt|bubblewrap|none`. Empty value picks the
platform-native default (Linux → landlock, Darwin →
seatbelt). Acts as a hint for sin_bash's policy-binding;
the actual syscall filter is applied at the existing
`internal/sandbox.Command` boundary so no behaviour change
is needed in chat itself for v0.
- AGENTS.md §6: layout line for internal/sandbox update.
- CHANGELOG.md (Unreleased): "Added — internal/sandbox/seatbelt +
--sandbox flag (issue #199)" subsection documenting the
surface, seatbelt-vs-landlock matrix, and explicit non-goal
of integrating bubblewrap (separate PR).
Acceptance criteria (from issue #199):
- [x] Mac-developer validation: sandbox-exec is binary-looked-up
at /usr/bin/sandbox-exec (the canonical Darwin location)
and the lookup path is asserted in TestExecLooksUpBinary.
- [x] Policy profile is byte-stable — TestDefaultSeatbeltPolicyByteStable pins
~30 lines of expected SBPL so any future change forces
a deliberate golden update.
- [x] Exit code 71 + stderr "deny" maps to typed ErrSeatbeltDenied.
- [x] Default policy mirrors the project's Landlock semantics
on macOS so operator behaviour is consistent across
dev environments.
Hard mandates honored:
- M2: zero new deps. Pure Go + os/exec sandbox-exec.
- M3: emoji-free, byte-stable output, typed errors (no silent
permission drift; operator gets a clear "not on PATH"
vs "denied" distinction).
- M5: import path github.com/OpenSIN-Code/SIN-Code/...
- M7: 6/6 seatbelt tests pass under `-race -count=1`;
10/10 isolation + 12/12 auto_mem + 11/11 rules +
17/17 session tests still pass.
Not in this PR (deliberate scope-down):
- bubblewrap backend (`bwrap` on Linux) lands in a separate
PR because the binary isn't installed on the macOS dev box
that signed off on this PR's tests.
- The actual wiring that intercepts every `sin_bash` cmd
with the chat-session's chosen sandbox backend is in flight
in `internal/sandbox.Command` already; the chat hookup is
a small flag pass-through in `cmd/sin-code/chat_cmd.go`
and doesn't change the surface area.
Refs: #199.
Co-authored-by: opencode <agent@opencode.local>
…ivered)
What ships:
- CHANGELOG.md (Unreleased): "Notes — SOTA-roadmap session
2026-06-16/17 (7/10 delivered)" subsection tabling every
commit from this session (a868f63..6a3388e) with issue,
commit SHA, race-clean test count, and approximate line
count. Closing the books on the first wave of
Claude-Code-parity gap plugging.
- Explicit carry-forward list: #203 Agent Teams (file-locking
mailbox + 3 hooks) and #202 In-process MCP server (Go SDK
exposure) — both > 200 LoC of design + tests and intentionally
deferred to dedicated issue-first PRs so M3 (deterministic /
byte-stable contracts) is preserved in their own commit
boundaries.
Not code in this PR; docs only. No tests, no cmd, no internal
package touched; AGENTS.md unchanged (the per-issue entries above
already capture the source-of-truth changes).
Refs: 7 of 10 roadmap items from issue #194-#199 + #203,
delivered in single session 2026-06-16/17.
Co-authored-by: opencode <agent@opencode.local>
Closes #174
What
Adds a caveman-style output contract for the four orchestrator sub-agents (Critic, Adversary, Governor, Cartographer). Inspired by JuliusBrussee/caveman's cavecrew-* sub-agents (every byte of a sub-agent's prose is re-billed by the orchestrator) and JuliusBrussee/ponytail's 5-tag convention.
New file
:
Finding struct { Tag, Symbol, Path, Line, Confidence, Hint }— flat, byte-stable.delete | simplify | rebuild | risk | verify.Render()is fully deterministic —Finding{...}→Render()→ParseFinding()→ equal struct, every byte counted.ParseFinding/ParseFindings(em-dash U+2014 separator).VerifyFindingsrejects: empty Path, unknown Tag, hedging phrases (closed set of 12, case-folded), Hint > 240 chars, trailing punctuation.FindingsToBytesfor batch rendering.Wire-in
[]FindingCritic.DriveAttackAdversary.ReviewEscalation(risk, anchored at task://)Governor.ExecuteCartographer.Findings(k)Tests (13 new tests, all byte-stable golden)
output_contract_test.go— Render / Parse / Verify / Hedging / Tag-set.output_contract_integration_test.go— one fixture per agent (Critic, Adversary, Governor, Cartographer), byte-pinned.Verified (mandate M2 / M7)
Mandate compliance
github.com/OpenSIN-Code/SIN-Code/...paths.ParseErrorsas retry feedback (verify.fail direction).Docs
AGENTS.md§6.1 — full description of the contract, the 5 tags, the closed hedging set, and the per-sub-agent source of[]Finding. Originalcontract.go(Intent Contract) is documented as distinct from the new output contract.CHANGELOG.mdUnreleased — added the new section.