Repository navigation
Conversation
The write path (tf-init/plan/apply/destroy) vendors the externalized provider terramate stacks and runs `terramate generate` before invoking terramate. The read/power commands (status, ip, start, stop, password across aws/gcp/truenas/ vultr) never run tf-init, so on a fresh checkout — or any tree where `up` hasn't run — terramate can't discover the stacks: status reports "not created" and ip emits a terramate error box that gets captured verbatim as the IP value. It only worked because an `up` happened to leave the stacks vendored. Add a shared core helper the read path uses: - `stage_provider_stacks` / `scripts/tf-stage <provider>`: vendor the stacks and run `terramate generate` only when staging changed something or no generated backend file exists yet. - `prepare_provider_stacks` is now idempotent: it short-circuits when the staged copy already matches the source (a read-only content compare that ignores generated, destination-only files), returning whether anything was re-staged. This keeps frequent callers (status polls) from churning the filesystem and clobbering generated z_backend.tf on every call. State is unaffected — the local backend lives under .terraform-cache-dir/, outside the staged tree. The provider commands invoke this via `eve_load_profile_env` (gated on the terraform engine) in the companion eve-providers change.
TUI plugin-sources screen now manages local-folder sources without env vars: - Type column (folder/remote) distinguishes local paths from git URLs - EditSourceScreen: edit id/url/ref/folder/auth of an existing source - Default action on configured entries opens Edit (not Remove); recommended entries keep add behavior - is_local_folder() helper + configured_row() + update_source() in plugins.py - AddSourceScreen placeholder now mentions local paths - 'e' keybind for Edit; Edit button added to controls row - Tests: is_local_folder, configured_row with local flag, update_source round-trip, TUI smoke test updated for new button label
Remove junk state files (--instance.json, --.json, schtasks directory, dozens of stale .json/.lock from old testing). Root cause was pre-v3 scripts that passed raw argv; current argparse-based instance-state doesn't reproduce.
…treaming windows scope, local-folder branch UI) + demo-instance task
…ckages stop declaring bundles
…th evidence for both demo instances
…n (v4.5 K) Bundles are now first-class kind:bundle plugins, not implied by package bundles: declarations. Core changes (eve): - kind enum: provider | package | os | bundle - New 'members' field: a bundle plugin lists its member package ids - Removed 'bundles' from schema + validator (packages no longer declare bundles) - 'supports' moved from global required to provider/package conditionals - catalog.py: aggregates bundles from kind:bundle plugins (reads 'members') - catalog_view.py: computes bundle installable_os_families from member packages - plugin_test.py: bundle/os kinds skip the SSH-readiness boundary check - Hermetic fixtures: mock-app/mock-win-app bundles: removed; mock-dev/mock-gaming bundle plugins created; test golden updated Package repos (v4.5): - eve-packages-linux: 9 bundle plugins created under bundles/; bundles: removed from 9 package manifests - eve-packages-windows: gaming-streaming bundle plugin [steam, sunshine, rustdesk] Tests updated: catalog aggregator tests use kind:bundle; manifest contract tests check bundle validation; relocation test reads bundle plugins.
…4.5 G, H, J) Wizard (Bug G): incompatible bundles and packages are now rendered dim in the new-instance wizard. The support_reason/conflict checks already prevented selection; now they're visually differentiated too. Dialog convention (Bug H): plugin-sources screen reordered — Edit is leftmost, primary-colored, and the default action (Enter/Space). The Remove toggle button is warning-colored and no longer flips. Edit label (Bug J): the EditSourceScreen ref field is now labeled 'Branch / ref (snapshot — re-pull to refresh)' making it explicit that uncommitted changes aren't picked up.
….5 Bug M) The status probe ran each provider's connectivity command with a bare environment, so a provider whose 'configured' gate is a secret (Vultr's VULTR_API_KEY, which lives only in the secrets file) reported unconfigured even though dispatch could create instances with it; AWS meanwhile reported 'configured' off ambient ~/.aws, bypassing eve's config entirely. The probe now resolves the same ConfigEnv.environment() + _inject_secrets the dispatch path uses, so status and dispatch see identical config/secrets. Also records the v4.5 architecture workstream (Bugs M-R): one shared config/ secret resolution, a central FSM platform with settings as machine context, XDG config layout, TUI-over-CLI parity, and streaming<->non-streaming parity.
The eve<->harel seam: EveFsm wraps a harel.Host, loads plugin-declared harel machines, and seeds each machine's declared `external` esvs from one pluggable ContextResolver (the shared config/secret resolver M/O need). Settings changes arrive as harel's `env` event + `refresh`; side effects stay host-driven (eve runs the probe, delivers `probe_ok`/`probe_fail`). Proven on a synthetic provider machine: configured/reachable are FSM-computed from injected context and re-derive on a settings change (status and dispatch physically cannot diverge). Test importorskips harel so CI stays green until the dependency is pinned (gated on a harel-python release tag). Reconciles docs/v4.5-fsm-design.md to harel's real YAML format.
…ence - provider_context_resolver(): resolves a provider machine's external esvs (named as their eve env vars, e.g. VULTR_API_KEY) from the one path dispatch uses (os.environ + ConfigEnv.environment() + _inject_secrets), so a provider's FSM context is byte-identical to what dispatch runs with (bug M). Hermetically tested. - Import the statechart engine behind one name (determa_state, falling back to the pre-rename harel) so the upcoming rename is a no-op for eve.
- core/fsm/provider.yaml: one shared provider lifecycle (unconfigured -> configured -> reachable) for every provider. reachable is a substate of configured reached by the connectivity probe (probe_ok/probe_fail). - provider_configured_resolver(): derives is_configured = every required config_schema secret/setting resolves non-empty via the shared path, so 'configured' is eve-resolved, never a plugin's ambient self-report (the AWS-off-~/.aws bug becomes structurally impossible). Tested end-to-end against the core machine. Next: rewire scripts/providers-status to load the core machine (configured from the FSM; connectivity answers reachable only).
… guard The statechart engine published as determa-state (import determa.state). Pin it in pyproject + poetry.lock as a real dependency; the FSM platform imports determa.state (falling back to the pre-rename harel). Remove the skip-if-missing test guard now that the engine is a hard dependency (a missing required dep should fail loudly, not skip).
configured is now FSM-derived (core/fsm/provider.yaml + provider_configured_resolver): true iff eve has resolved the provider's required config/secrets, so it can never be a connectivity command's ambient self-report. The connectivity probe runs only when configured, and only its reachable + notes are used (its configured field is ignored). Live-verified: vultr yes/yes, truenas 'not configured', docker/qemu/gcp yes; aws yes/no with an actionable note. Full suite green (493 passed, 1 skipped). AWS follow-up (eve-providers): AWS declares only a non-required config_file, so it reads configured=yes; mark an auth setting required or model it probe-derived if it should read unconfigured until eve holds a profile.
core/fsm/instance.yaml models the instance lifecycle as two orthogonal regions (provider terraform lifecycle + provisioning), with distinct transient states so each operation's outcome is unambiguous, and desired as context. core/fsm/package.yaml models the package lifecycle (install/remove + observe-driven drift). Both pass the engine's static validation and are exercised in tests/test_fsm_machines.py. These are the declarative replacements for state.py's PROVIDER/PROVISION/PACKAGE_STATES. Wiring them into live persistence/rendering (retiring state_machine.py) is gated on a state-vocabulary decision (match existing enums vs adopt cleaner set + migrate), recorded in docs/v4.5-fsm-design.md.
- instance machine: add provider region 'unknown' initial (unobserved) + drift observe_* edges from unknown/absent/error, so the old 'unknown' maps cleanly and live status can reconcile drift. - eve_sdk/fsm_migrate.py: translate persisted state files (pre-FSM vocabulary -> core machine vocabulary) on read; stable values are identity, terraform micro-stages -> unknown, provision error -> provision_error, package reinstalled -> installed. Idempotent + tested. Chosen path: adopt the cleaner vocabulary + migrate. Remaining live wiring (apply the migration on State.read, switch enum sets, move state_machine.py derivations onto the machines) is the invasive integration touching instance_view; tracked in the design doc.
… migration) No important instances, so per the delete-all decision: destroyed + deleted both demo instances, wiped their per-instance state, and removed eve_sdk/fsm_migrate.py + test (a runtime migration is no longer needed). Records the delete-all path + the remaining vocabulary alignment / FSM-driven status steps in the design doc.
Dispatch now records the instance machine's vocabulary: provider_state_for maps in-flight ops to creating/starting/stopping/destroying (init/plan -> creating), and package reinstall -> installed. state.py's PROVIDER/PACKAGE state sets, the observed-state + command-io schemas, the state_machine/sdk/test_state* tests, the valid-pending fixture, and test-plugins all follow the core/fsm machines. Old terraform micro-stages (initializing/initialized/planned/changing) and package reinstalled are gone. Full suite green (496 passed, 1 skipped).
… write-path authority provider_state is no longer a hand-maintained lookup table. eve_sdk/instance_fsm.py is the single lifecycle authority: dispatch maps a (command, op_status) to a machine event (dispatch_event) and State.record_operation(provider_event=...) fires it into core/fsm/instance.yaml seeded from the persisted provider_state, atomically inside the state write; the resulting leaf is the new provider_state. The state a status read sees is exactly what the machine produced — the table and the machine cannot diverge because there is only the machine. - delete dispatch.provider_state_for; provider_command.py + scripts/provider-dispatch fire events via dispatch_event - state.py: provider_event path computes the next leaf inside the modify callback (race-free); the direct provider_state param stays for instance-state / recovery - instance.yaml: every concrete provider state accepts every operator command (routing to its transient), so a command's terminal outcome holds from any state (start recovers absent->running). The provider command, not the machine, decides feasibility: a start that can't apply fails -> error, never a silent no-op. Preserves the old table's terminal semantics exactly, now with honest transients. - fsm.py: bind engine as a defined name so eve_sdk.fsm.engine is an explicit export - test_state.py: full lifecycle + recovery + read-only cases through the machine Read-path derivations in state_machine.py (effective_provider_state, live-overlay precedence, aggregate_summary) are display/aggregation policy, not a second lifecycle definition — one transition authority now, no divergence left.
…unctional engine API determa-state v0.1.0 replaced the draft grammar and the Host/Instance object model: machines are now format-1 bundles (format: 1, namespace, shared events with direction, machines[].root, esvs -> variables) and the engine interface is the pure functional spec-§8 pair create/dispatch over plain aggregate-state dicts. Port eve's whole FSM layer accordingly; pin determa-state (>=0.1.0,<0.2.0). - core/fsm/*.yaml: rewritten as bundles. Format 1 has no orthogonal regions, so the instance bundle holds two machines (instance_provider + instance_provision) — matching eve's persistence, which keeps provider_state and provision_state as separate fields anyway. YAML anchors are rejected (unsupported_yaml_feature), so the shared operator-command block is spelled out per concrete state. - eve_sdk/fsm.py: EveFsm now holds loaded bundles + live aggregate states per (scope, key); external variables are seeded as creation bindings; env/refresh unchanged in concept. Surface: load/aggregate/fire/refresh/leaves/state/context/ view. The harel fallback import is gone; import determa.state appears only here. - eve_sdk/instance_fsm.py: dispatch is pure, so the adapter seeds each provider leaf once by replaying a short event prefix from create, caches that aggregate, and dispatches the real event against it (the cache stays valid — dispatch never mutates its input). dispatch_event mapping unchanged. - scripts/providers-status: reads fsm.state() instead of engine instance objects. - tests: fixture bundle + machine/platform tests updated (provision machine gets its own lifecycle test); aggregate status is "running" not "active". Full scripts/test green; test-lifecycle green; providers-status live-verified (aws/docker/gcp/local-qemu/truenas/vultr — same semantics as before the port). The old IntType-leak issue is moot: 0.1.0 returns native values.
* feat(v4.5): complete Determa 0.2 migration * fix(v4.5): close recovery validation and secret handling gaps * fix(ci): create project environment before test runners * docs: use UTC date for Cloud validation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Behavior
Repair the externalized Terraform runtime and migrate provider, provisioning, and package lifecycles to Determa 0.2.0. Settings and lifecycle transitions use the same public FSM contract. Operation IDs remain monotonic, interrupted operations recover, and hierarchical package observations preserve the root lifecycle.
Provider/package commands receive isolated environments and target-scoped secrets. Secret payloads have restricted permissions before writing/upload, partial uploads are cleaned up, Windows ACL/deletion errors propagate, and installer paths expand only their intended home prefix. Standalone bundles and local plugin sources remain discoverable.
AWS requires an explicitly configured named profile. Eve does not declare, read, inject, or edit AWS key material; AWS tooling owns the profile's credentials and login/SSO session. The unused alternative-authentication feature was removed. Providers without secret fields skip secret-store reads, and failed Terraform environment resolution aborts backend commands. Draft core PRs run CI.
Incus contract and review fixes
Represent system containers with machine kind
containerand engineincus. Use strict SSH access fields (address, port, protocol/version, username, credential reference, host fingerprint) and a closed provider-discriminated identity envelope. Incus-specific endpoint, remote, project, instance name, and ownership digest live under itsidentityvariant. SSH host identity supports an explicit configured fingerprint or the namespaced Incus authenticated-exec mechanism; guest access remains OS-independent.Repair observation integration: validate the exact status JSON selected for persistence, normalize raw failed observations through the existing error presentation, disable running-only actions after observed failure, and replace/clear stale authenticated bindings on refresh. Running Incus status supplies its authenticated binding.
Explicitly package schema, FSM, scripts, config, TUI, and shipped OS runtime assets into wheels. Both CI matrix jobs run
python scripts/test-wheel, which builds and installs a wheel into a clean venv outside the source checkout, testseve --help, checks runtime assets, and validates positive/negative command outputs.The provider implementation and provisioning/lifecycle fixes are in Providers #10. No Determa dependency, FSM, provisional adapter, seed-by-replay restoration, or unreleased API is introduced or changed by these fixes. Retain the published compatible
>=0.2.0,<0.3.0dependency.Fresh review validation
Cloud validation on 2026-10-05 (Asia/Tokyo):
The complete Python invocation was attempted; lint/type checks and 523 tests passed before it stalled in the unchanged TUI smoke file and was interrupted. An isolated smoke-file run timed out at 120 seconds. The previously documented untouched baseline
13341e8reproduces the asynchronous shutdown timeout. No TUI code/test configuration changed; a completely green full suite is not claimed.See the contract and review validation record.
Rollout readiness
Remain draft; no merge requested. Review-fix head:
04919109ee398118d6e8cf5b450f3962ed9754d3. New-head GitHub checks must be evaluated independently of Cloud results.Live Incus TLS testing is pending restricted client enrollment, verified certificate pinning, and routed controller access. No private-pool access or live resources were used. The live test remains opt-in and excluded from normal CI.
Recovery #56, Providers #11, Linux #7, Windows #5, and AI #3 are merged into their intended branches. Linux #8 and Windows #6 are the main-facing package PRs. Merge core before companions once rollout validation is complete.
The roadmap's Vultr Windows GPU/VDD and Sunshine-streaming validation remains pending. Eve #46 independently changes
tui/app.py; review that overlap before landing it.