prd

package
v0.0.0-...-a6983c7 Latest Latest
Warning

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

Go to latest
Published: Feb 20, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package prd implements PRD decomposition with parallel shredding and merging.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AssignGlobalIDs

func AssignGlobalIDs(
	epicOrder []string,
	results map[string]*EpicTaskResult,
) ([]MergedTask, IDMapping)

AssignGlobalIDs assigns T-001, T-002, ... to all tasks across epics in the order determined by epicOrder. Tasks within each epic retain their original order.

Epics present in results but absent from epicOrder are appended at the end, sorted by epic ID, for deterministic output. Epics present in epicOrder but absent from results are silently skipped.

The zero-padding width is 3 digits for fewer than 1000 total tasks, or 4 digits for 1000 or more.

Returns the merged tasks with global IDs assigned and the ID mapping from temp_id to global_id.

func DeduplicateTasks

func DeduplicateTasks(tasks []MergedTask) ([]MergedTask, *DedupReport)

DeduplicateTasks removes duplicate tasks that share a normalized title. The task with the lowest GlobalID in each duplicate group is kept; all others are removed. Unique acceptance criteria from removed tasks are appended to the keeper's criteria list. All dependency references that pointed to removed tasks are rewritten to reference the keeper instead, and self-references are dropped. The final task list preserves the original ordering of the keeper tasks.

Returns the deduplicated task list and a DedupReport summarising what was done.

func FormatValidationErrors

func FormatValidationErrors(errs []ValidationError) string

FormatValidationErrors formats a slice of ValidationError as a numbered list suitable for appending to LLM retry prompts. Returns an empty string if errs is empty.

func NormalizeTitle

func NormalizeTitle(title string) string

NormalizeTitle returns a normalized version of a task title for deduplication comparison. Steps applied in order:

  1. Lowercase the entire string.
  2. Strip common action-verb prefixes (word-boundary aware -- only strips when the prefix is followed by a space or end-of-string, not by another letter).
  3. Collapse multiple consecutive spaces into one and trim leading/trailing space.
  4. Remove all punctuation (non-alphanumeric, non-space characters).

If the result after stripping is empty, the original lowercased+normalized title is returned as a fallback (e.g. when the title is itself the prefix word, like "Implement").

func ParseEpicBreakdown

func ParseEpicBreakdown(data []byte) (*EpicBreakdown, []ValidationError, error)

ParseEpicBreakdown parses JSON data into an EpicBreakdown, enforcing a 10 MB size cap. It unmarshals the JSON and validates the result, returning both the parsed value and any validation errors. Returns an error only for I/O or structural JSON failures.

func ParseEpicTaskResult

func ParseEpicTaskResult(data []byte, knownEpicIDs []string) (*EpicTaskResult, []ValidationError, error)

ParseEpicTaskResult parses JSON data into an EpicTaskResult, enforcing a 10 MB size cap. It unmarshals the JSON and validates the result against the provided known epic IDs. Returns an error only for I/O or structural JSON failures.

func RemapDependencies

func RemapDependencies(
	tasks []MergedTask,
	idMapping IDMapping,
	epicTasks map[string][]MergedTask,
) ([]MergedTask, *RemapReport)

RemapDependencies rewrites all task dependencies from temp IDs to global IDs. It processes both LocalDependencies (intra-epic temp_id references) and CrossEpicDeps ("E-NNN:label" references). The resolved global IDs are merged, deduplicated, and stored in each task's Dependencies field.

The epicTasks parameter maps an epic ID to the list of MergedTask values belonging to that epic; callers typically build this from the same tasks slice grouped by EpicID.

Returns the updated tasks and a report summarising how many references were resolved, which could not be resolved, and which were ambiguous.

func ResequenceIDs

func ResequenceIDs(tasks []MergedTask, startID ...int) ([]MergedTask, IDMapping)

ResequenceIDs re-assigns sequential IDs starting from startID (T-{startID}, T-{startID+1}, ...) to tasks, closing any gaps left by deduplication. All Dependencies fields are updated to use the new IDs. The original task ordering is preserved. A startID of 0 or less is treated as 1.

Returns the updated task slice and an IDMapping from old GlobalID to new GlobalID. Only IDs that actually changed are included in the mapping.

func Slugify

func Slugify(title string) string

Slugify converts a task title to a kebab-case slug suitable for file names. It lowercases the title, replaces spaces and special characters with hyphens, strips non-ASCII characters, collapses consecutive hyphens, trims leading and trailing hyphens, and truncates to 50 characters at a word boundary.

If the result is empty after sanitization, the task's GlobalID is returned as a safe fallback.

func SortEpicsByDependency

func SortEpicsByDependency(breakdown *EpicBreakdown) ([]string, error)

SortEpicsByDependency returns epic IDs in topological order using Kahn's algorithm. Epics with no dependencies are placed first, sorted lexicographically for determinism. Returns an error if a cycle is detected in the epic dependency graph.

func TopologicalDepths

func TopologicalDepths(tasks []MergedTask) map[string]int

TopologicalDepths computes the depth of each task in the DAG. Depth 0 = no dependencies; depth N = the longest dependency path from a root node. Requires a valid DAG (no cycles). Call after ValidateDAG confirms validity. Returns nil if the graph is invalid or empty.

Types

type AmbiguousRef

type AmbiguousRef struct {
	// TaskID is the global ID of the task that contains the ambiguous dependency.
	TaskID string
	// Reference is the original cross-epic ref (e.g., "E-003:some-label").
	Reference string
	// Candidates lists all global IDs whose title matched the label.
	Candidates []string
}

AmbiguousRef records a cross-epic dependency reference that matched multiple tasks.

type DAGError

type DAGError struct {
	// Type classifies the error.
	Type DAGErrorType
	// TaskID is the task with the error (or the first task in a cycle).
	TaskID string
	// Details is a human-readable description of the error.
	Details string
	// Cycle holds the ordered list of task IDs forming the cycle (CycleDetected only).
	Cycle []string
}

DAGError represents a specific validation error in the dependency graph.

type DAGErrorType

type DAGErrorType int

DAGErrorType enumerates the types of DAG validation errors.

const (
	// DanglingReference means a task depends on a nonexistent task ID.
	DanglingReference DAGErrorType = iota
	// SelfReference means a task lists itself as a dependency.
	SelfReference
	// CycleDetected means a cycle exists in the dependency graph.
	CycleDetected
)

type DAGValidation

type DAGValidation struct {
	// Valid is true when the graph is a valid DAG (no errors found).
	Valid bool
	// TopologicalOrder contains task IDs in topological order; empty when invalid.
	TopologicalOrder []string
	// Depths maps task GlobalID to its topological depth (0 = no dependencies).
	Depths map[string]int
	// MaxDepth is the maximum depth found in the graph.
	MaxDepth int
	// Errors lists all validation errors found.
	Errors []DAGError
}

DAGValidation holds the results of DAG validation.

func ValidateDAG

func ValidateDAG(tasks []MergedTask) *DAGValidation

ValidateDAG checks the task dependency graph for:

  1. Dangling references (dependencies on nonexistent task IDs)
  2. Self-references (task depending on itself)
  3. Cycles (using Kahn's algorithm)

If the graph is valid, ValidateDAG also computes the topological order and per-task depths (depth 0 = no dependencies, depth N = longest path from a root).

Graphs with more than 10 000 tasks are rejected with a single error entry.

type DedupGroup

type DedupGroup struct {
	// NormalizedTitle is the shared normalized form used for deduplication matching.
	NormalizedTitle string
	// Tasks holds the tasks in this group, ordered by GlobalID (earliest first).
	Tasks []MergedTask
}

DedupGroup represents a set of tasks with matching normalized titles.

type DedupMerge

type DedupMerge struct {
	// KeptTaskID is the global ID of the task that was kept.
	KeptTaskID string
	// KeptTitle is the original title of the kept task.
	KeptTitle string
	// RemovedTaskIDs lists the global IDs of the tasks that were removed.
	RemovedTaskIDs []string
	// RemovedTitles lists the original titles of the removed tasks.
	RemovedTitles []string
	// MergedCriteria is the number of acceptance criteria merged in from removed tasks.
	MergedCriteria int
}

DedupMerge describes a single merge operation where one or more duplicate tasks were merged into a keeper task.

type DedupReport

type DedupReport struct {
	// OriginalCount is the total number of tasks before deduplication.
	OriginalCount int
	// RemovedCount is the number of tasks removed as duplicates.
	RemovedCount int
	// FinalCount is the total number of tasks after deduplication.
	FinalCount int
	// Merges describes each merge operation performed.
	Merges []DedupMerge
	// RewrittenDeps is the number of dependency references rewritten to point to keeper tasks.
	RewrittenDeps int
}

DedupReport summarizes the deduplication results.

type EmitOpts

type EmitOpts struct {
	// Tasks is the final merged, deduplicated task list.
	Tasks []MergedTask
	// Validation holds DAG analysis results including topological depths.
	Validation *DAGValidation
	// Epics provides epic metadata used for phase naming.
	Epics *EpicBreakdown
	// StartID is the starting task number for re-sequencing (default 1).
	StartID int
}

EmitOpts holds the inputs needed to generate output files.

type EmitResult

type EmitResult struct {
	// OutputDir is the directory in which all files were written.
	OutputDir string
	// TaskFiles lists the paths of all generated T-XXX-slug.md files.
	TaskFiles []string
	// TaskStateFile is the path to the generated task-state.conf.
	TaskStateFile string
	// PhasesFile is the path to the generated phases.conf.
	PhasesFile string
	// ProgressFile is the path to the generated PROGRESS.md.
	ProgressFile string
	// IndexFile is the path to the generated INDEX.md.
	IndexFile string
	// TotalTasks is the number of task spec files written.
	TotalTasks int
	// TotalPhases is the number of phases written to phases.conf.
	TotalPhases int
}

EmitResult summarises all files generated by Emit.

type Emitter

type Emitter struct {
	// contains filtered or unexported fields
}

Emitter generates all output files from a merged, deduplicated, DAG-validated task list. It writes individual task spec files, task-state.conf, phases.conf, PROGRESS.md, and INDEX.md to the configured output directory.

func NewEmitter

func NewEmitter(outputDir string, opts ...EmitterOption) *Emitter

NewEmitter creates an Emitter that writes output files to outputDir. Call Emit to generate all files.

func (*Emitter) Emit

func (e *Emitter) Emit(opts EmitOpts) (*EmitResult, error)

Emit generates all output files from the merged task data. It re-sequences GlobalIDs to close any gaps left by deduplication, assigns phases from topological depth, and writes the following files:

  • T-XXX-slug.md for each task
  • task-state.conf
  • phases.conf
  • PROGRESS.md
  • INDEX.md

When WithForce(false) (the default), Emit returns an error if any output file already exists.

type EmitterOption

type EmitterOption func(*Emitter)

EmitterOption is a functional option for Emitter.

func WithEmitterLogger

func WithEmitterLogger(logger *log.Logger) EmitterOption

WithEmitterLogger sets the logger used by the Emitter.

func WithForce

func WithForce(force bool) EmitterOption

WithForce controls whether existing output files are overwritten. When false (the default), Emit returns an error if any output file already exists.

type Epic

type Epic struct {
	// ID is the unique epic identifier in E-NNN format (e.g., E-001).
	ID string `json:"id"`
	// Title is the short human-readable name for the epic.
	Title string `json:"title"`
	// Description is a longer explanation of the epic's scope.
	Description string `json:"description"`
	// PRDSections lists the PRD section references covered by this epic.
	PRDSections []string `json:"prd_sections"`
	// EstimatedTaskCount is the expected number of tasks in this epic; must be >= 0.
	EstimatedTaskCount int `json:"estimated_task_count"`
	// DependenciesOnEpics lists the IDs of other epics this epic depends on.
	DependenciesOnEpics []string `json:"dependencies_on_epics"`
}

Epic represents a single epic within an EpicBreakdown.

type EpicBreakdown

type EpicBreakdown struct {
	Epics []Epic `json:"epics"`
}

EpicBreakdown is the top-level struct for Phase 1 (shred) output containing a list of epics. It maps to the JSON produced by the LLM during PRD decomposition.

func (*EpicBreakdown) Validate

func (eb *EpicBreakdown) Validate() []ValidationError

Validate checks the EpicBreakdown for correctness.

Rules enforced:

  • epics array must not be empty
  • each epic must have non-empty id, title, description
  • epic id must match E-NNN format
  • duplicate epic IDs are not allowed
  • estimated_task_count must be >= 0
  • dependencies_on_epics entries must reference valid epic IDs within the same breakdown (no self-reference, no unknown IDs)

Returns a slice of ValidationError; returns nil if the breakdown is valid.

type EpicTaskResult

type EpicTaskResult struct {
	// EpicID identifies which epic these tasks belong to; must be in E-NNN format.
	EpicID string `json:"epic_id"`
	// Tasks is the list of task definitions for this epic.
	Tasks []TaskDef `json:"tasks"`
}

EpicTaskResult is the top-level struct for Phase 2 (scatter) output containing per-epic task definitions.

func (*EpicTaskResult) Validate

func (etr *EpicTaskResult) Validate(knownEpicIDs []string) []ValidationError

Validate checks the EpicTaskResult for correctness.

Parameters:

  • knownEpicIDs: the set of epic IDs from the EpicBreakdown used to validate cross_epic_dependencies

Rules enforced:

  • epic_id must be non-empty and match E-NNN format
  • each task must have non-empty temp_id, title, description
  • temp_id must match ENNN-TNN format
  • duplicate temp_ids are not allowed
  • effort must be one of: "small", "medium", "large"
  • priority must be one of: "must-have", "should-have", "nice-to-have"
  • acceptance_criteria should not be empty (produces a validation error)
  • local_dependencies must reference valid temp_ids within the same result (no self-reference)
  • cross_epic_dependencies use "E-NNN:label" format; the epic ID part is validated against knownEpicIDs

Returns a slice of ValidationError; returns nil if the result is valid.

type IDMapping

type IDMapping map[string]string

IDMapping maps a task's temp_id to its assigned global_id. For example: "E001-T01" -> "T-001".

type MergedTask

type MergedTask struct {
	// GlobalID is the sequential global identifier in T-NNN (or T-NNNN) format.
	GlobalID string
	// TempID is the original temporary task identifier (e.g., E001-T01).
	TempID string
	// EpicID is the source epic identifier in E-NNN format.
	EpicID string
	// Title is the short human-readable name for the task.
	Title string
	// Description explains what the task implements.
	Description string
	// AcceptanceCriteria lists the conditions for task completion.
	AcceptanceCriteria []string
	// LocalDependencies lists temp_ids of tasks within the same epic (not yet resolved).
	LocalDependencies []string
	// CrossEpicDeps lists cross-epic dependency references in "E-NNN:label" format (not yet resolved).
	CrossEpicDeps []string
	// Dependencies contains the resolved global task IDs after dependency remapping.
	// Populated by RemapDependencies; empty until that step runs.
	Dependencies []string
	// Effort is the size estimate; one of: "small", "medium", "large".
	Effort string
	// Priority is the importance classification; one of: "must-have", "should-have", "nice-to-have".
	Priority string
}

MergedTask holds a task with its assigned global ID, retaining the original temp ID and all fields from the source TaskDef.

type PhaseInfo

type PhaseInfo struct {
	// ID is the 1-based phase number.
	ID int
	// Name is a human-readable phase label.
	Name string
	// StartTask is the lowest GlobalID in the phase (e.g., "T-001").
	StartTask string
	// EndTask is the highest GlobalID in the phase (e.g., "T-010").
	EndTask string
	// Tasks holds the tasks that belong to this phase.
	Tasks []MergedTask
}

PhaseInfo describes a single phase derived from the topological depth grouping.

func AssignPhases

func AssignPhases(tasks []MergedTask, depths map[string]int, epics *EpicBreakdown) []PhaseInfo

AssignPhases groups tasks by topological depth and returns a slice of PhaseInfo values sorted by phase ID. Tasks not present in the depths map are treated as depth 0. Within each phase, tasks are sorted by GlobalID.

Phase names are derived from the most common epic title at each depth level. When no epics are provided or no common title can be determined, the fallback "Phase N" label is used.

type RemapReport

type RemapReport struct {
	// Remapped is the count of dependency references that were successfully resolved.
	Remapped int
	// Unresolved holds references that could not be mapped to any global ID.
	Unresolved []UnresolvedRef
	// Ambiguous holds cross-epic references that matched more than one task title.
	Ambiguous []AmbiguousRef
}

RemapReport summarizes the results of a dependency remapping operation.

type ScatterEvent

type ScatterEvent struct {
	// Type identifies the kind of event.
	Type ScatterEventType
	// EpicID is the epic being processed when this event was emitted.
	EpicID string
	// Message is a human-readable description of the event.
	Message string
	// Attempt is the 1-based attempt number associated with this event.
	Attempt int
}

ScatterEvent is emitted during the scatter phase for progress tracking.

type ScatterEventType

type ScatterEventType string

ScatterEventType identifies the kind of scatter event emitted during parallel epic decomposition.

const (
	// ScatterEventWorkerStarted is emitted when a worker begins processing an epic.
	ScatterEventWorkerStarted ScatterEventType = "worker_started"
	// ScatterEventWorkerCompleted is emitted when a worker successfully decomposes an epic.
	ScatterEventWorkerCompleted ScatterEventType = "worker_completed"
	// ScatterEventWorkerRetry is emitted before each retry attempt within a worker.
	ScatterEventWorkerRetry ScatterEventType = "worker_retry"
	// ScatterEventWorkerFailed is emitted when a worker exhausts all retries.
	ScatterEventWorkerFailed ScatterEventType = "worker_failed"
	// ScatterEventRateLimited is emitted when a rate limit is detected and the worker must wait.
	ScatterEventRateLimited ScatterEventType = "rate_limited"
)

type ScatterFailure

type ScatterFailure struct {
	// EpicID identifies the epic that failed.
	EpicID string
	// Errors holds the last set of validation errors, if any.
	Errors []ValidationError
	// Err is the underlying error (e.g., context cancellation, rate-limit exhaustion).
	Err error
}

ScatterFailure records information about an epic that could not be decomposed.

type ScatterOption

type ScatterOption func(*ScatterOrchestrator)

ScatterOption is a functional option for configuring a ScatterOrchestrator.

func WithConcurrency

func WithConcurrency(n int) ScatterOption

WithConcurrency sets the maximum number of epic workers running concurrently.

func WithRateLimiter

func WithRateLimiter(rl *agent.RateLimitCoordinator) ScatterOption

WithRateLimiter sets the shared rate-limit coordinator used by all workers.

func WithScatterEvents

func WithScatterEvents(ch chan<- ScatterEvent) ScatterOption

WithScatterEvents sets the event channel for progress tracking. Events are sent non-blocking; if the channel is full the event is dropped.

func WithScatterLogger

func WithScatterLogger(l *log.Logger) ScatterOption

WithScatterLogger sets the structured logger on the ScatterOrchestrator.

func WithScatterMaxRetries

func WithScatterMaxRetries(n int) ScatterOption

WithScatterMaxRetries sets the maximum number of retry attempts per epic worker.

type ScatterOpts

type ScatterOpts struct {
	// PRDContent is the full PRD text injected into each worker prompt for context.
	PRDContent string
	// Breakdown is the EpicBreakdown produced by Phase 1 (Shredder).
	Breakdown *EpicBreakdown
	// Model is an optional model override for each agent invocation.
	Model string
	// Effort is an optional effort-level override for each agent invocation.
	Effort string
}

ScatterOpts specifies the parameters for a single Scatter call.

type ScatterOrchestrator

type ScatterOrchestrator struct {
	// contains filtered or unexported fields
}

ScatterOrchestrator orchestrates the parallel Phase 2 decomposition of epics into tasks. It spawns one worker goroutine per epic, bounded by the configured concurrency limit.

func NewScatterOrchestrator

func NewScatterOrchestrator(a agent.Agent, workDir string, opts ...ScatterOption) *ScatterOrchestrator

NewScatterOrchestrator creates a ScatterOrchestrator with the given agent, working directory, and options. Defaults: concurrency=3, maxRetries=3.

func (*ScatterOrchestrator) Scatter

Scatter spawns one worker goroutine per epic in opts.Breakdown, with bounded concurrency. Workers collect results into shared slices protected by a mutex. Worker goroutines only return non-nil errors for fatal conditions (context cancellation); validation failures are recorded in ScatterResult.Failures.

Returns (empty ScatterResult, nil) for an empty or nil breakdown. Returns partial results alongside the context error on cancellation.

type ScatterResult

type ScatterResult struct {
	// Results holds one EpicTaskResult per epic that succeeded, ordered by epic ID.
	Results []*EpicTaskResult
	// Failures holds metadata for epics that failed after all retries.
	Failures []ScatterFailure
	// Duration is the total wall-clock time spent in Scatter.
	Duration time.Duration
}

ScatterResult contains the aggregated output of the scatter phase.

type ShredEvent

type ShredEvent struct {
	// Type identifies the kind of event.
	Type ShredEventType
	// Message is a human-readable description of the event.
	Message string
	// Attempt is the 1-based attempt number associated with this event.
	Attempt int
	// Errors holds the validation errors that triggered a retry event.
	Errors []ValidationError
}

ShredEvent is emitted during the shred process for progress tracking.

type ShredEventType

type ShredEventType string

ShredEventType identifies the kind of shred event emitted during processing.

const (
	// ShredEventStarted is emitted when the shred operation begins.
	ShredEventStarted ShredEventType = "shred_started"
	// ShredEventCompleted is emitted when the shred operation succeeds.
	ShredEventCompleted ShredEventType = "shred_completed"
	// ShredEventRetry is emitted before each retry attempt.
	ShredEventRetry ShredEventType = "shred_retry"
	// ShredEventFailed is emitted when all retry attempts are exhausted.
	ShredEventFailed ShredEventType = "shred_failed"
)

type ShredOpts

type ShredOpts struct {
	// PRDPath is the path to the PRD markdown file.
	PRDPath string
	// OutputFile is the path where the epic-breakdown JSON will be written.
	// If empty, defaults to filepath.Join(workDir, "epic-breakdown.json").
	OutputFile string
	// Model is an optional model override for the agent invocation.
	Model string
	// Effort is an optional effort-level override for the agent invocation.
	Effort string
}

ShredOpts specifies the parameters for a single Shred call.

type ShredResult

type ShredResult struct {
	// Breakdown is the validated epic breakdown produced by the agent.
	Breakdown *EpicBreakdown
	// Duration is the total wall-clock time spent in Shred (including retries).
	Duration time.Duration
	// Retries is the number of retry attempts; 0 means the first try succeeded.
	Retries int
	// OutputFile is the absolute path where the JSON was written.
	OutputFile string
}

ShredResult contains the validated EpicBreakdown and metadata.

type Shredder

type Shredder struct {
	// contains filtered or unexported fields
}

Shredder orchestrates the single-agent PRD-to-epics call. It reads a PRD file, sends it to an AI agent with a structured prompt, validates the resulting EpicBreakdown JSON, and retries on validation errors.

func NewShredder

func NewShredder(a agent.Agent, workDir string, opts ...ShredderOption) *Shredder

NewShredder creates a Shredder with the given agent, working directory, and options. The default maxRetries is 3. Pass functional options to customize behavior.

func (*Shredder) Shred

func (s *Shredder) Shred(ctx context.Context, opts ShredOpts) (*ShredResult, error)

Shred reads the PRD file, invokes the agent to produce epic JSON, validates it, and returns the EpicBreakdown. It retries up to maxRetries times on validation failure. Context cancellation is honored at the start of each retry iteration.

type ShredderOption

type ShredderOption func(*Shredder)

ShredderOption is a functional option for configuring a Shredder.

func WithEvents

func WithEvents(ch chan<- ShredEvent) ShredderOption

WithEvents sets the event channel for progress tracking. Events are sent non-blocking; if the channel is full the event is dropped.

func WithLogger

func WithLogger(l *log.Logger) ShredderOption

WithLogger sets the structured logger on the Shredder.

func WithMaxRetries

func WithMaxRetries(n int) ShredderOption

WithMaxRetries sets the maximum number of retry attempts on the Shredder.

type TaskDef

type TaskDef struct {
	// TempID is the temporary task identifier in ENNN-TNN format (e.g., E001-T01).
	TempID string `json:"temp_id"`
	// Title is the short human-readable name for the task.
	Title string `json:"title"`
	// Description explains what the task implements.
	Description string `json:"description"`
	// AcceptanceCriteria lists the conditions that must be met for the task to be complete.
	AcceptanceCriteria []string `json:"acceptance_criteria"`
	// LocalDependencies lists temp_ids of other tasks within the same epic that must complete first.
	LocalDependencies []string `json:"local_dependencies"`
	// CrossEpicDeps lists cross-epic dependency references in "E-NNN:label" format.
	CrossEpicDeps []string `json:"cross_epic_dependencies"`
	// Effort is the size estimate; must be one of: "small", "medium", "large".
	Effort string `json:"effort"`
	// Priority is the importance classification; must be one of: "must-have", "should-have", "nice-to-have".
	Priority string `json:"priority"`
}

TaskDef represents a single task definition within an EpicTaskResult.

type UnresolvedRef

type UnresolvedRef struct {
	// TaskID is the global ID of the task that contains the unresolved dependency.
	TaskID string
	// Reference is the original temp_id or cross-epic ref that could not be resolved.
	Reference string
}

UnresolvedRef records a dependency reference that could not be mapped to a global ID.

type ValidationError

type ValidationError struct {
	// Field is the dotted path to the invalid field (e.g., "epics[0].id").
	Field string `json:"field"`
	// Message describes the validation failure in human-readable terms.
	Message string `json:"message"`
}

ValidationError represents a single validation finding with a field path and human-readable message. It is designed to be serializable for use in retry prompt augmentation.

Jump to

Keyboard shortcuts

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