Entities.vala 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. using InvercargillSql.Orm;
  2. namespace ClankerSaddle.Data {
  3. /**
  4. * A software project worked on by saddle agents, stored in the
  5. * `projects` table.
  6. */
  7. public class Project : Object {
  8. public int64 id { get; set; }
  9. public string name { get; set; default = ""; }
  10. public string git_url { get; set; default = ""; }
  11. public string default_branch { get; set; default = "main"; }
  12. public string? summary { get; set; default = null; }
  13. public DateTime? created_at { get; set; default = null; }
  14. public static void entity_mapping(EntityMapperBuilder<Project> cfg) {
  15. cfg.table("projects")
  16. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  17. .column<string>("name", o => o.name, (o, v) => o.name = v)
  18. .column<string>("git_url", o => o.git_url, (o, v) => o.git_url = v)
  19. .column<string>("default_branch", o => o.default_branch, (o, v) => o.default_branch = v)
  20. .column<string>("summary", o => o.summary, (o, v) => o.summary = v)
  21. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v);
  22. }
  23. }
  24. /**
  25. * A directed relationship between two projects ('co-developed' or
  26. * 'reference'), stored in the `project_links` table.
  27. */
  28. public class ProjectLink : Object {
  29. public int64 id { get; set; }
  30. public int64 parent_project_id { get; set; }
  31. public int64 linked_project_id { get; set; }
  32. public string relationship { get; set; default = "reference"; }
  33. public static void entity_mapping(EntityMapperBuilder<ProjectLink> cfg) {
  34. cfg.table("project_links")
  35. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  36. .column<int64?>("parent_project_id", o => o.parent_project_id, (o, v) => o.parent_project_id = v)
  37. .column<int64?>("linked_project_id", o => o.linked_project_id, (o, v) => o.linked_project_id = v)
  38. .column<string>("relationship", o => o.relationship, (o, v) => o.relationship = v);
  39. }
  40. }
  41. /**
  42. * A unit of work for a saddle agent: created in {@link
  43. * TaskService.STATUS_DRAFT}, queued by its creator (human or goal
  44. * agent), dispatched to a saddle, worked, possibly blocked on
  45. * questions, and eventually done or failed (completion is
  46. * agent-only). The plan-12 shape: goals own the task graph — a task
  47. * links its {@link goal_id}, runs as a plain worker or the goal
  48. * agent itself ({@link kind}), carries a work {@link mode} and its
  49. * {@link creator}, and human tasks may carry an auto-enqueue
  50. * predecessor ({@link enqueue_after_task_id}). Stored in the
  51. * `tasks` table. Named `TaskEntity` (not `Task`) to stay clear of
  52. * `GLib.Task` in files that import Gio transitively.
  53. */
  54. public class TaskEntity : Object {
  55. public int64 id { get; set; }
  56. public int64 project_id { get; set; }
  57. public string title { get; set; default = ""; }
  58. public string? description { get; set; default = null; }
  59. public string status { get; set; default = "draft"; }
  60. public int64 priority { get; set; default = 5; }
  61. public string? summary { get; set; default = null; }
  62. public string? task_branch { get; set; default = null; }
  63. public string? branch_from { get; set; default = null; }
  64. public DateTime? created_at { get; set; default = null; }
  65. public DateTime? started_at { get; set; default = null; }
  66. public DateTime? completed_at { get; set; default = null; }
  67. public DateTime? suspended_at { get; set; default = null; }
  68. /**
  69. * Goal 4 task 1 (Force Wake): the human pressed Force wake on
  70. * the task page — this suspended plain task becomes
  71. * parked-offerable again with the explicit wake notice.
  72. * Consumed (cleared) by the allocation that resumes it.
  73. */
  74. public bool force_wake { get; set; default = false; }
  75. /** The goal this task belongs to (0 = standalone). */
  76. public int64 goal_id { get; set; default = 0; }
  77. /** "task" (a worker) or "goal_run" (the goal agent's own run). */
  78. public string kind { get; set; default = "task"; }
  79. /** implement / investigate / review / test (orchestrate for goal runs). */
  80. public string mode { get; set; default = "implement"; }
  81. /** "human" or "goal" — enqueueing is creator-only. */
  82. public string creator { get; set; default = "human"; }
  83. /** Human-created tasks only: auto-enqueue when this predecessor is done. */
  84. public int64 enqueue_after_task_id { get; set; default = 0; }
  85. public static void entity_mapping(EntityMapperBuilder<TaskEntity> cfg) {
  86. cfg.table("tasks")
  87. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  88. .column<int64?>("project_id", o => o.project_id, (o, v) => o.project_id = v)
  89. .column<string>("title", o => o.title, (o, v) => o.title = v)
  90. .column<string>("description", o => o.description, (o, v) => o.description = v)
  91. .column<string>("status", o => o.status, (o, v) => o.status = v)
  92. .column<int64?>("priority", o => o.priority, (o, v) => o.priority = v)
  93. .column<string>("summary", o => o.summary, (o, v) => o.summary = v)
  94. .column<string>("task_branch", o => o.task_branch, (o, v) => o.task_branch = v)
  95. .column<string>("branch_from", o => o.branch_from, (o, v) => o.branch_from = v)
  96. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v)
  97. .column<DateTime?>("started_at", o => o.started_at, (o, v) => o.started_at = v)
  98. .column<DateTime?>("completed_at", o => o.completed_at, (o, v) => o.completed_at = v)
  99. .column<DateTime?>("suspended_at", o => o.suspended_at, (o, v) => o.suspended_at = v)
  100. .column<bool>("force_wake", o => o.force_wake, (o, v) => o.force_wake = v)
  101. .column<int64?>("goal_id", o => o.goal_id, (o, v) => o.goal_id = v ?? 0)
  102. .column<string>("kind", o => o.kind, (o, v) => o.kind = v)
  103. .column<string>("mode", o => o.mode, (o, v) => o.mode = v)
  104. .column<string>("creator", o => o.creator, (o, v) => o.creator = v)
  105. .column<int64?>("enqueue_after_task_id", o => o.enqueue_after_task_id, (o, v) => o.enqueue_after_task_id = v ?? 0);
  106. }
  107. }
  108. /**
  109. * A named bundle of reference/co-developed projects (goal 8 task
  110. * 2): applied one-click to a project's or a goal's link set so a
  111. * fleet's common reference collection needs one click, not N.
  112. * Stored in the `stacks` table.
  113. */
  114. public class Stack : Object {
  115. public int64 id { get; set; }
  116. public string name { get; set; default = ""; }
  117. public string? summary { get; set; default = null; }
  118. public DateTime? created_at { get; set; default = null; }
  119. public static void entity_mapping(EntityMapperBuilder<Stack> cfg) {
  120. cfg.table("stacks")
  121. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  122. .column<string>("name", o => o.name, (o, v) => o.name = v)
  123. .column<string>("summary", o => o.summary, (o, v) => o.summary = v)
  124. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v);
  125. }
  126. }
  127. /**
  128. * One project of a {@link Stack} with the relationship it is
  129. * applied as ('co-developed' or 'reference'). Stored in the
  130. * `stack_projects` table.
  131. */
  132. public class StackProject : Object {
  133. public int64 id { get; set; }
  134. public int64 stack_id { get; set; }
  135. public int64 project_id { get; set; }
  136. public string relationship { get; set; default = "reference"; }
  137. public DateTime? created_at { get; set; default = null; }
  138. public static void entity_mapping(EntityMapperBuilder<StackProject> cfg) {
  139. cfg.table("stack_projects")
  140. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  141. .column<int64?>("stack_id", o => o.stack_id, (o, v) => o.stack_id = v)
  142. .column<int64?>("project_id", o => o.project_id, (o, v) => o.project_id = v)
  143. .column<string>("relationship", o => o.relationship, (o, v) => o.relationship = v)
  144. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v);
  145. }
  146. }
  147. /**
  148. * One row of the plan-17 unified event ledger (`events`): daemon
  149. * events carry their session and its per-session monotonic `seq`
  150. * (the idempotency key), web-originated events carry neither. The
  151. * payload is a JSON object whose shape depends on `kind` (see
  152. * Services.EventService).
  153. */
  154. public class EventRecord : Object {
  155. public int64 id { get; set; }
  156. public int64 session_id { get; set; default = 0; }
  157. public int64 seq { get; set; default = 0; }
  158. public string kind { get; set; default = ""; }
  159. public string actor { get; set; default = ""; }
  160. public string scope_type { get; set; default = ""; }
  161. public int64 scope_id { get; set; }
  162. public string payload { get; set; default = "{}"; }
  163. public DateTime? created_at { get; set; default = null; }
  164. public static void entity_mapping(EntityMapperBuilder<EventRecord> cfg) {
  165. cfg.table("events")
  166. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  167. .column<int64?>("session_id",
  168. o => o.session_id > 0 ? (int64?) o.session_id : (int64?) null,
  169. (o, v) => o.session_id = v ?? 0)
  170. .column<int64?>("seq",
  171. o => o.seq > 0 ? (int64?) o.seq : (int64?) null,
  172. (o, v) => o.seq = v ?? 0)
  173. .column<string>("kind", o => o.kind, (o, v) => o.kind = v)
  174. .column<string>("actor", o => o.actor, (o, v) => o.actor = v)
  175. .column<string>("scope_type", o => o.scope_type, (o, v) => o.scope_type = v)
  176. .column<int64?>("scope_id", o => o.scope_id, (o, v) => o.scope_id = v ?? 0)
  177. .column<string>("payload", o => o.payload, (o, v) => o.payload = v)
  178. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v);
  179. }
  180. }
  181. /** A remark on a task, authored either by a human or by the agent ('agent'). */
  182. public class TaskComment : Object {
  183. public int64 id { get; set; }
  184. public int64 task_id { get; set; }
  185. public string author { get; set; default = "agent"; }
  186. public string body { get; set; default = ""; }
  187. public string? quote { get; set; default = null; }
  188. public DateTime? created_at { get; set; default = null; }
  189. public static void entity_mapping(EntityMapperBuilder<TaskComment> cfg) {
  190. cfg.table("task_comments")
  191. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  192. .column<int64?>("task_id", o => o.task_id, (o, v) => o.task_id = v)
  193. .column<string>("author", o => o.author, (o, v) => o.author = v)
  194. .column<string>("body", o => o.body, (o, v) => o.body = v)
  195. .column<string>("quote", o => o.quote, (o, v) => o.quote = v)
  196. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v);
  197. }
  198. }
  199. /**
  200. * A blocking prompt raised by an agent mid-task — a multiple-choice
  201. * {@link block_type} question, a request for comment or a review
  202. * request — answered by a human in the web UI; the answer is collected
  203. * by the saddle on its next
  204. * {@link ClankerSaddle.Services.SaddlePollState} delivery ledger poll.
  205. */
  206. public class TaskBlock : Object {
  207. public int64 id { get; set; }
  208. public int64 task_id { get; set; }
  209. public string question { get; set; default = ""; }
  210. public string? answer { get; set; default = null; }
  211. public string block_type { get; set; default = "question"; }
  212. public string? options { get; set; default = null; }
  213. public string? body { get; set; default = null; }
  214. public DateTime? answered_at { get; set; default = null; }
  215. public string? answered_by { get; set; default = null; }
  216. public DateTime? created_at { get; set; default = null; }
  217. public static void entity_mapping(EntityMapperBuilder<TaskBlock> cfg) {
  218. cfg.table("task_blocks")
  219. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  220. .column<int64?>("task_id", o => o.task_id, (o, v) => o.task_id = v)
  221. .column<string>("question", o => o.question, (o, v) => o.question = v)
  222. .column<string>("answer", o => o.answer, (o, v) => o.answer = v)
  223. .column<string>("type", o => o.block_type, (o, v) => o.block_type = v)
  224. .column<string>("options", o => o.options, (o, v) => o.options = v)
  225. .column<string>("body", o => o.body, (o, v) => o.body = v)
  226. .column<DateTime?>("answered_at", o => o.answered_at, (o, v) => o.answered_at = v)
  227. .column<string>("answered_by", o => o.answered_by, (o, v) => o.answered_by = v)
  228. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v);
  229. }
  230. }
  231. /**
  232. * A saddle container registered with this app: one daemon managing one
  233. * bash session at a time, controlled over HTTP at {@link host}. The
  234. * per-saddle token ({@link token}, plan 10) authorises every
  235. * daemon→web call; removing the row revokes it. Plan 16 item 23:
  236. * sessions are the source of truth for "who runs what" — busy/idle
  237. * are DERIVED (busy iff an open session on an assigned/working task
  238. * exists; see {@link Services.SaddleService.current_work_view}) and
  239. * the row's `status` column is only the OFFLINE probe state
  240. * ('offline' vs 'idle'): the poller's unreachable stamp, cleared by
  241. * a successful probe or a proof-of-life ask. The former
  242. * `current_task_id`/`allocated_at` cache columns are gone.
  243. */
  244. public class Saddle : Object {
  245. public int64 id { get; set; }
  246. public string name { get; set; default = ""; }
  247. public string host { get; set; default = ""; }
  248. public string status { get; set; default = "idle"; }
  249. public string? git_name { get; set; default = null; }
  250. public string? git_email { get; set; default = null; }
  251. /**
  252. * The saddle admin's standing prompt note (goal 8 task 5):
  253. * a message about THIS machine (e.g. "You have root and may
  254. * install development tooling via DNF") served verbatim inside
  255. * every assignment's system prompt; null when unset.
  256. */
  257. public string? prompt_note { get; set; default = null; }
  258. public string? ssh_public_key { get; set; default = null; }
  259. public string? token { get; set; default = null; }
  260. /**
  261. * The workspace root this saddle's daemon reported at
  262. * /register (its SADDLE_WORKSPACE_ROOT), or null for daemons
  263. * that predate the field — assignment paths fall back to
  264. * SADDLE_PROJECTS_ROOT, then "/workspace".
  265. */
  266. public string? workspace_root { get; set; default = null; }
  267. public static void entity_mapping(EntityMapperBuilder<Saddle> cfg) {
  268. cfg.table("saddles")
  269. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  270. .column<string>("name", o => o.name, (o, v) => o.name = v)
  271. .column<string>("host", o => o.host, (o, v) => o.host = v)
  272. .column<string>("status", o => o.status, (o, v) => o.status = v)
  273. .column<string>("git_name", o => o.git_name, (o, v) => o.git_name = v)
  274. .column<string>("git_email", o => o.git_email, (o, v) => o.git_email = v)
  275. .column<string>("prompt_note", o => o.prompt_note, (o, v) => o.prompt_note = v)
  276. .column<string>("ssh_public_key", o => o.ssh_public_key, (o, v) => o.ssh_public_key = v)
  277. .column<string>("token", o => o.token, (o, v) => o.token = v)
  278. .column<string>("workspace_root", o => o.workspace_root, (o, v) => o.workspace_root = v);
  279. }
  280. }
  281. /**
  282. * One run of a task on a saddle: opened when the dispatcher assigns
  283. * the task, closed with an outcome when the session ends.
  284. */
  285. public class Session : Object {
  286. public int64 id { get; set; }
  287. public int64 task_id { get; set; }
  288. public int64 saddle_id { get; set; }
  289. public DateTime? started_at { get; set; default = null; }
  290. public DateTime? ended_at { get; set; default = null; }
  291. public string? outcome { get; set; default = null; }
  292. /**
  293. * What a resumed session's agent first received (plan 14 B4):
  294. * the resume_notice the allocation built, stored on the row at
  295. * resume-allocation; null for fresh sessions.
  296. */
  297. public string? resume_notice { get; set; default = null; }
  298. public static void entity_mapping(EntityMapperBuilder<Session> cfg) {
  299. cfg.table("sessions")
  300. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  301. .column<int64?>("task_id", o => o.task_id, (o, v) => o.task_id = v)
  302. .column<int64?>("saddle_id", o => o.saddle_id, (o, v) => o.saddle_id = v)
  303. .column<DateTime?>("started_at", o => o.started_at, (o, v) => o.started_at = v)
  304. .column<DateTime?>("ended_at", o => o.ended_at, (o, v) => o.ended_at = v)
  305. .column<string>("outcome", o => o.outcome, (o, v) => o.outcome = v)
  306. .column<string>("resume_notice", o => o.resume_notice, (o, v) => o.resume_notice = v);
  307. }
  308. }
  309. /**
  310. * A reusable instruction the dispatched agent must follow, stored in
  311. * the `rules` table and attached to projects and/or tasks.
  312. * `updated_at` stamps the last body/name edit (null until edited)
  313. * — the resume-time context_update delta keys on it.
  314. */
  315. public class Rule : Object {
  316. public int64 id { get; set; }
  317. public string name { get; set; default = ""; }
  318. public string body { get; set; default = ""; }
  319. public DateTime? created_at { get; set; default = null; }
  320. public DateTime? updated_at { get; set; default = null; }
  321. public static void entity_mapping(EntityMapperBuilder<Rule> cfg) {
  322. cfg.table("rules")
  323. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  324. .column<string>("name", o => o.name, (o, v) => o.name = v)
  325. .column<string>("body", o => o.body, (o, v) => o.body = v)
  326. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v)
  327. .column<DateTime?>("updated_at", o => o.updated_at, (o, v) => o.updated_at = v);
  328. }
  329. }
  330. /** An attachment of a rule to a project (`rule_projects`). */
  331. public class RuleProject : Object {
  332. public int64 id { get; set; }
  333. public int64 rule_id { get; set; }
  334. public int64 project_id { get; set; }
  335. public DateTime? created_at { get; set; default = null; }
  336. public static void entity_mapping(EntityMapperBuilder<RuleProject> cfg) {
  337. cfg.table("rule_projects")
  338. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  339. .column<int64?>("rule_id", o => o.rule_id, (o, v) => o.rule_id = v)
  340. .column<int64?>("project_id", o => o.project_id, (o, v) => o.project_id = v)
  341. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v);
  342. }
  343. }
  344. /** An attachment of a rule to a task (`task_rules`). */
  345. public class TaskRule : Object {
  346. public int64 id { get; set; }
  347. public int64 rule_id { get; set; }
  348. public int64 task_id { get; set; }
  349. public DateTime? created_at { get; set; default = null; }
  350. public static void entity_mapping(EntityMapperBuilder<TaskRule> cfg) {
  351. cfg.table("task_rules")
  352. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  353. .column<int64?>("rule_id", o => o.rule_id, (o, v) => o.rule_id = v)
  354. .column<int64?>("task_id", o => o.task_id, (o, v) => o.task_id = v)
  355. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v);
  356. }
  357. }
  358. /**
  359. * An LLM-authored remark about a project (`saddle note` via the
  360. * callback endpoint), curated from the project page. The source task
  361. * is null for notes without one.
  362. */
  363. public class ProjectNote : Object {
  364. public int64 id { get; set; }
  365. public int64 project_id { get; set; }
  366. public int64 source_task_id { get; set; default = 0; }
  367. public string body { get; set; default = ""; }
  368. public DateTime? created_at { get; set; default = null; }
  369. public static void entity_mapping(EntityMapperBuilder<ProjectNote> cfg) {
  370. cfg.table("project_notes")
  371. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  372. .column<int64?>("project_id", o => o.project_id, (o, v) => o.project_id = v)
  373. .column<int64?>("source_task_id", o => o.source_task_id, (o, v) => o.source_task_id = v ?? 0)
  374. .column<string>("body", o => o.body, (o, v) => o.body = v)
  375. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v);
  376. }
  377. }
  378. /**
  379. * A dashboard scratchpad note (goal 8 task 3): a personal
  380. * todo/idea jotted down before a batch of changes is ready to be
  381. * a full goal. Promoting ({@link ClankerSaddle.Services.NoteService.promote_to_goal})
  382. * creates a DRAFT goal from the body and sets {@link goal_id},
  383. * which links the created goal and freezes the note. Stored in
  384. * the `notes` table.
  385. */
  386. public class Note : Object {
  387. public int64 id { get; set; }
  388. public string body { get; set; default = ""; }
  389. public bool done { get; set; default = false; }
  390. public DateTime? done_at { get; set; default = null; }
  391. /** The goal this note promoted into (0 = not promoted). */
  392. public int64 goal_id { get; set; default = 0; }
  393. public DateTime? created_at { get; set; default = null; }
  394. public static void entity_mapping(EntityMapperBuilder<Note> cfg) {
  395. cfg.table("notes")
  396. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  397. .column<string>("body", o => o.body, (o, v) => o.body = v)
  398. .column<bool>("done", o => o.done, (o, v) => o.done = v)
  399. .column<DateTime?>("done_at", o => o.done_at, (o, v) => o.done_at = v)
  400. .column<int64?>("goal_id", o => o.goal_id > 0 ? (int64?) o.goal_id : (int64?) null,
  401. (o, v) => o.goal_id = v ?? 0)
  402. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v);
  403. }
  404. }
  405. /**
  406. * A named tag used for dispatch routing (`capabilities`): saddles
  407. * declare the tags they carry, tasks the tags they require.
  408. */
  409. public class Capability : Object {
  410. public int64 id { get; set; }
  411. public string name { get; set; default = ""; }
  412. public DateTime? created_at { get; set; default = null; }
  413. public static void entity_mapping(EntityMapperBuilder<Capability> cfg) {
  414. cfg.table("capabilities")
  415. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  416. .column<string>("name", o => o.name, (o, v) => o.name = v)
  417. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v);
  418. }
  419. }
  420. /** A tag declaration on a saddle (`saddle_capabilities`). */
  421. public class SaddleCapability : Object {
  422. public int64 id { get; set; }
  423. public int64 capability_id { get; set; }
  424. public int64 saddle_id { get; set; }
  425. public static void entity_mapping(EntityMapperBuilder<SaddleCapability> cfg) {
  426. cfg.table("saddle_capabilities")
  427. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  428. .column<int64?>("capability_id", o => o.capability_id, (o, v) => o.capability_id = v)
  429. .column<int64?>("saddle_id", o => o.saddle_id, (o, v) => o.saddle_id = v);
  430. }
  431. }
  432. /** A required tag on a task (`task_capabilities`). */
  433. public class TaskCapability : Object {
  434. public int64 id { get; set; }
  435. public int64 capability_id { get; set; }
  436. public int64 task_id { get; set; }
  437. public static void entity_mapping(EntityMapperBuilder<TaskCapability> cfg) {
  438. cfg.table("task_capabilities")
  439. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  440. .column<int64?>("capability_id", o => o.capability_id, (o, v) => o.capability_id = v)
  441. .column<int64?>("task_id", o => o.task_id, (o, v) => o.task_id = v);
  442. }
  443. }
  444. /**
  445. * A user's Web Push subscription endpoint (plan 11 task E shape):
  446. * `p256dh`/`auth` are the browser's application server keys; the
  447. * endpoint URL is unique per browser. `user_id` references the
  448. * Spry users table by value (no FK — the auth schema owns that
  449. * table).
  450. */
  451. public class PushSubscription : Object {
  452. public int64 id { get; set; }
  453. public int64 user_id { get; set; }
  454. public string endpoint { get; set; default = ""; }
  455. public string p256dh { get; set; default = ""; }
  456. public string auth { get; set; default = ""; }
  457. public DateTime? created_at { get; set; default = null; }
  458. public static void entity_mapping(EntityMapperBuilder<PushSubscription> cfg) {
  459. cfg.table("push_subscriptions")
  460. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  461. .column<int64?>("user_id", o => o.user_id, (o, v) => o.user_id = v)
  462. .column<string>("endpoint", o => o.endpoint, (o, v) => o.endpoint = v)
  463. .column<string>("p256dh", o => o.p256dh, (o, v) => o.p256dh = v)
  464. .column<string>("auth", o => o.auth, (o, v) => o.auth = v)
  465. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v);
  466. }
  467. }
  468. /**
  469. * A user's per-task "Notify me" opt-in (plan 11 task E shape): the
  470. * task's first start, failure and completion notify the opted-in
  471. * user; block events notify all push-subscribed users globally.
  472. */
  473. public class TaskNotifyPref : Object {
  474. public int64 id { get; set; }
  475. public int64 task_id { get; set; }
  476. public int64 user_id { get; set; }
  477. public static void entity_mapping(EntityMapperBuilder<TaskNotifyPref> cfg) {
  478. cfg.table("task_notify_prefs")
  479. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  480. .column<int64?>("task_id", o => o.task_id, (o, v) => o.task_id = v)
  481. .column<int64?>("user_id", o => o.user_id, (o, v) => o.user_id = v);
  482. }
  483. }
  484. /**
  485. * A user-created goal (plan 12): an agent-orchestrated unit of
  486. * work over one primary project plus optional links. The brief
  487. * locks once started; the lifecycle runs draft → planning → plan
  488. * review → active → completion review → complete / failed /
  489. * cancelled, with paused freezing supervision in between. Stored
  490. * in the `goals` table.
  491. */
  492. public class Goal : Object {
  493. public int64 id { get; set; }
  494. public int64 project_id { get; set; }
  495. public string title { get; set; default = ""; }
  496. public string brief { get; set; default = ""; }
  497. public string branch_name { get; set; default = ""; }
  498. public string? base_branch { get; set; default = null; }
  499. public string status { get; set; default = "draft"; }
  500. public int64 priority { get; set; default = 3; }
  501. public string? plan { get; set; default = null; }
  502. public string? completion_report { get; set; default = null; }
  503. public string creator { get; set; default = "human"; }
  504. /**
  505. * Plan 15 C3 (was last_seen_event_id): the timestamp through
  506. * which the goal agent has consumed its tasks' terminal
  507. * transitions — resume_due fires on transitions newer than
  508. * it, and a resume advance it. The narrative itself is
  509. * derived at read time.
  510. */
  511. public DateTime? last_terminal_watermark { get; set; default = null; }
  512. public DateTime? created_at { get; set; default = null; }
  513. public DateTime? started_at { get; set; default = null; }
  514. public DateTime? completed_at { get; set; default = null; }
  515. public DateTime? paused_at { get; set; default = null; }
  516. /**
  517. * Goal 4 task 1 (Force Wake): the human pressed Force wake on
  518. * the goal page — the parked run becomes offerable immediately
  519. * and the resume notice leads with the explicit wake line.
  520. * Consumed (cleared) by the resume that carries it.
  521. */
  522. public bool force_wake { get; set; default = false; }
  523. public static void entity_mapping(EntityMapperBuilder<Goal> cfg) {
  524. cfg.table("goals")
  525. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  526. .column<int64?>("project_id", o => o.project_id, (o, v) => o.project_id = v)
  527. .column<string>("title", o => o.title, (o, v) => o.title = v)
  528. .column<string>("brief", o => o.brief, (o, v) => o.brief = v)
  529. .column<string>("branch_name", o => o.branch_name, (o, v) => o.branch_name = v)
  530. .column<string>("base_branch", o => o.base_branch, (o, v) => o.base_branch = v)
  531. .column<string>("status", o => o.status, (o, v) => o.status = v)
  532. .column<int64?>("priority", o => o.priority, (o, v) => o.priority = v)
  533. .column<string>("plan", o => o.plan, (o, v) => o.plan = v)
  534. .column<string>("completion_report", o => o.completion_report, (o, v) => o.completion_report = v)
  535. .column<string>("creator", o => o.creator, (o, v) => o.creator = v)
  536. .column<DateTime?>("last_terminal_watermark", o => o.last_terminal_watermark, (o, v) => o.last_terminal_watermark = v)
  537. .column<DateTime?>("created_at", o => o.created_at, (o, v) => o.created_at = v)
  538. .column<DateTime?>("started_at", o => o.started_at, (o, v) => o.started_at = v)
  539. .column<DateTime?>("completed_at", o => o.completed_at, (o, v) => o.completed_at = v)
  540. .column<DateTime?>("paused_at", o => o.paused_at, (o, v) => o.paused_at = v)
  541. .column<bool>("force_wake", o => o.force_wake, (o, v) => o.force_wake = v);
  542. }
  543. }
  544. /** A project link on a goal (`goal_links`): co-developed or reference. */
  545. public class GoalLink : Object {
  546. public int64 id { get; set; }
  547. public int64 goal_id { get; set; }
  548. public int64 project_id { get; set; }
  549. public string relationship { get; set; default = "reference"; }
  550. public static void entity_mapping(EntityMapperBuilder<GoalLink> cfg) {
  551. cfg.table("goal_links")
  552. .column<int64?>("id", o => o.id, (o, v) => o.id = v)
  553. .column<int64?>("goal_id", o => o.goal_id, (o, v) => o.goal_id = v)
  554. .column<int64?>("project_id", o => o.project_id, (o, v) => o.project_id = v)
  555. .column<string>("relationship", o => o.relationship, (o, v) => o.relationship = v);
  556. }
  557. }
  558. }