Documentation
¶
Overview ¶
Package record supplies typed audit snapshots and generated registration contracts below audit storage. Capturing a record performs no database I/O.
Index ¶
- Constants
- func Capture[M, K, V any](builder *Builder[M, K], name string, c codec.Codec[V], ...) error
- func FoundryCapture[M, K any](builder *Builder[M, K], field FoundryStoredField, disclosure Disclosure, ...) error
- func FoundryReadField[M, K, V any](view View[M, K], name string, kind codec.ParameterType, ...) (value.Optional[FieldChange[V]], error)
- func ObserverName[M any]() (string, error)
- func ReadField[M, K, V any](view View[M, K], name string, c codec.Codec[V]) (value.Optional[FieldChange[V]], error)
- func SensitiveName(name string) bool
- type Builder
- type Declaration
- type Digest
- type Disclosure
- type Document
- type Entry
- type Field
- type FieldChange
- type FieldValue
- type FoundryStoredField
- type Model
- type Redaction
- type ResolveWriter
- type Snapshot
- type State
- type View
- type Writer
Constants ¶
const MaxCapturedValueBytes = jsonwire.MaxBytes / 4
MaxCapturedValueBytes bounds one captured value before the record-level payload bound applies. Larger values are stored as an Oversized digest; the recorder's configured value limit can replace smaller values the same way.
const MaxFields = 1024
Variables ¶
This section is empty.
Functions ¶
func Capture ¶
func Capture[M, K, V any](builder *Builder[M, K], name string, c codec.Codec[V], change lifecycle.FieldChange[V], disclosure Disclosure) error
Capture adds one generated field to builder. Updates, soft deletes and restorations record only assigned or changed fields plus the subject key, so unchanged columns never invoke their codec or enlarge the stored row. Create and delete operations retain complete snapshots.
func FoundryCapture ¶
func FoundryCapture[M, K any](builder *Builder[M, K], field FoundryStoredField, disclosure Disclosure, seal sqlowner.MetadataSeal) error
FoundryCapture reuses capture policy with already computed lifecycle flags. A valid metadata capability is required before any callback. Example: FoundryCapture(builder, field, Automatic, sqlowner.Metadata()).
func FoundryReadField ¶
func FoundryReadField[M, K, V any](view View[M, K], name string, kind codec.ParameterType, decode func(any) (V, error), seal sqlowner.MetadataSeal) (value.Optional[FieldChange[V]], error)
FoundryReadField retains a declaration's existing decoder without rebuilding a codec. The metadata capability is checked before the decoder is retained. Example: FoundryReadField(view, "name", codec.TypeText, decode, sqlowner.Metadata()).
func ObserverName ¶
ObserverName derives one stable identifier per concrete model for the existing database-wide observer namespace. It is not a durable model/subject identity. Hashing avoids invalid package-path characters and identifier truncation.
func ReadField ¶
func ReadField[M, K, V any](view View[M, K], name string, c codec.Codec[V]) (value.Optional[FieldChange[V]], error)
ReadField is a generated declaration boundary. Model adapters supply the column and existing codec; ordinary application code uses their named fields.
func SensitiveName ¶
SensitiveName is the current shared rule for stored columns and nested JSON keys. Explicit exclusions are still required for secrets whose names do not identify their meaning.
Types ¶
type Builder ¶
type Builder[M, K any] struct { // contains filtered or unexported fields }
Builder is a generated, operation-local capture boundary. It is not safe for concurrent use; the completed Model is immutable. Add errors remain sticky so ignoring one cannot publish a partial record. No database work occurs here. Updates, soft deletes and restorations keep only assigned or changed fields and the subject key; creation and deletion keep complete snapshots.
func NewBuilder ¶
func NewBuilder[M, K any](template model.Reference[M, K], operation lifecycle.Operation, primary string, disclosure Disclosure) (*Builder[M, K], error)
NewBuilder is emitted from the model's existing primary metadata. A subject key is necessarily present in audit identity; excluding/redacting that field would misleadingly retain its value elsewhere. Such policies, including a conventionally sensitive primary column, fail before binding the subject key.
func (*Builder[M, K]) Add ¶
Add validates and adds a captured field, retaining the first error for Build. An uninitialized builder returns fault.Invalid; a completed builder returns fault.Closed.
type Declaration ¶
type Declaration struct {
// contains filtered or unexported fields
}
Declaration wraps a generated model's existing observer registration. It is opaque outside this explicit declaration boundary and owns no global state.
func Declare ¶
func Declare(install func(*foundation.Registrar, foundation.Key[*database.DB], ResolveWriter) error) Declaration
Declare is called by generated model adapters. Application providers pass the resulting declaration to audit.Register with their typed database/writer keys.
func (Declaration) Register ¶
func (d Declaration) Register(r *foundation.Registrar, pool foundation.Key[*database.DB], resolve ResolveWriter) error
Register invokes the generated registration using foundation/database's existing duplicate, dependency, construction and frozen-state handling.
type Digest ¶
Digest describes an oversized value without retaining it. Size is the number of captured bytes: UTF-8 text, raw bytes or the already-redacted canonical JSON document. SHA256 is the lowercase hexadecimal digest of those bytes; it is empty for JSON that was too large to inspect for sensitive keys, so a digest never allows confirming a guessed secret.
type Disclosure ¶
type Disclosure uint8
Disclosure controls one generated model field's audit representation. Automatic includes ordinary fields and redacts sensitive codecs or conventional sensitive names. Exclude omits the entire field; Redact retains change flags without its value. Ignore omits the field and opts out of automatic update records when only ignored fields and the managed updated_at are touched. Exclude keeps that evidence. There is deliberately no option to override sensitive-value/name protection.
const ( Automatic Disclosure = iota Exclude Redact Ignore )
func (Disclosure) Validate ¶
func (d Disclosure) Validate() error
Validate reports fault.Invalid for an unknown disclosure mode.
type Document ¶
type Document[P any] struct { // contains filtered or unexported fields }
Document captures a typed domain audit DTO. Sensitive JSON keys use the same redaction rules as model fields. Redacted documents remain audit representations; they cannot be decoded into partially populated application DTOs.
func CaptureDocument ¶
CaptureDocument freezes an independent representation and isolates custom JSON callback faults. Domain DTOs should omit private fields altogether when even a redacted marker is inappropriate.
func ParseDocument ¶
ParseDocument checks restored redaction metadata under CurrentRedaction. Use ParseDocumentWith for stored history, which records the policy that wrote it.
func ParseDocumentWith ¶
ParseDocumentWith checks restored redaction metadata under the policy that captured the document and applies the concrete DTO schema only to complete, unredacted data. It never trusts a persisted flag to hide an unsanitized secret value, and extending the current policy never invalidates old rows. Keys that CurrentRedaction treats as sensitive in an older document are masked on read: the result is redacted and reports CurrentRedaction.
func (Document[P]) Decode ¶
Decode returns a fresh DTO or a Missing error for redacted history. Payload remains available for an explicit, already-redacted audit export.
func (Document[P]) Payload ¶
Payload returns the captured JSON text for explicit audit export, or an error if uninitialized.
type Entry ¶
type Entry struct {
// contains filtered or unexported fields
}
Entry is the immutable heterogeneous storage boundary of a model audit. Normal application code receives the model-owned Model wrapper and generated fields. Entry is attribution/history, never authentication or authorization evidence. Constructors validate the complete document once; copies share that result.
func ParseEntry ¶
func ParseEntry(identity model.Identity, operation lifecycle.Operation, payload string) (Entry, error)
ParseEntry is an explicit persistence/transport boundary. It validates stored metadata, snapshot states and redaction before allowing export or typed restore. Each stored document is checked against the redaction policy that wrote it.
func (Entry) Compact ¶
Compact returns an entry whose disclosed values above limit bytes are stored as Oversized digests. It never fails because values are large; it is used by recorders to apply their configured per-value threshold before storage. Entries captured under an older policy are returned unchanged.
func (Entry) Payload ¶
Payload exposes the versioned snapshot document only at a deliberate storage or report boundary. It contains audit values, not serialized model DTOs.
type Field ¶
type Field[M any] struct { // contains filtered or unexported fields }
Field is an opaque, model-owned captured field for generated audit adapters. Its constructor is a declaration boundary; normal callers use model Changes.
func CaptureField ¶
func CaptureField[M, V any](name string, c codec.Codec[V], change lifecycle.FieldChange[V], disclosure Disclosure) (Field[M], error)
CaptureField consumes the already-computed stored change. It never compares values again or invokes model presentation accessors. Excluded/redacted fields do not invoke their persistence codec at all. Codecs must be pure and return owned values, as for ordinary persistence; custom callback faults are isolated. Values above MaxCapturedValueBytes become Oversized digests rather than failing the business write.
type FieldChange ¶
type FieldChange[V any] struct { // contains filtered or unexported fields }
FieldChange contains a stored audit field with concrete before/after types. The surrounding Optional returned by generated readers represents a field omitted by policy or absent from an older record's schema.
func (FieldChange[V]) After ¶
func (c FieldChange[V]) After() FieldValue[V]
After returns the captured value after the operation.
func (FieldChange[V]) Assigned ¶
func (c FieldChange[V]) Assigned() bool
Assigned reports whether the field was explicitly assigned.
func (FieldChange[V]) Before ¶
func (c FieldChange[V]) Before() FieldValue[V]
Before returns the captured value before the operation.
func (FieldChange[V]) Changed ¶
func (c FieldChange[V]) Changed() bool
Changed reports whether the stored field changed.
type FieldValue ¶
type FieldValue[V any] struct { // contains filtered or unexported fields }
FieldValue retains the declared storage type while exposing disclosure state. A redacted value cannot hydrate T; JSON export remains the explicitly redacted audit representation rather than a partial application model.
func (FieldValue[V]) Format ¶
func (FieldValue[V]) Format(state fmt.State, _ rune)
Format writes a fixed label without exposing the captured value.
func (FieldValue[V]) Get ¶
func (v FieldValue[V]) Get() (value.Optional[V], error)
Get returns absence only when the model snapshot was absent. A nullable field decodes to its concrete Nullable type. Redaction is an explicit error, never a fabricated zero field value. Each decode gives the caller its own value.
func (FieldValue[V]) Snapshot ¶
func (v FieldValue[V]) Snapshot() Snapshot
Snapshot returns the immutable audit representation of the field value.
func (FieldValue[V]) State ¶
func (v FieldValue[V]) State() State
State returns the captured value's disclosure state.
type FoundryStoredField ¶
type FoundryStoredField struct {
Name string
Type codec.ParameterType
Sensitive bool
Before, After, Assigned, Changed bool
Bind func(after bool) (driver.Value, error)
}
FoundryStoredField is the framework's deferred stored-change boundary. Bind runs only for selected, disclosed snapshots. Example: FoundryStoredField{Name: "name", Type: codec.TypeText, After: true, Changed: true, Bind: bindStored}.
type Model ¶
type Model[M, K any] struct { // contains filtered or unexported fields }
Model preserves the audited subject and stored key types. Its snapshots remain audit representations: exclusions/redaction never produce incomplete models.
func RestoreModel ¶
RestoreModel reapplies the expected model/key owner to an already validated history entry. The template's current key is ignored, as with Reference.Parse.
type Redaction ¶
type Redaction uint8
Redaction identifies the sensitive-name policy that captured a stored audit row. Every row retains the policy that wrote it, so extending the recognized names never invalidates older history; reads check each row against its own policy. New captures always use CurrentRedaction.
const ( // RedactionV1 recognizes password, secret, token, credential, authorization // and API/private-key names split at snake, kebab and camel-case boundaries. RedactionV1 Redaction = 1 // RedactionV2 additionally splits letter/digit boundaries, ignores digit // suffixes and simple plurals, recognizes joined names such as accesstoken, // and adds passphrase, OTP, PIN, CVV/CVC, SSN, card number, cookie, session // and recovery-code conventions. RedactionV2 Redaction = 2 // CurrentRedaction is the policy applied to newly captured audit data. CurrentRedaction = RedactionV2 )
type ResolveWriter ¶
type ResolveWriter func(foundation.Resolver) (Writer, error)
ResolveWriter binds the writer during ordinary application construction, before the database starts. Generated callbacks retain it without a runtime service lookup or second application container.
type Snapshot ¶
type Snapshot struct {
// contains filtered or unexported fields
}
Snapshot owns one immutable audit value. It is an audit representation, not a model field or response DTO. Format omits content; JSON is an explicit export.
func (Snapshot) MarshalJSON ¶
MarshalJSON validates and encodes the snapshot's explicit audit representation.
func (*Snapshot) UnmarshalJSON ¶
UnmarshalJSON replaces the snapshot only after validating the complete representation. A nil receiver or invalid representation returns fault.Invalid.
type State ¶
type State uint8
State distinguishes missing model snapshots, disclosed SQL values, completely redacted values and JSON whose sensitive descendants have been redacted. SQL NULL is a disclosed SQL value, distinct from an absent model snapshot. Oversized marks a value that exceeded the audit value bound; its Digest retains the stored size and, when safe, a SHA-256 of the captured bytes.
type View ¶
type View[M, K any] struct { // contains filtered or unexported fields }
View indexes an immutable model audit once for generated typed field readers. Its map is private and owned; reading many fields does not repeatedly decode the entire payload. A zero view is invalid. A field missing from an update record was neither assigned nor changed by that operation.
type Writer ¶
type Writer interface {
// RecordModel stores a captured entry using the supplied business transaction.
// An error fails the associated model write.
RecordModel(context.Context, *database.Tx, Entry) error
}
Writer is the narrow storage boundary used by generated audit observers. The supplied transaction is the real business transaction; returning an error fails its model write. Implementations must support concurrent operations.