internal/infra/pg/recordretraction.go
internal/infra/pg · 295 lines · 17 declarations · source
Declarations
const MaxRecordMutations
const MaxRecordMutations = 20
const MaxRetractionSources
const MaxRetractionSources = 128
var ErrInvalidRecordMutation, ErrRecordConflict, ErrRecordMutationLimit and 1 more
var (
ErrInvalidRecordMutation = errors.New("invalid record mutation")
ErrRecordConflict = errors.New("record version changed or is already withdrawn")
ErrRecordMutationLimit = errors.New("record mutation exceeds its source bound")
ErrRetractedClaim = errors.New("claim was withdrawn for this source message")
)
type RecordMutation
type RecordMutation struct {
ID string `json:"id"`
ExpectedVersion string `json:"expected_version"`
}
type RetractionDetails
type RetractionDetails struct {
OperationID string `json:"operation_id"`
PrincipalID string `json:"principal_id"`
RetractedAt time.Time `json:"retracted_at"`
ReplacementObservationID *string `json:"replacement_source_observation_id,omitempty"`
ReplacementFactID *string `json:"replacement_record_id,omitempty"`
}
type RecordRetraction
type RecordRetraction struct {
ID string `json:"id"`
Version string `json:"version"`
RetractionDetails
}
type RetractionBatch
type RetractionBatch struct {
Records []RecordRetraction `json:"records"`
}
type retractionSource
type retractionSource struct {
FactID string
ObservationID string
Ordinal int
}
func claimSignature
func claimSignature(predicate, subjectKind, subjectKey, objectKind, objectKey string) []byte
The source message and structural identity define the instruction. A paraphrased statement or a different valid-from date cannot undo withdrawal; an independent later message can assert it. Hashes here are matching keys, not anonymization. Their source ownership governs erasure.
func claimEndpoint
func claimEndpoint(name, subject string, speaker bool) (string, string)
func sourceClaimID
func sourceClaimID(scope, observationID, subject string, claim domain.Claim, leftSpeaker, rightSpeaker bool) (uuid.UUID, error)
Identity follows the source assertion, so replay and derived-row recovery do not invent a new citation. Reinterpreting a retained source is an explicit generation operation, never a retry.
func lockClaimSource
func lockClaimSource(ctx context.Context, tx pgx.Tx, schema Schema, scope, observationID string) error
Formation and retraction serialize only when they address the same source. A hash collision delays unrelated work but cannot change its identity or project predicates.
func readRetraction
func readRetraction(ctx context.Context, tx pgx.Tx, schema Schema, scope, id string) (*RetractionDetails, error)
func refuseRetractedClaim
func refuseRetractedClaim(ctx context.Context, tx pgx.Tx, schema Schema, scope, observationID, subject string, claim domain.Claim, leftSpeaker, rightSpeaker bool) error
func retractionSources
func retractionSources(ctx context.Context, tx pgx.Tx, schema Schema, scope string, ids []string) ([]retractionSource, error)
method RecordStore.Retract
func (s *RecordStore) Retract(ctx context.Context, scope, principal string, requests []RecordMutation) (RetractionBatch, error)
Retract is an atomic bounded batch. Source instructions, closed knowledge, report invalidation, new versions and an attributable content-free audit entry either all commit or all roll back.
method RecordStore.retractTx
func (s *RecordStore) retractTx(ctx context.Context, tx pgx.Tx, scope, principal string, requests []RecordMutation) (RetractionBatch, error)
The caller owns commit so a correction can withdraw its target and assert its replacement together.