Feat v0.3.0 workflow schema (#14)
All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-frontend (push) Successful in 5s
CI/CD / test-go-pg (push) Successful in 2m23s
CI/CD / test-sqlite (push) Successful in 2m42s
CI/CD / build-and-deploy (push) Successful in 1m28s

Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #14.
This commit is contained in:
2026-03-27 17:52:29 +00:00
committed by xcaliber
parent 8580e1d93e
commit 965885a8f7
16 changed files with 414 additions and 161 deletions

View File

@@ -11,26 +11,26 @@ import (
"switchboard-core/store"
)
// ── on_advance Hook (v0.35.0) ───────────────
// ── on_advance Hook ─────────────────────────
//
// Fires synchronously after a stage transition succeeds.
// The hook can enrich/transform stage_data or reject the transition.
//
// Config in transition_rules:
// Config in stage_config:
// {"on_advance": {"package_id": "...", "entry_point": "on_advance"}}
//
// Hook receives dict: {stage_data, previous_stage, current_stage, channel_id}
// Hook receives dict: {stage_data, previous_stage, current_stage, instance_id}
// Hook returns: {stage_data: {...}} (enriched), None (no change),
// or {error: "msg"} (reject — caller should handle rollback)
// OnAdvanceHookConfig is the on_advance section of transition_rules.
// OnAdvanceHookConfig is the on_advance section of stage_config.
type OnAdvanceHookConfig struct {
PackageID string `json:"package_id"`
EntryPoint string `json:"entry_point"`
}
// TransitionRulesOnAdvance extracts on_advance config from transition_rules JSON.
type TransitionRulesOnAdvance struct {
// StageConfigOnAdvance extracts on_advance config from stage_config JSON.
type StageConfigOnAdvance struct {
OnAdvance *OnAdvanceHookConfig `json:"on_advance,omitempty"`
}
@@ -46,8 +46,8 @@ func FireOnAdvanceHook(
ctx context.Context,
stores store.Stores,
runner *sandbox.Runner,
previousStageRules json.RawMessage,
channelID string,
previousStageConfig json.RawMessage,
instanceID string,
previousStage, currentStage int,
stageData json.RawMessage,
) *OnAdvanceResult {
@@ -55,23 +55,23 @@ func FireOnAdvanceHook(
return nil
}
var rules TransitionRulesOnAdvance
if len(previousStageRules) > 0 {
_ = json.Unmarshal(previousStageRules, &rules)
var cfg StageConfigOnAdvance
if len(previousStageConfig) > 0 {
_ = json.Unmarshal(previousStageConfig, &cfg)
}
if rules.OnAdvance == nil || rules.OnAdvance.PackageID == "" || rules.OnAdvance.EntryPoint == "" {
if cfg.OnAdvance == nil || cfg.OnAdvance.PackageID == "" || cfg.OnAdvance.EntryPoint == "" {
return nil
}
pkg, err := stores.Packages.Get(ctx, rules.OnAdvance.PackageID)
pkg, err := stores.Packages.Get(ctx, cfg.OnAdvance.PackageID)
if err != nil || pkg == nil {
log.Printf("[workflow-hooks] on_advance: package %s not found", rules.OnAdvance.PackageID)
log.Printf("[workflow-hooks] on_advance: package %s not found", cfg.OnAdvance.PackageID)
return nil
}
// Build context dict for the hook
ctxDict := starlark.NewDict(4)
_ = ctxDict.SetKey(starlark.String("channel_id"), starlark.String(channelID))
_ = ctxDict.SetKey(starlark.String("instance_id"), starlark.String(instanceID))
_ = ctxDict.SetKey(starlark.String("previous_stage"), starlark.MakeInt(previousStage))
_ = ctxDict.SetKey(starlark.String("current_stage"), starlark.MakeInt(currentStage))
@@ -83,7 +83,7 @@ func FireOnAdvanceHook(
_ = ctxDict.SetKey(starlark.String("stage_data"), starlark.NewDict(0))
}
val, _, err := runner.CallEntryPoint(ctx, pkg, rules.OnAdvance.EntryPoint,
val, _, err := runner.CallEntryPoint(ctx, pkg, cfg.OnAdvance.EntryPoint,
starlark.Tuple{ctxDict}, nil, nil)
if err != nil {
log.Printf("[workflow-hooks] on_advance hook error: %v", err)