Skip to content

component execution: add deep snapshot primitives for transactional host commits #27

Description

@bomly-guy

Summary

Add SDK-owned deep-copy primitives that let a host treat component calls as transactions: components receive isolated inputs, and the host commits only a successful result.

The need exists because embedded and managed execution currently have different mutation boundaries:

  • PackageRegistry.Get and PackageRegistry.All return stored *Package pointers.
  • MatchRequest and AnalyzeRequest carry mutable *Graph, *PackageRegistry, and *Dependency values.
  • Package.Clone and Dependency.Clone exist, but PackageRegistry and Graph do not expose a complete deep snapshot operation.
  • A managed plugin crosses a JSON/gRPC boundary and naturally receives a copy. An embedded component receives host pointers and can mutate them before returning an error or observing cancellation.

This is an execution-mode semantic mismatch: the same module can produce different host state depending on whether it is compiled in or served out of process.

Desired contract

Provide efficient, explicit SDK primitives for producing mutation-isolated matcher/analyzer inputs without using a JSON round trip. At minimum, cover every reachable mutable value in MatchRequest and AnalyzeRequest:

  • registry entries and all nested package enrichment;
  • graph nodes, edges, and nested dependency data;
  • target dependencies;
  • mutable maps, slices, and pointers reachable through those values.

The API can be Clone methods on the owning models, request snapshot helpers, or a small combination. The important contract is no shared mutable memory between the source and snapshot for component-visible data.

The host will use these primitives in a separate CLI issue to commit Registry or PackageUpdates only after a successful call. The full-registry result remains the protocol v1 baseline; delta results remain an optional optimization.

Acceptance criteria

  • PackageRegistry has a documented deep clone/snapshot operation preserving canonical contents and deterministic iteration behavior.
  • Graph has a documented deep clone/snapshot operation preserving live nodes, edges, and graph invariants.
  • Matcher/analyzer request inputs can be cloned without a serialization round trip.
  • Tests mutate every class of nested field in the snapshot and prove the source is unchanged, and vice versa.
  • Tests cover nil registries/graphs/targets, empty values, and non-trivial graph topology.
  • Snapshot behavior preserves validation and canonical identity rules; it does not invent a second merge implementation.
  • Benchmarks or allocation assertions prevent an accidental JSON-based implementation from becoming the default hot path.
  • Exported additions have doc comments and use existing dependencies only.

Compatibility and ownership

This should be an additive in-process Go API change in bomly-sdk; no wire field or RPC is required. Shared model copying belongs in the SDK under the source-of-truth rule. The CLI owns when to snapshot and when to commit.

An ADR is required if the work changes component-visible execution semantics beyond adding copy primitives. Any proposed change to merge precedence should be split into its own decision.

Out of scope

  • Making all SDK model types immutable.
  • Parallel matcher/analyzer scheduling.
  • Removing the full-registry v1 result.
  • Treating JSON marshal/unmarshal as the production clone implementation.

Verification

Run:

go test ./...
go vet ./...
gofmt -l .
go mod tidy -diff

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions