// Package docrevision implements controlled/freeform document Version + Revision ledger. package docrevision import ( "errors" "time" ) const ( SchemaVersion = 1 VersionOpen = "open" VersionSealed = "sealed" OriginTemplate = "template" OriginAgent = "agent" OriginAgentSquad = "agent_squad" OriginMigration = "migration" SourceTemplate = "template" SourceHuman = "human" SourceAgent = "agent" SourceAgentSquad = "agent_squad" SourceMigration = "migration" SourceMigrationRepair = "migration_repair" SourceSystem = "system" ChangeHumanRevision = "human_revision" ChangeAgentCommit = "agent_commit" ChangeAgentNoop = "agent_noop" ChangeImport = "import" ChangeRestoreAsNew = "restore_as_new" ChangeMigrationRepair = "migration_repair" ActorHuman = "human" ActorAgent = "agent" ActorAgentSquad = "agent_squad" ActorTemplate = "template" ActorMigration = "migration" ActorSystem = "system" CandidateReady = "ready" CandidateNeedsConfirmation = "needs_confirmation" CandidateCommitted = "committed" CandidateRejected = "rejected" CandidateStale = "stale" CandidateQualityFailed = "quality_failed" RiskLow = "low" RiskMedium = "medium" RiskHigh = "high" RiskCritical = "critical" AnalysisComplete = "complete" AnalysisFallback = "fallback" AnalysisUnassessed = "unassessed" AnalysisCorrected = "corrected" // Trace coverage carried on a formal commit report. These are not PI analysis statuses. ImpactConfirmed = "confirmed_impact" ImpactPossible = "possible_impact" ImpactNoKnown = "no_known_dependencies" ImpactIndexPending = "index_pending" ImpactPartial = "partial" ImpactFailed = "failed" // Report authority separates a candidate estimate from the report written at formal commit. ReportProposed = "proposed" ReportAuthoritative = "authoritative" // Proposed reports stay actionable only while active. ReportActive = "active" ReportSuperseded = "superseded" ReportRejected = "rejected" ReportExpired = "expired" ReportCommitted = "committed" ErrCodeHeadConflict = "DOCUMENT_HEAD_CONFLICT" ErrCodeEditForbidden = "DOCUMENT_EDIT_FORBIDDEN" ErrCodeBusy = "DOCUMENT_BUSY" ErrCodeCandidateStale = "AGENT_CANDIDATE_STALE" ErrCodeReportInvalid = "CHANGE_REPORT_INVALID" ErrCodeLifecycleLocked = "DOCUMENT_LIFECYCLE_LOCKED" ErrCodeTooLarge = "DOCUMENT_TOO_LARGE" ErrCodeNeedsConfirmation = "AGENT_NEEDS_CONFIRMATION" ErrCodeNotFound = "DOCUMENT_REVISION_NOT_FOUND" ErrCodeInvalidDocID = "DOCUMENT_REVISION_INVALID_DOC_ID" ) var ( ErrNotFound = errors.New("docrevision: not found") ErrInvalidDocID = errors.New("docrevision: invalid doc_id") ErrHeadConflict = errors.New("docrevision: head conflict") ErrLifecycleLocked = errors.New("docrevision: lifecycle locked") ErrCandidateStale = errors.New("docrevision: candidate stale") ErrReportInvalid = errors.New("docrevision: change report invalid") ErrNeedsConfirmation = errors.New("docrevision: high/critical needs confirmation") ErrIdempotencyConflict = errors.New("docrevision: idempotency conflict") ErrForbidden = errors.New("docrevision: forbidden") ErrTooLarge = errors.New("docrevision: document too large") ErrNoOpenVersion = errors.New("docrevision: no open version") ) const MaxMarkdownBytes = 8 << 20 // 8 MiB // ActorSnapshot is an immutable attribution payload frozen at write time. type ActorSnapshot struct { DisplayName string `json:"display_name,omitempty"` Role string `json:"role,omitempty"` Duty string `json:"duty,omitempty"` AgentKey string `json:"agent_key,omitempty"` SquadName string `json:"squad_name,omitempty"` Model string `json:"model,omitempty"` ConfigVer string `json:"config_version,omitempty"` Extra map[string]string `json:"extra,omitempty"` } type ContentBlob struct { ContentSHA256 string `json:"content_sha256"` ContentMarkdown string `json:"content_markdown"` ByteSize int64 `json:"byte_size"` CreatedAt time.Time `json:"created_at"` } type BlockNode struct { ID string `json:"id"` Type string `json:"type"` StartOffset int `json:"start_offset"` EndOffset int `json:"end_offset"` HeadingPath string `json:"heading_path,omitempty"` BusinessKey string `json:"business_key,omitempty"` Fingerprint string `json:"fingerprint,omitempty"` Order int `json:"order"` } type Snapshot struct { ID int64 `json:"id"` DocID string `json:"doc_id"` ContentSHA256 string `json:"content_sha256"` ParentSnapshotID *int64 `json:"parent_snapshot_id,omitempty"` BlockMap []BlockNode `json:"block_map"` SourceKind string `json:"source_kind"` ActorUserID *int64 `json:"actor_user_id,omitempty"` ActorRef string `json:"actor_ref,omitempty"` ActorSnapshot ActorSnapshot `json:"actor_snapshot"` SourceRunID string `json:"source_run_id,omitempty"` CreatedAt time.Time `json:"created_at"` } type Version struct { ID int64 `json:"id"` DocID string `json:"doc_id"` VersionNo int `json:"version_no"` Status string `json:"status"` OriginKind string `json:"origin_kind"` BaselineSnapshotID int64 `json:"baseline_snapshot_id"` HeadSnapshotID int64 `json:"head_snapshot_id"` HumanRevisionCount int `json:"human_revision_count"` SourceRunID string `json:"source_run_id,omitempty"` ChangeReportID *int64 `json:"change_report_id,omitempty"` OpenedAt time.Time `json:"opened_at"` SealedAt *time.Time `json:"sealed_at,omitempty"` } type ChangeEvent struct { ID int64 `json:"id"` DocID string `json:"doc_id"` VersionID int64 `json:"version_id"` EventNo int `json:"event_no"` FromSnapshotID *int64 `json:"from_snapshot_id,omitempty"` ToSnapshotID int64 `json:"to_snapshot_id"` ChangeKind string `json:"change_kind"` ActorKind string `json:"actor_kind"` ActorUserID *int64 `json:"actor_user_id,omitempty"` ActorRef string `json:"actor_ref,omitempty"` ActorSnapshot ActorSnapshot `json:"actor_snapshot"` ChangeSet []DiffHunk `json:"change_set,omitempty"` EditSessionID string `json:"edit_session_id,omitempty"` RequestID string `json:"request_id,omitempty"` IdempotencyKey string `json:"idempotency_key"` CreatedAt time.Time `json:"created_at"` } type AgentCandidate struct { ID int64 `json:"id"` DocID string `json:"doc_id"` InputSnapshotID int64 `json:"input_snapshot_id"` OutputSnapshotID *int64 `json:"output_snapshot_id,omitempty"` RunID string `json:"run_id"` ProposalID string `json:"proposal_id,omitempty"` Status string `json:"status"` AuthorizedScope string `json:"authorized_scope,omitempty"` QualityResult string `json:"quality_result,omitempty"` ChangeReportID *int64 `json:"change_report_id,omitempty"` ActorKind string `json:"actor_kind"` ActorSnapshot ActorSnapshot `json:"actor_snapshot"` CreatedAt time.Time `json:"created_at"` DecidedAt *time.Time `json:"decided_at,omitempty"` } type ChangeReport struct { ID int64 `json:"id"` DocID string `json:"doc_id"` FromSnapshotID int64 `json:"from_snapshot_id"` ToSnapshotID int64 `json:"to_snapshot_id"` SchemaVersion int `json:"schema_version"` Summary []string `json:"summary"` RiskLevel string `json:"risk_level"` RiskItems []RiskItem `json:"risk_items"` ProjectImpacts map[string]any `json:"project_impacts"` DocumentImpacts []DocImpact `json:"document_impacts"` OpenQuestions []string `json:"open_questions"` AnalysisStatus string `json:"analysis_status"` ModelSnapshot string `json:"model_snapshot,omitempty"` PromptVersion string `json:"prompt_version,omitempty"` DeterministicFacts map[string]any `json:"deterministic_facts"` CorrectsReportID *int64 `json:"corrects_report_id,omitempty"` // Authority is proposed on a candidate estimate and authoritative on the formal-commit successor. Authority string `json:"authority,omitempty"` // Lifecycle is active, superseded, rejected, expired, or committed. Lifecycle string `json:"lifecycle,omitempty"` // SuccessorReportID points from a committed proposed report to its authoritative report. SuccessorReportID *int64 `json:"successor_report_id,omitempty"` RawJSON string `json:"-"` CreatedAt time.Time `json:"created_at"` } type RiskItem struct { Category string `json:"category"` Description string `json:"description"` Mitigation string `json:"mitigation,omitempty"` } type DocImpact struct { DocID string `json:"doc_id"` ImpactType string `json:"impact_type"` Reason string `json:"reason"` RecommendedAction string `json:"recommended_action,omitempty"` } type DiffHunk struct { ID string `json:"id"` Kind string `json:"kind"` // insert|delete|modify|move Section string `json:"section,omitempty"` BeforeText string `json:"before_text,omitempty"` AfterText string `json:"after_text,omitempty"` BlockIDBefore string `json:"block_id_before,omitempty"` BlockIDAfter string `json:"block_id_after,omitempty"` ActorKind string `json:"actor_kind,omitempty"` ActorLabel string `json:"actor_label,omitempty"` LineStart int `json:"line_start,omitempty"` LineEnd int `json:"line_end,omitempty"` } type DiffResult struct { FromSnapshotID int64 `json:"from_snapshot_id"` ToSnapshotID int64 `json:"to_snapshot_id"` Summary DiffSummary `json:"summary"` Hunks []DiffHunk `json:"hunks"` } type DiffSummary struct { Inserts int `json:"inserts"` Deletes int `json:"deletes"` Modifies int `json:"modifies"` Moves int `json:"moves"` } type DocRootPointers struct { DocID string Kind string // controlled|freeform LedgerVersionID *int64 HeadSnapshotID *int64 HeadRevisionNo int ReviewSnapshotID *int64 RevisionSchemaVer int RowRevision int64 LifecycleState string ContentSHA256 string LegacyVersionID int // freeform only WorkDir string ProjectID int64 AuthorID *int64 } type RevisionState struct { DocID string `json:"doc_id"` CurrentVersionNo int `json:"current_version_no"` VersionStatus string `json:"version_status"` BaselineSnapshotID int64 `json:"baseline_snapshot_id"` HeadSnapshotID int64 `json:"head_snapshot_id"` HeadRevisionNo int `json:"head_revision_no"` HeadSHA256 string `json:"head_sha256"` ManualChangeCount int `json:"manual_change_count"` Capabilities []string `json:"capabilities"` ETag string `json:"etag"` HeadBlockMap []BlockNode `json:"head_block_map,omitempty"` // Pending* expose the latest needs_confirmation agent candidate (not yet in version list). PendingCandidateID *int64 `json:"pending_candidate_id,omitempty"` PendingChangeReportID *int64 `json:"pending_change_report_id,omitempty"` PendingRiskLevel string `json:"pending_risk_level,omitempty"` PendingCandidateStatus string `json:"pending_candidate_status,omitempty"` // CanDecidePending is set by the API layer after authz (author/admin may decide). CanDecidePending bool `json:"can_decide_pending"` } type HumanRevisionRequest struct { DocID string Markdown string ExpectedHeadSnapshot *int64 ExpectedRevisionNo *int IdempotencyKey string EditSessionID string RequestID string ActorUserID int64 ActorSnapshot ActorSnapshot LifecycleState string WorkDir string ProjectID int64 AllowCreateBaseline bool ClientBlockMap []BlockNode } type HumanRevisionResult struct { State RevisionState `json:"state"` Event ChangeEvent `json:"event"` Overlay DiffResult `json:"manual_overlay"` Conflict *ConflictInfo `json:"conflict,omitempty"` Report *ChangeReport `json:"report,omitempty"` } type ConflictInfo struct { Code string `json:"code"` BaseSnapshotID int64 `json:"base_snapshot_id"` CurrentSnapshotID int64 `json:"current_snapshot_id"` CurrentRevisionNo int `json:"current_revision_no"` CurrentSHA256 string `json:"current_sha256"` } type AgentCandidateRequest struct { DocID string RunID string ProposalID string InputSnapshotID int64 OutputMarkdown string ReportJSON string ActorKind string ActorSnapshot ActorSnapshot AuthorizedScope string OnBehalfOf *int64 } type CommitAgentDecision struct { Decision string // commit|reject Confirmed bool // required when risk high/critical ExpectedInputSHA string ExpectedOutputSHA string Reason string ActorUserID int64 ActorSnapshot ActorSnapshot }