feedback

package
v0.0.0-...-c9e24ca Latest Latest
Warning

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

Go to latest
Published: Jun 29, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package feedback defines the typed implementer-feedback envelope, the Source enum that names every refer-back originator, the per-source diagnostic payload types, and the slot constants that the Required matrix in required.go keys against. The Envelope.Validate method asserts that an envelope tagged with a Source has every slot the matrix lists for that (Source, Target) pair populated.

This package is the foundation for the per-source builders + dispatcher renderer landing in subsequent chain issues; it intentionally ships the contract + validator only, with hand-constructed-envelope unit tests. It imports internal/sm (for the IssueState target type) and internal/role (for the existing ReviewConcern / AssemblyFixerConcern types reused by the reviewer and assembly_fixer slots) but must NOT import internal/daemon — the daemon imports this package, not the other way.

Index

Constants

View Source
const (
	SlotAcceptanceCriteria    slotName = "AcceptanceCriteria"
	SlotRepos                 slotName = "Repos"
	SlotPriorDefectHistory    slotName = "PriorDefectHistory"
	SlotReviewerConcerns      slotName = "ReviewerConcerns"
	SlotAssemblyFixerConcerns slotName = "AssemblyFixerConcerns"
	SlotSquashGateOutput      slotName = "SquashGateOutput"
	SlotCIFailureDetail       slotName = "CIFailureDetail"
	SlotVerifierChainDetail   slotName = "VerifierChainDetail"
	SlotOperatorReferBackNote slotName = "OperatorReferBackNote"
	SlotResolverDiagnosis     slotName = "ResolverDiagnosis"
)

Variables

View Source
var Required = map[Source]map[sm.IssueState][]slotName{
	SourceReviewerVerdict: {
		sm.IssueStateFeedback: {
			SlotPriorDefectHistory,
			SlotReviewerConcerns,
		},
	},
	SourceAssemblyFixer: {
		sm.IssueStateFeedback: {
			SlotPriorDefectHistory,
			SlotAssemblyFixerConcerns,
		},
	},
	SourceSquashGate: {
		sm.IssueStateFeedback: {
			SlotPriorDefectHistory,
			SlotSquashGateOutput,
		},
	},
	SourceCIFailure: {
		sm.IssueStateFeedback: {
			SlotPriorDefectHistory,
			SlotCIFailureDetail,
		},
	},
	SourceVerifierChain: {
		sm.IssueStateFeedback: {
			SlotPriorDefectHistory,
			SlotVerifierChainDetail,
		},
	},
	SourcePriorDefect: {
		sm.IssueStateImplementing: {
			SlotPriorDefectHistory,
		},
	},
	SourceOperatorReferBack: {
		sm.IssueStateFeedback: {
			SlotOperatorReferBackNote,
		},
	},
	SourceMergeResolver: {
		sm.IssueStateImplementing: {
			SlotResolverDiagnosis,
		},
	},
}

Required maps (Source, target IssueState) to the envelope slots that MUST be populated for an envelope tagged with that Source dispatched against that target state. Every refer-back source whose target is IssueStateFeedback requires the always-present PriorDefectHistory context plus the source's own typed diagnostic slot. SourcePriorDefect carries the initial-dispatch entry on IssueStateImplementing: there is no fresh refer-back diagnostic, only the regression sequence the supervisor accumulated. SourceOperatorReferBack carries only the operator's free-form note since the operator-edit refer-back is not required to carry a typed diagnostic. SourceMergeResolver mirrors the SourcePriorDefect shape — it targets IssueStateImplementing (the corrective child's initial dispatch, not a feedback re-entry) and requires only its own typed ResolverDiagnosis slot.

AcceptanceCriteria is deliberately NOT a required slot. The dispatcher threads the issue's acceptance criteria onto every envelope when the issue has them (a populate-from-the-canonical-source obligation), but an issue can legitimately carry NO parseable `## Acceptance criteria` section — an orphan-PR-adopted issue, a docs-errata fix whose body holds only a `## Summary`. Requiring the slot to be non-empty made a refer-back structurally impossible to satisfy for any such issue, so acceptance criteria are threaded-when-present, never required-non-empty. The Envelope still carries the AcceptanceCriteria field; the matrix simply does not gate dispatch on it.

Adding a new Source constant without a matching Required entry is a matrix gap the lint analyzer catches at CI time; the matrix-completeness test enforces the same property at `go test` time. The matrix is consulted by Validate at run time and by the unit tests in this package.

Functions

This section is empty.

Types

type CIFailure

type CIFailure struct {
	Workflow string `json:"workflow"`
	RunURL   string `json:"run_url"`
	Summary  string `json:"summary"`
}

CIFailure captures the relevant slice of a post-merge CI workflow failure. The workflow name + run URL let the implementer pull the full log; the summary is the failing job + first failing step.

type DiscoveryInput

type DiscoveryInput struct {
	IssueKey           string
	IssueBody          string
	AcceptanceCriteria []string
	SpecContext        *role.SpecExcerpt
}

DiscoveryInput is the typed dispatch-INPUT envelope for the read-only discovery roles (implementer_discovery, reviewer_discovery). It is the input-boundary analog of Envelope — the implementer refer-back OUTPUT contract — but deliberately a SEPARATE type: discovery input has no Source/Target matrix. Every discovery dispatch carries the same fixed shape, so Validate is two unconditional required-slot checks rather than a matrix lookup, and it does NOT overload Envelope's Source/Required system.

IssueKey and IssueBody are the always-required slots: a discovery session cannot map an implementation/review surface without the issue it is dispatched against. AcceptanceCriteria and SpecContext are threaded-when-present (mirroring Envelope.AcceptanceCriteria's discipline): an issue can legitimately carry no parseable `## Acceptance criteria` section, and a legacy non-spec-driven child resolves SpecContext to nil — neither gates dispatch, so Validate never errors on an empty AC slice or a nil SpecContext.

func (DiscoveryInput) Validate

func (d DiscoveryInput) Validate() error

Validate asserts the always-required slots (IssueKey, IssueBody) are populated, returning a structured error naming the first missing slot so the dispatch-boundary self-check surfaces the precise gap — the input-boundary mirror of Envelope.Validate. The optional threaded-when-present slots (AcceptanceCriteria, SpecContext) are never required: an AC-less or non-spec-driven issue validates cleanly.

type Envelope

type Envelope struct {
	IssueKey string        `json:"issue_key"`
	Target   sm.IssueState `json:"target"`
	Source   Source        `json:"source"`

	AcceptanceCriteria []string      `json:"acceptance_criteria,omitempty"`
	Repos              []string      `json:"repos,omitempty"`
	PriorDefectHistory []PriorDefect `json:"prior_defect_history,omitempty"`

	ReviewerConcerns      []role.ReviewConcern        `json:"reviewer_concerns,omitempty"`
	AssemblyFixerConcerns []role.AssemblyFixerConcern `json:"assembly_fixer_concerns,omitempty"`
	SquashGateOutput      *GateOutput                 `json:"squash_gate_output,omitempty"`
	CIFailureDetail       *CIFailure                  `json:"ci_failure_detail,omitempty"`
	VerifierChainDetail   *VerifierChainResult        `json:"verifier_chain_detail,omitempty"`
	OperatorReferBackNote string                      `json:"operator_refer_back_note,omitempty"`
	ResolverDiagnosis     *ResolverDiagnosis          `json:"resolver_diagnosis,omitempty"`
}

Envelope is the typed implementer-feedback envelope. Every refer-back dispatcher constructs one (via the per-source builders that land in the next chain issue) and calls Validate before handing the envelope to the implementer dispatch path.

The context fields (IssueKey, Target, Source, AcceptanceCriteria, Repos, PriorDefectHistory) carry the dispatcher-agnostic context every envelope needs. AcceptanceCriteria is threaded-when-present: the dispatcher populates it from the issue description when the issue has a parseable `## Acceptance criteria` section, but an AC-less issue (orphan-PR-adopted, docs-errata) leaves it empty and the matrix does NOT gate dispatch on it (see Required). The per-source slots hold the diagnostic payload the originating refer-back contributed; the matrix-required slot for the declared Source must be populated, and the discipline is that only the matching source's slot is populated in normal use (composite envelopes remain legal — the matrix only asserts the required minimum).

func FromAssemblyFixer

func FromAssemblyFixer(
	iss *sm.Issue,
	acceptanceCriteria []string,
	history []PriorDefect,
	action role.AssemblyFixerAction,
) Envelope

FromAssemblyFixer builds a feedback envelope from one refer_back_child action surfaced by the plan-assembly fixer. The caller already located the action (the dispatcher walks AssemblyFixerResult.Actions and only dispatches per-child on the refer_back_child kind), so the builder takes the AssemblyFixerAction directly rather than re-walking the result.

AssemblyFixerResult has no top-level .Concerns field; the diagnostic lives on the refer_back_child action's Concerns slice. The envelope stores the native []role.AssemblyFixerConcern shape — projection onto the implementer's ReviewFeedback (via the role.AssemblyFixerConcernsToReviewConcerns converter) is the dispatcher-renderer's job, not the envelope's.

The returned envelope's Target is IssueStateFeedback (the only matrix entry for SourceAssemblyFixer).

func FromCIFailure

func FromCIFailure(
	iss *sm.Issue,
	acceptanceCriteria []string,
	history []PriorDefect,
	detail CIFailure,
) Envelope

FromCIFailure builds a feedback envelope from a post-merge CI workflow failure surfaced through the reviewer's refer-back path. The dispatcher extracts the workflow name, the run URL, and the failing-job + first- failing-step summary from the CI status payload and wraps them in a CIFailure value before calling; the builder stores it as the envelope's CIFailureDetail slot pointer.

The returned envelope's Target is IssueStateFeedback (the only matrix entry for SourceCIFailure).

func FromMergeResolver

func FromMergeResolver(
	iss *sm.Issue,
	acceptanceCriteria []string,
	history []PriorDefect,
	diag ResolverDiagnosis,
) Envelope

FromMergeResolver builds the initial-dispatch envelope for the corrective child a plan-branch squash conflict the merge_resolver could not resolve surfaces. SourceMergeResolver targets IssueStateImplementing — the corrective child dispatches straight into implementing, not a feedback re-entry — and carries the resolver's structured diagnosis (verbatim verdict text + conflicting paths + the daemon-known repo / plan-branch / attempt context) on the ResolverDiagnosis slot.

diag is taken by value and stored as &diag so the matrix's nil-pointer emptiness check sees a populated slot. history is included for API symmetry with every other builder and is stored on PriorDefectHistory for context; it is NOT a matrix-required slot for this source, so an AC-less or history-less call still validates.

The returned envelope's Target is IssueStateImplementing (the only matrix entry for SourceMergeResolver).

func FromOperatorReferBack

func FromOperatorReferBack(
	iss *sm.Issue,
	acceptanceCriteria []string,
	history []PriorDefect,
	note string,
) Envelope

FromOperatorReferBack builds a feedback envelope for the `sorcerer issue refer-back` operator path. There is no typed diagnostic — the operator supplies a free-form note that the implementer reads directly. The note is stored on the envelope's OperatorReferBackNote slot; PriorDefectHistory is accepted for signature uniformity but is NOT a matrix-required slot for this source (the operator's note stands alone as the dispatch trigger).

The returned envelope's Target is IssueStateFeedback (the only matrix entry for SourceOperatorReferBack).

func FromPriorDefect

func FromPriorDefect(
	iss *sm.Issue,
	acceptanceCriteria []string,
	history []PriorDefect,
) Envelope

FromPriorDefect builds the initial-dispatch envelope for an issue transitioning into IssueStateImplementing. SourcePriorDefect has no fresh refer-back diagnostic; the load-bearing signal is the regression sequence the supervisor accumulated across prior cycles, which the builder stores verbatim on the envelope's PriorDefectHistory slot. The required-positional-parameter shape — the same shape every other builder uses for its source-specific payload — ensures the caller cannot accidentally dispatch an initial-state envelope without the regression sequence.

The returned envelope's Target is IssueStateImplementing (the only matrix entry for SourcePriorDefect).

func FromReviewerVerdict

func FromReviewerVerdict(
	iss *sm.Issue,
	acceptanceCriteria []string,
	history []PriorDefect,
	verdict role.ReviewerVerdict,
) Envelope

FromReviewerVerdict builds a feedback envelope from a reviewer verdict whose decision is refer_back. The reviewer's per-concern list (verdict.Concerns, []role.ReviewConcern) is stored verbatim on the envelope's ReviewerConcerns slot; the next implementer feedback-N cycle reads it via the dispatcher-renderer landing in the subsequent chain issue.

acceptanceCriteria is the parsed AC list (the dispatcher's existing pre-dispatch parse of iss.Description). Passed in rather than re-parsed here because the daemon-side parser (parseAcceptanceCriteria) lives in internal/daemon which this package must NOT import (the daemon imports this package, not the other way).

The returned envelope's Target is IssueStateFeedback (the only matrix entry for SourceReviewerVerdict).

func FromSquashGate

func FromSquashGate(
	iss *sm.Issue,
	acceptanceCriteria []string,
	history []PriorDefect,
	output GateOutput,
) Envelope

FromSquashGate builds a feedback envelope from a per-child squash-gate failure (continuous plan-branch integration). The squash-gate site in internal/daemon/plan_branch_merge_child.go captures the failing repo, the artifact path on disk, and a first-FAIL-line + N-line-context summary — exactly the GateOutput slot type's fields. The dispatcher wraps those into a GateOutput value before calling; the builder stores it as the envelope's SquashGateOutput slot pointer.

The returned envelope's Target is IssueStateFeedback (the only matrix entry for SourceSquashGate).

func FromVerifierChain

func FromVerifierChain(
	iss *sm.Issue,
	acceptanceCriteria []string,
	history []PriorDefect,
	detail VerifierChainResult,
) Envelope

FromVerifierChain builds a feedback envelope from a rejecting implementer post-submit verifier. The verifier-chain runner in internal/daemon/supervisor.go captures the verifier name, the gate phase (e.g. "post_submit"), the captured stdout/stderr the verifier emitted, and the wall-clock duration of the failing invocation — exactly the VerifierChainResult slot type's fields. The dispatcher wraps those into a VerifierChainResult value before calling; the builder stores it as the envelope's VerifierChainDetail slot pointer.

The returned envelope's Target is IssueStateFeedback (the only matrix entry for SourceVerifierChain).

func (Envelope) Validate

func (e Envelope) Validate() error

Validate asserts that the envelope's (Source, Target) pair has a matrix entry and that every slot the matrix lists for that pair is populated. Returns a structured error that names the source, the target, and (when applicable) the missing slot so the dispatcher's self-check failure surfaces the precise contract gap.

type GateOutput

type GateOutput struct {
	Repo         string `json:"repo"`
	ArtifactPath string `json:"artifact_path"`
	Summary      string `json:"summary"`
}

GateOutput captures the relevant slice of a squash-gate (or any pre-push gate) failure the implementer needs to act on. ArtifactPath points at the captured stdout/stderr dump under `<projectRoot>/.sorcerer/plan-assemble/` (or its per-child equivalent); Summary is the daemon-computed first-FAIL-line + N-line context the implementer reads before opening the full artifact.

type ImplementerFeedback

type ImplementerFeedback struct {
	// ReviewFeedback aggregates the envelope's structured diagnostic onto
	// the implementer task's REVIEW_FEEDBACK list. Reviewer +
	// assembly-fixer concerns ride through verbatim (the latter via the
	// role.AssemblyFixerConcernsToReviewConcerns converter); the
	// non-concern slots (squash-gate output, CI-failure detail, verifier
	// chain detail, operator note) project onto synthetic blocker
	// concerns whose Comment carries the diagnostic in a form the
	// implementer's prompt already knows how to read.
	ReviewFeedback []role.ReviewConcern
}

ImplementerFeedback is the projection of a validated feedback envelope onto the implementer-task wire shape's feedback-carrying fields. Today the implementer wire's REVIEW_FEEDBACK list is the single sink every refer-back source folds into; future-shape fields (a dedicated SQUASH_GATE_OUTPUT block, a CI_FAILURE block, etc.) would extend this struct without changing the per-source builder contract.

Returned in the same shape regardless of source so callers can write the projection back onto the implementer task's ReviewFeedback slot without per-source branching at the call site.

func RenderImplementerFeedback

func RenderImplementerFeedback(env Envelope) ImplementerFeedback

RenderImplementerFeedback projects a feedback envelope onto the implementer wire shape. The envelope is assumed to have been Validate()'d at the call site so every required slot is populated; the renderer is liberal about absent slots (a slot the matrix didn't mark required for the envelope's Source simply contributes nothing).

Slot-by-slot projection:

  • ReviewerConcerns → appended to ReviewFeedback verbatim.
  • AssemblyFixerConcerns → converted via role.AssemblyFixerConcernsToReviewConcerns and appended.
  • SquashGateOutput → synthesized blocker concern carrying the repo / artifact path / first-FAIL summary.
  • CIFailureDetail → synthesized blocker concern carrying the workflow / run URL / summary.
  • VerifierChainDetail → synthesized blocker concern carrying the verifier name / gate phase / captured stdout+stderr.
  • OperatorReferBackNote → synthesized blocker concern carrying the operator's free-form note.
  • ResolverDiagnosis → synthesized blocker concern carrying the resolver verdict text + conflicting paths + repo / plan-branch / attempt context.

Order is deterministic in source-declaration order so a caller that stuffs multiple slots into one envelope sees a stable projection.

type PriorDefect

type PriorDefect struct {
	Cycle   int    `json:"cycle"`
	Source  Source `json:"source"`
	Summary string `json:"summary"`
}

PriorDefect is one historical refer-back cycle the supervisor threads into every dispatch's PriorDefectHistory slot. Subsequent chain issues will widen the field set as the builders need; the minimum required for the matrix to assert presence is the originating cycle index, the source that triggered it, and a one-line summary the implementer can scan.

type ResolverDiagnosis

type ResolverDiagnosis struct {
	VerdictText       string   `json:"verdict_text"`
	ConflictingPaths  []string `json:"conflicting_paths"`
	RepoSlug          string   `json:"repo_slug"`
	PlanBranch        string   `json:"plan_branch"`
	AttemptNumber     int      `json:"attempt_number"`
	ConflictSignature string   `json:"conflict_signature"`
}

ResolverDiagnosis captures the diagnosis a plan-branch squash conflict the merge_resolver could not resolve hands to the corrective child's initial dispatch. VerdictText is the resolver's verbatim prose — the resolver emits prose, not parsed sides, so the two sides' identities (plan-branch architecture vs main's) live inside this field rather than as structured columns. The remaining fields are the daemon-known context: the repo-relative paths that still conflict, the repo slug and plan branch the squash targeted, the attempt number, and a conflict signature (declared here, populated by the capture child).

type Source

type Source string

Source names the originator of a refer-back. Every dispatcher that hands the implementer a feedback envelope tags it with one Source value so the Required matrix can assert the dispatcher populated the slots that source is contractually required to carry.

const (
	// SourceReviewerVerdict — a reviewer verdict with verdict=refer_back
	// produced one or more concerns against an open PR set; the
	// implementer's next cycle addresses them.
	SourceReviewerVerdict Source = "reviewer_verdict"
	// SourceAssemblyFixer — the plan-branch assembly_fixer surfaced
	// refer-back concerns against a parked child; the child re-runs with
	// those concerns threaded into the envelope.
	SourceAssemblyFixer Source = "assembly_fixer"
	// SourceSquashGate — the per-child squash gate (continuous plan-branch
	// integration) failed and the implementer re-runs against the
	// captured gate output.
	SourceSquashGate Source = "squash_gate"
	// SourceCIFailure — a post-merge CI workflow surfaced a failure the
	// reviewer routed back to the implementer.
	SourceCIFailure Source = "ci_failure"
	// SourceVerifierChain — the implementer post-submit verifier chain
	// rejected the submission; the implementer re-runs against the
	// rejecting verifier's output.
	SourceVerifierChain Source = "verifier_chain"
	// SourcePriorDefect — initial-dispatch tag for the implementing
	// target state. The current cycle has no fresh refer-back; the
	// envelope's load-bearing signal is the prior-defect regression
	// sequence the supervisor accumulated across prior cycles.
	SourcePriorDefect Source = "prior_defect"
	// SourceOperatorReferBack — the operator invoked `sorcerer issue
	// refer-back` with a free-form note; no typed diagnostic is required.
	SourceOperatorReferBack Source = "operator_refer_back"
	// SourceMergeResolver — a plan-branch squash conflict the
	// merge_resolver could not resolve surfaced a corrective child; the
	// child's initial dispatch (on the implementing target) carries the
	// resolver's verdict + conflicting paths so the implementer acts on
	// the structured diagnosis instead of re-deriving it from free text.
	SourceMergeResolver Source = "merge_resolver"
)

type VerifierChainResult

type VerifierChainResult struct {
	VerifierName string `json:"verifier_name"`
	Gate         string `json:"gate"`
	Stdout       string `json:"stdout"`
	Stderr       string `json:"stderr"`
	DurationMs   int64  `json:"duration_ms"`
}

VerifierChainResult captures the rejecting verifier's name plus the stdout/stderr the verifier emitted. Gate names the gate phase the verifier ran inside (e.g. "post_submit"); DurationMs is the wall-clock duration of the failing verifier invocation.

Directories

Path Synopsis
discoveryinputproptest
gen
Package gen is the operator-supplied generator-helper package backing the committed prop_test stub (../proptest_stubs_test.go) for SOR-2359 R7.
Package gen is the operator-supplied generator-helper package backing the committed prop_test stub (../proptest_stubs_test.go) for SOR-2359 R7.
Package lint holds the standalone go/analysis analyzer that gates the feedback envelope's Source-to-slot Required matrix.
Package lint holds the standalone go/analysis analyzer that gates the feedback envelope's Source-to-slot Required matrix.
cmd/feedbackmatrixlint command
Command feedbackmatrixlint is the standalone driver for the feedbackmatrix static analyzer.
Command feedbackmatrixlint is the standalone driver for the feedbackmatrix static analyzer.

Jump to

Keyboard shortcuts

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