| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 |
- using InvercargillSql.Migrations;
- using Sqlite;
- namespace ClankerSaddle.Data.Migrations {
- /**
- * Goal 27 refinements — the parking guard. `saddle suspend` on a
- * goal run that owns NO live task is refused by the web (there is
- * nothing whose terminal transition could ever wake the parked
- * agent): the park mechanics still run, but the run carries a
- * one-shot `pending_resume_notice`, so the daemon's next ask hands
- * it the refusal instruction instead of a sleep nothing ends.
- *
- * tasks.pending_resume_notice is that one-shot channel. It is set
- * by the refused park and consumed by the allocation that hands
- * the assignment out (the resume_notice discipline): while set,
- * a suspended task is immediately offerable — the exact lift the
- * task-level force_wake flag gives a plain parked task, but
- * carrying the guard's own instruction text. Nullable, NULL when
- * no refusal is pending.
- *
- * IDEMPOTENCE: same contract as M0002–M0006 — up() runs before the
- * apply transaction opens (the builder only queues), so it
- * introspects sqlite_master through a separate read-only handle
- * and adds the column only when the schema still lacks it.
- */
- public class M0007_ParkingGuard : Migration {
- public override string name { get { return "Parking guard"; } }
- public override uint64 serial { get { return 7; } }
- public override string migration_namespace { get { return "clanker-saddle"; } }
- // Same resolution as M0006: the runner never hands up() a
- // connection, so the schema is read through a read-only handle
- // on the SPRY_DB_PATH main.vala connects to.
- private string db_path() {
- var path = Environment.get_variable("SPRY_DB_PATH") ?? "";
- if (path.strip().length == 0) {
- return "./clanker-saddle.sqlite";
- }
- return path;
- }
- private bool column_exists() {
- Database db;
- int rc = Database.open_v2(db_path(), out db, Sqlite.OPEN_READONLY);
- if (rc != Sqlite.OK) {
- return false;
- }
- Statement statement;
- rc = db.prepare_v2(
- "select 1 from pragma_table_info('tasks') where name = 'pending_resume_notice'",
- -1, out statement);
- if (rc != Sqlite.OK) {
- return false;
- }
- return statement.step() == Sqlite.ROW;
- }
- public override void up(MigrationBuilder b) {
- if (column_exists()) {
- return;
- }
- b.alter_table("tasks", (t) => {
- t.add_column<string>("pending_resume_notice");
- });
- }
- public override void down(MigrationBuilder b) {
- // SQLite cannot drop a column through the builder's
- // alter_table path; the raw statement is the honest form.
- b.execute_sql("alter table tasks drop column pending_resume_notice");
- }
- }
- }
|