textmachine/backend/internal/seed/signaturemap.go

47 lines
2 KiB
Go

package seed
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"gopkg.in/yaml.v3"
)
// signaturemap.go: the ENVELOPE of the owner signature map.
//
// The map is the one seam artifact another side reads that carried no identity at all — no version and
// no way to tell two maps apart without diffing them (17-seam-inbound-law п.3 requires both of every
// document that crosses the seam). The body stays the plain seed schema so a row can still be moved
// into the owner's mined-delta file by copy-paste; the envelope is two keys on top of it.
// SignatureMapVersion versions the SHAPE of the signature map. It is not a snapshot input: the map is
// evidence for the owner, never a paid byte.
const SignatureMapVersion = "tm-signature-map-v1"
// SignatureMap is a whole signature-map document: the envelope plus the inlined seed schema.
type SignatureMap struct {
Version string `yaml:"map_version"`
// ID identifies the map's CONTENT — the sha256 of the rendered body (SignatureMapID). Two maps with
// one id offer the same terms, so a consumer can tell "the run re-wrote the same map" from "the run
// proposes something else" without diffing documents. It is an identity, not an integrity proof:
// recomputing it requires this engine's own renderer.
ID string `yaml:"map_id"`
File `yaml:",inline"`
}
// DecodeSignatureMap parses a signature-map document, strict like the other decoders of this schema.
// A map written before the envelope existed carries neither key and decodes with both empty — a book
// mid-signature across the upgrade must not lose the map it stopped on.
func DecodeSignatureMap(raw []byte) (SignatureMap, error) { return decodeStrict[SignatureMap](raw) }
// SignatureMapID derives the content identity the envelope carries. Deterministic: yaml.Marshal of the
// same document yields the same bytes.
func SignatureMapID(f File) (string, error) {
b, err := yaml.Marshal(f)
if err != nil {
return "", fmt.Errorf("seed: marshal the signature-map body for its id: %w", err)
}
sum := sha256.Sum256(b)
return hex.EncodeToString(sum[:]), nil
}