Skip to content

feat(external-runtime): persist and reconcile execution evidence - #4

Merged
bayleafwalker merged 3 commits into
feat/cncnet-private-allocatorfrom
feat/evidence-reconciliation
Aug 26, 2026
Merged

feat(external-runtime): persist and reconcile execution evidence#4
bayleafwalker merged 3 commits into
feat/cncnet-private-allocatorfrom
feat/evidence-reconciliation

Conversation

@bayleafwalker

Copy link
Copy Markdown
Owner

Purpose

Turn the RA2 two-client vertical-slice findings into generic Bindery Core boundaries: durable control-state identity, independent observation reconciliation, explicit gate applicability, and calibrated consequential gates.

Scope

  • persists identity, session, placement, execution, enrollment, idempotency, and evidence-set state through an atomic single-writer store;
  • records allocator implementation, repository, exact revision, and configuration digest on every placement;
  • adds stable known-ID reads for placements, executions, and evidence sets;
  • promotes exact-count and ordered-hash reconciliation into pkg/evidencev1 (the 6,651/6,651 RA2 result is the first exact-count regression fixture);
  • adds five-state gate results and mandatory positive/negative controls for consequential gates in pkg/gatev1;
  • links capture events to execution IDs;
  • changes the Helm deployment from two mutually unaware in-memory replicas to one Recreate replica over a PVC;
  • records the dated RA2 assessment, recovery drill, and post-RA2 ordering rule.

The original research pack under docs/research remains unchanged.

Important boundary

The successful 2026-08-25 RA2 run predates these stable IDs. The assessment records it as historical evidence and explicitly refuses to invent placement, execution, or evidence-set IDs retroactively. Acceptance requires repeating the run through the hardened control plane, then using a non-RA2 runtime to test abstraction.

Verification

Local checks passed:

  • all promoted JSON contracts parse;
  • OpenAPI, chart values, chart metadata, and roadmap YAML parse with duplicate-key rejection;
  • staged and committed diffs pass git diff --check;
  • the published GitHub tree exactly matches local committed tree ddee8b4fabb6f122f371e14c4d083b5df6492749.

This workspace has no Go or Helm binaries, so go test -race ./..., go vet ./..., and Helm lint are intentionally left to repository CI before the PR leaves draft.

Review focus

  1. Snapshot rollback and referential-integrity restoration.
  2. Single-writer deployment enforcement and PVC ownership.
  3. Evidence reconciliation semantics: consistency is not authority.
  4. Gate calibration/applicability state separation.
  5. Contract compatibility and the point at which a shared relational store becomes mandatory.

@bayleafwalker

Copy link
Copy Markdown
Owner Author

Assessment before merge

Merging as-is into feat/cncnet-private-allocator. The code is sound — recording two boundary facts so the green check isn't read as broader than it is.

1. This branch's CI does not compile the operator.

The green test job here runs a different, narrower workflow than the one on main. It covers go test -race ./... over pkg/ and internal/ plus helm lint, and its output lists only cmd/bindery-external-runtime, internal/{capture,externalruntime,harness,relay}, and pkg/{evidencev1,gatev1,relayv1}. It never builds api/, controllers/, or main.go, and it does not run envtest integration or the Kind e2e smoke — because this branch's tree does not contain them.

That is a consequence of the branch topology, not a defect in this PR: git merge-base origin/main origin/feat/cncnet-private-allocator returns nothing. This line is an orphan history rooted at 0486d83, with its own stdlib-only go.mod. So the check is structurally incapable of failing on operator breakage. Green here means "the external-runtime tree is healthy," not "bindery-core is healthy."

2. pkg/gatev1 has no production caller.

git grep gatev1 matches only pkg/gatev1/gate.go and its own test. No service, handler, or cmd/ imports it. The package is well-built — the five-state applicability model and the mandatory positive/negative calibration controls answer exactly the failure described in docs/assessments/2026-08-25-ra2-vertical-slice.md, where a diagnostic string was read as a verdict — and its four tests exercise the right failure modes. But docs/roadmap/post-ra2-hardening.yaml marks ERH-003 and ERH-004 implemented-pending-ci, which reads as stronger than "compiles and is unit-tested, nothing calls it."

Not a blocker. ERH-006 is the item that would give it a first caller, and the roadmap status should say so.

What does hold up. internal/externalruntime/state_store.go is a real crash-safe single writer: same-directory temp file, 0600, Sync, Close, os.Rename, then Sync on the containing directory, with restoreSnapshotLocked rolling back the in-memory mutation when the durable write fails. Load rejects symlinks, non-regular files, group/other permission bits, unknown fields, and trailing JSON values, then re-validates referential integrity across the whole graph. TestPersistentServiceRestoresResolvableControlAndEvidenceGraph and TestPersistenceFailureRollsBackMutation are genuine drills rather than assertions of intent. pkg/evidencev1 is wired through Service.CreateEvidenceSet, and its three unimplemented methods return ErrUnsupportedMethod rather than quietly aliasing to exact-count.

Follow-up tracked separately: unify this orphan line into main behind one module and one CI that runs both trees.

@bayleafwalker
bayleafwalker marked this pull request as ready for review August 26, 2026 07:16
@bayleafwalker
bayleafwalker merged commit 1ef3b21 into feat/cncnet-private-allocator Aug 26, 2026
4 checks passed
bayleafwalker added a commit that referenced this pull request Aug 26, 2026
feat/external-runtime-w0-w1 -> feat/cncnet-private-allocator (including the
evidence-reconciliation work merged as PR #4) shared no ancestry with main:
`git merge-base` returned nothing, its root commit 0486d83 had no parent, and
it carried its own go.mod, its own narrower CI, and charts/ instead of helm/.
It was started on 2026-08-23, twelve minutes after PR #3 merged, which is the
most likely explanation for the allocator that the RA2 gate report attributed
to a commit nobody could find in this repository -- it was authored in a tree
that shares no history with the one being searched.

Merged with --allow-unrelated-histories. The two trees were near-disjoint, so
this is a union rather than a replacement: api/, controllers/, main.go, e2e/,
helm/, k8s/, modules/ and services/ are untouched, and internal/externalruntime,
internal/relay, internal/harness, internal/capture, pkg/{evidencev1,gatev1,
relayv1}, cmd/bindery-{external-runtime,udp-relay,redaction-scan}, charts/,
contracts/externalruntime/ and verification/ arrive alongside them.

Seven files collided and were resolved by union rather than by picking a side:

  - go.mod keeps main's (a strict superset; the external-runtime packages need
    no dependencies). Its `go 1.22.0` turned out to be sufficient -- the other
    tree's `go 1.23` was not load-bearing -- and `go mod tidy` reports no drift.
  - Makefile keeps main's targets and gains test-race, vet, lint-charts,
    redaction, and verify-external-runtime.
  - .github/workflows/ci.yml keeps main's go-test, sample-game-test and
    e2e-smoke jobs and gains an external-runtime job running race tests, vet,
    chart lint, and the secret scan. One job is deliberately NOT carried over:
    the image job that published ghcr.io/bayleafwalker/bindery-core on every
    push. That tag's meaning is now ambiguous -- the root Dockerfile builds only
    the external-runtime binaries, not the operator -- and enabling an external
    publish as a side effect of a merge is not a decision to make silently.
  - bindery-core.dispatch.json unions scope roots, risk surfaces, skills, and
    verification commands, and takes the gates and hooks blocks that only the
    external-runtime side defined.
  - .envrc, .gitignore and README.md are unions.

This is the first time the external-runtime packages have been compiled or
tested alongside the operator. Their previous green CI ran `go test -race ./...`
over a tree that contained no api/, no controllers/ and no main.go, so it was
structurally incapable of failing on operator breakage. Under one module: go
build, go vet, go test ./..., go test -race ./..., make verify, and helm lint of
both charts all pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y7raRPAwARat3XE4JRHvMW
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.

1 participant