writeupdraft

package
v0.1.2 Latest Latest
Warning

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

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

Documentation

Overview

Package writeupdraft holds AI-proposed, human-gated finding write-up DRAFTS ("human-gated authoritative drafts").

A Draft is the ONE place LLM-authored PROSE enters the system as a proposal. The AI drafts a finding's description + remediation, but a draft is inert until a human signs off. It is kept DELIBERATELY SEPARATE from the judgment claim union (internal/domain/judgment), whose claims are structured tokens and carry a "never free prose" invariant – a write-up is inherently prose, so it cannot live there without breaking that invariant. The safety here is therefore PROCEDURAL, not structural:

A draft NEVER auto-flows into the templated report. Only a human-Accepted draft is eligible to be applied to its finding (a separate use case), and the report renders only the authoritative finding/writeup data – never a Draft. The agent may only Propose a draft. Accept/Reject is the human sign-off; the proposer cannot sign off its own draft (separation of duties, enforced here as defense-in-depth and again by RBAC/SoD at the usecase + HTTP layers, mirroring the judgment review gate). Both text fields are length-bounded so a proposal cannot dump unbounded model output.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Draft

type Draft struct {
	ID           shared.ID
	EngagementID shared.ID
	FindingID    shared.ID // the finding this draft proposes text for (the subject)
	Description  string
	Remediation  string
	State        State
	ProposedBy   string // the proposer identity (an agent id) – never the acceptor
	DecidedBy    string // the human who accepted/rejected; "" while Proposed
	CreatedAt    time.Time
	UpdatedAt    time.Time
}

Draft is an AI-proposed finding write-up (description + remediation) awaiting explicit human sign-off.

func Propose

func Propose(id, engagementID, findingID shared.ID, description, remediation, proposedBy string, now time.Time) (Draft, error)

Propose creates a new draft in StateProposed. It requires a subject finding, a proposer, and at least one non-empty text field, and it bounds both text fields. The agent proposes; it cannot accept.

func (Draft) Accept

func (d Draft) Accept(acceptedBy string, now time.Time) (Draft, error)

Accept is the human sign-off: a Proposed draft becomes Accepted, attributed to the accepting human. An accepted draft is only ELIGIBLE to be applied to its finding (a separate use case) – acceptance itself renders nothing.

func (Draft) Edit

func (d Draft) Edit(description, remediation string, now time.Time) (Draft, error)

Edit replaces a still-Proposed draft's text (a human revising the AI draft before sign-off). It fails on a decided (Accepted/Rejected) draft. Editing does not change attribution – ProposedBy is preserved.

func (Draft) Reject

func (d Draft) Reject(rejectedBy string, now time.Time) (Draft, error)

Reject discards a Proposed draft, attributed to the rejecting human. A rejected draft is terminal – it is never applied to a finding and never rendered.

type State

type State string

State is the closed draft lifecycle (fail-closed: an unknown state is invalid).

const (
	StateProposed State = "proposed" // AI-proposed, awaiting human sign-off
	StateAccepted State = "accepted" // a human signed off – eligible to be applied to the finding
	StateRejected State = "rejected" // a human discarded the draft
)

func (State) Valid

func (s State) Valid() bool

Valid reports whether s is a known state.

Jump to

Keyboard shortcuts

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