@@ -23,7 +23,6 @@ import (
2323 "github.com/operatorstack/boatstack/boatstack/internal/kernel/catalog"
2424 "github.com/operatorstack/boatstack/boatstack/internal/kernel/model"
2525 "github.com/operatorstack/boatstack/boatstack/internal/kernel/protocol"
26- "github.com/operatorstack/boatstack/boatstack/internal/kernel/supervisor"
2726 boatstackruntime "github.com/operatorstack/boatstack/boatstack/internal/runtime"
2827 "github.com/operatorstack/boatstack/boatstack/internal/surfaces"
2928)
@@ -37,22 +36,27 @@ func (s *stringList) Set(value string) error {
3736}
3837
3938type commandOptions struct {
40- repository string
41- format string
42- goalID string
43- goalKind string
44- deliveryID string
45- flowID string
46- transitionID string
47- idempotencyKey string
48- humanActor string
49- repositoryPolicy bool
50- acceptProgramChange bool
51- parameters stringList
52- authorityReceipts stringList
53- follow bool
54- host string
55- command string
39+ repository string
40+ format string
41+ goalID string
42+ goalKind string
43+ deliveryID string
44+ flowID string
45+ transitionID string
46+ correlationID string
47+ prescriptionID string
48+ expectedStateRevision uint64
49+ expectedProgramFingerprint string
50+ expectedSnapshotFingerprint string
51+ idempotencyKey string
52+ humanActor string
53+ repositoryPolicy bool
54+ acceptProgramChange bool
55+ parameters stringList
56+ authorityReceipts stringList
57+ follow bool
58+ host string
59+ command string
5660}
5761
5862func main () {
@@ -101,13 +105,27 @@ func run(arguments []string) error {
101105 if err != nil {
102106 return err
103107 }
104- response , handleErr := kernel .Handle (context .Background (), request )
105- if command == "update" && options .acceptProgramChange && handleErr != nil && response .ProgramChange != nil && response .Decision != nil &&
106- response .Decision .Kind == supervisor .DecisionUnresolved && response .Decision .Reason == supervisor .ReasonProgramDrift {
107- request .TransitionID = "installation.reconcile-update"
108- request .Parameters = append (request .Parameters , protocol.Parameter {Name : "accept_obligation_change" , Value : "true" }).Canonical ()
109- response , handleErr = kernel .Handle (context .Background (), request )
108+ if (operation == surfaces .OperationApply || operation == surfaces .OperationRecover ) && request .Prescription .ID == "" && command != "apply" && command != "recover" {
109+ resolveRequest := request
110+ resolveRequest .Operation = surfaces .OperationResolve
111+ resolveRequest .FlowID = ""
112+ resolveRequest .Prescription = protocol.Prescription {}
113+ resolved , resolveErr := kernel .Handle (context .Background (), resolveRequest )
114+ if resolveErr != nil || resolved .Prescription == nil {
115+ if renderErr := renderResponse (resolved , options .format ); renderErr != nil {
116+ return renderErr
117+ }
118+ if resolveErr == nil {
119+ if resolved .Decision != nil && resolved .Decision .Reason != "" {
120+ return errors .New (resolved .Decision .Reason )
121+ }
122+ return fmt .Errorf ("transition %q was not prescribed" , request .TransitionID )
123+ }
124+ return resolveErr
125+ }
126+ request .Prescription = * resolved .Prescription
110127 }
128+ response , handleErr := kernel .Handle (context .Background (), request )
111129 if command == "events" && options .follow {
112130 if options .format != "jsonl" {
113131 return fmt .Errorf ("events --follow requires --format jsonl" )
@@ -229,6 +247,11 @@ func parseOptions(command string, arguments []string, transition catalog.Transit
229247 flags .StringVar (& options .deliveryID , "delivery" , options .deliveryID , "delivery identity" )
230248 flags .StringVar (& options .flowID , "flow" , "" , "flow identity" )
231249 flags .StringVar (& options .transitionID , "transition" , options .transitionID , "stable semantic transition id" )
250+ flags .StringVar (& options .correlationID , "correlation" , "" , "command-scoped correlation identity from resolution" )
251+ flags .StringVar (& options .prescriptionID , "prescription-id" , "" , "exact prescription identity from resolution" )
252+ flags .Uint64Var (& options .expectedStateRevision , "expected-state-revision" , 0 , "exact durable state revision observed during resolution" )
253+ flags .StringVar (& options .expectedProgramFingerprint , "expected-program-fingerprint" , "" , "exact executable control-program fingerprint observed during resolution" )
254+ flags .StringVar (& options .expectedSnapshotFingerprint , "expected-snapshot-fingerprint" , "" , "exact admission-relevant snapshot fingerprint observed during resolution" )
232255 flags .StringVar (& options .idempotencyKey , "idempotency-key" , "" , "exact prior admission idempotency key for safe replay" )
233256 flags .StringVar (& options .humanActor , "human" , "" , "explicit command-scoped human authority actor" )
234257 flags .BoolVar (& options .repositoryPolicy , "repository-authority" , false , "derive repository-policy authority from the V2 project configuration" )
@@ -253,10 +276,11 @@ func parseOptions(command string, arguments []string, transition catalog.Transit
253276 if err := populateRuntimeParameters (& options ); err != nil {
254277 return commandOptions {}, err
255278 }
256- if command == "reconcile-update" {
279+ if command == "reconcile-update" || ( command == "update" && options . acceptProgramChange ) {
257280 if ! options .acceptProgramChange {
258281 return commandOptions {}, fmt .Errorf ("reconcile-update requires explicit --accept-program-change" )
259282 }
283+ options .transitionID = "installation.reconcile-update"
260284 options .parameters = append (options .parameters , "accept_obligation_change=true" )
261285 }
262286 case "correct-pr" :
@@ -405,7 +429,10 @@ func buildRevision() string {
405429
406430func buildRequest (operation surfaces.Operation , options commandOptions ) (surfaces.Request , error ) {
407431 now := time .Now ().UTC ()
408- correlation := fmt .Sprintf ("cli-%d-%d" , os .Getpid (), now .UnixNano ())
432+ correlation := options .correlationID
433+ if correlation == "" {
434+ correlation = fmt .Sprintf ("cli-%d-%d" , os .Getpid (), now .UnixNano ())
435+ }
409436 goal := model.Goal {}
410437 if options .goalKind != "" || options .goalID != "" || options .deliveryID != "" {
411438 goal = model.Goal {ID : options .goalID , Kind : model .GoalKind (options .goalKind ), DeliveryID : options .deliveryID }
@@ -431,6 +458,9 @@ func buildRequest(operation surfaces.Operation, options commandOptions) (surface
431458 return surfaces.Request {
432459 SchemaVersion : surfaces .SchemaVersion , Operation : operation , Repository : options .repository , Host : options .host , CorrelationID : correlation ,
433460 FlowID : flowID , Goal : goal , TransitionID : catalog .TransitionID (options .transitionID ), Authority : authority , Parameters : parameters ,
461+ Prescription : protocol.Prescription {SchemaVersion : protocol .PrescriptionSchemaVersion , ID : options .prescriptionID ,
462+ TransitionID : catalog .TransitionID (options .transitionID ), ExpectedStateRevision : options .expectedStateRevision ,
463+ ExpectedProgramFingerprint : options .expectedProgramFingerprint , ExpectedSnapshotFingerprint : options .expectedSnapshotFingerprint },
434464 RepositoryAuthority : options .repositoryPolicy , IdempotencyKey : options .idempotencyKey , Command : options .command ,
435465 }, nil
436466}
@@ -568,6 +598,15 @@ func renderResponse(response surfaces.Response, format string) error {
568598 fmt .Println ("transition:" , response .Decision .Transition .ID )
569599 }
570600 }
601+ if response .Prescription != nil {
602+ correlation := ""
603+ if response .Snapshot != nil {
604+ correlation = response .Snapshot .Invocation .Correlation
605+ }
606+ fmt .Printf ("prescription=%s state_revision=%d program=%s snapshot=%s correlation=%s\n " , response .Prescription .ID ,
607+ response .Prescription .ExpectedStateRevision , response .Prescription .ExpectedProgramFingerprint ,
608+ response .Prescription .ExpectedSnapshotFingerprint , correlation )
609+ }
571610 if response .Receipt != nil {
572611 fmt .Println ("receipt:" , response .Receipt .ID )
573612 }
0 commit comments