SolidForge: Port Design & Re-derivation
August 14, 2026 · View on GitHub
This document is the port's design rationale: how each discipline of the paper spec-gaming-orthogonal-axis.md is realized on the DeepSeek Harness, and where the port re-derives (rather than copies) the reference implementation.
The upstream reference implementation is SolidForge for Claude Code (a Claude Code plugin). This
project — SolidForge on the DeepSeek Harness — is the solidforge agent preset in ~/.dsh/.agent-presets/solidforge/,
developed from this workspace. A mechanical mapping table lives in
claude-code-to-dsh-map.md; this document is the
argument-level re-derivation.
1. What transfers unchanged (the discipline is harness-independent)
SolidForge's core is a set of deterministic, stdlib-only Python programs that own the convergence loop's state and gates:
loop_state.py— state machine + circuit breakers (thrash N=3, inner cap M=8, budget caps) + append-only event log + run-record rollup with thel4_assessmentblock (the per-run self-assessment of paper §6);fast_gate.py/blueprint_guard.py/counters.py— the per-edit gates (cheap lint/format; frozen-anchor read-only guard; terminal-state deny);arch_contract_*.py— the deterministic architecture-contract gates (cycles, layer isolation, API contracts, supply chain, tests, coverage);snapshot.py/plan_queue.py/scope_check.py— rollback, plan chaining, scope boundary;produce.py/converge.py/coverage_driver.py— the blueprint-crafting, cross-source-review, and primary-source/prior-art deterministic verifiers;produce.py/converge.py/coverage_driver.py— the blueprint-crafting, cross-source-review, and primary-source/prior-art deterministic verifiers;- the JSON schemas carrying the Process/Outcome split — including the
rightnessenum with exactly one value (human_confirm_required).
None of this references a harness; it references a project directory and env
vars. (Two exceptions, both re-derived in §4 and therefore NOT in the
byte-for-byte set: the hetero_*_review.py wrappers gained the DSH-native
substrate: dsh dispatch — they spawn dsh --profile headless and read the
profiles' _family metadata; they are the port's one substantive
re-derivation, not a rename.) The port renames the two env seams ($CLAUDE_PROJECT_DIR →
$SOLIDFORGE_PROJECT_DIR, $CLAUDE_PLUGIN_ROOT → $SOLIDFORGE_PRESET_ROOT)
and the state directory (.claude/parallel-dev/ → .solidforge/loop/) and
otherwise carries the programs with only the documented env/path renames — with the hetero wrappers carved out as the §4 re-derivation (the upstream tree is not vendored in this repo, so byte-for-byte identity is stated, not re-checkable here). The state machine
semantics — Thrashing → escalate, cap → degrade, budget → hard-terminate, and
the salience defenses (test set must not shrink, no hard-coded bypass, AC→test
name mapping) — are identical because they are the same code.
2. The Process/Outcome split, made implementation-level in DSH
Paper §4.2 demands that rightness be a schema invariant the agent cannot
write, not a prompted rule. Upstream enforces this in the JSON schemas
(enum-of-one) held in plugin code outside the workspace. The port keeps that
enforcement and adds a stronger seam that DSH makes natural:
-
solidforge-run-recordplugin (plugins/run-record.host.js): a harness-side tool. Itsexecute()runs in the harness process, reads the loop's ownconverged/dod_satisfiedemission verbatim (the paper'sprocess_convergedconcept maps to the pd record'sconverged+dod_satisfied; bc records carry the literalprocess_convergedfield), and appendsrightness: "human_confirm_required"— a constant baked into plugin source the agent cannot edit (dynamic-plugin sources live outside the session workspace and are immutable between activations). There is no code path in the tool that writes any other value. The confirmed-correct judgment remains an out-of-band human act; the field is a permanent conservative guard, not a state machine that reaches "solved" — exactly the paper's anti-gaming property. -
The file-based schemas (bc/csr/psv/pas) still validate the constant for the record files the deterministic scripts emit, so both seams agree.
3. Hooks become tool-event listeners (structural, not conventional)
Claude Code fires PreToolUse/PostToolUse hooks per edit. DSH's equivalent is
the tool registry's tools/pre-execute / tools/post-execute waterfall events
— and they are strictly stronger as a structural seam: listeners are plugins
in the harness process, not project files. The solidforge-loop-gates
plugin (plugins/loop-gates.host.js) wires:
| Gate | DSH event | Effect |
|---|---|---|
blueprint_guard.py | tools/pre-execute (edit/write) | {kind:'deny', reason} — frozen-anchor edits are blocked before dispatch |
counters.py pre | tools/pre-execute (edit/write) | deny once the loop state is terminal — a stalled task cannot thrash |
fast_gate.py | tools/post-execute (edit/write) | decision:block becomes an additionalContexts user message; the agent self-corrects next turn (the skill's orchestrator treats any block as inner-red short-circuit — agent-side rule, not plugin behavior) |
The listeners invoke the same Python gate scripts with the same stdin payload shape, so the deterministic behavior is byte-identical to upstream. A gate failure inside the listener can never wedge the tool call (falls through to allow), and the spawned gate subprocesses are bound to the tool call's abort signal.
4. The heterogeneous ring: the decoupling boundary, re-derived
Paper §4.4's worked example is "a Claude orchestrator reviewed by a DeepSeek/Qwen/GLM subprocess". The DSH port inverts it: the DSH orchestrator is DeepSeek, so DeepSeek is the same-source family, and the heterogeneous set is any DIFFERENT provider/model route served by the DSH harness itself (the pi-ai adapter's routes: Qwen, GLM/BigModel, MiniMax, …):
profiles/deepseek.jsonis removed from the ported profile dirs (it would be same-source); the default becomes FAIL-FAST (HETERO_PROFILE/HETERO_DOC_PROFILEunset → arming prompt); the worked dsh-substrate profiles arezai-coding-cn.json(_family: glm, effort-supported) andminimax-cn.json(_family: minimax), plus the unarmedqwen-token-plan-cn.jsonplaceholder (_family: qwen).- The substrate re-derivation (fixed after dogfood round 3). The first port
pass copied the upstream mechanism verbatim —
claude -p --settings <profile>— which REUSES the host harness upstream (the plugin lives inside Claude Code) but IMPORTS a foreign harness in DSH. Heterogeneity is a different LLM, not a different harness: the port now spawns a fresh, statelessdsh --profile headlesssubprocess whose throwawayDSH_HOMEpins a different provider/model route (substrate: dsh, default = FAIL-FAST arming prompt (no placeholder profile; arm one per the shippedzai-coding-cn.json/minimax-cn.jsonexamples)) — same harness, different model family, out of process. Theclaude -ppath survives only as an explicitly labeled external-harness opt-in (substrate: claude-code) for Anthropic-compatible-only backends, never the default. This is the paper's §8 open-problem-6 contingency resolved: a first-class-multi-provider harness re-derives the decoupling boundary by keeping the heterogeneous oracle a separate fresh process with its own provider pin, instead of inheriting it from a single-provider SDK. The boundary ("the heterogeneous ring is additive and non-replacing; the same-source ring always runs first") is kept by design: the same-source in-process ring runs first as the cost/reliability floor, and no global in-process multi-provider router is used. Whether the DSH in-process subagent/workflow paths could route to another provider is a harness detail this boundary does not depend on — the decoupling claim rests on the out-of-process leg. - The
solidforge-hetero-reviewplugin exposes the leg as a first-class tool with the reconciliation contract (both/same-only/hetero-only/neither; cap-hit degrades, never silently picks).
This is the port's only substantive re-derivation of the hetero mechanism (not a rename), and it is the mirror image the paper itself names as tier-2 decoupling. (§2's harness-side run-record tool and §3's event listeners are additions on the DSH extension seams — new pieces, not re-derivations of an existing mechanism.)
5. The agent corpus becomes prompt files
DSH has no filesystem role-agent registry; its subagent tool instantiates
children from prompts. The 22 SolidForge agents therefore port as the preset's
agents/*.agent.md role-prompt corpus (frontmatter kept; tool names mapped
Read/Glob/Grep/Bash/Edit/Write/WebSearch → read/glob/grep/bash/edit/write/ web_search; mcp__* tools apply only when that MCP server is configured).
Every skill instruction that said "spawn solidforge:<name>" now says "spawn
the agents/<name>.agent.md role prompt via the subagent tool". The role
semantics — same-source adversarial reviewer as the Axis-A outer ring, read-only
tools, context folding — are unchanged.
6. Scope line (what the port deliberately does not carry)
- Each upstream skill's
docs/convergence trail (historical maintainer-facing records) — the port keeps its own trail in this repo. - Claude-Code-only companion integrations (the Impeccable detector, and the external linter adapters spectral/semgrep/vale/oasdiff/license/iac): ported and degrading to coverage-noted no-ops; the reference docs say so.
- A benchmark evaluation: like the upstream, this port is evidence of realizability, not efficacy (paper §6, §8.3).
7. Known upstream quirks inherited
cross-source-review/infra/scripts/converge_fixtures/verify.py's malformed-finding case expects the jsonschema-path error message ("malformed finding ... evidence"); withoutjsonschemainstalled the core-reconciliation path fires first with "findings without disposition", so that one case fails. Reproduced on the unported upstream tree at port time — inherited, not a port regression (the upstream tree is not vendored here).pip install jsonschemarestores the intended path.