Skip to content

plugin assignments: paused -> enabled (default true) - #26

Merged
luma-founder merged 1 commit into
mainfrom
plugin-enabled-flag
May 9, 2026
Merged

luma-founder merged 1 commit into
mainfrom
plugin-enabled-flag

Conversation

@luma-founder

@luma-founder luma-founder commented May 9, 2026 •

Copy link
Copy Markdown

Summary

Inverts the plugin-assignment toggle so the field reads naturally — operators ask is this plugin enabled? instead of is it paused?. Mechanical rename + value flip everywhere; no behaviour change beyond the inversion.

  • Default for newly-created assignments: enabled = true (was: paused = false).
  • Disable: PATCH {\"enabled\": false} (was: {\"paused\": true}).
  • Dispatch filter: if live.enabled (was: if not live.paused).

Migration

New revision 0003_plugin_paused_to_enabled.py:

  • upgrade() drops paused, adds enabled with a temporary server_default=true so existing rows backfill to enabled, then drops the server_default so future inserts route through the SQLModel default.
  • downgrade() is the inverse.

Drop+recreate (rather than rename-and-flip) is fine pre-prod — upgrade/downgrade round-trips were tested live (/tmp/v3-state.sqlite). Any row that was previously paused becomes enabled on upgrade and vice versa, which is acceptable since no production assignments exist yet.

What's in

  • core/curfew/models.py — PluginAssignment.enabled: bool = Field(default=True).
  • core/curfew/plugin_runtime.py — AssignedInstance.enabled; register/update kwargs renamed and defaulted (enabled: bool = True); dispatch filter inverted.
  • core/curfew/schemas.py — PluginAssignmentRead/Update/PluginSnapshotRow use enabled.
  • api/curfew_api/routes/plugins.py + api/curfew_api/app.py — every read/write/runtime call updated; PATCH docstring changed (users/paused → users/enabled).
  • Tests — renamed and values flipped: test_update_enabled_doesnt_reinstantiate, test_dispatch_skips_disabled, test_patch_enabled, test_disabled_plugin_doesnt_reconcile. The reconcile-e2e helper takes enabled: bool = True and PATCHes {\"enabled\": false} when the test wants the plugin off.
  • web/src/api/schema.ts — regenerated from the live OpenAPI. No hand-written TS code referenced the old field.
  • Docs — PLAN.md, PLUGINS.md, DECISIONS.md updated, including the speculative CLI verb shape (curfew plugin pause/unpause → curfew plugin enable/disable).
  • Plan files — the two that documented the old shape (step-2 storage, step-11 runtime) updated in place per the user's preference.

Test plan

  • just check clean (ruff, ruff format, mypy, 250 pytest, 23 vitest, web build).
  • Migration round-trip on a fresh /tmp/v3-state.sqlite:
    • alembic upgrade head → enabled BOOLEAN NOT NULL.
    • alembic downgrade -1 → paused BOOLEAN NOT NULL.
    • alembic upgrade head → back to enabled.
  • Live smoke: assign reftest_plugin, lock kid → sentinel appears; PATCH {\"enabled\": false} → next lock toggle does NOT update the sentinel.

Inverts the plugin-assignment toggle so the field reads naturally —
operators ask "is this plugin enabled?" instead of "is it paused?". No
behaviour change beyond the inversion: assignments default to running
on create (was: default to running because `paused=false`); a PATCH
that disables the plugin sends `{"enabled": false}` (was: `{"paused":
true}`); the dispatch filter is `live.enabled` (was: `not live.paused`).

Schema: a new revision `0003_plugin_paused_to_enabled.py` drops the
`paused` column and adds `enabled` with a temporary `server_default=true`
so any existing rows backfill to enabled. The server_default is dropped
in the same migration so future inserts route through the SQLModel
default. Drop+recreate (rather than rename-and-flip) is fine pre-prod;
upgrade/downgrade round-trips cleanly.

What's in:

- New migration `api/migrations/versions/0003_plugin_paused_to_enabled.py`.
- `core/curfew/models.py` — `PluginAssignment.enabled: bool = Field(default=True)`.
- `core/curfew/plugin_runtime.py` — `AssignedInstance.enabled`, register/update
  kwargs renamed and defaulted (`enabled: bool = True`), dispatch filter
  inverted to `if live.enabled`.
- `core/curfew/schemas.py` — `PluginAssignmentRead`, `PluginAssignmentUpdate`,
  `PluginSnapshotRow` use `enabled`.
- `api/curfew_api/routes/plugins.py` and `api/curfew_api/app.py` — every
  read/write/runtime call updated.
- `plugins.py` PATCH docstring — `users/paused` -> `users/enabled`.
- Tests renamed + values flipped: `test_update_enabled_doesnt_reinstantiate`,
  `test_dispatch_skips_disabled`, `test_patch_enabled`,
  `test_disabled_plugin_doesnt_reconcile`. The reconcile-e2e helper
  takes `enabled: bool = True` and PATCHes `{"enabled": false}` when
  the test wants the plugin off.
- `web/src/api/schema.ts` regenerated from the live OpenAPI; no
  hand-written TS code referenced the old field.
- Docs `PLAN.md`, `PLUGINS.md`, `DECISIONS.md` updated, including the
  speculative CLI verb shape (`curfew plugin pause/unpause` becomes
  `curfew plugin enable/disable`).
- The two plan files that documented the old shape (step-2 storage,
  step-11 runtime) are updated in place.

Verified:

- `just check` clean (ruff, ruff format, mypy, 250 pytest, 23 vitest,
  web build).
- Migration round-trip on a fresh `/tmp/v3-state.sqlite`:
  - `alembic upgrade head` -> `enabled BOOLEAN NOT NULL`.
  - `alembic downgrade -1` -> `paused BOOLEAN NOT NULL`.
  - `alembic upgrade head` -> back to `enabled`.
@luma-founder
luma-founder merged commit bcad4d1 into main May 9, 2026
4 checks passed
@luma-founder
luma-founder deleted the plugin-enabled-flag branch May 9, 2026 01:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants