schema

package module
v0.1.0-rc2 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

README

peasant-labs/schema

The public API contract for Peasant and the village marketplace — a single, contract-only Go leaf module.

It holds the wire/domain types, the versioned OpenAPI specs, fixtures, the request validators, the village SQL migrations, and the codegen + release-guard tooling. It has no runtime: no HTTP server, no WebSocket hub, no CLI product. Both consumers (the peasant client and the village server) depend on it; it depends on nothing first-party except bestiary (a sibling dependency).

Module path: github.com/peasant-labs/schema

What's inside

Path What
*.go (root, package schema) Domain + wire types, content-hashing, metadata, push/pull contract types, annotations, the embedded-spec accessors (VillageAPISpecJSON).
versions.go Single source of truth for the versioned-spec semvers (VillageAPIVersion, PeasantLocalAPIVersion, TypesVersion).
openapi/ OpenAPI 3.1 spec builders (BuildVillageAPISpec, BuildPeasantLocalAPISpec, BuildTypesSpec) + the artifact generator.
generated/ Committed OpenAPI spec goldens (JSON + YAML) + the standalone PublishRequest JSON Schema. Gate-checked; regenerate with go run ./cmd/schema-gen.
publish_validate.go (root, package schema) ValidatePublishRequest — the JSON-Schema validator the village enforces on publish (compiles the PublishRequestSchemaJSON() bytes, so the served doc ≡ the enforced schema).
migrations/village/ Embedded village SQL migrations (embed.FS).
external/, testdata/, fixtures.go Vendored external schemas + test fixtures.
cmd/schema-gen/ Regenerates generated/ specs + Redoc/HTML docs. The contract gates' freshness/immutability/surface tests live here.
cmd/release-guard/ + internal/release/ The release pipeline's title/tag grammar + final-release guard CLI (see CONTRIBUTING).

Dev dependencies & provisioning

Everything is provisioned through Nix — the flake devShell IS the dev-dependency manifest (Go has no dev/prod dependency split). You do not install Go or any tool globally.

Prerequisites:

  • Nix with flakes enabled (experimental-features = nix-command flakes).
  • direnv with the nix-direnv integration (recommended).
cd <this-worktree>
direnv allow      # loads the flake devShell automatically on cd

The committed .envrc is just use flake .. On entry you'll see Go go1.26.3 dev shell, and go, gopls, golangci-lint, ast-grep, actionlint, etc. are on PATH.

Option B — nix develop
nix develop          # drops you into the dev shell
go test -race ./...
Build / test / regenerate
make check                     # the quality gate: gofmt + vet + release-workflow
                               #   guard + `go test -race ./...` (incl. leaf-audit +
                               #   oasdiff/go-apidiff synthetic-break tests)
make gates BASE_REF=origin/develop  # breaking-change gates vs a base ref
                               #   (oasdiff spec diff + go-apidiff + vacuum lint)
go run ./cmd/schema-gen        # regenerate generated/ specs + docs/api HTML
nix build                      # hermetic buildGoModule (cmd/schema-gen + cmd/release-guard)

make check is fully runnable with a bare go toolchain — the synthetic-break tests t.Skip (with an actionable message) when a gate binary is absent, and run for real inside nix develop. The committed contract goldens in generated/ must stay byte-identical to what go run ./cmd/schema-gen emits (the codegen-freshness gate), and retired spec versions are byte-frozen under the immutability gate. Run the generator and commit generated/ after any change to the Go schema source.

The leaf rule

This module's go.mod require set is a subset of: bestiary, santhosh-tekuri/jsonschema/v5, swaggest/jsonschema-go, swaggest/openapi-go, golang.org/x/crypto, gopkg.in/yaml.v3.

Contract-gate CLIs (oasdiff, go-apidiff, vacuum) are provisioned in the flake devTools, never in go.mod. See CONTRIBUTING for the leaf-audit and the no-local-replace (vendorHash-stability) rules.

Open items

  • LICENSE — Apache-2.0. The LICENSE file at the repo root carries the verbatim Apache License 2.0 text; the flake meta.license is the SPDX Apache-2.0 id (licenses.asl20).
  • CI + release pipeline — DONE (SLICE-B): contract gates (oasdiff / go-apidiff / vacuum, provisioned via the flake), tests.yml, release-pr.yml / release.yml, and nix-vendor-hash.yml. The release ceremony and the v0.1.0-rc1 cut are documented in docs/release-runbook.md.

Documentation

Index

Constants

View Source
const (
	HarnessClaudeCode  = bestiary.HarnessClaudeCode
	HarnessGeminiCLI   = bestiary.HarnessGeminiCLI
	HarnessCodex       = bestiary.HarnessCodex
	HarnessOpenCode    = bestiary.HarnessOpenCode
	HarnessCursor      = bestiary.HarnessCursor
	HarnessAntigravity = bestiary.HarnessAntigravity
)
View Source
const (
	// VillageAPIVersion is the info.version of the Village API spec. Bumped to
	// 0.2.0 when the /api/v1/pull surface was added (additive = minor bump).
	// Bumped to 0.3.0 (rc2 #118) when model + model.harness/model.model became
	// required — a tightening of the publish contract (selective required arrays on
	// SchemaPublishRequest + SchemaModelInfo). Bumped to 0.4.0 when
	// PublishRequest.License + PullTranscriptInfo.License were added (additive
	// optional field = minor bump). Each prior version's generated goldens are
	// retained byte-frozen under the retired-spec immutability guard.
	VillageAPIVersion = "0.4.0"
	// PeasantLocalAPIVersion is the info.version of the local dashboard API spec.
	// Bumped to 0.2.0 when the Map/Review/Search surface was added (8 additive ops
	// + FrictionCluster = minor bump). The retired 0.1.0 spec is retained byte-frozen
	// (no longer emitted) under the retired-versions immutability guard.
	PeasantLocalAPIVersion = "0.2.0"
	// TypesVersion is the info.version of the types spec (the foundational shared
	// domain types catalog; formerly "shared-types").
	TypesVersion = "0.1.0"
)

Versioned-spec info.version values. These are the SINGLE SOURCE OF TRUTH for each versioned OpenAPI spec's semantic version: they feed WithVersion(...) in the openapi.Build*Spec functions (re-exported there as openapi.VillageAPIVersion etc.), the generated artifact filenames, AND the version-aware accessors in this package (e.g. VillageAPISpecJSON). A version bump is a one-line edit here.

They live in the contract root (not the openapi sub-package) so the embedded-spec accessors below can key off them without an import cycle (openapi imports this package, so this package cannot import openapi).

Bump the relevant one when its API surface changes (minor for additive surface, major for breaking changes). Retired versions stay byte-frozen under the retired-spec immutability guard; new surface goes on a new version.

View Source
const MetadataSchemaVersion = 9

MetadataSchemaVersion is the schema version written by this build of the ingest tool. v1: initial schema v2: SQLite persistence layer, store integration v3: transcript filename {sessionId}--transcript.{ext} (was {unixMillis}--),

timestamp extraction scans all lines (was first/last line only)

v4: GitContext.Commits field added (session-to-commit linking) v5: Claude indexer fixes — system content extraction, tool_result tool_use_id linking v6: ContentHash, MetadataHash, RedactionInfo — deferred redaction model v7: CWD field — real working directory for context-aware slug redaction v8: DerivedAt field — Unix ms when metadata.json was derived from DB (DB as SOT) v9: harness key unification — UnifiedMetadata.ModelHarness re-keyed json:"modelHarness"

-> json:"harness" (SLICE-B1 emit-side flip). The bump forces the DIFF stage to
re-classify existing on-disk sessions as Updated so the stale "modelHarness" key
self-heals (re-extract + rewrite) on next ingest; UnmarshalJSON still accepts the
legacy key on pre-v9 files in the meantime.

Variables

AllAnnotationDatatypes is the canonical list of all known annotation datatypes.

AllAnnotationStatuses is the canonical list of all known annotation statuses.

AllAnnotatorKinds is the canonical list of all known annotator kinds.

AllClaudeBuiltinCmds is the canonical list of all known Claude Code built-in commands.

AllEntryTypes is the canonical list of all known entry types.

AllHarnesses is the canonical list of harnesses that peasant supports for ingestion.

AllLicenses is the canonical menu of known licenses.

AllOutcomes is the canonical list of all known session outcomes.

AllRoles is the canonical list of all known roles.

AllScaleKinds is the canonical list of all known scale kinds.

AllStopReasons is the canonical list of all known stop reasons.

AllTargetKinds is the canonical list of all known target kinds.

AllToolCallKinds is the canonical list of all known tool call kinds.

AllTypeOrigins is the canonical list of all known type origins.

View Source
var AllValueDomainKinds = []ValueDomainKind{
	DomainEnumerated, DomainDescribed,
}

AllValueDomainKinds is the canonical list of all known value domain kinds.

AllVisibilities is the canonical list of all known visibility levels.

View Source
var AnnotationsYAML []byte

AnnotationsYAML contains the raw YAML content for annotation test fixtures.

View Source
var ContractCorpusFS embed.FS

ContractCorpusFS is the push/pull back-compat golden corpus tree (testdata/contract/**): the current contract shape plus the retained legacy shapes (legacy-metadata-field / legacy-provider-keyed / legacy-raw-jsonl). Exported as an embed.FS so consumers (peasant internal/push back-compat round-trip tests) enumerate and read the corpus through the contract leaf rather than a cross-module filesystem path. Walk it from the "testdata/contract" root (e.g. fs.ReadDir(schema.ContractCorpusFS, "testdata/contract")).

View Source
var ErrCycleDetected = errors.New("annotation type dependency cycle detected")

ErrCycleDetected is returned when adding a dependency would create a cycle in the annotation_type_deps graph (V14: depth limit 20).

View Source
var ErrInvalidValue = errors.New("invalid annotation value")

ErrInvalidValue is returned when a value is not permissible for an annotation domain. Callers should wrap this error with fmt.Errorf("%w: ...", ErrInvalidValue) for context.

View Source
var ErrTypeNotFound = errors.New("annotation type not found")

ErrTypeNotFound is returned when a requested annotation type does not exist in the registry.

View Source
var EvalSchemaJSON []byte

EvalSchemaJSON is the vendored EEE (eval) JSON Schema (external/eee/eval.schema.json) — the contract that peasant's `export` surface validates its evaluation payloads against. Exported so consumers (peasant internal/export conformance + drift tests) read the schema through the contract leaf instead of a cross-module filesystem path. Provenance and re-vendoring policy: external/eee/PROVENANCE.md.

View Source
var PublishVerdictsYAML []byte

PublishVerdictsYAML contains the shared publish schema verdict corpus.

View Source
var PullManifestExampleJSON []byte

PullManifestExampleJSON is the golden one-complete-PullManifest example (round-trip shape-pin source).

View Source
var PullRefsYAML []byte

PullRefsYAML contains the raw YAML content for transcript-reference parse fixtures (internal/pull.ParseTranscriptRef).

View Source
var PullStatusesYAML []byte

PullStatusesYAML contains the raw YAML content for PullStatus<->wire mappings.

View Source
var QualitySessionsYAML []byte

QualitySessionsYAML contains the raw YAML content for mock quality sessions.

View Source
var RedactionExamples = []RedactionExample{
	{
		Name:                "aws_access_key",
		RuleID:              "aws_access_key",
		Category:            "secrets",
		Level:               RedactionLevelMinimal,
		OriginalText:        "AKIAIOSFODNN7EXAMPLE",
		RedactedReplacement: "<AWS_ACCESS_KEY>",
		Confidence:          98,
		LineNumber:          142,
		Description:         "AWS access key ID (pkg/redact rule: aws_access_key)",
	},
	{
		Name:                "email_address",
		RuleID:              "email",
		Category:            "pii",
		Level:               RedactionLevelStandard,
		OriginalText:        "vitor.eduardo@company.com",
		RedactedReplacement: "<EMAIL>",
		Confidence:          94,
		LineNumber:          587,
		Description:         "Email address (pkg/redact rule: email)",
	},
	{
		Name:                "home_directory",
		RuleID:              "unix_home_path",
		Category:            "paths",
		Level:               RedactionLevelMinimal,
		OriginalText:        "/Users/acme-dev/Projects/internal-api",
		RedactedReplacement: "/Users/<USER>/Projects/internal-api",
		Confidence:          72,
		LineNumber:          23,
		Description:         "Unix home directory path with username (pkg/redact rule: unix_home_path)",
	},
	{
		Name:                "github_token",
		RuleID:              "github_pat",
		Category:            "secrets",
		Level:               RedactionLevelMinimal,
		OriginalText:        "ghp_xK9mN2pL4qR7sT8vW1yZ3aB5cD6eF0gH12ab",
		RedactedReplacement: "<GITHUB_PAT>",
		Confidence:          96,
		LineNumber:          310,
		Description:         "GitHub personal access token (pkg/redact rule: github_pat)",
	},
	{
		Name:                "git_remote_url",
		RuleID:              "git_remote_https",
		Category:            "project",
		Level:               RedactionLevelStandard,
		OriginalText:        "https://github.com/acme-corp/internal-api",
		RedactedReplacement: "<PROJECT_URL>",
		Confidence:          61,
		LineNumber:          445,
		Description:         "Git remote URL exposing project identity (pkg/redact rule: git_remote_https)",
	},
	{
		Name:                "phone_number",
		RuleID:              "phone_us",
		Category:            "pii",
		Level:               RedactionLevelStandard,
		OriginalText:        "+1-555-867-5309",
		RedactedReplacement: "<PHONE>",
		Confidence:          89,
		LineNumber:          712,
		Description:         "US phone number (pkg/redact rule: phone_us)",
	},
	{
		Name:                "database_connection",
		RuleID:              "basic_auth_uri",
		Category:            "secrets",
		Level:               RedactionLevelMinimal,
		OriginalText:        "postgresql://admin:s3cretPass99@db.prod.internal:5432/maindb",
		RedactedReplacement: "postgresql://<BASIC_AUTH_URI>@db.prod.internal:5432/maindb",
		Confidence:          99,
		LineNumber:          18,
		Description:         "URL with embedded basic-auth credentials (pkg/redact rule: basic_auth_uri)",
	},
	{
		Name:                "workspace_path",
		RuleID:              "unix_home_path",
		Category:            "paths",
		Level:               RedactionLevelMinimal,
		OriginalText:        "/home/deploy/apps/acme-billing-service",
		RedactedReplacement: "/home/<USER>/apps/acme-billing-service",
		Confidence:          65,
		LineNumber:          891,
		Description:         "Unix home directory path with username (pkg/redact rule: unix_home_path)",
	},
	{
		Name:                "ip_address",
		RuleID:              "ip_address",
		Category:            "pii",
		Level:               RedactionLevelStandard,
		OriginalText:        "192.168.1.42",
		RedactedReplacement: "<IP_ADDRESS>",
		Confidence:          85,
		LineNumber:          156,
		Description:         "IPv4 address (pkg/redact rule: ip_address)",
	},
	{
		Name:                "slack_webhook",
		RuleID:              "slack_webhook_url",
		Category:            "secrets",
		Level:               RedactionLevelMinimal,
		OriginalText:        "https://hooks.slack.com/services/T024BE7LD/B0DAF2RC3/bJTqg8NS27FYm2pQL0jAiE",
		RedactedReplacement: "<SLACK_WEBHOOK_URL>",
		Confidence:          58,
		LineNumber:          234,
		Description:         "Slack incoming webhook URL (pkg/redact rule: slack_webhook_url)",
	},
	{
		Name:                "stripe_secret",
		RuleID:              "stripe_key",
		Category:            "secrets",
		Level:               RedactionLevelMinimal,
		OriginalText:        "sk_live_4eC39HqLyjWDarjtT1zdp7dc",
		RedactedReplacement: "<STRIPE_KEY>",
		Confidence:          92,
		LineNumber:          67,
		Description:         "Stripe API secret key (pkg/redact rule: stripe_key)",
	},
}

RedactionExamples is the canonical redaction example corpus — the CURRENT session-detail mock cases only (NOT the full pkg/redact corpus). Every RedactedReplacement here is the verbatim output of the real pkg/redact engine run on OriginalText at Level; the peasant conformance test (pkg/redact/redactconform_test.go) enforces that and fails on any drift.

View Source
var RedactionsYAML []byte

RedactionsYAML contains the GENERATED redaction example corpus (testdata/session-detail/redactions.yaml). It is produced by `go run ./cmd/schema-gen` from RedactionExamples (see redactions.go) and is the single source of truth consumed by peasant's behavioural conformance test (pkg/redact) and the web mock codegen. Regenerate + commit on any change to RedactionExamples; the leaf freshness gate enforces byte-identity.

View Source
var SessionsYAML []byte

SessionsYAML contains the raw YAML content for mock sessions.

Functions

func ComputeAnnotationHash

func ComputeAnnotationHash(
	annotationTypeID string,
	annotatorID string,
	value string,
	sessionID *string,
	entryIndex *int,
	endIndex *int,
	confidence *float64,
	reason *string,
	provenance *Provenance,
) string

ComputeAnnotationHash computes a SHA3-256 content hash over the core fields of an annotation for deduplication purposes. The hash is deterministic: the same annotation content always produces the same hex string.

Parameters mirror the annotation's content-bearing fields. Target-specific fields (sessionID, entryIndex, endIndex) are optional and contribute to the hash only when set (ensuring session-level and entry-level annotations of the same type/value/annotator produce different hashes).

func ComputeManifestDigest

func ComputeManifestDigest(hashes []string) string

ComputeManifestDigest computes a deterministic SHA3-256 digest over a SET of content-hashes. The result depends only on the underlying set, not on input order or duplicate multiplicity: the hashes are sorted and de-duplicated before hashing. Two callers observing the same logical set always produce the same digest, which is what makes the no-op short-circuit correct across machines.

The empty set hashes to a fixed, well-defined value (the digest of no input), so two empty manifests compare equal.

func ComputeMetadataHash

func ComputeMetadataHash(meta *UnifiedMetadata) string

ComputeMetadataHash computes the SHA3-256 hash of metadata fields, excluding ContentHash, MetadataHash, and Redaction to avoid circular dependency. Changing any content-bearing metadata field produces a different hash.

func ComputeTranscriptHash

func ComputeTranscriptHash(transcriptBytes []byte) string

ComputeTranscriptHash computes the SHA3-256 hash of raw transcript bytes. Used to detect content changes for incremental re-processing and stale redaction detection.

func HarnessDisplayName

func HarnessDisplayName(h Harness) string

HarnessDisplayName returns the human-readable name for a harness.

func HarnessJSONSchema

func HarnessJSONSchema() jsonschema.Schema

HarnessJSONSchema returns the JSON Schema for the Harness type. This is a standalone function because Harness is a type alias for bestiary.Harness, and Go does not allow methods on imported types.

func IsClaudeBuiltinCommand

func IsClaudeBuiltinCommand(name string) bool

IsClaudeBuiltinCommand reports whether name (with any leading slash stripped) matches a known Claude Code built-in command. Skill names like "aura:epoch" or "user-defined-command" will return false.

Examples:

IsClaudeBuiltinCommand("exit")   → true
IsClaudeBuiltinCommand("/exit")  → true
IsClaudeBuiltinCommand("aura:epoch") → false

func LicenseMenu

func LicenseMenu() string

LicenseMenu returns the known license IDs as a comma-separated string, derived from AllLicenses so help text and error messages can't drift from the canonical menu when a license is added.

func PublishRequestSchemaJSON

func PublishRequestSchemaJSON() []byte

PublishRequestSchemaJSON returns the standalone JSON-Schema (draft 2020-12) bytes for the PublishRequest wire format at the CURRENT VillageAPIVersion — the schema extracted from the Village API spec by openapi.BuildPublishRequestSchema and committed under generated/publish-request-<VillageAPIVersion>.schema.json.

This is the SINGLE BYTE-SOURCE the publish-enforce path validates against: schema.ValidatePublishRequest (root publish_validate.go) compiles exactly these bytes, and village's publish handler (W9 / Method 1) enforces through it rather than vendoring its own schema copy. Routing both the documented spec and the enforced schema through this one accessor means they can never drift (it retired the hand-maintained validate/schema.json, which had diverged from the generated artifact, and — rc2 #118 — folded the standalone `validate` subpackage into the root schema package).

It is version-aware: the filename is derived from VillageAPIVersion, never a literal, so a version bump in versions.go re-points it in lockstep. The bytes are embedded at compile time, so a miss here is a build/generation bug, not a runtime condition — it panics with an actionable message. The codegen-freshness gate and TestPublishRequestSchemaJSON_MatchesGenerated keep this unreachable in a healthy tree.

func RunPublishVerdicts

func RunPublishVerdicts(t *testing.T, validate func([]byte) error)

RunPublishVerdicts drives a publish-body validator over the ENTIRE shared publish-verdict corpus (testdata/publish/verdicts.yaml), in two passes — first the Acceptances() (schema_accepts:true), then the Rejections() (schema_accepts:false) — asserting each row's expectation with ASSERT-WHERE-PRESENT semantics (FINDING-2a):

  • an accepted row MUST validate with no error;
  • a rejected row MUST error;
  • WHERE a rejected row pins error_contains, the validator message MUST contain that exact (minimal/stable) substring — but rows WITHOUT error_contains are NOT required to carry one (no false-fail on the ~half the corpus that pins only error_category); and
  • EVERY rejected row MUST carry a non-empty error_category (no vacuous reject).

It is the one-call, reusable form of the accept/reject loop every corpus consumer would otherwise open-code, so the corpus stays the SINGLE source of publish-validation cases. Pass the validator under test — e.g. schema.RunPublishVerdicts(t, schema.ValidatePublishRequest) for the root client validator, or a compiled-schema closure for the extracted-schema side.

ERROR-STRING BREADCRUMB (FINDING-2b): the pinned error_contains substrings are coupled to the message text of github.com/santhosh-tekuri/jsonschema/v5, pinned at v5.3.1 (see go.mod). They are kept MINIMAL/stable on purpose — e.g. "value must be one of", "missing properties: 'model'"/'harness'", "does not match pattern". If a future jsonschema/v5 bump changes the wording, the error_contains assertions here (and TestPublishVerdicts_ErrorContainsPinnedStrings) fail loudly so the drift is diagnosable at the dep, not silently tolerated.

NOTE on placement: this helper takes *testing.T, so it necessarily imports "testing". It is isolated in this dedicated file (not the production-logic files) and is consumed only by _test packages (publish_validate_test, openapi); production code never calls it.

func ValidateAnnotationValue

func ValidateAnnotationValue(domain ValueDomain, value string) error

ValidateAnnotationValue checks that value is permissible for the given ValueDomain.

Rules:

  • value must not be empty (regardless of domain kind).
  • For enumerated domains: value must be in PermissibleValues.
  • For described domains: delegates to ValidateDescribedValue (datatype coercion + JSON schema).

Returns nil if valid. Returns an error wrapping ErrInvalidValue otherwise.

func ValidateDescribedValue

func ValidateDescribedValue(domain ValueDomain, value string) error

ValidateDescribedValue validates that value is permissible for the given described ValueDomain. It performs two checks in order:

  1. Datatype coercion: the string value must parse as the declared Datatype before schema validation. This catches "3.7" for an integer field before jsonschema sees it.

  2. JSON-schema validation: the ConstraintSpec is compiled (with caching) and the coerced Go value is validated against it.

Returns nil if valid, or an error wrapping ErrInvalidValue when rejected. Returns a non-ErrInvalidValue error when the ConstraintSpec is malformed JSON.

Callers:

  • ValidateAnnotationValue (delegated for described domains)

Where: annotation_validate.go ValidateDescribedValue.

func ValidatePublishRequest

func ValidatePublishRequest(data []byte) error

ValidatePublishRequest validates a publish-request JSON body against the generated PublishRequest JSON-Schema (the bytes PublishRequestSchemaJSON() returns for the current VillageAPIVersion). A non-nil error means the body is invalid — a type/enum/pattern violation, the rc2 (#118) required model object or its harness/model fields missing (e.g. "missing properties: 'model'"/'harness'), or not valid JSON — and the caller must reject it (the village maps this to HTTP 422). It returns nil for a conforming body, or the compile error if the embedded schema failed to compile at init.

func ValidateScaleDomainCombo

func ValidateScaleDomainCombo(scale ScaleKind, domain ValueDomainKind) error

ValidateScaleDomainCombo returns an error when the (scale, domain) combination is structurally incoherent:

  • described + ordinal: rejected because ordinal requires explicit ordering via permissible values (enumerated), not a range constraint.
  • enumerated + continuous: rejected because continuous ranges must be described with a JSON-schema constraint, not a finite list of permissible values.

func VillageAPISpecJSON

func VillageAPISpecJSON() []byte

VillageAPISpecJSON returns the JSON bytes of the CURRENT Village API OpenAPI spec — the version named by VillageAPIVersion. It is version-aware: the filename is derived from the single-source VillageAPIVersion constant, never a literal, so a version bump in versions.go re-points this accessor in lockstep and consumers (e.g. village's GET /openapi.json) need no change.

The bytes are embedded at compile time, so a failure here means the committed generated/ artifact for VillageAPIVersion is missing — a build/generation bug, not a runtime condition. It panics with an actionable message in that case; the codegen-freshness gate and TestVillageAPISpecJSON_MatchesCurrentVersion make this unreachable in a healthy tree.

Types

type ActivityEdge

type ActivityEdge struct {
	From      string `json:"from"`
	To        string `json:"to"`
	TaskCount int    `json:"taskCount"` // distinct tasks that edited both
}

ActivityEdge is a co-edit observation: two nodes repeatedly edited by the same tasks.

type AnnotationAxis

type AnnotationAxis string

AnnotationAxis is the subscription dimension for annotation channels.

const (
	AxisType    AnnotationAxis = "type"
	AxisSession AnnotationAxis = "session"
	AxisProject AnnotationAxis = "project"
)

type AnnotationDatatype

type AnnotationDatatype string

AnnotationDatatype is the storage type for annotation values.

const (
	DatatypeText    AnnotationDatatype = "text"
	DatatypeInteger AnnotationDatatype = "integer"
	DatatypeReal    AnnotationDatatype = "real"
	DatatypeBoolean AnnotationDatatype = "boolean"
)

func (AnnotationDatatype) IsValid

func (d AnnotationDatatype) IsValid() bool

IsValid returns true if the annotation datatype is one of the known variants.

func (AnnotationDatatype) JSONSchema

func (AnnotationDatatype) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (AnnotationDatatype) String

func (d AnnotationDatatype) String() string

type AnnotationEntryTarget

type AnnotationEntryTarget struct {
	SessionID  string `json:"sessionId"`
	EntryIndex int    `json:"entryIndex"`
	EndIndex   int    `json:"endIndex"` // half-open [start, end)
}

AnnotationEntryTarget identifies an entry-level annotation target. EndIndex is a half-open range [EntryIndex, EndIndex).

type AnnotationFixtureSummary

type AnnotationFixtureSummary struct {
	Name            string `yaml:"name"`
	ID              string `yaml:"id"`
	TargetKind      string `yaml:"targetKind"`
	TargetSessionID string `yaml:"targetSessionId,omitempty"`
	IsPrimary       bool   `yaml:"isPrimary"`
	AnnotatorKind   string `yaml:"annotatorKind"`
	AnnotatorName   string `yaml:"annotatorName"`
	TypeID          string `yaml:"typeId"`
	TypeName        string `yaml:"typeName"`
	Value           string `yaml:"value"`
	CreatedAt       int64  `yaml:"createdAt"`
}

AnnotationFixtureSummary is a named annotation template in YAML.

func (*AnnotationFixtureSummary) ToAnnotationSummary

func (f *AnnotationFixtureSummary) ToAnnotationSummary() AnnotationSummary

ToAnnotationSummary converts the fixture to a real AnnotationSummary.

type AnnotationFixtures

type AnnotationFixtures struct {
	Summaries   []AnnotationFixtureSummary   `yaml:"annotation_summaries"`
	Validations []SubscriptionValidationCase `yaml:"subscription_validations"`
}

AnnotationFixtures is the top-level YAML structure for annotation test data.

func LoadAnnotationFixtures

func LoadAnnotationFixtures() (*AnnotationFixtures, error)

LoadAnnotationFixtures parses AnnotationsYAML into structured fixtures.

func (*AnnotationFixtures) FindSummary

func (f *AnnotationFixtures) FindSummary(name string) *AnnotationFixtureSummary

FindSummary returns the fixture annotation with the given name, or nil.

type AnnotationManifestResponse

type AnnotationManifestResponse struct {
	// Hex-encoded SHA3-256 annotation content-hashes the village holds for the owner (sorted, de-duplicated).
	// Always emitted as a (possibly empty) NON-null array: NewAnnotationManifestResponse
	// normalizes via sortedUniqueHashes, which never returns nil — so nullable:"false"
	// is the correct wire contract (matches develop's served village-api spec).
	Hashes []string `` /* 148-byte string literal not displayed */
	// Deterministic, order-independent digest over the hash set; a client computing the same digest over its local set knows nothing diverged.
	Digest string `` /* 164-byte string literal not displayed */
}

AnnotationManifestResponse is the body returned by GET /api/v1/annotations/manifest (PROPOSAL-4 C3). It advertises the SET of annotation content-hashes the village currently holds for the authenticated owner, so a push client can SKIP any local annotation whose hash already appears here (server-authoritative skip-gate).

Hashes are hex-encoded SHA3-256 content-hashes — the SAME identity the client already computes via content_hash.go (ComputeContentHash / ComputeAnnotationHash). No annotation CONTENT is carried, only its hash, so the manifest is privacy-safe.

Digest is a deterministic, ORDER-INDEPENDENT digest over the hash set (see ComputeManifestDigest). A no-op re-push can short-circuit: if the client computes the same digest over its own local hash set, nothing has diverged.

This type is ADDITIVE — it introduces a new endpoint's response shape and does not alter any existing publish/annotation-push wire contract.

func NewAnnotationManifestResponse

func NewAnnotationManifestResponse(hashes []string) AnnotationManifestResponse

NewAnnotationManifestResponse builds a manifest from a set of content-hashes, normalizing the set (sorted + de-duplicated) and computing the matching digest.

Normalizing on construction means the wire payload is canonical: two villages holding the same logical set emit byte-identical manifests, and the Digest is always consistent with the Hashes it accompanies.

func (AnnotationManifestResponse) ComputeDigest

func (r AnnotationManifestResponse) ComputeDigest() string

ComputeDigest recomputes the order-independent digest over this manifest's Hashes. It is provided so a client can verify the server's Digest field or compare against its own locally-derived digest for the no-op short-circuit.

type AnnotationPushItem

type AnnotationPushItem struct {
	ContentHash   string                 `json:"contentHash"`
	TargetKind    TargetKind             `json:"targetKind"`
	SessionID     *string                `json:"sessionId,omitempty"`
	EntryTarget   *AnnotationEntryTarget `json:"entryTarget,omitempty"`
	AnnotationID  *string                `json:"annotationId,omitempty"`
	ProjectHash   *string                `json:"projectHash,omitempty"`
	TypeID        string                 `json:"typeId"`
	Value         string                 `json:"value"`
	IsPrimary     bool                   `json:"isPrimary"`
	Confidence    *float64               `json:"confidence,omitempty"`
	Reason        *string                `json:"reason,omitempty"`
	AnnotatorName string                 `json:"annotatorName,omitempty"`
	Provenance    *Provenance            `json:"provenance,omitempty"`
}

AnnotationPushItem is the wire type for a single annotation in a push request. ContentHash is SHA3-256 of the canonical JSON representation of all other fields, computed by ComputeContentHash(). Used for server-side deduplication.

func (*AnnotationPushItem) ComputeContentHash

func (item *AnnotationPushItem) ComputeContentHash() string

ComputeContentHash computes a SHA3-256 content hash over the canonical JSON representation of the AnnotationPushItem, excluding the ContentHash field itself.

The hash is deterministic: the same logical annotation always produces the same hex string regardless of struct field order. This is because encoding/json marshals struct fields in declaration order, producing stable output for the same values.

Use case: server-side deduplication. The caller sets item.ContentHash to this value before adding it to an AnnotationPushRequest.

type AnnotationPushRequest

type AnnotationPushRequest struct {
	Annotations []AnnotationPushItem `json:"annotations"`
	Retractions []string             `json:"retractions,omitempty"`
}

AnnotationPushRequest is the body sent to POST /api/v1/annotations.

Retractions (PROPOSAL-4 C3b) is an ADDITIVE, backwards-compatible field: a set of content-hashes the client wants the village to DROP (tombstone) for this owner. It carries propagated deletions/supersessions inline on the existing push request rather than via a separate DELETE endpoint (avoids a second auth/owner-scoping path and round-trip). The hashes are the SAME hex SHA3 content-hashes used for dedup; only hashes the owner authored AND locally retired are sent, so a foreign machine's annotation can never be retracted. omitempty preserves the prior wire shape for clients that send no retractions.

type AnnotationPushResponse

type AnnotationPushResponse struct {
	Created int                    `json:"created"`
	Updated int                    `json:"updated"`
	Skipped int                    `json:"skipped"`
	Errors  int                    `json:"errors"`
	Results []AnnotationPushResult `json:"results,omitempty"`
}

AnnotationPushResponse is returned by the village after processing an annotation push.

type AnnotationPushResult

type AnnotationPushResult struct {
	ContentHash string               `json:"contentHash,omitempty"`
	Status      AnnotationPushStatus `json:"status"`
	Error       string               `json:"error,omitempty"`
}

AnnotationPushResult is the per-item result within an AnnotationPushResponse.

type AnnotationPushStatus

type AnnotationPushStatus string

AnnotationPushStatus is the per-item outcome status from the village.

const (
	PushStatusCreated AnnotationPushStatus = "created"
	PushStatusUpdated AnnotationPushStatus = "updated"
	PushStatusSkipped AnnotationPushStatus = "skipped"
	PushStatusError   AnnotationPushStatus = "error"
)

func (AnnotationPushStatus) String

func (s AnnotationPushStatus) String() string

String returns the string representation of the push status.

type AnnotationRegistry

type AnnotationRegistry interface {
	AnnotationTypeReader

	// Register inserts a new annotation type from the given definition.
	// Returns the newly created AnnotationTypeSummary (status=proposed by default).
	Register(ctx context.Context, def TypeDefinition) (*AnnotationTypeSummary, error)

	// Activate transitions a type from proposed -> active.
	Activate(ctx context.Context, typeID string) error

	// Deprecate transitions a type from active -> deprecated, recording the superseding typeID.
	Deprecate(ctx context.Context, typeID string, supersededBy string) error

	// AddDependency records that typeID depends on dependsOn (V14: cycle detection enforced).
	// required=true means the dependency must be satisfied before typeID can produce a value.
	// rationale documents the reason for the dependency.
	AddDependency(ctx context.Context, typeID, dependsOn string, required bool, rationale string) error

	// GetDependencies returns the dependency entries for typeID.
	GetDependencies(ctx context.Context, typeID string) ([]TypeDependency, error)
}

AnnotationRegistry extends AnnotationTypeReader with mutation operations. Used by admin commands and the registry management layer.

type AnnotationStatus

type AnnotationStatus string

AnnotationStatus is the lifecycle state of an annotation type (ISO 11179 Part 6).

const (
	StatusProposed   AnnotationStatus = "proposed"
	StatusActive     AnnotationStatus = "active"
	StatusDeprecated AnnotationStatus = "deprecated"
	StatusRetired    AnnotationStatus = "retired"
)

func (AnnotationStatus) IsValid

func (s AnnotationStatus) IsValid() bool

IsValid returns true if the annotation status is one of the known variants.

func (AnnotationStatus) JSONSchema

func (AnnotationStatus) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (AnnotationStatus) String

func (s AnnotationStatus) String() string

type AnnotationSummary

type AnnotationSummary struct {
	ID                  string        `json:"id"`
	TargetKind          TargetKind    `json:"targetKind"`
	TargetSessionID     *string       `json:"targetSessionId,omitempty"`
	TargetEntryIndex    *int          `json:"targetEntryIndex,omitempty"`
	TargetEntryEndIndex *int          `json:"targetEntryEndIndex,omitempty"` // V16: half-open [start, end)
	TargetAnnotID       *string       `json:"targetAnnotationId,omitempty"`
	TargetProjectHash   *string       `json:"targetProjectHash,omitempty"`
	IsPrimary           bool          `json:"isPrimary"`
	AnnotatorKind       AnnotatorKind `json:"annotatorKind"`
	AnnotatorName       string        `json:"annotatorName"`
	TypeID              string        `json:"typeId"`
	TypeName            string        `json:"typeName"`
	Value               string        `json:"value"`
	Confidence          *float64      `json:"confidence,omitempty"`
	Reason              *string       `json:"reason,omitempty"`
	Provenance          *Provenance   `json:"provenance,omitempty"`
	ContentHash         *string       `json:"contentHash,omitempty"` // V16: push dedup
	CreatedAt           int64         `json:"createdAt"`
	SupersededBy        *string       `json:"supersededBy,omitempty"`
}

AnnotationSummary is the wire format for annotations in API responses. TargetKind is derived via TPT child table JOINs (annotations_with_target view).

type AnnotationTypeReader

type AnnotationTypeReader interface {
	// GetType returns the annotation type summary for the given type_id string.
	// Returns an error wrapping ErrTypeNotFound if no matching type exists.
	GetType(ctx context.Context, typeID string) (*AnnotationTypeSummary, error)

	// ListTypes returns all annotation types matching the given filter.
	// An empty TypeFilter returns all non-deprecated/retired types.
	ListTypes(ctx context.Context, f TypeFilter) ([]AnnotationTypeSummary, error)

	// ValidateValue validates that value is permissible for the annotation type identified by typeID.
	// Returns nil if valid. Returns an error wrapping ErrTypeNotFound if the type does not exist,
	// or an error wrapping ErrInvalidValue if the value is not permissible.
	ValidateValue(ctx context.Context, typeID string, value string) error
}

AnnotationTypeReader provides read-only access to the annotation type registry. Consumed by classifiers, the ingest pipeline, and the REST API handler. Returns AnnotationTypeSummary (wire type) — the internal domain object stays in internal/annotations.

type AnnotationTypeSummary

type AnnotationTypeSummary struct {
	ID               string           `json:"id,omitempty"` // UUID PK — populated from store for CLI use; omitted in REST responses
	TypeID           string           `json:"typeId"`
	Version          int              `json:"version"`
	DisplayName      string           `json:"displayName"`
	Description      string           `json:"description,omitempty"`
	Family           string           `json:"family"`
	Class            string           `json:"class"`
	ScaleKind        ScaleKind        `json:"scaleKind,omitempty"` // measurement level (ISO 11179 Part 5)
	ValueDomain      ValueDomain      `json:"valueDomain"`
	LowerIsBetter    *bool            `json:"lowerIsBetter,omitempty"`
	Status           AnnotationStatus `json:"status"`
	Origin           TypeOrigin       `json:"origin"`
	PriorityOverride *int             `json:"priorityOverride,omitempty"`
	// AllowedTargetKinds lists the target kinds this type may annotate (V16).
	// Empty/omitted means the type places no restriction (all kinds allowed).
	// Clients filter entry-level pickers to types whose list includes "entry".
	AllowedTargetKinds []TargetKind `json:"allowedTargetKinds,omitempty"`
}

AnnotationTypeSummary is the wire format for annotation types in API responses. Class is derived via the annotation_families → annotation_classes join (BCNF: no redundant column).

type AnnotationsPayload

type AnnotationsPayload struct {
	Axis        AnnotationAxis      `json:"axis"`
	ID          string              `json:"id"`
	Annotations []AnnotationSummary `json:"annotations"`
}

AnnotationsPayload is the data sent on the annotations WebSocket channel. Axis and ID echo the subscription parameters so clients can correlate updates.

type AnnotatorKind

type AnnotatorKind string

AnnotatorKind identifies the type of entity that produced an annotation. Priority for effective annotation resolution: human(3) > agent(2) > rule(1).

const (
	AnnotatorHuman AnnotatorKind = "human"
	AnnotatorAgent AnnotatorKind = "agent"
	AnnotatorRule  AnnotatorKind = "rule"
)

func (AnnotatorKind) IsValid

func (k AnnotatorKind) IsValid() bool

IsValid returns true if the annotator kind is one of the known variants.

func (AnnotatorKind) JSONSchema

func (AnnotatorKind) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (AnnotatorKind) Priority

func (k AnnotatorKind) Priority() int

Priority returns the resolution priority for effective annotation selection. Higher value wins: human(3) > agent(2) > rule(1). Returns 0 for unknown kinds.

func (AnnotatorKind) String

func (k AnnotatorKind) String() string

type AnnotatorSummary

type AnnotatorSummary struct {
	ID          string        `json:"id"`
	Kind        AnnotatorKind `json:"kind"`
	Name        string        `json:"name"`
	DisplayName string        `json:"displayName"`
	Description string        `json:"description,omitempty"`
	ModelID     *string       `json:"modelId,omitempty"`
	// DO NOT TOUCH (TRAP): ProviderKey is the model-VENDOR credential
	// (e.g. "anthropic"), a DIFFERENT axis from the coding-tool Harness. The
	// SLICE-B1 harness changeover left this as json:"providerKey" on purpose.
	// Never flip it to json:"harness" — enforced by ast-grep/no-trap-harness-flip.yml.
	ProviderKey *string `json:"providerKey,omitempty"`
	Status      string  `json:"status"`
}

AnnotatorSummary is the wire format for annotators in API responses. ModelID and ProviderKey are only populated for agent annotators.

type BatchCreateAnnotationsErrorResponse

type BatchCreateAnnotationsErrorResponse struct {
	Error        string `json:"error"`
	FailingIndex int    `json:"failingIndex"`
}

BatchCreateAnnotationsErrorResponse is the JSON error response for POST /api/v1/annotations/batch (400). FailingIndex is the zero-based index of the first annotation that failed validation.

type BatchCreateAnnotationsRequest

type BatchCreateAnnotationsRequest struct {
	Annotations []CreateAnnotationRequest `json:"annotations"`
}

BatchCreateAnnotationsRequest is the JSON body for POST /api/v1/annotations/batch. All annotations are committed as a single all-or-nothing SQLite transaction.

type BatchCreateAnnotationsResponse

type BatchCreateAnnotationsResponse struct {
	IDs []string `json:"ids"`
}

BatchCreateAnnotationsResponse is the JSON response for POST /api/v1/annotations/batch (201 Created). IDs are returned in the same order as the request Annotations slice.

type BuiltinCommand

type BuiltinCommand string

BuiltinCommand represents a built-in slash command supported by Claude Code. These are first-party commands that ship with the tool (e.g. /exit, /compact). Slash-command entries in transcripts whose name matches a BuiltinCommand are structural signals rather than user-initiated tool calls.

const (
	ClaudeBuiltinCmdExit             BuiltinCommand = "exit"
	ClaudeBuiltinCmdCompact          BuiltinCommand = "compact"
	ClaudeBuiltinCmdClear            BuiltinCommand = "clear"
	ClaudeBuiltinCmdNew              BuiltinCommand = "new"
	ClaudeBuiltinCmdModel            BuiltinCommand = "model"
	ClaudeBuiltinCmdUsage            BuiltinCommand = "usage"
	ClaudeBuiltinCmdCost             BuiltinCommand = "cost"
	ClaudeBuiltinCmdContext          BuiltinCommand = "context"
	ClaudeBuiltinCmdPlugin           BuiltinCommand = "plugin"
	ClaudeBuiltinCmdPermissions      BuiltinCommand = "permissions"
	ClaudeBuiltinCmdLogin            BuiltinCommand = "login"
	ClaudeBuiltinCmdResume           BuiltinCommand = "resume"
	ClaudeBuiltinCmdPlan             BuiltinCommand = "plan"
	ClaudeBuiltinCmdFast             BuiltinCommand = "fast"
	ClaudeBuiltinCmdVoice            BuiltinCommand = "voice"
	ClaudeBuiltinCmdTodos            BuiltinCommand = "todos"
	ClaudeBuiltinCmdReloadPlugins    BuiltinCommand = "reload-plugins"
	ClaudeBuiltinCmdSandbox          BuiltinCommand = "sandbox"
	ClaudeBuiltinCmdConfig           BuiltinCommand = "config"
	ClaudeBuiltinCmdStatusline       BuiltinCommand = "statusline"
	ClaudeBuiltinCmdUpgrade          BuiltinCommand = "upgrade"
	ClaudeBuiltinCmdExtraUsage       BuiltinCommand = "extra-usage"
	ClaudeBuiltinCmdRateLimitOptions BuiltinCommand = "rate-limit-options"
	ClaudeBuiltinCmdPrivacySettings  BuiltinCommand = "privacy-settings"
	ClaudeBuiltinCmdHelp             BuiltinCommand = "help"
	ClaudeBuiltinCmdCommands         BuiltinCommand = "commands"
)

func (BuiltinCommand) IsValid

func (c BuiltinCommand) IsValid() bool

IsValid returns true if the command is one of the known built-in variants. Derived from AllClaudeBuiltinCmds (single source of truth).

func (BuiltinCommand) String

func (c BuiltinCommand) String() string

type CLILoginQuery

type CLILoginQuery struct {
	Port  int    `json:"port" query:"port" description:"Local callback server port"`
	State string `json:"state" query:"state" description:"OAuth state parameter for CSRF protection"`
}

CLILoginQuery represents the query parameters for the CLI login initiation endpoint. GET /api/v1/auth/cli/login?port={port}&state={state}

type ChangeBinding

type ChangeBinding string

ChangeBinding states how strongly a session is tied to a change (contract §2 binding rule, spec §6.2).

const (
	ChangeBindingBound     ChangeBinding = "bound"
	ChangeBindingCandidate ChangeBinding = "candidate"
)

ChangeBinding values. A session is bound when at least one of its linked commits is contained in the branch AND its recorded edits overlap the branch's changed files; one-arm matches (or git_branch equality alone) are candidates. Candidates are never silently dropped.

func (ChangeBinding) IsValid

func (b ChangeBinding) IsValid() bool

IsValid reports whether b is one of the defined bindings.

func (ChangeBinding) String

func (b ChangeBinding) String() string

String returns the wire representation of the binding.

type ChangeDetailPayload

type ChangeDetailPayload struct {
	Branch            string          `json:"branch"`
	BaseRef           string          `json:"baseRef"` // merge-base hash
	DefaultBranch     string          `json:"defaultBranch"`
	Files             []FileChange    `json:"files"`
	Slice             MapSlice        `json:"slice"` // touched nodes + 1-hop
	NewEdges          []MapEdge       `json:"newEdges"`
	RemovedEdges      []MapEdge       `json:"removedEdges"`
	NewNodes          []string        `json:"newNodes"` // node IDs
	RemovedNodes      []string        `json:"removedNodes"`
	Violations        []EdgeViolation `json:"violations"` // NEW violations introduced by this change
	Work              []ChangeSession `json:"work"`
	UnrecordedCommits []CommitRef     `json:"unrecordedCommits"`
	// Unusual holds NEUTRAL rate-elevation observations vs the project baseline
	// (e.g. more retry loops per conversation than usual) — facts, never a
	// verdict or grade (Round 4.4).
	Unusual []UnusualSignal `json:"unusual"`
	// Frictions holds NEUTRAL recurring-friction counts keyed by (kind, file):
	// "this kind of friction touched this file N times across M conversations"
	// — facts for orientation, never a verdict (Round 5.1).
	Frictions    []FrictionCluster `json:"frictions"`
	LinesAdded   int               `json:"linesAdded"`
	LinesRemoved int               `json:"linesRemoved"`
	OutputTokens int64             `json:"outputTokens"` // SUM of output_tokens over bound sessions
	CostUsd      *float64          `json:"costUsd,omitempty"`
}

ChangeDetailPayload backs the Review change-detail surface, served by GET /api/v1/review/{projectHash}/change?branch=<name>.

func NewChangeDetailPayload

func NewChangeDetailPayload(branch string) *ChangeDetailPayload

NewChangeDetailPayload returns a ChangeDetailPayload with all slices (including the nested MapSlice's) initialized to empty (never-nil marshal guarantee).

type ChangeDiffPayload

type ChangeDiffPayload struct {
	Branch    string     `json:"branch"`
	File      string     `json:"file"` // the new path
	OldPath   *string    `json:"oldPath,omitempty"`
	Status    string     `json:"status"` // "M" | "A" | "D" | "R"
	Binary    bool       `json:"binary"`
	Truncated bool       `json:"truncated"`
	Hunks     []DiffHunk `json:"hunks"`
}

ChangeDiffPayload is the rendered unified diff of ONE changed file of a change (branch vs its merge-base with the default branch) — the lazy per-file companion to ChangeDetailPayload (contract §3, GET /review/{projectHash}/diff ?branch=&file=). Binary files come back Binary=true with no hunks; files exceeding the size cap come back Truncated.

func NewChangeDiffPayload

func NewChangeDiffPayload(branch, file string) *ChangeDiffPayload

NewChangeDiffPayload returns a ChangeDiffPayload with Hunks initialized to empty (never-nil marshal guarantee).

type ChangeSession

type ChangeSession struct {
	SessionID string        `json:"sessionId"`
	Title     string        `json:"title"`
	Harness   string        `json:"harness"`
	StartMs   *int64        `json:"startMs,omitempty"`
	Binding   ChangeBinding `json:"binding"` // bound = commit-in-branch AND touch overlap; candidate = one arm only
	Tasks     []TaskSummary `json:"tasks"`
}

ChangeSession is one recorded session behind a change, with its tasks.

func NewChangeSession

func NewChangeSession(sessionID string, binding ChangeBinding) ChangeSession

NewChangeSession returns a ChangeSession with all slices initialized to empty (never-nil marshal guarantee).

type ChangeSummary

type ChangeSummary struct {
	Branch       string `json:"branch"`
	AheadCount   int    `json:"aheadCount"`
	BehindCount  int    `json:"behindCount"`
	FilesChanged int    `json:"filesChanged"`
	SessionCount int    `json:"sessionCount"`
	TaskCount    int    `json:"taskCount"`
	NewEdges     int    `json:"newEdges"`
	RemovedEdges int    `json:"removedEdges"`
	Violations   int    `json:"violations"`
	LastWorkMs   *int64 `json:"lastWorkMs,omitempty"`
	Merged       bool   `json:"merged"`
	MergedAtMs   *int64 `json:"mergedAtMs,omitempty"`
	// Reverted is true when this change was merged and later undone by a
	// `git revert` on the default branch (git-native signal only). Round 4.5.
	Reverted bool `json:"reverted,omitempty"`

	// Graph anchors (Changes graph): how this row attaches to lane 0
	// (ReviewListPayload.RecentCommits). Open branches fork at BaseHash and
	// sit at TipCommitMs; merged rows rejoin at MergeCommitHash.
	BaseHash        string `json:"baseHash,omitempty"`        // merge-base commit hash (fork anchor; open branches)
	TipCommitMs     *int64 `json:"tipCommitMs,omitempty"`     // branch tip committer time (row position; open branches)
	MergeCommitHash string `json:"mergeCommitHash,omitempty"` // merge commit hash (join anchor; merged rows)
}

ChangeSummary is one row of the Review list: a local branch measured against the default branch.

type ChannelSubscription

type ChannelSubscription struct {
	Topic ChannelTopic   `json:"topic"`
	ID    string         `json:"id,omitempty"`
	Axis  AnnotationAxis `json:"axis,omitempty"`
}

ChannelSubscription describes a single channel subscription. Topic is always required. Additional fields are topic-specific:

  • TopicSessionDetail: ID = session ID
  • TopicAnnotations: Axis + ID

type ChannelTopic

type ChannelTopic string

ChannelTopic identifies a subscribable data stream.

const (
	TopicDashboard          ChannelTopic = "dashboard"
	TopicSessions           ChannelTopic = "sessions"
	TopicSessionDetail      ChannelTopic = "session_detail"
	TopicTrends             ChannelTopic = "trends"
	TopicQuality            ChannelTopic = "quality"
	TopicAnnotations        ChannelTopic = "annotations"
	TopicProjectFamiliarity ChannelTopic = "project_familiarity"
)

type ChildSessionRef

type ChildSessionRef struct {
	ID        string    `json:"id"`
	StartTime time.Time `json:"startTime"`
	Project   string    `json:"project,omitempty"`
}

ChildSessionRef is a lightweight reference to a child (subagent) session.

type ClientMessage

type ClientMessage struct {
	Type     MessageType           `json:"type"`
	Channels []ChannelSubscription `json:"channels,omitempty"`
}

ClientMessage is sent from the browser to the server via WebSocket.

type CommitInfo

type CommitInfo struct {
	Hash        string `json:"hash"`        // commit SHA-1 (full or abbreviated)
	Message     string `json:"message"`     // commit message first line
	AuthorName  string `json:"authorName"`  // author display name
	AuthorEmail string `json:"authorEmail"` // author email (used for attribution filtering)
	CommitTime  int64  `json:"commitTime"`  // committer date, Unix millis
	AuthorTime  int64  `json:"authorTime"`  // author date, Unix millis
}

CommitInfo records a single git commit linked to a session.

type CommitRef

type CommitRef struct {
	Hash       string `json:"hash"`
	Subject    string `json:"subject"`
	TimeMs     *int64 `json:"timeMs,omitempty"`
	HasSession bool   `json:"hasSession"` // a recorded session is bound to it
}

CommitRef is lightweight commit metadata for time strips and rail panels.

type ContentKind

type ContentKind string

ContentKind discriminates the concrete payload carried inside a TranscriptContent envelope. It exists so the village can dispatch on the kind without sniffing the payload, and so future kinds (e.g. raw-jsonl passthrough) can be added without changing the envelope shape.

const ContentKindSessionDetail ContentKind = "session_detail"

ContentKindSessionDetail marks an envelope whose SessionDetail field carries a normalized SessionDetailPayload. It is the only kind peasant currently emits.

func (ContentKind) String

func (k ContentKind) String() string

String returns the bare kind string for serialization/log boundaries.

type ContractVersion

type ContractVersion string

ContractVersion is the semantic version of a peasant/village WIRE contract. It is a newtype over string so that the version flows through the codebase typed rather than stringly. The same value-type carries BOTH axes (push and pull): they share one semver shape and one comparison/classification machinery, and the field/constant NAME disambiguates the axis (PushContractVersion vs PullContractVersion). See the PushContractVersion alias below.

It tracks the push/village wire SEPARATELY from:

  • MetadataSchemaVersion (the on-disk {sessionId}--metadata.json structure), and
  • ingest.CurrentIndexVersion (the local indexer evolution),

mirroring the CurrentIndexVersion precedent: a single canonical constant (defaults.PublishSchemaVersion) is the source of truth, bumped on a breaking change to the push wire format.

func (ContractVersion) String

func (v ContractVersion) String() string

String returns the bare semver string for serialization boundaries (OpenAPI filenames, JSON tags handled by the marshaller, CLI output).

type CreateAnnotationRequest

type CreateAnnotationRequest struct {
	SessionID     string   `json:"sessionId"`
	TypeID        string   `json:"typeId"`
	Value         string   `json:"value"`
	IsPrimary     bool     `json:"isPrimary"`
	Confidence    *float64 `json:"confidence,omitempty"`
	Reason        *string  `json:"reason,omitempty"`
	AnnotatorName string   `json:"annotatorName,omitempty"`
	// Entry-level targeting — if set, creates an annotation_target_entry row.
	// TargetEntryEndIndex defaults to TargetEntryIndex+1 (single-entry span) when omitted.
	TargetEntryIndex    *int `json:"targetEntryIndex,omitempty"`
	TargetEntryEndIndex *int `json:"targetEntryEndIndex,omitempty"`
	// Meta-annotation targeting — if set, creates an annotation_target_annotation row.
	TargetAnnotationID *string `json:"targetAnnotationId,omitempty"`
}

CreateAnnotationRequest is the JSON body for POST /api/v1/annotations. Target selection rules (mutually exclusive):

  • Session-level: SessionID set, no entry/annotation fields.
  • Entry-level: SessionID + TargetEntryIndex set; TargetEntryEndIndex optional (defaults to index+1).
  • Meta-annotation: TargetAnnotationID set (annotation on annotation).

type CreateAnnotationResponse

type CreateAnnotationResponse struct {
	ID string `json:"id"`
}

CreateAnnotationResponse is the JSON response for POST /api/v1/annotations (201 Created).

type DashboardPayload

type DashboardPayload struct {
	TotalSessions      int             `json:"totalSessions"`
	TotalTokens        int             `json:"totalTokens"`
	AvgDurationMins    float64         `json:"avgDurationMins"`
	HarnessBreakdown   map[Harness]int `json:"harnessBreakdown"`
	AvgTurnsPerSession float64         `json:"avgTurnsPerSession"`
	AcceptanceRate     float64         `json:"acceptanceRate"`
}

DashboardPayload is the data sent on the dashboard WebSocket channel.

type DayStats

type DayStats struct {
	Date     string `json:"date"` // "2006-01-02" format
	Tokens   int    `json:"tokens"`
	Sessions int    `json:"sessions"`
}

DayStats holds aggregated data for a single day in trends.

type DecayLevel

type DecayLevel string

DecayLevel classifies how recently a file was engaged.

const (
	DecayFresh      DecayLevel = "fresh"
	DecayFading     DecayLevel = "fading"
	DecayStale      DecayLevel = "stale"
	DecayUnexplored DecayLevel = "unexplored"
)

func (DecayLevel) String

func (d DecayLevel) String() string

type DiagnosticEntry

type DiagnosticEntry struct {
	ErrorType   string `json:"errorType"`   // e.g. "parse_error", "permission_denied", "copy_failed"
	Location    string `json:"location"`    // e.g. "line 47", "debug/tool_output_3.json"
	Message     string `json:"message"`     // Human-readable description
	Remediation string `json:"remediation"` // Actionable fix suggestion
}

DiagnosticEntry is a structured error object recorded during ingestion or processing.

type DiagnosticsInfo

type DiagnosticsInfo struct {
	Warnings []DiagnosticEntry `json:"warnings"`
	Partial  *bool             `json:"partial,omitempty"` // true if any file copy failed; nil if not determined
}

DiagnosticsInfo records issues encountered during ingestion.

type DiffHunk

type DiffHunk struct {
	OldStart int        `json:"oldStart"`
	OldLines int        `json:"oldLines"`
	NewStart int        `json:"newStart"`
	NewLines int        `json:"newLines"`
	Header   string     `json:"header,omitempty"`
	Lines    []DiffLine `json:"lines"`
	// Attribution (the mission climax): the recorded conversation that wrote
	// most of this hunk's added lines, resolved via git blame → commit →
	// session. Empty when the hunk's new lines trace to no recorded session
	// (hand-written, or authored outside this tool).
	SessionID    string `json:"sessionId,omitempty"`
	SessionTitle string `json:"sessionTitle,omitempty"`
}

DiffHunk is one "@@ -oldStart,oldLines +newStart,newLines @@" section. Line numbers in the gutter are derivable from OldStart/NewStart plus position.

type DiffLine

type DiffLine struct {
	Kind string `json:"kind"`
	Text string `json:"text"`
}

DiffLine is one line within a hunk. Kind is "context" | "add" | "del"; Text excludes the leading +/-/space marker.

type EdgeViolation

type EdgeViolation struct {
	Kind EdgeViolationKind `json:"kind"`
	From string            `json:"from"`
	To   string            `json:"to"`
}

EdgeViolation flags an edge that breaks the layering discipline.

type EdgeViolationKind

type EdgeViolationKind string

EdgeViolationKind classifies a structural violation on the map.

const (
	EdgeViolationCycle    EdgeViolationKind = "cycle"
	EdgeViolationWrongWay EdgeViolationKind = "wrong_way"
)

EdgeViolationKind values (mirrors codegraph's violation kinds).

func (EdgeViolationKind) IsValid

func (k EdgeViolationKind) IsValid() bool

IsValid reports whether k is one of the defined violation kinds.

func (EdgeViolationKind) String

func (k EdgeViolationKind) String() string

String returns the wire representation of the violation kind.

type EntryType

type EntryType string

EntryType classifies a single entry within an agent session transcript.

const (
	EntryTypeText       EntryType = "text"
	EntryTypeToolUse    EntryType = "tool_use"
	EntryTypeToolResult EntryType = "tool_result"
	EntryTypeThinking   EntryType = "thinking"
	EntryTypeSystem     EntryType = "system"
	EntryTypeError      EntryType = "error"
	EntryTypeResult     EntryType = "result"
)

func (EntryType) IsValid

func (e EntryType) IsValid() bool

IsValid returns true if the entry type is one of the known variants.

func (EntryType) JSONSchema

func (EntryType) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (EntryType) String

func (e EntryType) String() string

type ExchangeCodeRequest

type ExchangeCodeRequest struct {
	Code  string `json:"code"`
	State string `json:"state"`
}

ExchangeCodeRequest is the JSON body sent to the village CLI auth exchange endpoint. POST /api/v1/auth/cli/exchange

type ExchangeCodeResponse

type ExchangeCodeResponse struct {
	APIKey   string `json:"api_key"`
	KeyID    string `json:"key_id"`
	UserID   string `json:"user_id"`
	Username string `json:"username"`
}

ExchangeCodeResponse is the JSON response from the village CLI auth exchange endpoint.

type FamiliarityPayload

type FamiliarityPayload struct {
	ProjectHash     string             `json:"projectHash"`
	FamiliarityPct  float64            `json:"familiarityPct"`  // % of source files engaged
	UnexploredCount int                `json:"unexploredCount"` // source files with 0 engagement
	FreshnessDays   *int               `json:"freshnessDays"`   // days since last learning session
	Files           []FileFamiliarity  `json:"files"`
	Trails          []WalkthroughTrail `json:"trails"`
	Suggestions     []ReviewSuggestion `json:"suggestions"`
}

FamiliarityPayload is the data sent on the project_familiarity WebSocket channel.

type FileChange

type FileChange struct {
	Path         string  `json:"path"`
	Status       string  `json:"status"` // "M" | "A" | "D" | "R"
	OldPath      *string `json:"oldPath,omitempty"`
	LinesAdded   int     `json:"linesAdded"`
	LinesRemoved int     `json:"linesRemoved"`
}

FileChange is one file-level delta of a change (branch vs merge-base). LinesAdded/LinesRemoved are the per-file numstat churn (0 for binary files or when numstat is unavailable) — the change-weight treemap's sizing input (Round 5.3). Always present; 0 is meaningful, so no omitempty.

type FileFamiliarity

type FileFamiliarity struct {
	Path          string     `json:"path"`
	Depth         int        `json:"depth"` // 0=unexplored, 1=touched, 2=engaged, 3=deep
	SessionCount  int        `json:"sessionCount"`
	TotalTurns    int        `json:"totalTurns"`
	HumanTurns    int        `json:"humanTurns"`
	LastEngagedAt *string    `json:"lastEngagedAt"` // ISO 8601, nil if never
	DaysSince     *int       `json:"daysSince"`     // nil if never engaged
	DecayLevel    DecayLevel `json:"decayLevel"`
	IsSourceFile  bool       `json:"isSourceFile"` // true for relevant source files, false for config/generated
}

FileFamiliarity represents familiarity data for a single file.

type FrictionCluster

type FrictionCluster struct {
	Kind     string `json:"kind"`     // signal slug, e.g. "retryLoop"
	Label    string `json:"label"`    // plain, neutral (e.g. "retry loops")
	File     string `json:"file"`     // repo-relative path
	Count    int    `json:"count"`    // occurrences (retry-loop tasks touching this file)
	Sessions int    `json:"sessions"` // distinct conversations those occurrences span
}

FrictionCluster is a NEUTRAL count of a recurring friction signal keyed to a file: "this kind of friction touched this file N times across M conversations". A fact for orientation — the surface shows, it does not grade (Round 5.1). Kind is a stable slug ("retryLoop") so more kinds can be added without a breaking change.

type GitContext

type GitContext struct {
	Branch   *string      `json:"branch,omitempty"`   // Current git branch
	Remote   *string      `json:"remote,omitempty"`   // Git remote URL
	Worktree *string      `json:"worktree,omitempty"` // Worktree path (if applicable)
	Tracking *string      `json:"tracking,omitempty"` // Upstream tracking branch (e.g. "origin/main")
	Commits  []CommitInfo `json:"commits,omitempty"`  // Commits produced during this session (v4+)
}

GitContext holds git repository state at the time of the session.

type Harness

type Harness = bestiary.Harness

Harness identifies the coding tool or AI-assisted development environment that is driving the model interaction. Re-exported from bestiary.

func Harnesses

func Harnesses() []Harness

Harnesses returns every harness identifier known to bestiary — the full set, a superset of AllHarnesses (which is only the ingestion-supported subset). Re-exported so callers can enumerate the canonical known set without importing bestiary directly.

type HealthResponse

type HealthResponse struct {
	Status string `json:"status"`
}

HealthResponse is the JSON response for GET /api/v1/health.

type HostSlug

type HostSlug string

HostSlug is a sanitized, filesystem-safe identifier derived from git remote. Contains [a-zA-Z0-9._<>-] characters. The <> characters support redaction placeholders like <USER> and <PATH> in redacted slugs.

func NewHostSlug

func NewHostSlug(raw string) (HostSlug, error)

NewHostSlug validates and constructs a HostSlug.

func (HostSlug) JSONSchema

func (HostSlug) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (HostSlug) String

func (h HostSlug) String() string

type IDCasing

type IDCasing struct {
	Name      string `yaml:"name"`
	Transform string `yaml:"transform"`
}

IDCasing is one entry of the id_casings axis: a named transform of values.uuid_lower (lower / upper / mixed).

type InteractionType

type InteractionType string

InteractionType classifies how deeply a session engaged with a file.

const (
	InteractionMentioned  InteractionType = "mentioned"
	InteractionRead       InteractionType = "read"
	InteractionDiscussed  InteractionType = "discussed"
	InteractionQuestioned InteractionType = "questioned"
)

func (InteractionType) String

func (i InteractionType) String() string

type InvalidRefCategory

type InvalidRefCategory struct {
	Category    string              `yaml:"category"`
	ErrContains string              `yaml:"err_contains"`
	Cases       []InvalidRefSubcase `yaml:"cases"`
}

InvalidRefCategory is a group of explicit reject cases sharing an expected error substring (attached to the category; a case may override it).

type InvalidRefSubcase

type InvalidRefSubcase struct {
	Name        string `yaml:"name"`
	Input       string `yaml:"input,omitempty"`
	Template    string `yaml:"template,omitempty"`
	ErrContains string `yaml:"err_contains,omitempty"` // overrides category default
}

InvalidRefSubcase is one reject case. Exactly one of Input/Template is set.

type License

type License string

License is the content license a contributor selects for a published transcript. Closed menu: the village `licenses` table (its migration 026) carries each license's obligations, and the peasant local store mirrors the set in a CHECK (migration v37). This is the single source of truth for the menu on the publish/pull wire.

const (
	LicenseCC0    License = "CC0-1.0"
	LicenseCCBY   License = "CC-BY-4.0"
	LicenseCCBYSA License = "CC-BY-SA-4.0"
)

func (License) IsValid

func (l License) IsValid() bool

IsValid reports whether the license is one of the known menu entries.

func (License) JSONSchema

func (License) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (License) String

func (l License) String() string

type MapEdge

type MapEdge struct {
	From  string `json:"from"` // node ID
	To    string `json:"to"`
	Count int    `json:"count"` // underlying import count (aggregated)
}

MapEdge is a structure (import) dependency between two nodes.

type MapGraphPayload

type MapGraphPayload struct {
	ProjectHash     string          `json:"projectHash"`
	RepoFound       bool            `json:"repoFound"` // canonical_cwd resolved to a git repo
	RepoPath        string          `json:"repoPath,omitempty"`
	ParsedLanguages []string        `json:"parsedLanguages"` // e.g. ["go","typescript"]; empty => activity-only
	Nodes           []MapNode       `json:"nodes"`           // all zoom levels; parent links form the tree
	StructureEdges  []MapEdge       `json:"structureEdges"`  // parsed imports, aggregated per node pair
	ActivityEdges   []ActivityEdge  `json:"activityEdges"`   // co-EDIT observations
	Violations      []EdgeViolation `json:"violations"`      // cycles + wrong-way edges
	GeneratedAtMs   int64           `json:"generatedAtMs"`
	AtCommit        string          `json:"atCommit,omitempty"` // set when ?commit= was used (phase 2 scrub)
}

MapGraphPayload is the full map graph for one project, served by GET /api/v1/map/{projectHash}.

func NewMapGraphPayload

func NewMapGraphPayload(projectHash string) *MapGraphPayload

NewMapGraphPayload returns a MapGraphPayload with all slices initialized to empty (never-nil marshal guarantee).

type MapNode

type MapNode struct {
	ID            string      `json:"id"`               // repo-relative path ("internal/ingest", "web/src/lib/api.ts")
	Parent        string      `json:"parent,omitempty"` // ID of parent node ("" for top-level modules)
	Kind          MapNodeKind `json:"kind"`
	Name          string      `json:"name"` // display leaf ("ingest")
	Language      string      `json:"language,omitempty"`
	Layer         int         `json:"layer"`         // 0 = top row; deterministic
	Order         int         `json:"order"`         // stable sort within layer
	Loc           int         `json:"loc"`           // size metric (lines)
	FileCount     int         `json:"fileCount"`     // 1 for files
	RecordedFiles int         `json:"recordedFiles"` // files whose last edit is attributable to a recorded session
	TotalFiles    int         `json:"totalFiles"`
	TouchCount    int         `json:"touchCount"`    // recorded edits in window (activity size metric)
	EffortDensity float64     `json:"effortDensity"` // 0..1 per-file re-edit/error density rollup (0 when unknown)
}

MapNode is one square card on the map: a module, package, or file.

type MapNodeDetailPayload

type MapNodeDetailPayload struct {
	Path          string      `json:"path"`
	Kind          MapNodeKind `json:"kind"`
	Language      string      `json:"language,omitempty"` // e.g. "go", "typescript"; "" for activity-only nodes
	Loc           int         `json:"loc"`
	RecordedFiles int         `json:"recordedFiles"`
	TotalFiles    int         `json:"totalFiles"`
	SessionCount  int         `json:"sessionCount"`
	TaskCount     int         `json:"taskCount"`
	LastTouchMs   *int64      `json:"lastTouchMs,omitempty"`
	// DependsOn / UsedBy are the node's structural role, derived deterministically
	// from the parsed import graph (Round 5.6 "what this area does"): the node IDs
	// this node imports, and those that import it. Most-connected first, capped.
	// Empty when there is no parsed graph (activity-only) or no edges.
	DependsOn     []string      `json:"dependsOn"`
	UsedBy        []string      `json:"usedBy"`
	ShapedBy      []TaskSummary `json:"shapedBy"`          // most recent first, cap 20
	RecentCommits []CommitRef   `json:"recentCommits"`     // touching this node, cap 10
	RetryLoops    int           `json:"retryLoops"`        // summed over touching sessions
	ReEdits       int           `json:"reEdits"`           // re-edited files within this node
	CostUsd       *float64      `json:"costUsd,omitempty"` // nil when unknown
}

MapNodeDetailPayload backs the node rail panel, served by GET /api/v1/map/{projectHash}/node?path=<id>.

func NewMapNodeDetailPayload

func NewMapNodeDetailPayload(path string) *MapNodeDetailPayload

NewMapNodeDetailPayload returns a MapNodeDetailPayload with all slices initialized to empty (never-nil marshal guarantee).

type MapNodeKind

type MapNodeKind string

MapNodeKind classifies a map node within the path-derived tree.

const (
	MapNodeKindModule  MapNodeKind = "module"
	MapNodeKindPackage MapNodeKind = "package"
	MapNodeKindFile    MapNodeKind = "file"
)

MapNodeKind values. Top-level directories are modules, nested directories are packages, and files are leaves (mirrors codegraph's node kinds).

func (MapNodeKind) IsValid

func (k MapNodeKind) IsValid() bool

IsValid reports whether k is one of the defined node kinds.

func (MapNodeKind) String

func (k MapNodeKind) String() string

String returns the wire representation of the node kind.

type MapSlice

type MapSlice struct {
	Nodes          []MapNode      `json:"nodes"` // layer/order preserved from full map
	StructureEdges []MapEdge      `json:"structureEdges"`
	ActivityEdges  []ActivityEdge `json:"activityEdges"`
}

MapSlice is a scoped sub-map: the touched nodes plus their one-hop neighborhood, with layer/order preserved from the full map.

func NewMapSlice

func NewMapSlice() MapSlice

NewMapSlice returns a MapSlice with all slices initialized to empty (never-nil marshal guarantee).

type MessageType

type MessageType string

MessageType represents the type discriminator for WebSocket messages.

const (
	MsgSubscribe          MessageType = "subscribe"
	MsgUnsubscribe        MessageType = "unsubscribe"
	MsgDashboard          MessageType = "dashboard"
	MsgSessions           MessageType = "sessions"
	MsgSessionDetail      MessageType = "session_detail"
	MsgTrends             MessageType = "trends"
	MsgQuality            MessageType = "quality"
	MsgAnnotations        MessageType = "annotations"
	MsgProjectFamiliarity MessageType = "project_familiarity"
	MsgConnected          MessageType = "connected"
	MsgError              MessageType = "error"
)

type MockConfigResponse

type MockConfigResponse struct {
	Enabled bool     `json:"enabled"`
	Web     []string `json:"web,omitempty"`
	TUI     []string `json:"tui,omitempty"`
	API     []string `json:"api,omitempty"`
}

MockConfigResponse is the JSON response for GET /api/v1/config/mock.

type ModelID

type ModelID string

ModelID identifies a specific model version (e.g. "claude-opus-4-6").

func NewModelID

func NewModelID(raw string) (ModelID, error)

NewModelID validates and constructs a ModelID.

func (ModelID) JSONSchema

func (ModelID) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (ModelID) String

func (m ModelID) String() string

type ModelInfo

type ModelInfo struct {
	Harness        Harness  `json:"harness" required:"true"`
	Model          ModelID  `json:"model" required:"true"`
	HarnessVersion string   `json:"version,omitempty"`
	HostSlug       HostSlug `json:"hostSlug,omitempty"`
}

ModelInfo holds harness and model version information for a session. JSON tags use camelCase to match CLI UnifiedMetadata wire format. The harness is keyed json:"harness" (SLICE-B1 emit-side flip; was json:"modelHarness").

rc2 (#118): Harness and Model carry required:"true" so swaggest emits a SchemaModelInfo.required:["harness","model"] array — the village rejects a model object missing either key (the harness/model-within-model contract). Metadata only: these tags change the GENERATED schema's `required`, not the Go wire shape.

type NegativeLookalike

type NegativeLookalike struct {
	Name        string `yaml:"name"`
	Template    string `yaml:"template"`
	ErrContains string `yaml:"err_contains"`
}

NegativeLookalike is a first-class reject case that LOOKS valid (e.g. a URL whose last path segment is a UUID but whose path is not the canonical /transcripts/<uuid> shape). ParseTranscriptRef rejects all of these, so each asserts LIVE in the InvalidCases loop.

type ProjectContext

type ProjectContext struct {
	Hash     ProjectHash `json:"hash"`               // SHA-256 of project origin URL or path
	FilePath string      `json:"filePath,omitempty"` // Local repo path
	Name     string      `json:"name"`               // Repo basename
}

ProjectContext identifies the project associated with a session.

type ProjectHash

type ProjectHash string

ProjectHash is a SHA-256 hex digest of the project's origin URL or local path.

func NewProjectHash

func NewProjectHash(raw string) (ProjectHash, error)

NewProjectHash validates and constructs a ProjectHash.

func (ProjectHash) JSONSchema

func (ProjectHash) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (ProjectHash) String

func (p ProjectHash) String() string

type ProjectSummariesPayload

type ProjectSummariesPayload struct {
	Projects []ProjectSummary `json:"projects"`
}

ProjectSummariesPayload backs the home project picker, served by GET /api/v1/projects/summary.

func NewProjectSummariesPayload

func NewProjectSummariesPayload() *ProjectSummariesPayload

NewProjectSummariesPayload returns a ProjectSummariesPayload with all slices initialized to empty (never-nil marshal guarantee).

type ProjectSummary

type ProjectSummary struct {
	ProjectHash   string `json:"projectHash"`
	Project       string `json:"project"`       // display name (canonical cwd, else the hash)
	Sessions      int    `json:"sessions"`      // recorded session count
	RecordedFiles int    `json:"recordedFiles"` // coverage numerator (same rule as MapNode)
	TotalFiles    int    `json:"totalFiles"`    // coverage denominator
	LastWorkMs    *int64 `json:"lastWorkMs,omitempty"`
	OpenChanges   int    `json:"openChanges"` // local non-default branches not merged (0 when no repo)
}

ProjectSummary is one row of the home picker: a project with its recorded stats (sessions · recorded coverage · last work · open changes).

type ProjectTasksPayload

type ProjectTasksPayload struct {
	ProjectHash string        `json:"projectHash"`
	Tasks       []TaskSummary `json:"tasks"` // reverse-chronological, cap 500
	FileFilter  string        `json:"fileFilter,omitempty"`
}

ProjectTasksPayload backs the Tasks lens, served by GET /api/v1/map/{projectHash}/tasks?file=<path>.

func NewProjectTasksPayload

func NewProjectTasksPayload(projectHash string) *ProjectTasksPayload

NewProjectTasksPayload returns a ProjectTasksPayload with all slices initialized to empty (never-nil marshal guarantee).

type Provenance

type Provenance struct {
	Method   string            `json:"method"` // "heuristic", "regex", "llm_judge", "manual"
	Function string            `json:"function,omitempty"`
	Version  string            `json:"version,omitempty"`
	Details  map[string]string `json:"details,omitempty"`
}

Provenance records how a non-human annotator derived its annotation value (EvalevalAI R7). Only populated for rule-based and agent annotators; nil for human annotations.

type PublishRequest

type PublishRequest struct {
	Identity    SessionIdentity `json:"identity"`
	Model       ModelInfo       `json:"model" required:"true"`
	Timestamp   TimestampInfo   `json:"timestamp"`
	Source      SourceInfo      `json:"source"`
	Git         GitContext      `json:"git"`
	Project     ProjectContext  `json:"project"`
	Stats       SessionStats    `json:"stats"`
	Quality     *QualityMetrics `json:"quality,omitempty"`
	Entries     []SessionEntry  `json:"entries,omitempty"`
	Subagents   []SubagentRef   `json:"subagents,omitempty"`
	Diagnostics DiagnosticsInfo `json:"diagnostics"`
	// License is the content license the contributor selected for this transcript
	// (CC0-1.0 / CC-BY-4.0 / CC-BY-SA-4.0). Optional — omitempty ⇒ a publish with no
	// license stores NULL (legacy/un-set). The village persists it to
	// transcripts.license_id; the vendored schema enum makes an invalid value a
	// documented schema-422. NOT `required` (keeps SchemaPublishRequest.required = [model]).
	License License `json:"license,omitempty"`
}

PublishRequest is the canonical wire type for CLI → Village upload. The CLI sends this; the village validates and persists it.

Uses nested composites for logical grouping. The JSON tags on each composite struct preserve CLI wire compatibility — the top-level keys are identity, model, timestamp, source, git, project, stats, quality, subagents, and diagnostics.

MIGRATION NOTE: The CLI's current flat UnifiedMetadata will need a coordinated update to send this nested structure. This is NOT backward-compatible with the current village handler — both CLI and village must update together.

rc2 (#118): Model carries required:"true" so swaggest emits a SchemaPublishRequest.required:["model"] array — a publish body with no model object is rejected at the root. Metadata only (changes the generated schema's `required`, not the Go wire shape).

type PublishResponse

type PublishResponse struct {
	TranscriptID  string `json:"transcriptId"`  // Server-generated UUID
	BlobKey       string `json:"blobKey"`       // S3 storage path
	BlobSizeBytes int64  `json:"blobSizeBytes"` // Uploaded file size in bytes
	PublishedAt   int64  `json:"publishedAt"`   // Unix millis
	UpdatedAt     int64  `json:"updatedAt"`     // Unix millis
	Created       bool   `json:"created"`       // true if new, false if updated
}

PublishResponse is returned by the village after successful publish.

type PublishVerdictCase

type PublishVerdictCase struct {
	Name   string                    `yaml:"name"`
	Body   string                    `yaml:"body"`
	Expect PublishVerdictExpectation `yaml:"expect"`
}

PublishVerdictCase is one concrete publish body and its schema/HTTP verdict.

func (PublishVerdictCase) ModelHarness

func (c PublishVerdictCase) ModelHarness() (string, bool, error)

ModelHarness returns body.model.harness when the case body contains one.

type PublishVerdictExpectation

type PublishVerdictExpectation struct {
	SchemaAccepts bool   `yaml:"schema_accepts"`
	LegacyAccepts *bool  `yaml:"legacy_accepts,omitempty"`
	HTTPStatus    int    `yaml:"http_status,omitempty"`
	ErrorCategory string `yaml:"error_category,omitempty"`
	ErrorContains string `yaml:"error_contains,omitempty"`
}

PublishVerdictExpectation attaches expected outcomes to a publish verdict row.

type PublishVerdictFixtures

type PublishVerdictFixtures struct {
	Cases []PublishVerdictCase `yaml:"cases"`
}

PublishVerdictFixtures is the parsed testdata/publish/verdicts.yaml corpus.

func LoadPublishVerdictFixtures

func LoadPublishVerdictFixtures() (*PublishVerdictFixtures, error)

LoadPublishVerdictFixtures parses PublishVerdictsYAML into structured fixtures.

func (*PublishVerdictFixtures) Acceptances

func (f *PublishVerdictFixtures) Acceptances() []PublishVerdictCase

Acceptances returns the corpus rows the schema MUST accept (schema_accepts:true). It is the accept-pass input to RunPublishVerdicts; together with Rejections it partitions Cases exactly (the partition-completeness guard in RunPublishVerdicts depends on len(Acceptances)+len(Rejections)==len(Cases)).

func (*PublishVerdictFixtures) CaseByName

func (f *PublishVerdictFixtures) CaseByName(name string) (PublishVerdictCase, bool)

CaseByName returns the verdict row with the given stable name.

func (*PublishVerdictFixtures) Rejections

func (f *PublishVerdictFixtures) Rejections() []PublishVerdictCase

Rejections returns the corpus rows the schema MUST reject (schema_accepts:false). It is the reject-pass input to RunPublishVerdicts (see Acceptances).

type PullAnnotation

type PullAnnotation struct {
	AnnotationSummary        // embedded existing summary (annotator entity, content hash, etc.)
	AuthorUserID      string `json:"authorUserId"`
	AuthorUsername    string `json:"authorUsername"`
}

PullAnnotation is the authored-annotation row for the pull surface (GET /api/v1/pull/transcripts/{id}/annotations). It embeds the existing AnnotationSummary and adds the village account identity (AuthorUserID / AuthorUsername) the summary does not carry — required to foreign-mark pulled annotations and to exclude the requester's own authored rows during the annotation-refresh path (creds.UserID == AuthorUserID).

type PullListResponse

type PullListResponse struct {
	Transcripts []PullTranscriptInfo `json:"transcripts"`
	Page        int                  `json:"page"`
	Limit       int                  `json:"limit"`
	Total       int                  `json:"total"`
}

PullListResponse is the village's paginated listing of pullable transcripts (GET /api/v1/pull/transcripts) — own + group-shared (public excluded by the canPullTranscript policy).

type PullRefFixtures

type PullRefFixtures struct {
	Values            PullRefValues        `yaml:"values"`
	IDCasings         []IDCasing           `yaml:"id_casings"`
	RefForms          []RefForm            `yaml:"ref_forms"`
	ValidGeneration   ValidGeneration      `yaml:"valid_generation"`
	InvalidRefs       []InvalidRefCategory `yaml:"invalid_refs"`
	NegativeLookalike []NegativeLookalike  `yaml:"negative_lookalikes"`
}

PullRefFixtures is the top-level parsed transcript_refs.yaml structure.

func LoadPullRefFixtures

func LoadPullRefFixtures() (*PullRefFixtures, error)

LoadPullRefFixtures parses PullRefsYAML into structured fixtures. Mirrors LoadAnnotationFixtures.

func (*PullRefFixtures) AllCases

func (f *PullRefFixtures) AllCases() ([]RefCase, error)

AllCases is ValidCases followed by InvalidCases — the full materialised suite internal/pull/types_test.go ranges over.

func (*PullRefFixtures) InvalidCases

func (f *PullRefFixtures) InvalidCases() ([]RefCase, error)

InvalidCases materialises the explicit invalid_refs plus the negative_lookalikes. Every case expects an error with the category/case-attached substring.

func (*PullRefFixtures) UUIDLower

func (f *PullRefFixtures) UUIDLower() string

UUIDLower returns the canonical lowercase UUID the fixture owns (== testutil TestTranscriptUUID).

func (*PullRefFixtures) ValidCases

func (f *PullRefFixtures) ValidCases() ([]RefCase, error)

ValidCases materialises the valid cross-product (id_casings x ref_forms) with the generator-attached expectation: every case parses, normalizes its ID to values.uuid_lower, and reports FromURL per its ref_form.

func (*PullRefFixtures) VillageHost

func (f *PullRefFixtures) VillageHost() string

VillageHost returns the canonical village host the fixture owns (== testutil TestVillageHost).

type PullRefValues

type PullRefValues struct {
	UUIDLower   string `yaml:"uuid_lower"`
	VillageHost string `yaml:"village_host"`
}

PullRefValues are the self-contained canonical strings the fixture owns. They are ADOPTED VERBATIM from internal/testutil (which re-exports them), so the fixture is the single source of truth with zero behaviour change.

type PullStatusFixtures

type PullStatusFixtures struct {
	Statuses []PullStatusMapping `yaml:"statuses"`
}

PullStatusFixtures is the parsed pull_statuses.yaml structure.

func LoadPullStatusFixtures

func LoadPullStatusFixtures() (*PullStatusFixtures, error)

LoadPullStatusFixtures parses PullStatusesYAML into structured fixtures.

func (*PullStatusFixtures) WireFor

func (f *PullStatusFixtures) WireFor(constName string) (string, bool)

WireFor returns the expected wire string for a given const_name, or "".

type PullStatusMapping

type PullStatusMapping struct {
	Name      string `yaml:"name"`
	ConstName string `yaml:"const_name"`
	Wire      string `yaml:"wire"`
}

PullStatusMapping is one PullStatus<->wire row.

type PullTranscriptInfo

type PullTranscriptInfo struct {
	TranscriptID    TranscriptID    `json:"transcriptId"`
	LocalID         string          `json:"localId,omitempty"` // peasant SessionID at publish — round-trip correlation
	OwnerUserID     string          `json:"ownerUserId"`
	OwnerUsername   string          `json:"ownerUsername"`
	Title           string          `json:"title,omitempty"`
	Harness         Harness         `json:"harness,omitempty"` // existing typed form
	ProjectName     string          `json:"projectName,omitempty"`
	Visibility      Visibility      `json:"visibility"`                // existing typed form
	License         License         `json:"license,omitempty"`         // legal axis; omitempty ⇒ legacy/un-set
	ContentHash     string          `json:"contentHash,omitempty"`     // SERVED-BLOB hash; empty ⇒ server has none
	ContractVersion ContractVersion `json:"contractVersion,omitempty"` // push contract the blob was published under
	PublishedAt     int64           `json:"publishedAt"`
	UpdatedAt       int64           `json:"updatedAt"`
	AnnotationCount int             `json:"annotationCount"`
}

PullTranscriptInfo is the village's metadata view of a single pullable transcript (GET /api/v1/pull/transcripts/{id}). ContentHash is the SERVER-COMPUTED hash of the served blob bytes (empty when the village has not yet computed one), and is distinct from UnifiedMetadata.ContentHash (the ingest-time, pre-push-redaction hash). ContractVersion records the push content contract the blob was published under (the blob carries its own publish-time version; the pull envelope does not version the blob).

type PushContractVersion

type PushContractVersion = ContractVersion

PushContractVersion is a zero-churn alias for ContractVersion kept for the push axis. Existing references (SchemaVersionResponse push fields, the defaults push constants) keep compiling unchanged; new code may use either name (they are the identical type).

type QualityFixtureName

type QualityFixtureName string
const (
	QualityFixtureResolvedTypical    QualityFixtureName = "resolved_typical"
	QualityFixtureResolvedHighTokens QualityFixtureName = "resolved_high_tokens"
	QualityFixturePartialMedium      QualityFixtureName = "partial_medium"
	QualityFixtureFailedComplex      QualityFixtureName = "failed_complex"
	QualityFixtureResolvedMinimal    QualityFixtureName = "resolved_minimal"
)

type QualityFixtureSet

type QualityFixtureSet struct {
	Name  QualityFixtureSetName `yaml:"name"`
	Cases []QualityFixtureName  `yaml:"cases"`
}

QualityFixtureSet is a named reusable list of quality-session fixture rows.

type QualityFixtureSetName

type QualityFixtureSetName string
const (
	QualityFixtureSetProjectMix QualityFixtureSetName = "project_mix"
)

type QualityFixtures

type QualityFixtures struct {
	Sessions []QualitySessionFixture `yaml:"quality_sessions"`
	Sets     []QualityFixtureSet     `yaml:"quality_fixture_sets"`
}

QualityFixtures is the parsed testdata/quality/sessions.yaml corpus.

func LoadQualityFixtures

func LoadQualityFixtures() (*QualityFixtures, error)

LoadQualityFixtures parses QualitySessionsYAML into structured fixtures.

func (*QualityFixtures) QualitySessions

func (f *QualityFixtures) QualitySessions() []QualitySession

QualitySessions returns all quality-session fixtures as wire payload rows.

func (*QualityFixtures) QualitySessionsForSet

func (f *QualityFixtures) QualitySessionsForSet(name QualityFixtureSetName) ([]QualitySession, error)

QualitySessionsForSet returns a named fixture set as wire payload rows.

func (*QualityFixtures) SessionByName

SessionByName returns the named quality-session fixture row.

func (*QualityFixtures) SetByName

SetByName returns the named quality fixture set.

type QualityMetrics

type QualityMetrics struct {
	// Basic session counts
	TurnCount            *int            `json:"turnCount,omitempty"`
	SubagentCount        *int            `json:"subagentCount,omitempty"`
	TotalTokens          *int            `json:"totalTokens,omitempty"`
	InputTokens          *int            `json:"inputTokens,omitempty"`
	OutputTokens         *int            `json:"outputTokens,omitempty"`
	ToolCalls            *int            `json:"toolCalls,omitempty"`
	TitleGenerated       *string         `json:"titleGenerated,omitempty"`
	Outcome              *SessionOutcome `json:"outcome,omitempty"`
	FilesTouched         *int            `json:"filesTouched,omitempty"`
	LinesChanged         *int            `json:"linesChanged,omitempty"`
	RetryLoops           *int            `json:"retryLoops,omitempty"`
	RetryTokensWasted    *int            `json:"retryTokensWasted,omitempty"`
	WithinSessionReverts *int            `json:"withinSessionReverts,omitempty"`
	SignalDensity        *float64        `json:"signalDensity,omitempty"`
	SpecQualityScore     *float64        `json:"specQualityScore,omitempty"`
	ExplorationRatio     *float64        `json:"explorationRatio,omitempty"`
	ScopeBreadth         *int            `json:"scopeBreadth,omitempty"`
	DiscoveryTurns       *int            `json:"discoveryTurns,omitempty"`
	DurationMinutes      *float64        `json:"durationMinutes,omitempty"`
	// M-series advanced metrics (v2 computed)
	M2TokenOutcomeRatio     *float64 `json:"m2TokenOutcomeRatio,omitempty"`
	M3UniqueToolCount       *int     `json:"m3UniqueToolCount,omitempty"`
	M4ErrorRecoveryCount    *int     `json:"m4ErrorRecoveryCount,omitempty"`
	M4ConsecutiveErrorMax   *int     `json:"m4ConsecutiveErrorMax,omitempty"`
	M5ContextUtilizationPct *float64 `json:"m5ContextUtilizationPct,omitempty"`
	M5PeakContextTokens     *int     `json:"m5PeakContextTokens,omitempty"`
	M5AvgMessageTokens      *int     `json:"m5AvgMessageTokens,omitempty"`
	M6OutputSurvivalPct     *float64 `json:"m6OutputSurvivalPct,omitempty"`
	M6LinesSurvived         *int     `json:"m6LinesSurvived,omitempty"`
	M6LinesTotal            *int     `json:"m6LinesTotal,omitempty"`
	M7SpecWordCount         *int     `json:"m7SpecWordCount,omitempty"`
	M7SpecHasExamples       *bool    `json:"m7SpecHasExamples,omitempty"`
	M7SpecHasConstraints    *bool    `json:"m7SpecHasConstraints,omitempty"`
	// v3 cost analytics
	CostInputUSD      *float64 `json:"costInputUsd,omitempty"`
	CostOutputUSD     *float64 `json:"costOutputUsd,omitempty"`
	CostReasoningUSD  *float64 `json:"costReasoningUsd,omitempty"`
	CostCacheReadUSD  *float64 `json:"costCacheReadUsd,omitempty"`
	CostCacheWriteUSD *float64 `json:"costCacheWriteUsd,omitempty"`
	CostTotalUSD      *float64 `json:"costTotalUsd,omitempty"`
	CostModelID       *string  `json:"costModelId,omitempty"`
	// v3 scope classification
	Scope *string `json:"scope,omitempty"`
	// Compute metadata
	ComputedAt     *int64 `json:"computedAt,omitempty"`     // Unix millis
	ComputeVersion *int   `json:"computeVersion,omitempty"` // 0=v1 migrated, 1+=v2 computed
}

QualityMetrics holds session statistics and derived quality signals for a session. The type name is intentionally broad post-unification: it covers two distinct groups.

Group A — Basic session stats (TurnCount, SubagentCount, TotalTokens, InputTokens, OutputTokens, ToolCalls, TitleGenerated, Outcome, DurationMinutes): populated for all fully-ingested sessions; a nil value here indicates the session has not been fully ingested.

Group B — Derived quality signals (FilesTouched, LinesChanged, RetryLoops, M-series fields, SignalDensity, SpecQualityScore, ExplorationRatio, etc.): populated only when quality analysis has run. Nil = "not computed" — analysis may not have been performed yet.

All fields are pointers with omitempty so that serialisation omits fields that have not been populated, regardless of which group they belong to. JSON tags use camelCase to match the backend data contract (QualitySession) field names.

type QualityPayload

type QualityPayload struct {
	Sessions []QualitySession `json:"sessions"`
}

QualityPayload is the data sent on the quality WebSocket channel.

type QualitySession

type QualitySession struct {
	ID              string  `json:"id"`
	Date            string  `json:"date"` // "2006-01-02" format
	Project         string  `json:"project"`
	TotalTokens     int     `json:"totalTokens"`
	InputTokens     int     `json:"inputTokens"`
	OutputTokens    int     `json:"outputTokens"`
	TurnCount       int     `json:"turnCount"`
	ToolCalls       int     `json:"toolCalls"`
	DurationMinutes float64 `json:"durationMinutes"`
	// v2 fields -- zero-valued until implemented.
	Scope                string  `json:"scope"`
	Title                string  `json:"title"`
	Outcome              string  `json:"outcome"`
	FilesTouched         int     `json:"filesTouched"`
	LinesChanged         int     `json:"linesChanged"`
	RetryLoops           int     `json:"retryLoops"`
	RetryTokensWasted    int     `json:"retryTokensWasted"`
	WithinSessionReverts int     `json:"withinSessionReverts"`
	SignalDensity        float64 `json:"signalDensity"`
	SpecQualityScore     float64 `json:"specQualityScore"`
	ExplorationRatio     float64 `json:"explorationRatio"`
	ScopeBreadth         int     `json:"scopeBreadth"`
	DiscoveryTurns       int     `json:"discoveryTurns"`
	// EffectiveAnnotations are the non-superseded annotations for this session.
	// Clients derive display labels (e.g. humanLabel, agentLabel) by filtering
	// on typeId and annotatorKind — no pre-computed string fields needed.
	EffectiveAnnotations []AnnotationSummary `json:"effectiveAnnotations,omitempty"`
}

QualitySession is the analytics payload for the quality dashboard.

type QualitySessionFixture

type QualitySessionFixture struct {
	Name                 QualityFixtureName `yaml:"name"`
	ID                   string             `yaml:"id"`
	Date                 string             `yaml:"date"`
	Project              string             `yaml:"project"`
	Scope                string             `yaml:"scope"`
	Title                string             `yaml:"title"`
	TotalTokens          int                `yaml:"totalTokens"`
	InputTokens          int                `yaml:"inputTokens"`
	OutputTokens         int                `yaml:"outputTokens"`
	TurnCount            int                `yaml:"turnCount"`
	ToolCalls            int                `yaml:"toolCalls"`
	Outcome              string             `yaml:"outcome"`
	FilesTouched         int                `yaml:"filesTouched"`
	LinesChanged         int                `yaml:"linesChanged"`
	DurationMinutes      float64            `yaml:"durationMinutes"`
	RetryLoops           int                `yaml:"retryLoops"`
	RetryTokensWasted    int                `yaml:"retryTokensWasted"`
	WithinSessionReverts int                `yaml:"withinSessionReverts"`
	SignalDensity        float64            `yaml:"signalDensity"`
	SpecQualityScore     float64            `yaml:"specQualityScore"`
	ExplorationRatio     float64            `yaml:"explorationRatio"`
	ScopeBreadth         int                `yaml:"scopeBreadth"`
	DiscoveryTurns       int                `yaml:"discoveryTurns"`
}

QualitySessionFixture is one named quality-session fixture row.

func (QualitySessionFixture) ToQualitySession

func (f QualitySessionFixture) ToQualitySession() QualitySession

ToQualitySession converts a named fixture row to the wire payload shape.

type RedactionExample

type RedactionExample struct {
	// Name is the stable case key (snake_case). The web codegen joins its
	// presentation side-table (UI context snippets) to a case by this Name.
	Name string `yaml:"name"`
	// RuleID is the pkg/redact rule that fires on OriginalText (e.g. "github_pat").
	RuleID string `yaml:"ruleId"`
	// Category is the ENGINE category vocabulary: "secrets" | "pii" | "paths" |
	// "project". This is the ONE canonical category vocabulary; the web display
	// enum (CREDENTIAL|PII|PATH|INTERNAL) is a derived, audited projection.
	Category string `yaml:"category"`
	// Level is the minimum redaction level at which RuleID fires.
	Level RedactionFixtureLevel `yaml:"level"`
	// OriginalText is a realistic, public-safe secret FORMAT (non-functional
	// example value) that the engine genuinely detects.
	OriginalText string `yaml:"originalText"`
	// RedactedReplacement is the engine-APPLIED output, stored verbatim. For
	// back-reference rules this is the partially-redacted form
	// (e.g. "/Users/<USER>/Projects/internal-api"), not a bare label.
	RedactedReplacement string `yaml:"redactedReplacement"`
	// Confidence is a presentation-only 0-100 score shown in the mock UI.
	Confidence int `yaml:"confidence"`
	// LineNumber is a presentation-only source line shown in the mock UI.
	LineNumber int `yaml:"lineNumber"`
	// Description is a human-readable label shown in the mock UI.
	Description string `yaml:"description"`
}

RedactionExample is one entry in the redaction example corpus. It is the single source of truth for the redaction session-detail fixture: the leaf STORES this data and a format-only generator serialises it to testdata/session-detail/redactions.yaml. The leaf never recomputes RedactedReplacement — the redaction ENGINE lives only in peasant (pkg/redact), and a peasant-side behavioural conformance test binds RedactedReplacement to the real engine output (the no-drift guarantee). See SLICE-F-PROPOSAL-2.

func LoadRedactionExamples

func LoadRedactionExamples() ([]RedactionExample, error)

LoadRedactionExamples parses RedactionsYAML (the embedded, generated artifact) into typed cases. Consumers (peasant conformance test, web codegen) bind to the PUBLISHED bytes via this loader rather than the in-memory RedactionExamples slice, so they validate exactly what ships; the leaf freshness gate keeps the two in lockstep.

type RedactionFixtureLevel

type RedactionFixtureLevel string

RedactionFixtureLevel is the redaction level at which a fixture case's rule fires. The string values are byte-identical to peasant pkg/redact's RedactionLevel ("minimal"/"standard"/"maximum") so the peasant conformance test can construct a redactor at the exact firing level via redact.RedactionLevel(string(level)) with no translation table.

Firing semantics (pkg/redact/redactor.go isActiveCategory):

  • secrets, paths → fire at Minimal and above (unconditional)
  • pii, project → fire at Standard and above

The fixture stores the MINIMUM level at which each case's rule fires so the conformance test exercises the narrowest level that still triggers the rule (avoids entropy/AST over-redaction that only Maximum adds).

const (
	// RedactionLevelMinimal redacts only secrets and paths.
	RedactionLevelMinimal RedactionFixtureLevel = "minimal"
	// RedactionLevelStandard adds PII and project-identity redaction.
	RedactionLevelStandard RedactionFixtureLevel = "standard"
	// RedactionLevelMaximum adds AST anonymization + entropy detection.
	RedactionLevelMaximum RedactionFixtureLevel = "maximum"
)

func (RedactionFixtureLevel) IsValid

func (l RedactionFixtureLevel) IsValid() bool

IsValid reports whether l is one of the three known levels.

func (RedactionFixtureLevel) String

func (l RedactionFixtureLevel) String() string

String returns the wire form of the level.

type RedactionInfo

type RedactionInfo struct {
	Applied             bool   `json:"applied"`
	Level               string `json:"level,omitempty"`                  // redaction level used (validate with redact.RedactionLevel)
	RuleSetVersion      string `json:"rule_set_version,omitempty"`       // rule set version that produced this redaction (e.g. "1.1.0")
	RedactedAtMs        *int64 `json:"redacted_at_ms,omitempty"`         // unix ms when redacted
	ContentHashAtRedact string `json:"content_hash_at_redact,omitempty"` // content hash snapshot at redaction time
}

RedactionInfo tracks whether and when redaction was applied to a session's transcript. Level is stored as a string because this schema module is a public contract module that must not import internal packages. Callers should validate using redact.RedactionLevel(level).IsValid().

func (RedactionInfo) IsCurrent

func (r RedactionInfo) IsCurrent(currentContentHash string) bool

IsCurrent returns true if the redaction matches the current content.

func (RedactionInfo) IsRaw

func (r RedactionInfo) IsRaw() bool

IsRaw returns true if no redaction has been applied.

func (RedactionInfo) IsStale

func (r RedactionInfo) IsStale(currentContentHash string) bool

IsStale returns true if the content has changed since redaction was applied.

type RefCase

type RefCase struct {
	// Name is a stable, human-readable case identifier (used as the t.Run name).
	Name string
	// Input is the raw string fed to ParseTranscriptRef.
	Input string
	// WantID is the expected canonical (lowercase) TranscriptID string for a
	// PARSING case; empty for a reject case.
	WantID string
	// WantFromURL is the expected TranscriptRef.FromURL for a parsing case.
	WantFromURL bool
	// WantErr is true when ParseTranscriptRef is expected to return an error.
	WantErr bool
	// ErrContains is a substring the returned error must contain (reject cases).
	ErrContains string
}

RefCase is a single concrete ParseTranscriptRef test case, materialised from the axes/categories. It is what internal/pull/types_test.go ranges over.

type RefForm

type RefForm struct {
	Name     string `yaml:"name"`
	Template string `yaml:"template"`
	FromURL  bool   `yaml:"from_url"`
}

RefForm is one entry of the ref_forms axis: a templated reference shape plus the FromURL the parser is expected to report for it.

type ReviewListPayload

type ReviewListPayload struct {
	ProjectHash   string          `json:"projectHash"`
	RepoFound     bool            `json:"repoFound"`
	DefaultBranch string          `json:"defaultBranch,omitempty"`
	Changes       []ChangeSummary `json:"changes"`       // open first, then merged (phase 2)
	RecentCommits []CommitRef     `json:"recentCommits"` // default-branch, cap 200 (time strip)
}

ReviewListPayload lists a project's changes, served by GET /api/v1/review/{projectHash}.

func NewReviewListPayload

func NewReviewListPayload(projectHash string) *ReviewListPayload

NewReviewListPayload returns a ReviewListPayload with all slices initialized to empty (never-nil marshal guarantee).

type ReviewSuggestion

type ReviewSuggestion struct {
	Path            string `json:"path"`
	LastEngaged     string `json:"lastEngaged"`
	DaysSince       int    `json:"daysSince"`
	SuggestedPrompt string `json:"suggestedPrompt"`
}

ReviewSuggestion nudges the user to revisit a fading file.

type Role

type Role string

Role represents the sender of a message turn.

const (
	RoleUser      Role = "user"
	RoleAssistant Role = "assistant"
	RoleTool      Role = "tool"
	RoleSystem    Role = "system"
)

func (Role) IsValid

func (r Role) IsValid() bool

IsValid returns true if the role is one of the known variants.

func (Role) JSONSchema

func (Role) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (Role) String

func (r Role) String() string

type ScaleKind

type ScaleKind string

ScaleKind classifies the measurement level of an annotation value domain (Stevens 1946 levels of measurement, ISO 11179 Part 5).

  • nominal: categories without order (e.g. session scope: feature/bug/docs)
  • ordinal: ordered categories with no meaningful interval (e.g. approval: deny<approve)
  • continuous: numeric range with meaningful intervals (e.g. confidence 0.0–1.0)

Valid combinations with ValueDomainKind:

  • enumerated + nominal: OK (categories without order)
  • enumerated + ordinal: OK (ordered categories with permissible values list)
  • described + continuous: OK (range with JSON schema constraint spec)
  • described + nominal: OK (pattern-constrained categories)
  • described + ordinal: REJECTED (ordinal requires explicit ordering via permissible values)
  • enumerated + continuous: REJECTED (continuous ranges must be described, not enumerated)
const (
	ScaleNominal    ScaleKind = "nominal"
	ScaleOrdinal    ScaleKind = "ordinal"
	ScaleContinuous ScaleKind = "continuous"
)

func (ScaleKind) IsValid

func (k ScaleKind) IsValid() bool

IsValid returns true if the scale kind is one of the known variants.

func (ScaleKind) JSONSchema

func (ScaleKind) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (ScaleKind) String

func (k ScaleKind) String() string

type SchemaVersionResponse

type SchemaVersionResponse struct {
	AnnotationSchemaVersion string              `json:"annotationSchemaVersion"`
	SupportedTargetKinds    []string            `json:"supportedTargetKinds"`
	SupportedTypeIDs        []string            `json:"supportedTypeIds"`
	PushContractVersion     PushContractVersion `json:"pushContractVersion"`
	MinPushContractVersion  PushContractVersion `json:"minPushContractVersion"`
	PullContractVersion     PushContractVersion `json:"pullContractVersion,omitempty"`
	MinPullContractVersion  PushContractVersion `json:"minPullContractVersion,omitempty"`
}

SchemaVersionResponse is returned by GET /api/v1/schema/version. It communicates which annotation schema AND which push CONTENT contract the village currently supports, so the CLI can preflight and version-negotiate (SLICE-B2).

PushContractVersion / MinPushContractVersion advertise the village's accept WINDOW [Min, Current] for the TranscriptContent push wire:

  • PushContractVersion is the CURRENT contract the village emits/prefers.
  • MinPushContractVersion is the PUSH-ACCEPTANCE FLOOR: the oldest contract the village will still accept on the publish path. A CLI ahead of Current downgrade-emits toward this window (never "upgrade the village").

A3/C3 — TWO DISTINCT FLOORS: MinPushContractVersion is the push-acceptance floor (gates INCOMING uploads). It is deliberately SEPARATE from the village's display MIGRATE-ON-READ floor (how far back stored blobs can be normalized for rendering), which may reach FURTHER back than MinPushContractVersion — the village can still render a legacy stored blob it would no longer ACCEPT as a fresh push. The migrate-on-read floor lives village-side (SLICE-B3) and is not advertised here; only the push-acceptance window is negotiated over the wire.

PullContractVersion / MinPullContractVersion advertise the village's PULL envelope WINDOW [Min, Current] (PullTranscriptInfo/PullListResponse/ PullAnnotation shapes, the /api/v1/pull/* endpoint semantics, ETag behaviour). This window is DISTINCT from the push window: it does NOT version the blob (the stored blob carries its own publish-time push contract version). Both fields are `omitempty` so an OLDER village that predates the pull surface emits the prior wire shape; the CLI treats an ABSENT advertisement as "village too old for pull" (actionable error), not as compatible.

type SearchPayload

type SearchPayload struct {
	Query   string         `json:"query"`
	Results []SearchResult `json:"results"`
}

SearchPayload is the result set for one query, served by GET /api/v1/search.

func NewSearchPayload

func NewSearchPayload(query string) *SearchPayload

NewSearchPayload returns a SearchPayload with Results initialized to empty (never-nil marshal guarantee).

type SearchResult

type SearchResult struct {
	SessionID   string  `json:"sessionId"`
	Project     string  `json:"project"`               // raw canonical_cwd (else hash); web formats for display
	ProjectHash string  `json:"projectHash,omitempty"` // for round-trips
	EntryIndex  int     `json:"entryIndex"`            // depth-0 turn index — deep-link coordinate
	Role        string  `json:"role"`                  // user | assistant | ... (display facet)
	Snippet     string  `json:"snippet"`               // FTS5 snippet() with [match] markers
	Score       float64 `json:"score"`                 // negated bm25: higher = more relevant (result order is authoritative)
}

SearchResult is one FTS5 hit: a single message entry, ranked by relevance, with a snippet for display and the coordinates to deep-link to it.

type ServerMessage

type ServerMessage struct {
	Type    MessageType `json:"type"`
	Data    any         `json:"data,omitempty"`
	Message string      `json:"message,omitempty"` // for error type
	Version string      `json:"version,omitempty"` // for connected type
}

ServerMessage is a message sent from the server to the browser via WebSocket.

type SessionDetailPayload

type SessionDetailPayload struct {
	SchemaVersion PushContractVersion `json:"schemaVersion,omitempty"`
	ID            string              `json:"id"`
	Harness       Harness             `json:"harness"`
	StartTime     time.Time           `json:"startTime"`
	EndTime       time.Time           `json:"endTime"`
	DurationMins  float64             `json:"durationMins"`
	TotalTokens   int                 `json:"totalTokens"`
	TokensIn      int                 `json:"tokensIn"`
	TokensOut     int                 `json:"tokensOut"`
	TurnCount     int                 `json:"turnCount"`
	ToolCallCount int                 `json:"toolCallCount"`
	Turns         []TurnDetail        `json:"turns"`
	// Optional fields — populated when backend has the data.
	Source           string            `json:"source,omitempty"`
	Status           string            `json:"status,omitempty"`
	Project          string            `json:"project,omitempty"`
	Model            string            `json:"model,omitempty"`
	WorkingDirectory string            `json:"workingDirectory,omitempty"`
	GitBranch        string            `json:"gitBranch,omitempty"`
	GitRemote        string            `json:"gitRemote,omitempty"`
	ChildSessions    []ChildSessionRef `json:"childSessions,omitempty"`
	// Outcome is the heuristic resolution status of the session
	// (resolved/partial/failed), sourced from session_metrics.outcome. Empty
	// when the session has no computed outcome. The metadata columns expose no
	// per-signal reason, so no reason field accompanies it yet.
	Outcome SessionOutcome `json:"outcome,omitempty"`
	// Scorecard carries the per-session quality signals used by the "How this
	// session went" self-assessment card. Nil when the session has no computed
	// metrics. Sourced from the same session_metrics row that backs QualitySession.
	Scorecard *SessionScorecard `json:"scorecard,omitempty"`
}

SessionDetailPayload is the data sent on the session_detail WebSocket channel AND promoted to the versioned `peasant push` wire body inside a TranscriptContent envelope (D2).

SchemaVersion is the EMBEDDED push-contract version (Δ1). It is advisory: when this payload travels inside a TranscriptContent envelope the envelope's ContractVersion is authoritative (see TranscriptContent's conflict-winner note). The embedded copy keeps the payload self-describing when stored on its own. It is omitempty so the local WebSocket session_detail channel (which never sets it) does not gain a spurious "schemaVersion":"" field; the push builder sets it explicitly.

type SessionEntry

type SessionEntry struct {
	SessionID      SessionID     `json:"sessionId"`
	EntryIndex     int           `json:"entryIndex"`
	Harness        Harness       `json:"harness"`
	EntryType      EntryType     `json:"entryType"`
	Role           Role          `json:"role"`
	TimestampMs    *int64        `json:"timestampMs,omitempty"`
	ContentPreview *string       `json:"contentPreview,omitempty"` // max 500 chars
	TokensIn       *int          `json:"tokensIn,omitempty"`
	TokensOut      *int          `json:"tokensOut,omitempty"`
	HasToolUse     bool          `json:"hasToolUse"`
	ToolKind       *ToolCallKind `json:"toolKind,omitempty"` // ACP-aligned tool classification
	ToolNamesCSV   *string       `json:"toolNamesCsv,omitempty"`
	HasThinking    bool          `json:"hasThinking"`
	IsError        bool          `json:"isError"`
	StopReason     *StopReason   `json:"stopReason,omitempty"` // ACP per-turn stop reason
	RawByteLength  *int          `json:"rawByteLength,omitempty"`
	ToolCallID     *string       `json:"toolCallId,omitempty"`    // MCP correlation (was toolUseId)
	EntryID        *string       `json:"entryId,omitempty"`       // Provider-native ID
	ParentEntryID  *string       `json:"parentEntryId,omitempty"` // Parent entry link
	Depth          int           `json:"depth"`                   // 0 = message, 1 = content part
	ParentIndex    *int          `json:"parentIndex,omitempty"`   // entryIndex of parent (nil for depth=0)
	ToolInput      *string       `json:"toolInput,omitempty"`     // tool_use input JSON
	ToolOutput     *string       `json:"toolOutput,omitempty"`    // tool_result output JSON
	Extra          *string       `json:"extra,omitempty"`         // JSON overflow for provider-specific data
	PartType       *string       `json:"partType,omitempty"`      // provider's original part type label (nil for depth=0)
}

SessionEntry represents a single indexed entry within a session transcript. Defined for v2 content-layer use; NOT used in v1 PublishRequest wire format. Maps 1:1 to a row in the session_entries table. All optional fields use pointer types to distinguish absent from zero. JSON tags use camelCase aligned with ACP content model.

type SessionID

type SessionID string

SessionID is a validated session identifier from a source provider. Accepted formats:

  • UUID: "99d59925-36bc-424c-a789-8be54d9702ba"
  • Claude subagent: "agent-a3aee4f"
  • ACP session: "sess_3cd91f52effeXd3QAJ54jOyzv5" (ACP sess_ prefix)
  • OpenCode session: "ses_3cd91f52effeXd3QAJ54jOyzv5"
  • OpenCode message: "msg_001abc"

func NewSessionID

func NewSessionID(raw string) (SessionID, error)

NewSessionID validates and constructs a SessionID.

func (SessionID) JSONSchema

func (SessionID) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (SessionID) String

func (s SessionID) String() string

type SessionIdentity

type SessionIdentity struct {
	SessionID       SessionID  `json:"sessionId"`
	ParentSessionID *SessionID `json:"parentUuid,omitempty"`
	SchemaVersion   int        `json:"schemaVersion"`
}

SessionIdentity holds the identification fields for a session. JSON tags use camelCase to match CLI UnifiedMetadata wire format.

type SessionOutcome

type SessionOutcome string

SessionOutcome represents the resolution status of a session.

const (
	OutcomeResolved SessionOutcome = "resolved"
	OutcomePartial  SessionOutcome = "partial"
	OutcomeFailed   SessionOutcome = "failed"
)

func (SessionOutcome) IsValid

func (o SessionOutcome) IsValid() bool

IsValid returns true if the outcome is one of the known variants.

func (SessionOutcome) JSONSchema

func (SessionOutcome) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (SessionOutcome) String

func (o SessionOutcome) String() string

type SessionScorecard

type SessionScorecard struct {
	// Token efficiency inputs.
	M2TokenOutcomeRatio     *float64 `json:"m2TokenOutcomeRatio,omitempty"`
	M5ContextUtilizationPct *float64 `json:"m5ContextUtilizationPct,omitempty"`
	M6OutputSurvivalPct     *float64 `json:"m6OutputSurvivalPct,omitempty"`
	RetryTokensWasted       *int     `json:"retryTokensWasted,omitempty"`
	TotalTokens             *int     `json:"totalTokens,omitempty"`
	CostTotalUSD            *float64 `json:"costTotalUsd,omitempty"`
	// Prompt quality inputs.
	SpecQualityScore     *float64 `json:"specQualityScore,omitempty"`
	SignalDensity        *float64 `json:"signalDensity,omitempty"`
	M7SpecHasExamples    *bool    `json:"m7SpecHasExamples,omitempty"`
	M7SpecHasConstraints *bool    `json:"m7SpecHasConstraints,omitempty"`
	// Loop efficiency inputs.
	M4ConsecutiveErrorMax *int `json:"m4ConsecutiveErrorMax,omitempty"`
	WithinSessionReverts  *int `json:"withinSessionReverts,omitempty"`
	// Outcome echoes the session outcome so the card can apply the
	// "failed outcome with above-median cost" token-efficiency trigger.
	Outcome SessionOutcome `json:"outcome,omitempty"`
}

SessionScorecard holds the deterministic per-session quality signals needed by the Highlights self-assessment card. It is a flat projection of the session_metrics fields the three axis cards (token efficiency, prompt quality, loop efficiency) consume. Fields are pointers so the client can distinguish "not computed" (nil) from a real zero value when applying threshold bands.

type SessionStats

type SessionStats struct {
	TurnCount     int   `json:"turnCount"`
	ToolCallCount int   `json:"toolCallCount"`
	SubagentCount int   `json:"subagentCount"`
	DurationMs    int64 `json:"durationMs"`
	TokensIn      int   `json:"tokensIn"`
	TokensOut     int   `json:"tokensOut"`
	// ACP-aligned token breakdown (optional — not all providers report these).
	ThoughtTokens     *int `json:"thoughtTokens,omitempty"`     // Reasoning/thinking tokens
	CachedReadTokens  *int `json:"cachedReadTokens,omitempty"`  // Prompt cache hits
	CachedWriteTokens *int `json:"cachedWriteTokens,omitempty"` // Prompt cache writes
}

SessionStats holds aggregate metrics extracted from transcript data.

type SessionSummary

type SessionSummary struct {
	ID            string    `json:"id"`
	Harness       Harness   `json:"harness"`
	StartTime     time.Time `json:"startTime"`
	DurationMins  float64   `json:"durationMins"`
	TotalTokens   int       `json:"totalTokens"`
	TurnCount     int       `json:"turnCount"`
	ToolCallCount int       `json:"toolCallCount"`
	Project       string    `json:"project,omitempty"`
	// ProjectHash is the opaque project identifier (projects.project_hash).
	// The frontend resolves display name → hash from this field for the
	// Map/Review REST endpoints (contract §9.1).
	ProjectHash     string  `json:"projectHash,omitempty"`
	Outcome         string  `json:"outcome,omitempty"`
	ParentSessionID *string `json:"parentSessionId,omitempty"`
	// Preview is the raw first user message of the session, sourced from the
	// already-redacted indexed transcript (session_entries.content_preview). It
	// is redaction-safe by construction. Empty when the session has no indexed
	// user entry. The web client formats it for display.
	Preview string `json:"preview,omitempty"`
}

SessionSummary is a session without turns, used in the sessions list.

type SessionsPayload

type SessionsPayload struct {
	Sessions []SessionSummary `json:"sessions"`
}

SessionsPayload is the data sent on the sessions WebSocket channel.

type ShutdownResponse

type ShutdownResponse struct {
	Status string `json:"status"`
}

ShutdownResponse is the JSON response for POST /api/v1/shutdown.

type SourceFormat

type SourceFormat string

SourceFormat identifies the transcript file format.

const (
	SourceFormatJSONL SourceFormat = "jsonl" // Claude Code JSONL transcripts
	SourceFormatJSON  SourceFormat = "json"  // OpenCode JSON transcripts
)

func (SourceFormat) IsValid

func (f SourceFormat) IsValid() bool

IsValid returns true if the SourceFormat is one of the known variants.

func (SourceFormat) JSONSchema

func (SourceFormat) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (SourceFormat) String

func (f SourceFormat) String() string

type SourceInfo

type SourceInfo struct {
	FilePath string       `json:"filePath,omitempty"` // Original source transcript path
	Format   SourceFormat `json:"format"`             // "jsonl" or "json"
}

SourceInfo identifies the original transcript file and its format.

type StopReason

type StopReason string

StopReason represents why a session or turn ended. ACP per-turn stop reasons; content-layer type for future use.

const (
	StopReasonEndTurn         StopReason = "end_turn"
	StopReasonCancelled       StopReason = "cancelled"
	StopReasonMaxTokens       StopReason = "max_tokens"
	StopReasonMaxTurnRequests StopReason = "max_turn_requests"
	StopReasonRefusal         StopReason = "refusal"
)

func (StopReason) IsValid

func (r StopReason) IsValid() bool

IsValid returns true if the stop reason is one of the known variants.

func (StopReason) JSONSchema

func (StopReason) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (StopReason) String

func (r StopReason) String() string

type SubagentRef

type SubagentRef struct {
	SessionID  SessionID `json:"sessionId"`
	ParentUUID SessionID `json:"parentUuid"`
}

SubagentRef records a reference to a subagent session spawned during a parent session.

type SubscriptionValidationCase

type SubscriptionValidationCase struct {
	Name  string `yaml:"name"`
	Topic string `yaml:"topic"`
	Axis  string `yaml:"axis,omitempty"`
	ID    string `yaml:"id,omitempty"`
	Valid bool   `yaml:"valid"`
}

SubscriptionValidationCase is a test case for ValidateSubscription.

type TargetKind

type TargetKind string

TargetKind identifies what is being annotated. Derived from the 4-arm exclusive arc on the annotations table (R3).

const (
	TargetSession    TargetKind = "session"
	TargetEntry      TargetKind = "entry"      // turn, tool call, tool result
	TargetAnnotation TargetKind = "annotation" // meta-annotation
	TargetProject    TargetKind = "project"    // project-level annotation (F1)
)

func (TargetKind) IsValid

func (k TargetKind) IsValid() bool

IsValid returns true if the target kind is one of the known variants.

func (TargetKind) JSONSchema

func (TargetKind) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (TargetKind) String

func (k TargetKind) String() string

type TaskSummary

type TaskSummary struct {
	SessionID   string   `json:"sessionId"`
	EntryIndex  int      `json:"entryIndex"` // depth-0 user-turn entry index (task identity)
	Title       string   `json:"title"`      // first words of the user turn, <=80 chars
	StartMs     *int64   `json:"startMs,omitempty"`
	Outcome     string   `json:"outcome,omitempty"` // session-level outcome
	EditedFiles []string `json:"editedFiles"`
	ReadCount   int      `json:"readCount"`
	RetryLoop   bool     `json:"retryLoop"` // an error streak >=2 occurs inside this task's range
	Labels      []string `json:"labels"`    // effective auto/manual annotation values, plain strings
}

TaskSummary is one task: a depth-0 user turn and everything until the next user turn (spec §2 "Task", v1 grain).

func NewTaskSummary

func NewTaskSummary(sessionID string, entryIndex int) TaskSummary

NewTaskSummary returns a TaskSummary with all slices initialized to empty (never-nil marshal guarantee).

type TaxonomyFamilyNode

type TaxonomyFamilyNode struct {
	Family string                  `json:"family"`
	Types  []AnnotationTypeSummary `json:"types"`
}

TaxonomyFamilyNode represents a family node with its associated annotation types.

type TaxonomyNode

type TaxonomyNode struct {
	Class    string               `json:"class"`
	Families []TaxonomyFamilyNode `json:"families"`
}

TaxonomyNode represents a class node in the class > family > type taxonomy tree.

type TimestampInfo

type TimestampInfo struct {
	Start    int64  `json:"start"`              // Unix millis
	End      int64  `json:"end"`                // Unix millis
	Ingested *int64 `json:"ingested,omitempty"` // Unix millis; nil if not yet ingested
}

TimestampInfo records session timing in Unix milliseconds.

type ToolCallDetail

type ToolCallDetail struct {
	ID         string       `json:"id"`
	Name       string       `json:"name"`
	Arguments  string       `json:"arguments"`
	Result     string       `json:"result"`
	DurationMs *int         `json:"durationMs,omitempty"`
	ExitCode   *int         `json:"exitCode,omitempty"`
	FilePath   string       `json:"filePath,omitempty"`
	IsError    bool         `json:"isError,omitempty"`
	ToolKind   ToolCallKind `json:"toolKind,omitempty"`
}

ToolCallDetail is a tool call in the detail view.

type ToolCallKind

type ToolCallKind string

ToolCallKind classifies a tool call in an agent session. Aligns with ACP's ToolCallUpdate.kind — enables ExplorationRatio without heuristic parsing.

const (
	ToolCallKindRead    ToolCallKind = "read"
	ToolCallKindEdit    ToolCallKind = "edit"
	ToolCallKindDelete  ToolCallKind = "delete"
	ToolCallKindMove    ToolCallKind = "move"
	ToolCallKindSearch  ToolCallKind = "search"
	ToolCallKindExecute ToolCallKind = "execute"
	ToolCallKindThink   ToolCallKind = "think"
	ToolCallKindFetch   ToolCallKind = "fetch"
	ToolCallKindOther   ToolCallKind = "other"
)

func (ToolCallKind) IsValid

func (k ToolCallKind) IsValid() bool

IsValid returns true if the tool call kind is one of the known variants.

func (ToolCallKind) JSONSchema

func (ToolCallKind) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (ToolCallKind) String

func (k ToolCallKind) String() string

type TranscriptContent

type TranscriptContent struct {
	ContractVersion PushContractVersion   `json:"contractVersion"`
	Kind            ContentKind           `json:"kind"`
	SessionDetail   *SessionDetailPayload `json:"sessionDetail,omitempty"`
}

TranscriptContent is the versioned, self-describing wire body that `peasant push` uploads in place of raw provider JSONL. The village decodes this envelope (migrate-on-read for legacy/older blobs) and renders SessionDetail.

VERSION CONFLICT-WINNER (N1/B5): a TranscriptContent envelope carries TWO version markers — the envelope's ContractVersion and the embedded SessionDetailPayload.SchemaVersion. They are emitted IN LOCKSTROKE by peasant (both equal defaults.PublishSchemaVersion). If a decoder ever observes them to DISAGREE (e.g. a hand-edited or partially-migrated blob), the ENVELOPE's ContractVersion WINS and is authoritative for migrate-on-read dispatch; the embedded SchemaVersion is advisory and exists so a SessionDetailPayload extracted and stored on its OWN (outside any envelope) remains self-describing. The village SLICE-B3 ContentMigrator MUST honor this same rule.

type TranscriptID

type TranscriptID string

TranscriptID is a validated village-side transcript identifier. The village generates a UUID per published transcript (the same value carried in PublishResponse.TranscriptID); the pull surface keys off it. Newtype over string so the identifier flows typed across the pull pipeline, mirroring the SessionID/ProjectHash precedent.

func NewTranscriptID

func NewTranscriptID(raw string) (TranscriptID, error)

NewTranscriptID validates and constructs a TranscriptID. The input must be a canonical lowercase-hex UUID; anything else is rejected so a pasted URL slug, truncated id, or path-bearing string never reaches the filesystem layout ({villageHost}/{transcriptId}/...).

func (TranscriptID) JSONSchema

func (TranscriptID) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (TranscriptID) String

func (t TranscriptID) String() string

type TrendsPayload

type TrendsPayload struct {
	Days          []DayStats `json:"days"`
	TotalTokens   int        `json:"totalTokens"`
	TotalSessions int        `json:"totalSessions"`
}

TrendsPayload is the data sent on the trends WebSocket channel.

type TurnDetail

type TurnDetail struct {
	Index       int              `json:"index"`
	Role        Role             `json:"role"`
	Content     string           `json:"content"`
	ToolCalls   []ToolCallDetail `json:"toolCalls,omitempty"`
	Timestamp   time.Time        `json:"timestamp"`
	Depth       int              `json:"depth"`
	ParentIndex *int             `json:"parentIndex,omitempty"`
	AgentName   string           `json:"agentName,omitempty"`

	// Enrichment fields — propagated from session_entries.
	EntryType   EntryType   `json:"entryType,omitempty"`
	HasThinking bool        `json:"hasThinking,omitempty"`
	StopReason  *StopReason `json:"stopReason,omitempty"`
	TokensIn    *int        `json:"tokensIn,omitempty"`
	TokensOut   *int        `json:"tokensOut,omitempty"`
}

TurnDetail is a turn with full content for the detail view.

type TypeDefinition

type TypeDefinition struct {
	// TypeID is the dot-notation identifier (e.g., "quality.my_signal").
	// Must match the CHECK (type_id LIKE '%.%') constraint.
	TypeID string

	// DisplayName is the human-readable name.
	DisplayName string

	// Description is optional free-text documentation.
	Description string

	// FamilyID is the UUID FK to annotation_families.id.
	FamilyID string

	// ValueDomain defines permissible values for this type.
	ValueDomain ValueDomain

	// LowerIsBetter is nil for non-ordinal types, false for higher-is-better, true for lower-is-better.
	LowerIsBetter *bool

	// Origin is who created this type (system, user, group).
	Origin TypeOrigin

	// AllowedTargetKinds specifies which target kinds this type allows (V16).
	// Nil or empty means all target kinds are allowed.
	AllowedTargetKinds []TargetKind
}

TypeDefinition is the input for registering a new annotation type.

type TypeDependency

type TypeDependency struct {
	// TypeID is the dependent annotation type.
	TypeID string

	// DependsOn is the type that must be computed first.
	DependsOn string

	// Required: true means this dependency must be satisfied before TypeID can produce a value.
	Required bool

	// Rationale documents why this dependency exists.
	Rationale string
}

TypeDependency represents a dependency edge in the annotation_type_deps table.

type TypeFilter

type TypeFilter struct {
	// Status filters to types with this status (e.g., StatusActive).
	// Zero value includes all statuses except deprecated/retired (unless IncludeDeprecated is set).
	Status AnnotationStatus

	// FamilyID filters to types in this family by UUID FK. "" means all families.
	FamilyID string

	// Origin filters to types from this origin. Zero value means all origins.
	Origin TypeOrigin

	// IncludeDeprecated includes deprecated types when true.
	// Has no effect when Status is set (Status takes precedence).
	IncludeDeprecated bool
}

TypeFilter constrains which annotation types ListTypes returns. Zero values mean "no filter" (include all non-deprecated types).

type TypeOrigin

type TypeOrigin string

TypeOrigin identifies who created an annotation type.

const (
	OriginSystem TypeOrigin = "system"
	OriginUser   TypeOrigin = "user"
	OriginGroup  TypeOrigin = "group"
)

func (TypeOrigin) IsValid

func (o TypeOrigin) IsValid() bool

IsValid returns true if the type origin is one of the known variants.

func (TypeOrigin) JSONSchema

func (TypeOrigin) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (TypeOrigin) String

func (o TypeOrigin) String() string

type UnifiedMetadata

type UnifiedMetadata struct {
	SchemaVersion int             `json:"schemaVersion"`
	SessionID     SessionID       `json:"sessionId"`
	ParentUUID    *SessionID      `json:"parentUuid"` // nil for root sessions, pointer for nullable JSON
	ModelHarness  Harness         `json:"harness"`
	Model         ModelID         `json:"model"`
	Version       string          `json:"version"` // provider tool version (e.g. "2.1.47")
	Timestamp     TimestampInfo   `json:"timestamp"`
	Source        SourceInfo      `json:"source"`
	Git           GitContext      `json:"git"`
	Project       ProjectContext  `json:"project"`
	HostSlug      HostSlug        `json:"hostSlug"`
	Stats         SessionStats    `json:"stats"`
	Subagents     []SubagentRef   `json:"subagents"`
	CWD           string          `json:"cwd,omitempty"`       // Real project working directory (v7+)
	DerivedAt     *int64          `json:"derivedAt,omitempty"` // Unix ms when metadata.json was derived from DB (v8+); nil if written before DB insert
	Diagnostics   DiagnosticsInfo `json:"diagnostics"`
	ContentHash   string          `json:"contentHash"`  // SHA3-256 of transcript bytes
	MetadataHash  string          `json:"metadataHash"` // SHA3-256 of metadata (excluding hashes + redaction)
	Redaction     RedactionInfo   `json:"redaction"`
}

UnifiedMetadata is the on-disk JSON stored alongside each raw transcript. It drives the adapter layer for downstream consumers and incremental diff logic.

func NewUnifiedMetadata

func NewUnifiedMetadata() UnifiedMetadata

NewUnifiedMetadata creates a UnifiedMetadata with SchemaVersion set to MetadataSchemaVersion and empty slices initialized (not nil) so JSON serialization produces [] instead of null.

func (*UnifiedMetadata) UnmarshalJSON

func (m *UnifiedMetadata) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes UnifiedMetadata, accepting the legacy pre-v9 on-disk harness key. The canonical key is json:"harness" (v9+); pre-v9 files wrote json:"modelHarness". When the canonical key is absent but the legacy key is present, the legacy value is adopted so a pre-v9 file still reads its harness correctly in the window before the v9 DIFF-stage re-extract rewrites it. Marshalling is unaffected (struct tags emit only "harness").

type UnusualSignal

type UnusualSignal struct {
	Kind       string  `json:"kind"`       // e.g. "retryLoops"
	Label      string  `json:"label"`      // plain, neutral
	PerChange  float64 `json:"perChange"`  // this change's per-conversation rate
	PerProject float64 `json:"perProject"` // the project's per-conversation baseline
}

UnusualSignal is one neutral rate-elevation: a per-conversation rate for this change that runs notably above the project baseline. Facts for orientation — the surface shows, it does not grade.

type ValidGenExpectation

type ValidGenExpectation struct {
	Parses         bool   `yaml:"parses"`
	WantID         string `yaml:"want_id"`           // casing name whose value is the expected normalized ID
	FromURLPerForm bool   `yaml:"from_url_per_form"` // take FromURL from each ref_form
}

ValidGenExpectation is the expectation attached to the valid generator.

type ValidGeneration

type ValidGeneration struct {
	Axes   []string            `yaml:"axes"`
	Expect ValidGenExpectation `yaml:"expect"`
}

ValidGeneration declares the valid cross-product and its attached expectation.

type ValueDomain

type ValueDomain struct {
	Kind              ValueDomainKind    `json:"kind"`
	Datatype          AnnotationDatatype `json:"datatype"`
	PermissibleValues []string           `json:"permissibleValues,omitempty"` // for enumerated
	ConstraintSpec    string             `json:"constraintSpec,omitempty"`    // for described; JSON
}

ValueDomain defines the permissible values for an annotation type (ISO 11179). For enumerated domains, PermissibleValues holds the finite set of allowed strings. For described domains, ConstraintSpec holds a JSON-encoded range or pattern.

type ValueDomainKind

type ValueDomainKind string

ValueDomainKind distinguishes enumerated (finite set of allowed values) from described (range or pattern constraint) annotation value domains (ISO 11179).

const (
	DomainEnumerated ValueDomainKind = "enumerated"
	DomainDescribed  ValueDomainKind = "described"
)

func (ValueDomainKind) IsValid

func (k ValueDomainKind) IsValid() bool

IsValid returns true if the value domain kind is one of the known variants.

func (ValueDomainKind) JSONSchema

func (ValueDomainKind) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (ValueDomainKind) String

func (k ValueDomainKind) String() string

type Visibility

type Visibility string

Visibility controls who can access a published transcript.

const (
	VisibilityPrivate Visibility = "private"
	VisibilityGroup   Visibility = "group"
	VisibilityPublic  Visibility = "public"
)

func (Visibility) IsValid

func (v Visibility) IsValid() bool

IsValid returns true if the visibility is one of the known variants.

func (Visibility) JSONSchema

func (Visibility) JSONSchema() (jsonschema.Schema, error)

JSONSchema implements jsonschema.Exposer.

func (Visibility) String

func (v Visibility) String() string

type WalkthroughStep

type WalkthroughStep struct {
	File    string `json:"file"`
	Line    *int   `json:"line,omitempty"`
	Excerpt string `json:"excerpt"`
}

WalkthroughStep is a single file visit in a session trail.

type WalkthroughTrail

type WalkthroughTrail struct {
	SessionID  string            `json:"sessionId"`
	Title      string            `json:"title"`
	Date       string            `json:"date"`
	TurnCount  int               `json:"turnCount"`
	Steps      []WalkthroughStep `json:"steps"`
	IsCoherent bool              `json:"isCoherent"` // true if linear path, false if scattered
}

WalkthroughTrail is the file path extracted from a single session.

Directories

Path Synopsis
cmd
release-guard command
Command release-guard is the thin CLI the release workflows shell out to.
Command release-guard is the thin CLI the release workflows shell out to.
schema-gen command
internal
contractgates
Package contractgates holds the SYNTHETIC-BREAK tests for the schema repo's breaking-change contract gates (PROPOSAL-4 W5 / b3).
Package contractgates holds the SYNTHETIC-BREAK tests for the schema repo's breaking-change contract gates (PROPOSAL-4 W5 / b3).
release
Package release holds the pure, table-driven-testable logic that the release CI workflows depend on: the release-PR title grammar, the git-tag grammar, the typed release-kind derivation, and the final-release guard decision.
Package release holds the pure, table-driven-testable logic that the release CI workflows depend on: the release-PR title grammar, the git-tag grammar, the typed release-kind derivation, and the final-release guard decision.
migrations
Package openapi builds the committed OpenAPI 3.1 / JSON-Schema artifacts from the Go schema source.
Package openapi builds the committed OpenAPI 3.1 / JSON-Schema artifacts from the Go schema source.

Jump to

Keyboard shortcuts

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