Skip to content

feat(opencode): support PrivacyCode as a compatible install target - #27

Merged
SignalLayerLabs merged 1 commit into
SignalLayerLabs:mainfrom
ralyodio:feat/privacycode-target
Aug 17, 2026
Merged

SignalLayerLabs merged 1 commit into
SignalLayerLabs:mainfrom
ralyodio:feat/privacycode-target

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Stacked on #26, which is stacked on #25. Review those first; the diff to read here is the
third commit.

Problem

PrivacyCode is an OpenCode fork that reuses OpenCode's plugin loader unchanged. Governing it needs no
second adapter, but it does need MARGINAL to stop assuming one installation layout per plugin API.

Interface

One OpenCodeTarget entry. A target records only what differs between compatible engines: the
executable name, the global configuration directory, and the ledger location. Nothing about the
governance contract is per-target.

marginal install privacycode / marginal uninstall privacycode.

installer.render_plugin binds the copied plugin to its engine at install time, so the plugin reports
the right engine without depending on an environment variable, and both engines can be installed at
once without interfering. The shipped file still defaults to opencode, so it stays valid as written.

Behavior

Capability label: Observe, identical to OpenCode, because it is the same plugin and the same bridge.

The engine label stays distinct. A ledger that pooled two engines could not answer "does governing this
engine help", so opencode and privacycode get separate labels, separate ledger roots, and separate
MARGINAL_<TARGET>_DATA overrides.

Install also now refuses a source file that does not carry MARGINAL's marker
(PLUGIN_SOURCE_UNRECOGNIZED), which closes the gap where --source could be pointed at arbitrary
JavaScript and have it installed as a governance plugin.

Validation

779 passed, 1 skipped; ruff and mypy src/marginal clean. 11 new tests pin what must stay identical
and what must stay distinct, including both engines installed side by side and removal of one leaving the
other in place.

End-to-end against PrivacyCode 1.18.10: marginal install privacycode, then a session was asked to run
echo one twice and then a failing command. The ledger recorded engine: privacycode on every record,
SHADOW_OVERRIDE with a DUPLICATE_ACTION recommendation on the repeated command (nothing blocked),
two proven successes and one proven failure from shell exit codes, and a session summary with no pending
or unmatched actions. Governance latency was 10.5–11.7 ms per decision. The ledger contained no command
text.

Compatibility

Additive. Existing opencode behavior, paths, and ledger location are unchanged.

Scientific limitations

  • Same limits as feat(opencode): Observe adapter and plugin over a stdio bridge #26: no performance claim, single-machine latency observations, and outcome evidence
    limited to tools that report an exit code.
  • Compatibility was established by observation, not by a guarantee. PrivacyCode currently tracks
    OpenCode's plugin API; if it diverges, it stops being a target and becomes a separate adapter. The
    version floor (1.18.0) and the PLUGIN_SUPPORT_UNVERIFIED reason code are what surface that, and
    neither detects a silent behavioral change within a supported version.
  • Adding a fork as a target is a claim that its plugin API is unchanged. This PR makes that claim for one
    fork on the strength of one validated session plus captured protocol shapes.

@SignalLayerLabs SignalLayerLabs left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is the right abstraction.

I agree that PrivacyCode should be a target rather than a separate adapter as long as it is genuinely reusing the OpenCode plugin contract unchanged. Duplicating the adapter here would create divergence for no benefit.

A few things I like in particular:

  • keeping opencode and privacycode as separate engine identities in the ledger;
  • separate ledger roots and data overrides, so evidence is never pooled across engines;
  • binding the engine identity at install time instead of relying on an environment variable;
  • allowing both targets to coexist;
  • refusing unrecognized --source JavaScript via PLUGIN_SOURCE_UNRECOGNIZED;
  • being explicit that compatibility is observed rather than guaranteed.

The last point matters. A target is effectively a claim that two engines expose the same governance surface, and that claim should stay narrow.

I have two requests before merge.

First, I would formalize the target/adapter boundary in code or docs if it is not already explicit:

  • a target may vary installation/runtime identity only;
  • it must not override event semantics, outcome classification, capabilities, or enforcement behavior;
  • if any of those diverge, it becomes a separate adapter.

That invariant will matter if more OpenCode forks get added later. I don't want OpenCodeTarget to slowly become an escape hatch for engine-specific behavior.

Second, the current compatibility check is still mostly version-based plus observed protocol compatibility. That's fine for Observe mode, but I would not let a compatible target inherit future enforcement eligibility automatically from OpenCode.

Even if they share the plugin API, Earned Enforcement evidence should remain engine-specific. PrivacyCode should have to earn its own enforcement window and counterfactual/regression evidence rather than inheriting OpenCode's trust state.

In other words:

same adapter != same trust

The separate engine label/ledger you added already gives us the right foundation for that.

The PLUGIN_SOURCE_UNRECOGNIZED change is also a good hardening improvement. Please make sure marker validation is strict enough that we're checking a MARGINAL-owned artifact rather than just looking for an easily spoofed substring. It doesn't need to become package signing in this PR, but the trust boundary should be documented accurately.

The E2E result looks appropriate for this stage: Observe only, duplicate recommendation recorded, shell outcomes backed by exit codes, nothing blocked, and no command text persisted.

Since this PR is stacked on #26 → #25, I'd still merge in order:

  1. get #25 green and merge it;
  2. rebase / merge #26 and validate the OpenCode runtime boundary;
  3. rebase #27 onto that clean main;
  4. run the full CI independently for the PrivacyCode delta.

Architecturally I'm in favor of this.

The main rule I want preserved going forward is:

protocol compatibility can be shared; governance evidence and earned authority cannot.

If PrivacyCode diverges from OpenCode at the plugin/event semantics level, it should stop being a target and become its own adapter, exactly as you noted.

PrivacyCode reuses OpenCode's plugin loader unchanged, so the same plugin and the
same bridge protocol govern it. A target records only what differs: the executable
name, the global configuration directory, and the ledger location.

The engine label stays distinct so one ledger never conflates two engines and a
later measurement can compare them rather than pool them. Installing binds the
copied plugin to its engine, so both engines can be installed at once without
interfering, and install now refuses a source file that is not a MARGINAL plugin.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@SignalLayerLabs
SignalLayerLabs force-pushed the feat/privacycode-target branch from aa18844 to 5bdff93 Compare August 17, 2026 09:10
@SignalLayerLabs
SignalLayerLabs merged commit 7c0e953 into SignalLayerLabs:main Aug 17, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants