feat(planning): plans, validation, planner and a restart-safe executor

Plans turn intentions into revisable dependency graphs (migration 0027):
objective, assumptions, ordered or dependent steps, capabilities,
expected observations, preconditions, risk, estimates, budget,
completion criteria, abort conditions and the alternatives considered.

- Validation owns structure: acyclic dependencies, registered and
  unlocked capabilities only, schema-valid parameters, targets that agree
  with parameters, read-only checks, a closed set of step kinds and
  internal actions. Model proposals are parsed into the same structure;
  fields that could carry authority or claim progress are reported as
  ignored, and an invalid draft is stored as a draft that never runs.
- The planner prefers deterministic strategies: a direct action verified
  by observation, a read-only diagnosis that requests temporary scoped log
  access with risk and fallback stated, and an escalation that diagnoses
  and informs the operator instead of repeating a failed action. Failed
  strategies are not reused; a model is consulted only when none applies.
- The executor holds no state in memory: it claims a step with a
  conditional update, acts only through Invoke and RequestCapability, and
  records the outcome. Waiting for approval or access forms a subordinate
  intention and blocks the parent with the reason. Expectations become
  verification predictions resolved from a read-only observation, so an
  HTTP-level success is never taken as the outcome; a miss is a prediction
  error that weakens the supporting belief and triggers reconsideration.
  Replanning creates a new revision, withdraws open requests of the old
  one and keeps it as history, within a replan limit. Checks never raise
  approval prompts. Budgets stop runaway plans. Preconditions skip actions
  when the world already changed. Dream plans and disabled sandbox minds
  never act. An interrupted non-idempotent action with no record is
  blocked for verification instead of repeated; recorded outcomes are
  adopted. Completed plans are stored as procedural memories; a completed
  escalation does not count as fulfilling the intention.
- Executions and approvals record their origin; minds may withdraw their
  own pending approval requests; Preview reports a decision without side
  effects; service.status is allowed by default as a bounded read.
This commit is contained in:
Andy Dixon
2026-09-14 23:38:44 +01:00
parent 9db188ffe6
commit 813b067842
14 changed files with 3464 additions and 20 deletions
+10
View File
@@ -40,6 +40,8 @@ const (
// event summary of the given types within the window.
// belief: the referenced belief's confidence reaches min_confidence by the window end.
// operator: only an operator can resolve it.
// verification: a plan step's expected outcome, resolved by the planning
// executor from a read-only observation after the action.
type Criteria struct {
Kind string `json:"kind"`
Expect string `json:"expect,omitempty"` // occurs | absent
@@ -140,6 +142,9 @@ func (n *New) validate() error {
if n.Criteria.BeliefID.IsZero() || n.Criteria.MinConfidence <= 0 {
return fmt.Errorf("%w: belief criteria need belief_id and min_confidence", ErrInvalid)
}
case "verification":
// An expectation attached to a plan step; the planning executor
// resolves it by observing the world after the action.
case "operator", "":
n.Criteria.Kind = "operator"
default:
@@ -312,6 +317,11 @@ func Judge(p Prediction, now time.Time, window []events.Event, beliefConfidence
return Outcome{Status: StatusRefuted, Evidence: []events.EvidenceRef{{Kind: "belief", ID: string(p.Criteria.BeliefID)}}, Reason: "window closed below the confidence threshold"}, true
}
return Outcome{}, false
case "verification":
if now.After(p.WindowEnd.Add(time.Hour)) {
return Outcome{Status: StatusExpired, Reason: "no verification was performed within an hour of the window"}, true
}
return Outcome{}, false
default:
if now.After(p.WindowEnd.Add(7 * 24 * time.Hour)) {
return Outcome{Status: StatusExpired, Reason: "operator did not resolve it within a week of the window"}, true