Skip to content

Latest commit

 

History

History
218 lines (175 loc) · 10.4 KB

File metadata and controls

218 lines (175 loc) · 10.4 KB
phase P
title Generated Go Bindings for sc-sha
status complete
branch sprint/p-3-release-prep-v1.5.0
worktree ../sc-compose-worktrees/sprint/p-3-release-prep-v1.5.0
target integrate/phase-p
planning_branch plan/sha-go
planning_worktree ../sc-compose-worktrees/plan/sha-go
related_issue #510

Phase P — Generated Go Bindings for sc-sha

Goal

Publish a generated, typed Go binding for the two existing sc-sha operations so sc-dolt and atm-core can consume the canonical hash contract without copying the algorithm. Establish the repository's reusable Go-binding policy at the same time: UniFFI is the ordinary SDK generator; rust2go is an explicit future opt-in for a proven async/shared-memory need.

This phase implements bindings/sc-sha-go only. It does not implement Go bindings for sc-composer, introduce ATM code, change the two-operation sc-sha core API, add graph discovery, or invent an async hash interface.

Decision and design gate

ADR-0020 is the governing binding strategy and is Accepted. P.1 records the required amendment to ADR-0018 / CLAUDE.md / sc-boundary inventories and its review evidence.

The P.1 gate pins a compatible UniFFI plus uniffi-bindgen-go pair and proves the pair can generate and build the actual Go package. The Go generator is a third-party 0.x tool, so this gate is a release-quality requirement, not a best-effort developer setup check. Do not substitute handwritten CGo glue if the generator proof fails; resolve the generator compatibility issue or revise the plan through ADR review.

The initial approved compatibility pair is UniFFI 0.31.0 and uniffi-bindgen-go v0.7.1+v0.31.0. P.1 records that pair in committed tool configuration and may not replace either component with a newer release unless the generation/conformance suite is deliberately re-approved.

Requirements and traceability

ID Requirement Closure sprint
P-R1 A Go consumer calls the canonical Rust calculate_hash behavior through generated bindings and receives the same lowercase digest and stable failure identity. P.1
P-R2 A Go consumer supplies a typed, resolved composition manifest and receives the canonical Rust calculate_composition_hash behavior. P.1
P-R3 Go source is generated from a version-pinned interface contract, committed for the released module, and CI rejects generator drift. P.1
P-R4 The Go module includes a reproducible native-library distribution contract and is consumable outside this Cargo workspace. P.2
P-R5 sc-dolt and atm-core receive an external-consumer handoff with exact package/version, vectors, and migration steps; neither repository is modified by this phase. P.2
P-N1 sc-sha remains pure and receives no UniFFI, rust2go, CGo, Go, resolver, filesystem, CLI, or ATM dependency. P.1
P-N2 Normal Go safety checks remain enabled; no adapter, test, CI job, or consumer requires GODEBUG=cgocheck=0 or GODEBUG=invalidptr=0. P.1, P.2
P-N3 A future sc-composer Go binding is estimated and bounded, but not silently started. Phase plan only

Architecture

sc-dolt / atm-core (external Go consumers)
                │
                ▼
generated Go package ── generated by uniffi-bindgen-go
                │
                ▼
bindings/sc-sha-go ── UniFFI adapter only
                │
                ▼
crates/sc-sha ── canonical two-operation Rust implementation

The Go-facing types are generated records, enums, and typed errors—not JSON maps. The adapter performs the same input validation currently exposed by bindings/sc-sha-python: strict UTF-8 handling, canonical tagged source validation, digest parsing, schema-version validation, and stable error-code mapping. It delegates every successful calculation to sc-sha.

The generated public contract is intentionally limited to:

CalculateHash(utf8FileBytes []byte) -> TemplateHash / ScShaError
CalculateCompositionHash(manifest ResolvedTemplateManifest)
    -> CompositionHash / ScShaError

The exact generated Go spelling follows the selected pinned generator's output and is recorded in P.1's generated-artifact fixture. It must preserve the semantics of the existing Rust and Python contracts:

CanonicalSource = LocalPath(string) | Url(string)
ResolvedTemplateNode = { source, sha256 }
ResolvedIncludeEdge = { parent, child, occurrence }
ResolvedTemplateManifest = { schema, nodes, edges }

schema accepts only sc-sha/manifest/v1 / its explicitly documented V1 representation. Node order, edge order, and edge occurrence remain identity inputs; graph discovery, sorting, deduplication, cycle detection, and source canonicalization stay with callers.

Sprint sequence and parallelism

P.1 is the sole foundation sprint. It creates the generated interface, adapter, boundary enforcement, source-generation check, and conformance suite. P.2 depends on P.1's merged public contract and owns native artifact/module release and external consumer handoff.

Therefore P.1 and P.2 are sequential and may not run in parallel. Each may run in parallel with unrelated phases that do not modify sc-sha, the Go adapter, ADR-0018, CLAUDE.md, or the same boundary inventories.

Scope boundary

In scope:

  • UniFFI and uniffi-bindgen-go generated bindings for sc-sha;
  • a dedicated Go adapter package and native library distribution contract;
  • Rust/Python/Go conformance vectors and generator-drift verification;
  • ADR-0018 / CLAUDE.md / sc-boundary amendments required for the adapter;
  • release and consumer handoff documentation for sc-dolt and atm-core.

Out of scope:

  • an atm-core or sc-dolt source change;
  • a third sc-sha core operation, raw-byte hashing, filesystem access, or template graph discovery;
  • a rust2go adapter or an async/shared-memory API;
  • Go bindings for sc-composer;
  • manually maintained public CGo glue;
  • relaxing Go pointer checks or accepting GODEBUG safety bypasses.

Optional follow-on: sc-composer Go bindings (estimate only)

This phase does not authorize bindings/sc-composer-go. The existing bindings/python surface is roughly 2,500 Rust/Python test lines across conversion, errors, functions, and enums; a Go equivalent is not a one-sprint extension of the sc-sha adapter.

Rough estimate after a separate API inventory: three to five sprints.

  1. Specify the supported sc-composer Go value/error/result contract and identify the intentionally unsupported Python-only convenience surface.
  2. Build the generated UniFFI adapter and core conformance suite.
  3. Add render/resolve/extract fixtures and publication packaging.
  4. Optionally split complex callback/async behavior into a separately ADR'd rust2go adapter only if benchmarked workload evidence requires it.
  5. Adopt the module in external consumers and complete compatibility release validation.

The applicable boundaries are non-negotiable: sc-compose remains the CLI consumer of sc-composer (Rule 2); the Go adapter is a new dedicated adapter, not an expansion of bindings/python (Rules 3–4); and sc-composer must never depend back on any Go adapter (Rule 5). A later phase must amend those rules and add a dedicated sc-boundary contract before code begins.

Phase acceptance criteria

  • ADR-0020 and the P.1 ADR-0018/boundary amendments are accepted before adapter source is authored (PR #513).
  • A generated Go package exposes exactly the two existing sc-sha operations and typed manifest/error values (PR #513).
  • Go, Rust, and Python agree on all committed success and failure vectors (PR #513).
  • CI regenerates the Go source using the pinned toolchain and detects committed-artifact drift (PR #513).
  • The released module has a documented target-bundle download/linking contract and passes an independent consumer-module smoke test (PR #515).
  • Neither sc-sha nor sc-composer acquires a binding/runtime reverse dependency, and sc-boundary negative tests prove it (PR #513).
  • sc-dolt and atm-core receive the released package/version, vectors, and handoff instructions; their adoption remains separately owned work (PR #515).
  • All sprint and required fix/ worktrees are QA-approved, merged, and revalidated on the merged parent (PR #514).

Phase validation

Each implementation sprint must run its own exact validation list. The phase closeout reruns:

cargo fmt --all --check
cargo test --workspace
cargo clippy --all-targets --all-features -- -D warnings
just lint
go test ./...                         # from bindings/sc-sha-go
git diff --check

QA routing and sc-lint cleanup

Run all applicable sc-lint targets after each sprint's implementation. Fix minor findings within the sprint. Create a fix/ worktree from the sprint commit for remaining findings, grouping independent rule classes together (for example, one crate-local constant-string group, not one worktree per literal; keep each length-refactor violation separate). Send team-lead the parent commit, target paths, finding class, evidence, tests, and fix commit; team-lead opens the PR and sends it to quality-mgr. The originating sprint is not closed until required fix PRs are QA-approved, merged, and its merged parent is revalidated.

Phase P Release Preparation

Status: complete on sprint/p-3-release-prep-v1.5.0.

P.3 publishes the Phase P release documentation and metadata: the generated sc-sha-go consumer section and integration guide use the 1.5.0 module tag, the Rust and Python package versions are synchronized, and the Phase P boundary and planning gates are closed. External adoption by sc-dolt and atm-core remains consumer-owned work as documented in the integration guide.

Sprint index