Files
Agent-System-Backend/internal/runmgr/document_delivery.go
T
weichen fec2d16cc6 Close Task 10 renderer delivery gaps
Why:
- Independent review found trusted-boundary, semantic parity, replay-budget,
  comparison, persistence, cancellation, provenance, and routing gaps.
- Storage migration must include the new durable delivery table.

Evidence:
- go test -count=1 ./...
- go test -race ./internal/docgen ./internal/tools ./internal/runmgr
- go test ./... (deps/agent-document-renderer)
- go vet ./...
- go build ./...
- CGO_ENABLED=0 go build -trimpath ./cmd/agent-system
- Python house-style unittest suite and git diff --check

Impact:
- Word delivery now uses host-owned freezes, Markdown-first resumable persistence,
  closed registration boundaries, semantic shared rendering, and real comparison.
- Controlled/project documents still fail closed to RDM and non-Word flows remain
  unchanged.

Refs:
- Unified Document Renderer implementation plan Task 10
- /tmp/task10-backend-review-last.md
- Renderer d5cd8c126045a27d5a5cc5da23f64d3c737e116a
2026-10-15 21:44:03 +00:00

175 lines
7.0 KiB
Go

package runmgr
import (
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"strings"
"agent-system-backend/internal/docgen"
"agent-system-backend/internal/store"
core "agent-system-core"
)
func (t *toolCtx) ExecuteDocumentDelivery(ctx context.Context, request docgen.OperationRequest) (docgen.OperationReceipt, error) {
receipt, err := t.rc.executeDocumentDelivery(ctx, request)
if receipt.Outcome == "complete" || receipt.Outcome == "unknown" {
for _, artifact := range receipt.Artifacts {
if artifact.Role != string(store.DocumentArtifactArchive) {
continue
}
t.arts = append(t.arts, core.Artifact{
ID: core.ID(artifact.ID), ProjectID: t.rc.run.ProjectID, Owner: t.rc.run.Owner,
Name: artifact.Name, Kind: "document", MIME: artifact.MIME, Size: artifact.Size,
})
break
}
}
return receipt, err
}
func (c *runCtx) executeDocumentDelivery(ctx context.Context, operation docgen.OperationRequest) (docgen.OperationReceipt, error) {
if ctx == nil {
return docgen.OperationReceipt{}, errors.New("document delivery: nil context")
}
if err := c.mgr.authorizeRunWork(ctx, c.run.Owner, c.run.ProjectID); err != nil {
return docgen.OperationReceipt{}, err
}
requestHash, err := documentOperationHash(operation)
if err != nil {
return docgen.OperationReceipt{}, err
}
record, err := c.mgr.st.BeginDocumentDeliveryAccountChecked(c.run.Owner, store.DocumentDeliveryBeginInput{
OperationID: operation.OperationID, RequestSHA256: requestHash,
ProjectID: string(c.run.ProjectID), ConversationID: string(c.run.ConversationID), SourceRun: string(c.run.ID),
DocumentID: operation.DocumentID, Mode: string(operation.Mode), RendererIdentity: docgen.RendererIdentity,
}, c.mgr.accountAllowImplicitLocal)
if err != nil {
return receiptFromDelivery(record, "partial", false, err), err
}
if record.State == store.DocumentDeliveryComplete {
return receiptFromDelivery(record, "complete", true, nil), nil
}
request := docgen.Request{
DocumentID: operation.DocumentID, Title: operation.Title, DocumentType: operation.DocumentType, Language: operation.Language,
Markdown: operation.Markdown, Mode: operation.Mode, FrozenAt: record.FrozenAt, RequestedBy: c.run.Owner,
Controlled: operation.Controlled, ProjectDocument: operation.ProjectDocument,
}
if record.MarkdownArtifactID != "" {
persisted, readErr := c.mgr.st.DocumentDeliveryMarkdown(c.run.Owner, operation.OperationID)
if readErr != nil {
return receiptFromDelivery(record, "unknown", false, readErr), readErr
}
request.Markdown = persisted
}
prepared, err := docgen.Prepare(ctx, request)
if err != nil {
return receiptFromDelivery(record, "partial", false, err), err
}
if record.MarkdownArtifactID == "" {
record, err = c.mgr.st.PersistDocumentDeliveryMarkdownAccountChecked(c.run.Owner, operation.OperationID,
deliveryArtifactInput(store.DocumentArtifactMarkdown, prepared.Markdown), prepared.CanonicalHash,
c.mgr.accountAllowImplicitLocal)
if err != nil {
outcome := "partial"
if errors.Is(err, store.ErrDocumentDeliveryOutcomeUnknown) {
outcome = "unknown"
}
return receiptFromDelivery(record, outcome, false, err), err
}
}
request.LegacySource = append([]byte(nil), operation.Markdown...)
request.Markdown = prepared.Markdown.Bytes
if err := c.mgr.authorizeRunWork(ctx, c.run.Owner, c.run.ProjectID); err != nil {
return receiptFromDelivery(record, "partial", false, err), err
}
delivery, err := docgen.GenerateWithOptions(ctx, request, docgen.RenderOptions{MigrationComparison: c.mgr.documentMigrationComparison})
if err != nil {
record, markErr := c.mgr.st.MarkDocumentDeliveryFailedAccountChecked(c.run.Owner, operation.OperationID, err.Error(), c.mgr.accountAllowImplicitLocal)
if markErr != nil {
return receiptFromDelivery(record, "unknown", false, markErr), errors.Join(err, markErr)
}
return receiptFromDelivery(record, "partial", false, err), err
}
if err := c.mgr.authorizeRunWork(ctx, c.run.Owner, c.run.ProjectID); err != nil {
return receiptFromDelivery(record, "partial", false, err), err
}
deliveryKey := documentDeliveryKey(delivery)
record, err = c.mgr.st.CommitDocumentDeliveryDerivedAccountChecked(c.run.Owner, operation.OperationID,
deliveryKey, delivery.Profile.SnapshotHash, delivery.Renderer.ReviewHash,
[]store.DocumentDeliveryArtifactInput{
deliveryArtifactInput(store.DocumentArtifactDOCX, delivery.DOCX),
deliveryArtifactInput(store.DocumentArtifactManifest, delivery.Manifest),
deliveryArtifactInput(store.DocumentArtifactArchive, delivery.Archive),
}, c.mgr.accountAllowImplicitLocal)
if err != nil {
outcome := "partial"
if errors.Is(err, store.ErrDocumentDeliveryOutcomeUnknown) {
outcome = "unknown"
}
return receiptFromDelivery(record, outcome, false, err), err
}
return receiptFromDelivery(record, "complete", false, nil), nil
}
func documentOperationHash(operation docgen.OperationRequest) (string, error) {
payload := struct {
DocumentID string `json:"documentId"`
Title string `json:"title"`
DocumentType string `json:"documentType"`
Language string `json:"language"`
Markdown string `json:"markdown"`
Mode string `json:"mode"`
Controlled bool `json:"controlled"`
ProjectDocument bool `json:"projectDocument"`
}{
DocumentID: operation.DocumentID, Title: operation.Title, DocumentType: operation.DocumentType,
Language: operation.Language, Markdown: string(operation.Markdown), Mode: string(operation.Mode),
Controlled: operation.Controlled, ProjectDocument: operation.ProjectDocument,
}
raw, err := json.Marshal(payload)
if err != nil {
return "", err
}
sum := sha256.Sum256(raw)
return hex.EncodeToString(sum[:]), nil
}
func documentDeliveryKey(delivery docgen.Delivery) string {
manifest := delivery.Renderer
value := strings.Join([]string{manifest.DocumentHash, manifest.ProfileHash, manifest.ReviewHash, string(manifest.Mode), docgen.RendererIdentity}, "\x00")
sum := sha256.Sum256([]byte(value))
return hex.EncodeToString(sum[:])
}
func deliveryArtifactInput(role store.DocumentDeliveryArtifactRole, artifact docgen.Artifact) store.DocumentDeliveryArtifactInput {
kind := "document"
if artifact.MIME == "application/json" {
kind = "data"
}
return store.DocumentDeliveryArtifactInput{
Role: role, Name: artifact.Name, Kind: kind, MIME: artifact.MIME,
SHA256: artifact.SHA256, Content: artifact.Bytes,
}
}
func receiptFromDelivery(record store.DocumentDeliveryRecord, outcome string, cacheHit bool, cause error) docgen.OperationReceipt {
receipt := docgen.OperationReceipt{
OperationID: record.OperationID, Outcome: outcome, State: string(record.State), FrozenAt: record.FrozenAt,
DeliveryKey: record.DeliveryKey, Renderer: record.RendererIdentity, CacheHit: cacheHit,
}
if cause != nil {
receipt.Error = cause.Error()
}
for _, item := range record.Artifacts {
receipt.Artifacts = append(receipt.Artifacts, docgen.ReceiptArtifact{
Role: string(item.Role), ID: string(item.Artifact.ID), Name: item.Artifact.Name,
MIME: item.Artifact.MIME, Size: item.Artifact.Size, SHA256: item.SHA256,
})
}
return receipt
}