next

package
v0.3.5 Latest Latest
Warning

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

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

Documentation

Overview

CANARY: REQ=CP-252; FEATURE="NextPriorityCommand"; ASPECT=CLI; STATUS=BENCHED; TEST=TestCANARY_CBIN_132_CLI_NextPrioritySelection,TestCANARY_CBIN_132_CLI_DBAndScanAgreeOnOrder,TestCANARY_CBIN_132_CLI_Candidate51IsFound,TestCANARY_CBIN_132_CLI_PromptResolvesUnderRoot; BENCH=BenchmarkCANARY_CBIN_132_CLI_PriorityQuery; OWNER=canary; UPDATED=2026-08-31

Index

Constants

View Source
const (
	FormatJSON = "json"
	FormatText = "text"
)

Output formats accepted by --format.

View Source
const (
	SourceDatabase   = "database"
	SourceFilesystem = "filesystem"
)

Sources a selection can come from, reported verbatim in --format json's "source" field so a caller always knows what the answer was computed from.

Variables

View Source
var NextCmd = &cobra.Command{
	Use:   "next [flags]",
	Short: "Identify and implement next highest priority requirement",
	Long: `Identify the next highest priority unimplemented requirement and generate
comprehensive implementation guidance.

This command automatically:
- Uses the token index when it still describes this tree, and scans the tree
  itself when it does not
- Identifies highest priority STUB or IMPL requirement
- Excludes hidden requirements (test files, templates, examples)
- Requires every dependency to be proven complete -- passing evidence at the
  current commit for a local one, a satisfied external/peer state otherwise
- Generates comprehensive implementation prompt with:
  - Specification details
  - Constitutional principles
  - Test-first guidance
  - Token placement examples

Priority determination factors:
1. PRIORITY field (1=highest, 10=lowest); a token that declares none is
   ranked -- and reported -- at the neutral default 5
2. STATUS (STUB before IMPL)
3. DEPENDS_ON (every dependency must be proven complete by evidence, or
   satisfied as an external/peer requirement)

The answer names its own source: "database" when the index is present and
still describes this tree, "filesystem" when the tree had to be scanned
directly. Completion is only ever claimed from a current index.`,
	RunE: func(cmd *cobra.Command, args []string) error {
		format, err := resolveFormat(cmd)
		if err != nil {
			return err
		}
		dbPath, _ := cmd.Flags().GetString("db")
		promptFlag, _ := cmd.Flags().GetBool("prompt")
		dryRun, _ := cmd.Flags().GetBool("dry-run")
		filterStatus, _ := cmd.Flags().GetString("status")
		filterAspect, _ := cmd.Flags().GetString("aspect")
		allowUnknownExternal, _ := cmd.Flags().GetBool("allow-unknown-external")
		root, _ := cmd.Flags().GetString("root")
		if root == "" {
			root = "."
		}

		dbPath = resolveDBPath(root, dbPath)

		filters := make(map[string]string)
		if filterStatus != "" {
			filters["status"] = filterStatus
		}
		if filterAspect != "" {
			filters["aspect"] = filterAspect
		}

		projectID := utils.ReadProjectID(cmd)

		sel, err := selectNext(selection{
			DBPath:               dbPath,
			Root:                 root,
			ProjectID:            projectID,
			Filters:              filters,
			AllowUnknownExternal: allowUnknownExternal,
			Stderr:               cmd.ErrOrStderr(),
		})
		if err != nil {

			if guarded := utils.GuardContract(cmd, err); errors.Is(guarded, utils.ErrContractFailed) {
				return guarded
			}
			return fmt.Errorf("select next priority: %w", err)
		}

		out := cmd.OutOrStdout()

		if format == FormatJSON {
			return emitJSON(out, sel)
		}

		if sel.Token == nil {
			printNoWork(out, sel.Source, sel.Blocked)
			return nil
		}

		if dryRun {
			fmt.Fprintf(out, "Next priority (dry run): %s - %s\n", sel.Token.ReqID, sel.Token.Feature)
			fmt.Fprintf(out, "Priority: %d | Status: %s | Aspect: %s\n", sel.Token.Priority, sel.Token.Status, sel.Token.Aspect)
			fmt.Fprintf(out, "Location: %s\n", sel.Token.FilePath)
			fmt.Fprintf(out, "Source: %s\n", sel.Source)
			return nil
		}

		promptArg, _ := cmd.Flags().GetString("prompt-arg")
		output, err := renderPrompt(root, sel.Token, projectID, dbPath, promptFlag, promptArg)
		if err != nil {
			return fmt.Errorf("render prompt: %w", err)
		}

		fmt.Fprintln(out, output)
		return nil
	},
}

CANARY: REQ=CP-252; FEATURE="NextCmd"; ASPECT=CLI; STATUS=BENCHED; TEST=TestCANARY_CBIN_132_CLI_NextPrioritySelection,TestCANARY_CBIN_132_CLI_DBAndScanAgreeOnOrder,TestCANARY_CBIN_132_CLI_Candidate51IsFound,TestCANARY_CBIN_132_CLI_PromptResolvesUnderRoot; BENCH=BenchmarkCANARY_CBIN_132_CLI_PriorityQuery; OWNER=canary; DOC=user:docs/user/next-priority-guide.md; DOC_HASH=6a276e6735100236; UPDATED=2026-08-31

Functions

func SelectNext added in v0.3.3

func SelectNext(dbPath, root, projectID string, filters map[string]string, allowUnknownExternal bool, stderr io.Writer) (token *storage.Token, source string, blocked int, err error)

SelectNext is the exported entry point to `canary next`'s selection: the same source decision (fresh index, else canonical filesystem scan) and the same dependency gate the CLI applies, returning the chosen token, the source that answered, and how many candidates were passed over as blocked.

It exists so the MCP `next` tool can delegate rather than reimplement. The MCP tool used to carry a hand-maintained replica of the dependency rule, and the replica drifted: it still accepted a declared STATUS=TESTED as proof and still let an unresolvable external dependency pass, months after the CLI stopped doing either. Two answers to "may this work start?" is one answer too many, so there is now exactly one implementation and the MCP surface calls it.

root is the tree the answer is about; projectID scopes index queries ("" means every project, refused only when ambiguous); stderr receives the one-line notes about unresolvable dependencies (io.Discard is fine).

Types

type PromptData

type PromptData struct {
	ReqID             string
	Feature           string
	Aspect            string
	Status            string
	Priority          int
	SpecFile          string
	SpecContent       string
	Constitution      string
	RelatedSpecs      []RelatedSpec
	Dependencies      []*storage.Token
	SuggestedFiles    []string
	TestGuidance      string
	TokenExample      string
	SuccessCriteria   []string
	Today             string
	SuggestedTestFile string
	PackageName       string
	// PromptArg is the --prompt-arg value as given, and PromptContent the
	// prompt it resolved to. Both are empty when no extra prompt was asked
	// for.
	PromptArg     string
	PromptContent string
}

PromptData holds template variables for prompt generation

type RelatedSpec

type RelatedSpec struct {
	ReqID    string
	Feature  string
	SpecFile string
}

RelatedSpec represents a related specification reference

Jump to

Keyboard shortcuts

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