feat: destination-conditional synthetic marker + attestation + deployment boundary (roadmap #3) - #91
Merged
Conversation
… + deployment boundary Roadmap 2026-09 item 3 (folds in #1 attestation and #5 deployment boundary). The single control that keeps Replicant from being banned the first time it burns a shift. - Marker default is now destination-conditional (Orchestrator._resolve_marker): ON for a non-loopback send, where analyst de-confliction on a shared collector outranks a flex slot no detection reads; OFF for --to-file and loopback, where the golden line is the oracle. flexString1 is unused by all three vendor profiles, so marking a live send corrupts no field a rule keys on. - --mark-synthetic forces it on everywhere; new --no-marker forces it off and logs a warning when it overrides a non-loopback send (settings.no_marker, which wins over benign_marker). - Manifest records the decision in a new marker_attestation field (RunManifest and ScenarioManifest), so a run's marking is auditable after the fact. - Applied uniformly through the existing _mark choke point, so run, scenario, and the connect test all follow the same rule. - docs/deployment-boundary.md states the 'detection lab, not production SIEM' boundary and the authorization workflow (marker on + manifest as the record). Positive control: the six new tests in test_synthetic_marker.py were run against the unfixed code and observed to fail (the end-to-end one shows lines captured but unmarked); they pass after the change. 1057 tests, gates clean.
From /code-review on PR #91, verified against the code before fixing: 1. (main) Web /api/connect/test sent an UNMARKED line to a non-loopback collector while the CLI send_test marked it: the recurring 'fixed one send path, not the parallel one' class. server.connect_test now resolves the marker per destination like the CLI. Positive control: reverted the line, web guard went red, restored it green. 2. Scenario sends carried the literal flexString1=synthetic with no run id to trace them. run_scenario now generates a run_id, threads it into the emit path, and records it in ScenarioManifest (new run_id field), so a marked scenario line traces back to its manifest. 3. marker_attestation claimed a '--no-marker override' even on loopback/file where the default was already off; now only a real override is reported so. 4. Docs said 'off for --to-file' flatly; a run that both sends live and writes a file marks both (the file mirrors the wire). Wording made precise across README, CLAUDE.md, deployment-boundary, settings, and the docstring. 5. The --no-marker warning read as if lines were emitted though it resolves at plan time; reworded as configuration intent. +3 guards (web probe marking, loopback attestation, scenario run-id marking). 1060 tests, black/ruff/mypy clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Roadmap 2026-09 item 3, the gate precondition for any live pilot. Folds in #1 (manifest attestation) and #5 (deployment-boundary doc) as the governance layer that makes the marker coherent.
What changed
Orchestrator._resolve_marker): the synthetic marker is now ON by default for a non-loopback send, OFF for--to-fileand loopback (where the golden line is the oracle).flexString1is a flex slot none of the three vendor profiles populate, so marking a live send corrupts no field a detection reads. Both fidelity leads conceded this in the debate.--mark-syntheticforces it on everywhere; new--no-markerforces it off and logs a warning when it overrides a non-loopback send.no_markerwins overbenign_marker.marker_attestationfield onRunManifestandScenarioManifestrecords the decision and why, so a run's marking is auditable. Defaulted, so old manifests still load._markchoke point, so run, scenario, and the connect test all follow one rule. Loopback detection is conservative: anything not confidently loopback (including a hostname we will not resolve) is treated as non-loopback, so ambiguity resolves to "mark it".docs/deployment-boundary.md: the "detection lab, not production SIEM" boundary and the authorization workflow (marker on + manifest as the record). Referenced from the README safety table andCLAUDE.mdsafety rules.Positive control (definition of done)
The six new tests in
tests/test_synthetic_marker.pywere run against the unfixed code and observed to fail (the end-to-end case shows lines captured but unmarked,assert False), then pass after the change. Full suite: 1057 passed; black/ruff/mypy clean.Decision record:
docs/roadmap-2026-09.md(#89).