Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0b3124e
add user controller type
tgoodwin Feb 21, 2026
6e368ce
jesus I am burnt out on this
tgoodwin Feb 21, 2026
d62a56b
add nextUserActionIdx to state
tgoodwin Feb 21, 2026
8c0079b
check in beads state
tgoodwin Feb 21, 2026
761e772
check in design doc
tgoodwin Feb 22, 2026
f63fda3
Merge pull request #67 from tgoodwin/kamera-9gz-2-user-types
tgoodwin Feb 22, 2026
df7c82c
Merge branch 'multi-step-actions' of github.com:tgoodwin/kamera into …
tgoodwin Feb 22, 2026
689c638
WIP integrating user actions into the simulation flow
tgoodwin Feb 24, 2026
7ea3e57
cleaning
tgoodwin Feb 24, 2026
62e663c
check in knative examples
tgoodwin Feb 24, 2026
08a0b79
update old design docs to be consistent with current approach
tgoodwin Feb 24, 2026
1b1c66c
update knative harness
tgoodwin Feb 24, 2026
6705985
bugfix: increment generation for UPDATE and PATCH events in addition …
tgoodwin Feb 24, 2026
77d3e8e
make generation incrementation logic more robust to weird JSON edge c…
tgoodwin Feb 24, 2026
a081273
fix broken test
tgoodwin Feb 24, 2026
b7f4982
fix TUI display logic bug
tgoodwin Feb 24, 2026
01fe607
revert method promotion
tgoodwin Feb 24, 2026
49f931d
add flag to disable the analyze+perturb+rerun phase so users can just…
tgoodwin Feb 24, 2026
a096df8
drop dead code
tgoodwin Feb 24, 2026
dafcae6
API compatibility changes for existing projects
tgoodwin Feb 24, 2026
1c9c92b
update docs
tgoodwin Feb 24, 2026
1e1237a
remove explicit name from knative template spec
tgoodwin Feb 24, 2026
f6c0273
fix missing-object diff detection in converged-state analysis
tgoodwin Feb 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions .beads/issues.jsonl

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ go run .
}
```

`Runner` honors the standard `-interactive` and `-dump-output` flags (see `pkg/explore/flags.go`) so you can disable the inspector or persist results when scripting.
`Runner` honors the standard `-interactive`, `-perturb`, and `-dump-output` flags (see `pkg/explore/flags.go`) so you can disable the inspector, skip closed-loop analysis reruns (`--perturb=false`), or persist results when scripting.

That’s enough to start evaluating how your controllers interact across different interleavings.

Expand Down
29 changes: 13 additions & 16 deletions docs/plans/2026-01-30-coverage-hotspot-input-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@
Define a concrete, deterministic translation from a `HotspotInstance` (from static dependency graphs) to a simple `Input` representation suitable for later conversion into a `Scenario`. This step intentionally excludes “dimensions of variation,” which will be handled later.

## Scope
- **In:** Hotspot → Input translation, object materialization from the input map, pending reconcile construction, and tuning fields.
- **In:** Hotspot → Input translation, object materialization from the input map, and tuning fields.
- **Out:** Dimension expansion (Input → []Input) and any tracecheck-specific configuration details.

## Data Types (pkg/coverage)
Keep the translation layer independent of `tracecheck`.

```
type Input struct {
Name string
Objects []*unstructured.Unstructured
Pending []Pending
Tuning InputTuning
Name string
EnvironmentState EnvironmentState
UserInputs []UserInput
Tuning InputTuning
}

type Pending struct {
ControllerID string
Key NamespacedName
type EnvironmentState struct {
Objects []*unstructured.Unstructured
}

type NamespacedName struct {
Namespace string
Name string
type UserInput struct {
ID string
Type string
Object *unstructured.Unstructured
}

type InputTuning struct {
Expand All @@ -48,7 +48,6 @@ type InputTemplate struct {
```

Notes:
- `Pending` is explicit and deterministic; conversion to `tracecheck.PendingReconcile` happens later.
- `StaleReads` is keyed by controller ID; `StaleLookback` is keyed by canonical GroupKind.

## Input Map Assumption
Expand Down Expand Up @@ -78,10 +77,8 @@ Inputs: `HotspotInstance`, dependency graph lookup, input map.
- Deduplicate by GVK.
2. **Resolve objects:**
- For each GVK, look up a template, deep-copy, normalize, and store.
3. **Build Pending:**
- For each hotspot controller, find its **primary reconciles target** in the graph.
- If multiple reconciles targets exist, emit a **warning** and choose deterministically (lexicographic GVK).
- Create a `Pending` using the normalized object’s name/namespace for that GVK.
3. **Build user inputs:**
- For each resolved resource, create a `UserInput` with `type=CREATE` and the normalized object.
4. **Set Tuning (compact hints):**
- **Multi-writer / Diamond / Feedback cycle:** `PermuteControllers = hotspot.Controllers`.
- **Missing trigger / Reducer:** `StaleReads[reader] = []groupKind{...}` for referenced inputs.
Expand Down
109 changes: 109 additions & 0 deletions docs/plans/2026-02-21-user-controller-workflow-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# User Controller Workflow Design

## Objective
Promote multi-step user workflows to a first-class concept in Kamera by modeling
the user as an in-engine actor, integrated directly into `pkg/tracecheck/explore.go`,
so user actions can interleave with controller reconciles during exploration.

## Context
Current workflow handling is scenario/phase oriented at runner level and does not
provide a direct mechanism for injecting user actions at arbitrary points during
an unfolding execution path.

This design narrows to one user actor per exploration instance and keeps existing
controller reconcile semantics intact.

## Core Design Decisions
1. Single user actor: each `Explorer` has exactly one `UserController`.
2. The user actor is conceptually "another controller", but executed via a
dedicated user-action path in `tracecheck` (not as a normal pending
reconciler entry).
3. User actions are ordered and stateful across a branch via
`StateNode.nextUserActionIdx`.
4. Action scheduling is abstracted behind:
`shouldApplyNextUserAction(state StateNode) bool`.
5. Initial scheduler policy is quiescence-only.
6. Assumption for v1: every user action mutates state.
7. User action writes must flow through the same replay/effect recording path
used by controller-runtime reconcilers.

## Data Model
### UserAction
`UserAction` is data-only, intended to support future external workflow files:
- `id`
- `type`
- `payload`

No per-action function fields are stored on `UserAction`.

### UserController
One controller object per `Explorer` instance:
- Owns an internal ordered list of `UserAction`.
- Executes the next action for a branch based on `nextUserActionIdx`.
- Returns a normal step result (`Changes`, effects, errors) through the same
effect recording mechanism used by other reconciler paths.

### Branch Progress Tracking
`StateNode` gets:
- `nextUserActionIdx int`

This is branch-local progress and advances only when a user action step is
successfully applied on that branch.

## Explore Loop Integration
Integrate in `pkg/tracecheck/explore.go` main step loop:

1. Pop state from stack/queue as today.
2. Before terminal convergence classification, evaluate:
`shouldApplyNextUserAction(currentState)`.
3. If true:
- Execute one user action step.
- Apply resulting effects to produce a successor state.
- Determine triggered reconciles.
- Update pending reconciles.
- Increment `nextUserActionIdx`.
- Append synthetic history step with `ControllerID = "UserController"`.
- Enqueue successor and continue.
4. If false, proceed with normal reconcile step selection/execution.
5. A state is terminal/converged only if:
- there is no actionable pending reconcile work, and
- there are no remaining user actions.

## Scheduling Abstraction
`shouldApplyNextUserAction(state)` is called each explore step.

Initial internal predicate:
- apply next user action when the branch is quiescent.

Future policies can plug in behind this method without changing outer loop
structure, enabling finer-grained interleavings like midpoint injections.

## Invariants and Guardrails
1. Mutating action invariant:
- if a user action produces no effective write/effect, treat as invalid under
v1 assumptions (fail branch or fail run, policy TBD).
2. History visibility:
- user action steps must appear in `ExecutionHistory` and dumps for
explainability.
3. Trigger semantics:
- reconciler triggering after user actions uses existing trigger manager logic.

## Non-Goals (This Iteration)
- Multi-user concurrency models.
- Generic executor registries or per-action handler maps.
- External workflow file parser implementation.
- Custom midpoint predicate language.

## Follow-on Implementation Tasks
1. Add user workflow/controller types in `pkg/tracecheck`.
2. Add `nextUserActionIdx` to `StateNode` and clone/copy plumbing.
3. Add `shouldApplyNextUserAction(state)` and quiescence predicate in `Explorer`.
4. Add user action step execution path in `explore.go` using replay/effect path.
5. Update convergence gate to require no remaining user actions.
6. Emit user action history metadata in dumps/inspector context as needed.
7. Add tests for:
- quiescence scheduling behavior,
- user-action-triggered reconcile fanout,
- branch-local index progression,
- mutating-action invariant enforcement.

2 changes: 1 addition & 1 deletion examples/crossplane/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func main() {
fmt.Fprintf(os.Stderr, "runner setup error: %v\n", err)
os.Exit(1)
}
if err := runner.Run(ctx, initialState); err != nil {
if err := runner.Run(ctx, explore.RunInput{EnvironmentState: initialState}); err != nil {
fmt.Fprintf(os.Stderr, "session error: %v\n", err)
os.Exit(1)
}
Expand Down
Loading