service

package
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 27, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package service provides the orchestration layer for pulse operations.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func SplitAnchorPath added in v0.8.0

func SplitAnchorPath(path string) (string, string, bool)

SplitAnchorPath is the exported form of splitAnchorPath, used by the pulse facade (Predict, Inspect) so anchor paths resolve consistently across every entry point. See splitAnchorPath for semantics.

Types

type AskInput added in v0.5.0

type AskInput struct {
	// Request is the structured processing request. Required.
	Request *types.Request

	// OnInvalid controls behavior when predict reports the request as
	// invalid. "" / "abort" returns a SERVICE_VALIDATION error; "suggest"
	// returns a successful AskOutput with structured Suggestions populated.
	OnInvalid string

	// PredictOnly skips Process even when predict succeeds. Predict
	// always runs; the caller can read schema info, streamability,
	// suggestions, and defaults_applied from PredictResult.
	PredictOnly bool
}

AskInput captures the per-call options the facade hands the service. Mirrors the public pulse.AskRequest shape but reads the cohort path from the embedded request's Cohort so the service does not duplicate the path-resolution dance.

type AskOutput added in v0.5.0

type AskOutput struct {
	// Predict is always populated when Ask returns without error.
	Predict *descriptor.PredictResult

	// Process is the execution result. Nil when PredictOnly=true,
	// nil when predict reported the request invalid (OnInvalid="suggest").
	Process *types.Response

	// Suggestions enumerates structured Fixup entries derived from every
	// predict error code's metadata template, de-duplicated by
	// (Code, Action). Empty when there were no errors or when
	// OnInvalid != "suggest".
	Suggestions []errors.Fixup

	// Errors / Warnings echo the predict envelope's entries so callers
	// can present them without re-running predict. Never nil — empty slices
	// when there are none.
	Errors   []*descriptor.EnvelopeEntry
	Warnings []*descriptor.EnvelopeEntry
}

AskOutput is the service-level envelope returned by Service.Ask. The facade re-marshals into the public pulse.AskResponse — see pulse.go.

type Cohort

type Cohort struct {
	// contains filtered or unexported fields
}

Cohort represents an opened .pulse file with its parsed schema. For shard archives Shards is populated in central-directory order (which equals shard insertion order). For single-file cohorts Shards is empty.

func (*Cohort) RecordCount

func (c *Cohort) RecordCount() (int64, error)

RecordCount returns the number of records in the cohort file. It reads the file and counts records based on the schema's per-record byte size.

func (*Cohort) Records

Records returns a streaming iterator over records in the cohort. Records are decoded lazily from disk — the full file is not materialized.

func (*Cohort) Schema

func (c *Cohort) Schema() *encoding.Schema

Schema returns the cohort's schema.

func (*Cohort) Shards added in v0.8.0

func (c *Cohort) Shards() []ShardEntry

Shards returns the shard manifest for an archive-backed cohort. Returns an empty slice for single-file cohorts. The returned slice is a defensive copy; callers may mutate freely.

type ComposeOptions added in v0.2.0

type ComposeOptions struct {
	// MaxWorkers caps concurrent in-flight Process calls. Zero means
	// runtime.GOMAXPROCS(0). Negative values are clamped to 1.
	MaxWorkers int

	// PerRequestTimeout, if positive, derives a context.WithTimeout for
	// each request. Zero means no per-request timeout (the parent ctx's
	// deadline still applies).
	PerRequestTimeout time.Duration

	// FailFast cancels in-flight siblings on the first request error.
	// Default is true: surface errors quickly. Set false to collect every
	// request's outcome (errors aggregated into a single CodedError with
	// per-index detail).
	FailFast bool
}

ComposeOptions controls parallel execution of a ComposedRequest.

Order of responses is always preserved — slot-by-index — regardless of MaxWorkers or completion order.

type Row added in v0.2.0

type Row = map[string]any

Row is a single result row in a processing stream. Aliased so callers can write `service.Row` without leaking the underlying map type.

type RowIter added in v0.2.0

type RowIter interface {
	Next(ctx context.Context) (Row, bool, error)
	Close() error
	// Metadata returns the run metadata (total/filtered row counts,
	// cohort filename). Available after the iterator is exhausted; may
	// return nil before then. Streaming consumers that need metadata
	// before draining should call Process instead.
	Metadata() *types.ResponseMetadata
}

RowIter is a pull-based iterator over a processing result. Next reports (row, true, nil) for each available row, then (nil, false, nil) on exhaustion. Close releases any underlying file handles.

Implementations are NOT goroutine-safe. A single consumer per iterator.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service is the orchestration layer connecting filesystem, encoding, and processing.

func New

func New(fsConfig *fs.Config) *Service

New creates a new Service with the given filesystem configuration. Smart-defaults resolution runs by default; call DisableDefaults to opt out per instance (or pass pulse.Options{DisableDefaults: true} via the facade).

func (*Service) AddShard added in v0.8.0

func (s *Service) AddShard(ctx context.Context, archivePath, shardPath string) error

AddShard appends shardPath to the archive at archivePath. The incoming shard is validated against the archive's canonical schema via ValidateStructuralCohesion + ValidateDictPrefixRule. If the dict prefix rule extends the canonical dictionary, the rewritten `_schema.pulse` payload reflects the extension.

v1 strategy: read the full archive into memory, append the new shard entry, rewrite the central directory + EOCD, and write the resulting bytes back via the atomic temp+rename pattern (§7.1). A future PR may implement true in-place append on top of lower-level zip primitives; the in-memory rebuild keeps semantics identical and crash-safe with minimal code surface.

func (*Service) Ask added in v0.5.0

func (s *Service) Ask(ctx context.Context, in AskInput) (*AskOutput, error)

Ask is the unified pipeline that collapses inspect → predict → process into one call. It opens the cohort file, validates the request against the schema via Predict, and on success runs Process. The exposed pulse.Ask facade is a thin shim over this method.

OnInvalid governs predict-invalid behavior:

  • "" or "abort" — return a SERVICE_VALIDATION error wrapping the predict envelope.
  • "suggest" — return AskOutput with Suggestions populated; Process stays nil.

PredictOnly skips execution even on a valid request (the caller's "what would happen if I ran this?" probe).

func (*Service) CompactShardArchive added in v0.8.0

func (s *Service) CompactShardArchive(ctx context.Context, archivePath string) error

CompactShardArchive rewrites the archive at archivePath to eliminate orphaned bytes from prior in-place mutations and refresh the canonical schema-doc metadata (aggregate_record_count + shard_count). The rewrite reads every shard payload (excluding the reserved `_schema.pulse` entry) in central-directory order, re-emits the canonical schema with the recomputed metadata, and writes the result via the standard atomic temp+rename pattern (§7.1).

v1 note: AddShard / RemoveShard already use temp+rename for the whole-archive rewrite, so v1 archives never accumulate orphan bytes from Pulse-issued mutations. Compact still has a job in v1: it refreshes the canonical _schema.pulse metadata that may have drifted (for example, if the archive was edited by a third-party zip tool outside Pulse) and is the explicit reclaim path for archives containing orphan bytes from any source. Future PRs may introduce true in-place AddShard atop lower-level zip primitives; Compact's contract remains identical — produce a clean archive byte-for-byte.

Errors:

  • PULSE_ARCHIVE_MAGIC_INVALID / PULSE_ARCHIVE_CORRUPT — surfaced when the source archive cannot be opened.
  • PULSE_SHARD_HEADER_INVALID — surfaced when a shard payload's header cannot be parsed during record-count recomputation.
  • SERVICE_RESOURCE — I/O failure on read, temp-write, or rename.

func (*Service) Compose

func (s *Service) Compose(ctx context.Context, composed *types.ComposedRequest) ([]*types.Response, error)

Compose executes multiple requests, returning a response for each.

func (*Service) ComposeParallel added in v0.2.0

func (s *Service) ComposeParallel(
	ctx context.Context,
	composed *types.ComposedRequest,
	opts ComposeOptions,
) ([]*types.Response, error)

ComposeParallel runs every request in composed concurrently across a bounded worker pool. Responses are returned in the same order as composed.Requests; per-request errors are surfaced according to opts.

Registry factories return fresh stateful instances per request, so concurrent Process calls do not share aggregator/attribute state. Geo and decimal aggregators dispatch through buffered code paths that are also safe for concurrent invocation (no shared mutable state).

func (*Service) CountRecords added in v0.10.0

func (s *Service) CountRecords(ctx context.Context, path string) (uint64, error)

CountRecords returns the total record count for the cohort at path without decoding any payload bytes. Three resolution paths:

  • Single-file `.pulse`: stat the file, stream the header + schema, and derive count = (file_size − header − schema) / record_stride. Bytes read is bounded by header + schema size — O(1) in the record count.
  • Shard archive (zip magic): read the archive's central directory
  • the reserved `_schema.pulse` entry. The SHRD trailer's AggregateRecordCount is the cached sum of every shard's record count; cohesive archives keep it in lockstep with the per-shard headers. Cost is O(N shards) for the directory walk, not O(total records).
  • Anchor path `archive#shard`: opens the archive's central directory and uses the named shard's header to derive count. Cost is O(shard payload size) today; the v1 contract is "no full-archive decode," not "header-only" for anchors.

Embedders that want strict O(1) for anchors can call pulse.Inspect(archive) and read the per-shard counts from the returned Shards slice.

func (*Service) CreateShardArchive added in v0.8.0

func (s *Service) CreateShardArchive(ctx context.Context, archivePath string, shardPaths []string) error

CreateShardArchive builds a fresh Pulse shard archive at archivePath from the constituent shardPaths. The first shard seeds the canonical schema; every other shard is validated via encoding.ValidateStructuralCohesion + encoding.ValidateDictPrefixRule. Dictionary growth across shards accumulates into the canonical schema. The archive is written to a temp path on the same filesystem and Rename'd over the destination — partial writes never appear at archivePath (atomic temp+rename, §7.1).

Errors:

  • PULSE_SHARD_RESERVED_NAME — any shardPath has basename `_schema.pulse`.
  • PULSE_SHARD_NAME_COLLISION — two shardPaths share a basename.
  • PULSE_SHARD_SCHEMA_MISMATCH / PULSE_SHARD_DICT_DIVERGENCE — propagated from cohesion validators.
  • SERVICE_VALIDATION — empty shardPaths.
  • SERVICE_RESOURCE — I/O failure on any input/output.

func (*Service) Extensions added in v0.7.0

func (s *Service) Extensions() *processing.ExtensionRegistry

Extensions returns the installed ExtensionRegistry, or nil when no extensions are registered. Exposed for descriptor/manifest emission and MCP schema-binding paths.

func (*Service) ExtensionsSnapshot added in v0.7.0

func (s *Service) ExtensionsSnapshot() *descriptor.ExtensionsSnapshot

ExtensionsSnapshot returns the descriptor-side projection of the registered extensions, or nil when no extensions are installed.

func (*Service) ExtractShard added in v0.8.0

func (s *Service) ExtractShard(ctx context.Context, archivePath, shardBasename string) (io.ReadCloser, error)

ExtractShard returns an io.ReadCloser over the named shard's standalone single-file `.pulse` bytes. The closer releases the archive resources; callers must invoke Close after draining.

func (*Service) Facet

func (s *Service) Facet(ctx context.Context, path string, field string) ([]string, error)

Facet returns distinct values for the named field in the cohort.

For categorical fields the dictionary is the authoritative source:

  • Single-file cohorts return the schema's field dictionary directly.
  • Shard archives return the canonical dictionary carried by `_schema.pulse`, which is guaranteed to be the union of every shard's per-shard dictionary by the append-only prefix rule enforced at insert time (sharding design contract §3.2). No record streaming is required.

For numeric fields the cohort is streamed once and the set of distinct values observed is returned in encounter order. For shard archives the stream spans every shard in central-directory (insertion) order — the union semantics specified in §5.4.

func (*Service) FacetSchema added in v0.7.0

func (s *Service) FacetSchema(ctx context.Context, req *types.FacetRequest) (*types.FacetResult, error)

FacetSchema is the rich multi-field facet implementation. The pulse.FacetSchema facade is a thin wrapper around this method.

Algorithm: one streaming pass over the cohort applies the base filterers, then for each requested field updates the appropriate accumulator (discrete dictionary count, online numeric stats, online histogram bin). Numeric percentiles force a buffered second-stage sort over the per-field non-null value slices. Additive contribution counts run a parallel discrete accumulator with the additive field's own filter clauses stripped from the base filter.

func (*Service) FilterToFile added in v0.8.1

func (s *Service) FilterToFile(ctx context.Context, src, dst, filterExpr string) (int64, error)

FilterToFile reads the .pulse cohort at src, evaluates filterExpr against every record using FILTER_EXPRESSION semantics, and writes a new .pulse cohort at dst containing only records that pass. Custom expr functions and lookup tables registered via pulse.Options.Extensions are honored.

Three input shapes are supported, dispatched on the first four bytes:

  • Single-file cohort (magic "PULSE\x00\x00\x00"): the dst is a single-file cohort whose header + schema bytes are copied byte-for-byte from src; only the record payload differs.

  • Shard archive (magic "PK\x03\x04"): the dst is a new shard archive preserving the per-shard layout — one input shard maps to one output shard at the same basename, in central-directory (insertion) order. Per-shard header + schema + categorical dictionary bytes are copied byte-for-byte (records inside each shard reference that shard's local dictionary, which is preserved under the prefix-rule invariant). Shards with zero surviving records are written as empty payloads (header + schema + zero record bytes). The canonical `_schema.pulse` trailer is refreshed: aggregate_record_count = sum of surviving rows across shards, shard_count = unchanged.

  • Anchor syntax `archive.pulse#shard.pulse`: resolves to a single shard inside an archive; dst is a single-file cohort built from that shard alone.

Returns the number of records written to dst (sum across shards for archive inputs).

func (*Service) FilterToFileBySetAndExpr added in v0.8.3

func (s *Service) FilterToFileBySetAndExpr(ctx context.Context, src, dst, includeField string, set processing.MemberSet, filterExpr string) (int64, error)

FilterToFileBySetAndExpr applies an include-set predicate (membership test against an externally-supplied list of values) and optionally a filter expression to every record in src, writing the survivors to dst. At least one of (set, filterExpr) must be supplied — if both, the set is tested first and the expression evaluated only on surviving rows (cheap-check-first short-circuit).

Input-shape dispatch matches FilterToFile (single-file, shard archive, anchor). includeField names the field whose value is tested for membership in set; the set must have been built against the same canonical schema as src (the field is resolved per-call to keep the predicate schema-coherent across shards).

Returns the number of records written to dst.

func (*Service) ListShards added in v0.8.0

func (s *Service) ListShards(ctx context.Context, archivePath string) ([]ShardEntry, error)

ListShards opens the archive and returns its ShardEntry slice in central-directory order (reuses Service.Open which peeks per-shard headers to populate RecordCount). Single-file cohorts return an empty slice.

func (*Service) Open

func (s *Service) Open(ctx context.Context, path string) (*Cohort, error)

Open reads a .pulse file and returns a Cohort with the parsed schema. Dispatches on the file's leading magic bytes:

  • "PULSE\x00\x00\x00" (single-file cohort) — reads header + schema directly from the file. Shards is empty.
  • "PK\x03\x04" (zip archive) — parses the zip central directory, reads the canonical schema from the reserved `_schema.pulse` entry, and populates Shards with every other entry in central-directory order. S1 leaves RecordCount at zero; later phases populate from `_schema.pulse` metadata or shard headers.

Returns PULSE_ARCHIVE_MAGIC_INVALID when the file matches neither magic, PULSE_ARCHIVE_CORRUPT when the zip EOCD or central directory is unreadable, and PULSE_SHARD_MISSING when an archive lacks the reserved `_schema.pulse` entry.

func (*Service) OpenAnchor added in v0.8.0

func (s *Service) OpenAnchor(_ context.Context, archivePath, entry string) (*Cohort, error)

OpenAnchor opens a single shard inside a Pulse shard archive as if it were a standalone single-file `.pulse` cohort. The schema is read from the shard's own header (NOT the archive's canonical schema) so anchor-addressed shards stand alone for the purposes of facade methods. Shards is empty on the returned Cohort.

Errors:

  • PULSE_ARCHIVE_MAGIC_INVALID — archivePath is not a Pulse shard archive.
  • PULSE_SHARD_MISSING — the named entry is not present in the archive.
  • PULSE_SHARD_RESERVED_NAME — entry is the reserved `_schema.pulse`.
  • PULSE_SHARD_HEADER_INVALID / ENCODING_INVALID — the shard payload is malformed.

func (*Service) Process

func (s *Service) Process(ctx context.Context, req *types.Request) (*types.Response, error)

Process executes a single request against the specified cohort. Records are streamed from disk — the full file is never held in memory as raw bytes alongside the decoded records.

func (*Service) ProcessChain added in v0.10.0

func (s *Service) ProcessChain(ctx context.Context, req *types.ChainRequest) (*types.ChainResponse, error)

ProcessChain executes a source-rooted linear chain of Process requests. The first stage runs against the cohort identified by req.Cohort; each subsequent stage receives the previous stage's rows as its input, materialised through an in-memory SliceIterator against a synthesised schema.

All stages must pass processing.CanChainRequest (mergeable + scalar-emitting aggregators only). The executor returns PULSE_CHAIN_NOT_MERGEABLE with the offending stage index in details on first failure, allowing callers to fall back to per-stage Process. Stage 0's Request.Cohort is replaced with req.Cohort; any Request.Cohort on stages >= 1 is ignored.

func (*Service) ProcessStream added in v0.2.0

func (s *Service) ProcessStream(ctx context.Context, req *types.Request) (RowIter, error)

ProcessStream executes a request and returns a pull-based row iterator over the result. The semantics match Process — same gates, same errors, same metadata — but the consumer can drain rows incrementally instead of receiving the whole []map[string]any up front.

Today the iterator buffers internally (calls Process and walks Data). The signature is forward-compatible with a future true-streaming path driven by the streaming Processor; consumers that adopt it now will pick up that change without a code change on their side.

func (*Service) ProjectBufferedFields added in v0.8.0

func (s *Service) ProjectBufferedFields() bool

ProjectBufferedFields reports the current setting. Read by callers that need to know whether to compute NeededFields ahead of time.

func (*Service) RemoveShard added in v0.8.0

func (s *Service) RemoveShard(ctx context.Context, archivePath, shardBasename string) error

RemoveShard rewrites the archive at archivePath omitting the named shard. The canonical schema is preserved (orphaned dictionary entries are retained — canonical only grows). Returns PULSE_SHARD_MISSING when the named shard is not present.

func (*Service) ResolveCanonicalSchema added in v0.8.3

func (s *Service) ResolveCanonicalSchema(_ context.Context, src string) (*encoding.Schema, error)

ResolveCanonicalSchema reads the canonical schema for src without streaming the record payload. Single-file cohorts return their own schema; shard archives return the canonical `_schema.pulse` schema; anchored shards return the anchored shard's local schema. Used by callers (notably the CLI cohort-filter include-from path) that need schema introspection to build an include-set before invoking FilterToFileBySetAndExpr.

func (*Service) Sample

func (s *Service) Sample(ctx context.Context, path string, n int) ([]map[string]any, error)

Sample returns up to n rows from the cohort as maps of field name to value. Streams from disk — stops reading as soon as n rows are collected. For shard archives the rows span the union of shards in central-directory (insertion) order; offset+limit apply globally across the union, never per-shard (sharding design contract §5.4).

func (*Service) SampleWithRequest added in v0.10.1

func (s *Service) SampleWithRequest(ctx context.Context, req *types.SampleRequest, path string) ([]map[string]any, []processing.ResolverWarning, error)

SampleWithRequest is the labelled variant. The req struct carries the cohort path (via Cohort.Filename), the row cap (N), and any LabelBinding entries that translate categorical values to display labels in the returned rows. Path resolution mirrors the rest of the facade — Cohort.Filename is resolved against the Service's data-dir / fs. Returns the rows plus the resolver-side warnings (PULSE_LABEL_COLLISION / PULSE_LABEL_LOOKUP_MISS) so callers can fold them into the response envelope at their boundary.

func (*Service) SetDisableDefaults added in v0.5.0

func (s *Service) SetDisableDefaults(disabled bool)

SetDisableDefaults toggles the smart-defaults pass. Predict still computes and reports DefaultsApplied independently; this flag governs only what the runtime mutates before Process / Compose execution.

func (*Service) SetExtensions added in v0.7.0

func (s *Service) SetExtensions(r *processing.ExtensionRegistry)

SetExtensions installs an ExtensionRegistry containing embedder- registered operator overlays. The registry is read-only after this call; pass nil to clear. The processor consults this registry before falling through to built-in factories.

func (*Service) SetExtensionsSnapshot added in v0.7.0

func (s *Service) SetExtensionsSnapshot(snap *descriptor.ExtensionsSnapshot)

SetExtensionsSnapshot installs the descriptor-side projection of the registered extensions for manifest + predict consumption. Pass nil to clear; pulse.New populates this alongside SetExtensions.

func (*Service) SetProjectBufferedFields added in v0.8.0

func (s *Service) SetProjectBufferedFields(enabled bool)

SetProjectBufferedFields enables buffered-decode field projection. When enabled the streaming iterator computes the set of fields a request actually reads (NeededFields) and skips map writes for fields outside that set. Per-record memory drops proportional to the projection ratio; decode CPU is unchanged. Default is false; pulse.Options{ProjectBufferedFields: true} opts in.

Extension operators without a registered FieldInputs hook widen the projection to "every field" automatically — projection is always a strict superset of the fields actually consumed, so it can never produce a wrong answer.

func (*Service) SetShardWorkers added in v0.8.0

func (s *Service) SetShardWorkers(n int)

SetShardWorkers configures the per-shard parallel worker pool cap. Zero falls back to runtime.NumCPU() at dispatch time; 1 disables parallelism (strictly serial path). Negative values are not rejected here — pulse.New() performs that validation at the public API boundary.

func (*Service) SetStrict added in v0.8.4

func (s *Service) SetStrict(strict bool)

SetStrict toggles the strict request-validation flag. When true, Process promotes the categorical-aggregation warning into a PULSE_AGG_NOT_MEANINGFUL_FOR_CATEGORICAL CodedError instead of running the request.

func (*Service) ShardWorkers added in v0.8.0

func (s *Service) ShardWorkers() int

ShardWorkers returns the configured cap. Exposed for tests and the shard-reduce orchestrator.

func (*Service) Strict added in v0.8.4

func (s *Service) Strict() bool

Strict reports the current strict-validation setting.

func (*Service) VerifyShardArchive added in v0.8.0

func (s *Service) VerifyShardArchive(ctx context.Context, archivePath string) (*VerifyResult, error)

VerifyShardArchive walks the archive at archivePath and re-validates every shard against the canonical schema. For every real shard (excluding `_schema.pulse`) it:

  1. Calls encoding.Archive.PeekShardHeader to check magic + format_version, raising PULSE_SHARD_HEADER_INVALID on mismatch.
  2. Parses the shard's full header + schema block.
  3. Calls encoding.ValidateStructuralCohesion against the canonical schema. Structural mismatches surface as PULSE_SHARD_SCHEMA_MISMATCH errors; per-field description divergence emits PULSE_SHARD_DESCRIPTION_DIVERGENCE warnings.
  4. Calls encoding.ValidateDictPrefixRule. Any prefix-rule violation surfaces as PULSE_SHARD_DICT_DIVERGENCE.
  5. Re-peeks the shard's record count and sums across the archive. A drift against the canonical AggregateRecordCount emits a warning (the live per-shard sum is authoritative per the design contract).

Returns a non-nil error only when the archive itself cannot be opened (PULSE_ARCHIVE_MAGIC_INVALID, PULSE_ARCHIVE_CORRUPT, SERVICE_RESOURCE). Per-shard cohesion failures are accumulated into VerifyResult.Errors so the caller renders the full diagnosis — partial failures should not mask later shards' issues.

type ShardEntry added in v0.8.0

type ShardEntry struct {
	// Filename is the basename of the shard inside the archive
	// (e.g. "20190101.pulse"). Equals the zip entry name.
	Filename string

	// RecordCount is the number of records carried by the shard. S1
	// leaves this at zero; S2 populates it either from the
	// `_schema.pulse` aggregate metadata or from a first-read peek of
	// the shard's own header.
	RecordCount int64
}

ShardEntry is one shard inside a Pulse shard archive. Populated on a Cohort opened against a `.pulse` artifact whose first four bytes match the zip magic; empty for single-file cohorts.

type VerifyResult added in v0.8.0

type VerifyResult struct {
	Errors   []*errors.CodedError       `json:"errors"`
	Warnings []encoding.CohesionWarning `json:"warnings"`
}

VerifyResult carries the structured outcome of VerifyShardArchive. Errors aggregates every fatal cohesion failure discovered while walking the archive's shards; Warnings carry non-fatal divergences (per-field description drift, aggregate-record-count drift). An empty Errors slice means the archive is structurally sound.

The shape parallels descriptor.Envelope's {errors, warnings} so callers can lift entries straight into the --json envelope without reshaping. encoding.CohesionWarning is the canonical warning carrier (shared with insert-time cohesion validators).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL