Unknown, partial, and failed coverage stay distinct from no known dependencies. Co-authored-by: Cursor <cursoragent@cursor.com>
362 lines
14 KiB
Go
362 lines
14 KiB
Go
// 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
|
|
}
|