@lifeaitools/rdc-skills 0.24.38 → 0.24.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.json +15 -15
- package/.claude-plugin/marketplace.json +21 -21
- package/.claude-plugin/plugin.json +1371 -1371
- package/.github/workflows/publish.yml +34 -34
- package/.github/workflows/self-test.yml +58 -58
- package/CHANGELOG.md +310 -310
- package/LICENSE +21 -21
- package/MANIFEST.md +221 -221
- package/README.md +377 -377
- package/README.sandbox.md +3 -3
- package/assets/watcher/viewer.html +164 -164
- package/bin/rdc-skills-mcp.mjs +316 -316
- package/commands/build.md +183 -183
- package/commands/collab.md +180 -180
- package/commands/deploy.md +152 -152
- package/commands/design.md +31 -31
- package/commands/edit.md +28 -28
- package/commands/fixit.md +124 -124
- package/commands/handoff.md +173 -173
- package/commands/help.md +95 -95
- package/commands/overnight.md +220 -220
- package/commands/plan.md +158 -158
- package/commands/preplan.md +131 -131
- package/commands/prototype.md +145 -145
- package/commands/release.md +49 -49
- package/commands/report.md +99 -99
- package/commands/review.md +120 -120
- package/commands/self-test.md +113 -113
- package/commands/status.md +86 -86
- package/commands/watch.md +98 -98
- package/commands/workitems.md +137 -137
- package/git-sha.json +1 -1
- package/guides/agent-bootstrap.md +295 -295
- package/guides/agents/backend.md +104 -104
- package/guides/agents/content.md +94 -94
- package/guides/agents/cs2.md +56 -56
- package/guides/agents/data.md +87 -87
- package/guides/agents/design.md +77 -77
- package/guides/agents/frontend.md +92 -92
- package/guides/agents/infrastructure.md +81 -81
- package/guides/agents/setup.md +281 -281
- package/guides/agents/verify.md +151 -151
- package/guides/agents/viz.md +106 -106
- package/guides/backend.md +146 -146
- package/guides/content.md +147 -147
- package/guides/cs2.md +190 -190
- package/guides/data.md +123 -123
- package/guides/design.md +116 -116
- package/guides/engineering-behavior.md +43 -43
- package/guides/escalation-protocol.md +125 -125
- package/guides/frontend.md +151 -151
- package/guides/history-md-spec.md +297 -297
- package/guides/infrastructure.md +179 -179
- package/guides/lessons-learned-spec.md +153 -153
- package/guides/output-contract.md +108 -108
- package/guides/publish-md-spec.md +289 -289
- package/guides/rdc-skills-startup.md +30 -30
- package/guides/verify.md +11 -11
- package/hooks/check-cwd.js +31 -31
- package/hooks/check-rdc-environment.js +164 -164
- package/hooks/check-services.js +6 -6
- package/hooks/check-stale-work-items.js +19 -19
- package/hooks/foreground-process-gate.js +128 -128
- package/hooks/gate-watchdog-selfcheck.js +257 -257
- package/hooks/hook-logger.js +25 -25
- package/hooks/lib/run-evidence-gate.mjs +241 -241
- package/hooks/no-stop-open-epics.js +127 -127
- package/hooks/post-tool-batch-gate.js +203 -203
- package/hooks/post-work-check.js +21 -21
- package/hooks/postcompact-log.js +13 -13
- package/hooks/precompact-log.js +13 -13
- package/hooks/rate-limit-retry.js +46 -46
- package/hooks/rdc-invocation-marker.js +157 -157
- package/hooks/rdc-output-contract-gate.js +94 -94
- package/hooks/require-work-item-on-commit.js +294 -294
- package/hooks/restart-brief.js +19 -19
- package/hooks/run-hidden-hook.ps1 +47 -47
- package/hooks/task-completed-gate.js +274 -274
- package/hooks/work-item-exit-gate.js +944 -944
- package/lib/catalog.mjs +236 -236
- package/lib/cloud-rewrite.mjs +155 -155
- package/package.json +56 -56
- package/rules/work-items-rpc.md +520 -520
- package/scaffold/templates/HISTORY.md.template +39 -39
- package/scaffold/templates/PUBLISH.md.template +21 -21
- package/scaffold/templates/brochure-studio-default.html +70 -70
- package/scripts/acceptance.mjs +502 -502
- package/scripts/fixtures/guides/bad-guide.md +15 -15
- package/scripts/fixtures/guides-clean/good-guide.md +16 -16
- package/scripts/install-rdc-skills.js +1289 -1289
- package/scripts/install.ps1 +202 -202
- package/scripts/install.sh +132 -132
- package/scripts/lib/assertions.mjs +287 -287
- package/scripts/lib/manifest-schema.mjs +754 -754
- package/scripts/lib/runner.mjs +465 -465
- package/scripts/lib/sandbox.mjs +435 -435
- package/scripts/prepack.mjs +32 -32
- package/scripts/rdc-brochure.mjs +464 -464
- package/scripts/rdc-design-cli.mjs +134 -134
- package/scripts/rebuild-mcp.mjs +107 -107
- package/scripts/self-test.mjs +1460 -1460
- package/scripts/stamp-git-sha.mjs +29 -29
- package/scripts/test-guide-validator.mjs +196 -196
- package/scripts/test-rdc-hooks.mjs +145 -145
- package/scripts/uninstall.ps1 +77 -77
- package/scripts/uninstall.sh +69 -69
- package/scripts/update.ps1 +43 -43
- package/scripts/update.sh +43 -43
- package/scripts/validate-place-histories.js +461 -461
- package/scripts/validate-publish-manifests.js +424 -424
- package/scripts/watch-init.mjs +100 -100
- package/skills/brochure/SKILL.md +107 -107
- package/skills/build/SKILL.md +563 -563
- package/skills/channel-formatter/SKILL.md +533 -533
- package/skills/co-develop/SKILL.md +196 -196
- package/skills/collab/SKILL.md +239 -239
- package/skills/convert/SKILL.md +140 -140
- package/skills/deploy/SKILL.md +541 -541
- package/skills/design/SKILL.md +211 -211
- package/skills/design/reference/ownership.md +16 -16
- package/skills/design/reference/rampa.md +92 -92
- package/skills/design/reference/studio-model.md +153 -153
- package/skills/edit/SKILL.md +98 -98
- package/skills/fixit/SKILL.md +165 -165
- package/skills/fs-mcp/SKILL.md +148 -148
- package/skills/handoff/SKILL.md +236 -200
- package/skills/help/SKILL.md +143 -143
- package/skills/housekeeping/SKILL.md +189 -189
- package/skills/lifeai-brochure-author/SKILL.md +340 -340
- package/skills/overnight/SKILL.md +251 -251
- package/skills/plan/SKILL.md +345 -345
- package/skills/preplan/SKILL.md +90 -90
- package/skills/prototype/SKILL.md +150 -150
- package/skills/rdc-brochurify/SKILL.md +245 -245
- package/skills/rdc-extract-verifier-rules/SKILL.md +191 -191
- package/skills/release/SKILL.md +140 -140
- package/skills/report/SKILL.md +100 -100
- package/skills/review/SKILL.md +152 -152
- package/skills/rpms-filemap/SKILL.cloud.md +111 -111
- package/skills/rpms-filemap/SKILL.md +111 -111
- package/skills/self-test/SKILL.md +132 -132
- package/skills/status/SKILL.md +99 -99
- package/skills/terminal-config/SKILL.md +62 -62
- package/skills/tests/MATRIX.md +54 -54
- package/skills/tests/README.md +47 -47
- package/skills/tests/rdc-brochure.test.json +34 -34
- package/skills/tests/rdc-build.test.json +36 -36
- package/skills/tests/rdc-channel-formatter.test.json +45 -45
- package/skills/tests/rdc-co-develop.test.json +29 -29
- package/skills/tests/rdc-collab.test.json +29 -29
- package/skills/tests/rdc-convert.test.json +35 -35
- package/skills/tests/rdc-deploy.test.json +30 -30
- package/skills/tests/rdc-design.test.json +27 -27
- package/skills/tests/rdc-edit.test.json +29 -29
- package/skills/tests/rdc-fixit.test.json +36 -36
- package/skills/tests/rdc-fs-mcp.test.json +36 -36
- package/skills/tests/rdc-handoff.test.json +28 -28
- package/skills/tests/rdc-help.test.json +29 -29
- package/skills/tests/rdc-housekeeping.test.json +31 -31
- package/skills/tests/rdc-lifeai-brochure-author.test.json +35 -35
- package/skills/tests/rdc-overnight.test.json +37 -37
- package/skills/tests/rdc-plan.test.json +27 -27
- package/skills/tests/rdc-preplan.test.json +31 -31
- package/skills/tests/rdc-prototype.test.json +28 -28
- package/skills/tests/rdc-rdc-brochurify.test.json +23 -23
- package/skills/tests/rdc-rdc-extract-verifier-rules.test.json +34 -34
- package/skills/tests/rdc-release.test.json +29 -29
- package/skills/tests/rdc-report.test.json +28 -28
- package/skills/tests/rdc-review.test.json +29 -29
- package/skills/tests/rdc-rpms-filemap.test.json +28 -28
- package/skills/tests/rdc-self-test.test.json +24 -24
- package/skills/tests/rdc-status.test.json +29 -29
- package/skills/tests/rdc-terminal-config.test.json +29 -29
- package/skills/tests/rdc-watch.test.json +24 -24
- package/skills/tests/rdc-workitems.test.json +27 -27
- package/skills/watch/SKILL.md +97 -97
- package/skills/workitems/SKILL.md +151 -151
- package/tests/acceptance.test.mjs +59 -59
- package/tests/channel-formatter.contract.test.mjs +251 -251
- package/tests/curl-surface.test.mjs +289 -289
- package/tests/harness-gates.test.mjs +325 -325
- package/tests/help-surface.test.mjs +61 -61
- package/tests/install-rdc-skills.test.mjs +49 -49
- package/tests/manifest-contract-fields.test.mjs +78 -78
- package/tests/mcp.test.mjs +271 -271
- package/tests/require-work-item-on-commit.test.mjs +162 -162
- package/tests/run-evidence-gate.test.mjs +82 -82
- package/tests/skill-test-matrix.test.mjs +66 -66
- package/tests/validate-skills.js +27 -27
- package/tests/work-item-exit-gate-l2.test.mjs +368 -368
- package/tests/work-item-exit-gate-l3.test.mjs +197 -197
package/rules/work-items-rpc.md
CHANGED
|
@@ -1,520 +1,520 @@
|
|
|
1
|
-
# Work Items RPC Reference
|
|
2
|
-
|
|
3
|
-
> Complete reference for work_items table operations via Supabase RPC functions.
|
|
4
|
-
> Use these functions for ALL CRUD operations. Never write raw INSERT/UPDATE/SELECT against work_items.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Core Rule
|
|
9
|
-
|
|
10
|
-
**Always use RPC functions.** They handle defaults, check constraints, timestamps, sorting, and return structured JSONB.
|
|
11
|
-
|
|
12
|
-
Exception: Ad-hoc analytics queries (e.g., `SELECT count(*)`) are acceptable as raw SQL.
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## Valid Enum Values
|
|
17
|
-
|
|
18
|
-
| Column | Allowed Values |
|
|
19
|
-
|--------|---|
|
|
20
|
-
| `status` | `todo` · `in_progress` · `blocked` · `review` · `done` · `archived` |
|
|
21
|
-
| `priority` | `urgent` · `high` · `normal` · `low` |
|
|
22
|
-
| `item_type` | `epic` · `task` · `subtask` · `bug` · `spike` |
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## RPC Functions
|
|
27
|
-
|
|
28
|
-
### 1. get_open_epics — List open epics
|
|
29
|
-
|
|
30
|
-
Returns all non-done/archived epics sorted by priority, then created_at.
|
|
31
|
-
|
|
32
|
-
**Supabase SQL:**
|
|
33
|
-
```sql
|
|
34
|
-
SELECT get_open_epics();
|
|
35
|
-
SELECT get_open_epics('urgent');
|
|
36
|
-
SELECT get_open_epics(p_label_filter := 'feature-x');
|
|
37
|
-
SELECT get_open_epics('high', 'backend');
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
**Supabase JS Client:**
|
|
41
|
-
```ts
|
|
42
|
-
const { data } = await supabase.rpc('get_open_epics');
|
|
43
|
-
const { data } = await supabase.rpc('get_open_epics', {
|
|
44
|
-
p_priority_filter: 'urgent'
|
|
45
|
-
});
|
|
46
|
-
const { data } = await supabase.rpc('get_open_epics', {
|
|
47
|
-
p_label_filter: 'cs2'
|
|
48
|
-
});
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
**Parameters:**
|
|
52
|
-
|
|
53
|
-
| Name | Type | Required | Notes |
|
|
54
|
-
|------|------|----------|-------|
|
|
55
|
-
| `p_priority_filter` | text | no | NULL = all priorities. One of: `urgent`, `high`, `normal`, `low` |
|
|
56
|
-
| `p_label_filter` | text | no | NULL = all labels. Uses array containment (`@>`) for matching |
|
|
57
|
-
|
|
58
|
-
**Returns:**
|
|
59
|
-
- JSONB array of epic objects (sorted by priority then created_at)
|
|
60
|
-
- Empty `[]` if none found
|
|
61
|
-
- Each epic has: `id`, `title`, `status`, `priority`, `item_type`, `labels`, `created_at`, `updated_at`
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
### 2. insert_work_item — Create a work item
|
|
66
|
-
|
|
67
|
-
Create a new task, epic, subtask, bug, or spike.
|
|
68
|
-
|
|
69
|
-
**Supabase SQL:**
|
|
70
|
-
```sql
|
|
71
|
-
SELECT insert_work_item(
|
|
72
|
-
p_title := 'Build user authentication',
|
|
73
|
-
p_description := 'Implement OAuth2 flow...',
|
|
74
|
-
p_status := 'todo',
|
|
75
|
-
p_priority := 'high',
|
|
76
|
-
p_item_type := 'task',
|
|
77
|
-
p_parent_id := 'epic-uuid'::uuid,
|
|
78
|
-
p_labels := ARRAY['backend', 'auth'],
|
|
79
|
-
p_source := 'agent'
|
|
80
|
-
);
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
**Supabase JS Client:**
|
|
84
|
-
```ts
|
|
85
|
-
const { data } = await supabase.rpc('insert_work_item', {
|
|
86
|
-
p_title: 'Build user authentication',
|
|
87
|
-
p_description: 'Implement OAuth2 flow...',
|
|
88
|
-
p_status: 'todo',
|
|
89
|
-
p_priority: 'high',
|
|
90
|
-
p_item_type: 'task',
|
|
91
|
-
p_parent_id: epicId,
|
|
92
|
-
p_labels: ['backend', 'auth'],
|
|
93
|
-
p_source: 'agent'
|
|
94
|
-
});
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
**All Parameters:**
|
|
98
|
-
|
|
99
|
-
| Name | Type | Default | Notes |
|
|
100
|
-
|------|------|---------|-------|
|
|
101
|
-
| `p_title` | text | *required* | Work item name (max 255 chars) |
|
|
102
|
-
| `p_description` | text | NULL | Long-form description |
|
|
103
|
-
| `p_status` | text | `'todo'` | One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
|
|
104
|
-
| `p_priority` | text | `'normal'` | One of: `urgent`, `high`, `normal`, `low` |
|
|
105
|
-
| `p_item_type` | text | `'task'` | One of: `epic`, `task`, `subtask`, `bug`, `spike` |
|
|
106
|
-
| `p_parent_id` | uuid | NULL | Parent epic UUID for hierarchy (for subtasks) |
|
|
107
|
-
| `p_company_id` | uuid | NULL | Foreign key to companies table |
|
|
108
|
-
| `p_customer_id` | uuid | NULL | Foreign key to customers table |
|
|
109
|
-
| `p_campaign_id` | uuid | NULL | Foreign key to campaigns table |
|
|
110
|
-
| `p_contact_id` | uuid | NULL | Foreign key to contacts table |
|
|
111
|
-
| `p_project_id` | uuid | NULL | Project identifier (project-specific) |
|
|
112
|
-
| `p_assignee` | text | NULL | Assigned person name or email |
|
|
113
|
-
| `p_assigned_to` | text | NULL | Same as assignee (alternate field) |
|
|
114
|
-
| `p_due_date` | date | NULL | Due date for the task |
|
|
115
|
-
| `p_tags` | text[] | `'{}'` | Array of tags |
|
|
116
|
-
| `p_labels` | text[] | `'{}'` | Array of labels (used for filtering) |
|
|
117
|
-
| `p_linked_table` | text | NULL | Name of external table to link (if any) |
|
|
118
|
-
| `p_linked_id` | uuid | NULL | ID in linked_table |
|
|
119
|
-
| `p_created_by` | text | NULL | Who created this item |
|
|
120
|
-
| `p_estimated_hours` | numeric | NULL | Time estimate in hours |
|
|
121
|
-
| `p_notes` | jsonb | `'[]'` | Array of note objects `[{ text, author, timestamp }]` |
|
|
122
|
-
| `p_session_id` | text | NULL | Session UUID (for audit trail) |
|
|
123
|
-
| `p_package` | text | NULL | Package/module name (e.g., '@regen/ui') |
|
|
124
|
-
| `p_source` | text | `'manual'` | How was this created: `manual`, `agent`, `api`, `import` |
|
|
125
|
-
| `p_checklist` | jsonb | `NULL` | Checklist items. If NULL and parent has `definition_of_done`, auto-inherited with all `checked: false` |
|
|
126
|
-
| `p_definition_of_done` | jsonb | `NULL` | DoD template (epics only). Child tasks inherit this as their checklist at insert time |
|
|
127
|
-
|
|
128
|
-
**Returns:**
|
|
129
|
-
- Full inserted work_item row as JSONB
|
|
130
|
-
- Includes auto-generated `id`, `created_at`, `updated_at`
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
### 3. update_work_item_status — Change status
|
|
135
|
-
|
|
136
|
-
Transition a work item's status. Auto-manages `completed_at`.
|
|
137
|
-
|
|
138
|
-
**Hard gate:** implementation agents do not set non-epic work directly to `done`.
|
|
139
|
-
They submit a report and move the item to `review`. A validator closes it as
|
|
140
|
-
`done` only after fresh verification.
|
|
141
|
-
|
|
142
|
-
**Supabase SQL:**
|
|
143
|
-
```sql
|
|
144
|
-
SELECT update_work_item_status(
|
|
145
|
-
'work-item-uuid'::uuid,
|
|
146
|
-
'in_progress'
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
SELECT update_work_item_status(
|
|
150
|
-
'work-item-uuid'::uuid,
|
|
151
|
-
'review',
|
|
152
|
-
'["Implementation complete; ready for validator"]'::jsonb,
|
|
153
|
-
'agent-session-id',
|
|
154
|
-
'agent'
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
SELECT update_work_item_status(
|
|
158
|
-
'work-item-uuid'::uuid,
|
|
159
|
-
'done',
|
|
160
|
-
'["Validator verified implementation report, CodeFlow post, and checklist evidence"]'::jsonb,
|
|
161
|
-
'validator-session-id',
|
|
162
|
-
'validator'
|
|
163
|
-
);
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
**Supabase JS Client:**
|
|
167
|
-
```ts
|
|
168
|
-
const { data } = await supabase.rpc('update_work_item_status', {
|
|
169
|
-
p_id: itemId,
|
|
170
|
-
p_status: 'in_progress'
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const { data } = await supabase.rpc('update_work_item_status', {
|
|
174
|
-
p_id: itemId,
|
|
175
|
-
p_status: 'review',
|
|
176
|
-
p_notes_append: ['Implementation complete; ready for validator'],
|
|
177
|
-
p_actor_session_id: agentSessionId,
|
|
178
|
-
p_actor_role: 'agent'
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
const { data } = await supabase.rpc('update_work_item_status', {
|
|
182
|
-
p_id: itemId,
|
|
183
|
-
p_status: 'done',
|
|
184
|
-
p_notes_append: ['Validator verified implementation report, CodeFlow post, and checklist evidence'],
|
|
185
|
-
p_actor_session_id: validatorSessionId,
|
|
186
|
-
p_actor_role: 'validator'
|
|
187
|
-
});
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
**Parameters:**
|
|
191
|
-
|
|
192
|
-
| Name | Type | Required | Notes |
|
|
193
|
-
|------|------|----------|-------|
|
|
194
|
-
| `p_id` | uuid | yes | work_item ID |
|
|
195
|
-
| `p_status` | text | yes | One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
|
|
196
|
-
| `p_notes_append` | jsonb | no | Array of strings appended to existing notes |
|
|
197
|
-
| `p_actor_session_id` | text | review/done | Current agent or validator session ID |
|
|
198
|
-
| `p_actor_role` | text | review/done | `agent` for `review`, `validator` for `done` |
|
|
199
|
-
|
|
200
|
-
**Behavior:**
|
|
201
|
-
- Setting `done` auto-sets `completed_at = now()`
|
|
202
|
-
- Setting non-epic work to `review` raises EXCEPTION unless `implementation_report.codeflow_post` exists and caller role is `agent`
|
|
203
|
-
- Setting non-epic work to `done` raises EXCEPTION unless current status is `review`, caller role is `validator`, `implementation_report.codeflow_post` exists, every required checklist item is checked, and required checklist evidence was ticked by the originating agent session
|
|
204
|
-
- Setting `todo`, `in_progress`, `blocked`, or `review` clears `completed_at`
|
|
205
|
-
- `updated_at` always refreshed to current timestamp
|
|
206
|
-
- Raises exception if ID not found
|
|
207
|
-
|
|
208
|
-
**Returns:**
|
|
209
|
-
- Full updated work_item row as JSONB
|
|
210
|
-
|
|
211
|
-
---
|
|
212
|
-
|
|
213
|
-
### 4. update_checklist_item — Tick off a checklist item
|
|
214
|
-
|
|
215
|
-
**Supabase SQL:**
|
|
216
|
-
```sql
|
|
217
|
-
SELECT update_checklist_item(
|
|
218
|
-
'work-item-uuid'::uuid,
|
|
219
|
-
'tsc-clean', -- string id of the checklist item
|
|
220
|
-
true, -- checked state
|
|
221
|
-
'agent-session-id',
|
|
222
|
-
'agent',
|
|
223
|
-
'rpc'
|
|
224
|
-
);
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
**Parameters:**
|
|
228
|
-
|
|
229
|
-
| Name | Type | Required | Notes |
|
|
230
|
-
|------|------|----------|-------|
|
|
231
|
-
| `p_work_item_id` | uuid | yes | the work item ID |
|
|
232
|
-
| `p_item_id` | text | yes | the `id` field of the checklist item |
|
|
233
|
-
| `p_checked` | boolean | yes | `true` = checked, `false` = unchecked |
|
|
234
|
-
| `p_actor_session_id` | text | yes for checked=true | originating implementation agent session ID |
|
|
235
|
-
| `p_actor_role` | text | yes for checked=true | must be `agent` for completion evidence ticks |
|
|
236
|
-
| `p_event_source` | text | no | source label, default `rpc` |
|
|
237
|
-
|
|
238
|
-
Call this as each checklist item is completed — not all at once at the end.
|
|
239
|
-
The tick is written to `work_item_checklist_events`; supervisor or validator
|
|
240
|
-
re-ticks are rejected by the exit gate.
|
|
241
|
-
|
|
242
|
-
**Returns:** updated checklist JSONB array.
|
|
243
|
-
|
|
244
|
-
---
|
|
245
|
-
|
|
246
|
-
### 5. submit_implementation_report — File agent completion narrative
|
|
247
|
-
|
|
248
|
-
MUST be called BEFORE `update_work_item_status(..., 'review', ...)`.
|
|
249
|
-
|
|
250
|
-
**Supabase SQL:**
|
|
251
|
-
```sql
|
|
252
|
-
SELECT submit_implementation_report(
|
|
253
|
-
'work-item-uuid'::uuid,
|
|
254
|
-
'{
|
|
255
|
-
"tldr": "One-sentence summary",
|
|
256
|
-
"assumptions": [],
|
|
257
|
-
"deviations": [],
|
|
258
|
-
"uncertainty": [],
|
|
259
|
-
"detail": "Full narrative",
|
|
260
|
-
"flags": [],
|
|
261
|
-
"codeflow_post": {
|
|
262
|
-
"agent_session_id": "agent-session-id",
|
|
263
|
-
"summary": "What changed and why",
|
|
264
|
-
"files_changed": ["path/to/file"],
|
|
265
|
-
"verification": ["command or evidence"],
|
|
266
|
-
"commit": "optional commit hash"
|
|
267
|
-
}
|
|
268
|
-
}'::jsonb
|
|
269
|
-
);
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
**Parameters:**
|
|
273
|
-
|
|
274
|
-
| Name | Type | Required | Notes |
|
|
275
|
-
|------|------|----------|-------|
|
|
276
|
-
| `p_work_item_id` | uuid | yes | the work item ID |
|
|
277
|
-
| `p_report` | jsonb | yes | implementation report (shape below) |
|
|
278
|
-
|
|
279
|
-
**Returns:** `{ "flags_count": N, "deviations_count": N, "has_deviations": bool }` — signal only.
|
|
280
|
-
|
|
281
|
-
**`implementation_report` shape:**
|
|
282
|
-
```json
|
|
283
|
-
{
|
|
284
|
-
"tldr": "string",
|
|
285
|
-
"assumptions": ["string", "..."],
|
|
286
|
-
"deviations": ["string — deviation from plan", "..."],
|
|
287
|
-
"uncertainty": ["string — anything unclear", "..."],
|
|
288
|
-
"detail": "string — full narrative",
|
|
289
|
-
"flags": ["string — supervisor attention needed", "..."],
|
|
290
|
-
"codeflow_post": {
|
|
291
|
-
"agent_session_id": "string — originating implementation session",
|
|
292
|
-
"summary": "string — agent-authored CodeFlow post",
|
|
293
|
-
"files_changed": ["string", "..."],
|
|
294
|
-
"verification": ["string", "..."],
|
|
295
|
-
"commit": "string — optional"
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
If `has_deviations` is true or `flags_count > 0`, supervisor pulls full report from DB.
|
|
301
|
-
|
|
302
|
-
---
|
|
303
|
-
|
|
304
|
-
### 6. get_work_items_by_epic — Fetch epic + children
|
|
305
|
-
|
|
306
|
-
Get an epic and all its child tasks/subtasks, sorted by priority.
|
|
307
|
-
|
|
308
|
-
**Supabase SQL:**
|
|
309
|
-
```sql
|
|
310
|
-
SELECT get_work_items_by_epic('epic-uuid'::uuid);
|
|
311
|
-
SELECT get_work_items_by_epic('epic-uuid'::uuid, 'todo');
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
**Supabase JS Client:**
|
|
315
|
-
```ts
|
|
316
|
-
const { data } = await supabase.rpc('get_work_items_by_epic', {
|
|
317
|
-
p_epic_id: epicId
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
const { data } = await supabase.rpc('get_work_items_by_epic', {
|
|
321
|
-
p_epic_id: epicId,
|
|
322
|
-
p_status_filter: 'todo'
|
|
323
|
-
});
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
**Parameters:**
|
|
327
|
-
|
|
328
|
-
| Name | Type | Required | Notes |
|
|
329
|
-
|------|------|----------|-------|
|
|
330
|
-
| `p_epic_id` | uuid | yes | The epic's work_item ID |
|
|
331
|
-
| `p_status_filter` | text | no | NULL = all statuses. One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
|
|
332
|
-
|
|
333
|
-
**Returns:**
|
|
334
|
-
- JSONB array with parent epic first, then children
|
|
335
|
-
- Sorted by: priority (urgent > high > normal > low), then created_at
|
|
336
|
-
- Each item has same structure as returned from insert_work_item
|
|
337
|
-
|
|
338
|
-
---
|
|
339
|
-
|
|
340
|
-
### 7. bump_epic_version — Version with history
|
|
341
|
-
|
|
342
|
-
Snapshot an epic's current state and assign a version number.
|
|
343
|
-
|
|
344
|
-
**Supabase SQL:**
|
|
345
|
-
```sql
|
|
346
|
-
SELECT bump_epic_version(
|
|
347
|
-
'epic-uuid'::uuid,
|
|
348
|
-
'0.2.0',
|
|
349
|
-
'Added async task execution',
|
|
350
|
-
'agent'
|
|
351
|
-
);
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
**Supabase JS Client:**
|
|
355
|
-
```ts
|
|
356
|
-
const { data } = await supabase.rpc('bump_epic_version', {
|
|
357
|
-
p_epic_id: epicId,
|
|
358
|
-
p_version: '0.2.0',
|
|
359
|
-
p_change_summary: 'Added async task execution',
|
|
360
|
-
p_changed_by: 'agent'
|
|
361
|
-
});
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
**Parameters:**
|
|
365
|
-
|
|
366
|
-
| Name | Type | Required | Notes |
|
|
367
|
-
|------|------|----------|-------|
|
|
368
|
-
| `p_epic_id` | uuid | yes | Must be item_type = `'epic'` |
|
|
369
|
-
| `p_version` | text | yes | Semantic version string (e.g., `'0.1.0'`, `'1.0.0'`) |
|
|
370
|
-
| `p_change_summary` | text | no | What changed in this version |
|
|
371
|
-
| `p_changed_by` | text | no | Who bumped the version |
|
|
372
|
-
|
|
373
|
-
**Behavior:**
|
|
374
|
-
- Snapshots the epic's current state into work_item_versions table
|
|
375
|
-
- Updates the epic's `version` column
|
|
376
|
-
- Raises exception if item is not an epic (item_type != 'epic')
|
|
377
|
-
|
|
378
|
-
**Returns:**
|
|
379
|
-
- JSONB object: `{ epic_id, version, version_record_id, change_summary, changed_by, bumped_at }`
|
|
380
|
-
|
|
381
|
-
---
|
|
382
|
-
|
|
383
|
-
## Common Patterns
|
|
384
|
-
|
|
385
|
-
### Create an Epic + Child Tasks
|
|
386
|
-
|
|
387
|
-
```ts
|
|
388
|
-
// 1. Create epic
|
|
389
|
-
const { data: epic } = await supabase.rpc('insert_work_item', {
|
|
390
|
-
p_title: 'Implement feature X',
|
|
391
|
-
p_item_type: 'epic',
|
|
392
|
-
p_status: 'todo',
|
|
393
|
-
p_priority: 'high',
|
|
394
|
-
p_source: 'agent'
|
|
395
|
-
});
|
|
396
|
-
const epicId = epic[0].id;
|
|
397
|
-
|
|
398
|
-
// 2. Create child tasks
|
|
399
|
-
for (const task of tasks) {
|
|
400
|
-
await supabase.rpc('insert_work_item', {
|
|
401
|
-
p_title: task.title,
|
|
402
|
-
p_item_type: 'task',
|
|
403
|
-
p_priority: task.priority,
|
|
404
|
-
p_parent_id: epicId,
|
|
405
|
-
p_source: 'agent'
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
### Fetch Epic Tree, Filter by Status, Update Each
|
|
411
|
-
|
|
412
|
-
```ts
|
|
413
|
-
const { data: tree } = await supabase.rpc('get_work_items_by_epic', {
|
|
414
|
-
p_epic_id: epicId,
|
|
415
|
-
p_status_filter: 'todo'
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
for (const item of tree) {
|
|
419
|
-
if (item.item_type === 'epic') continue; // skip parent
|
|
420
|
-
|
|
421
|
-
await supabase.rpc('update_work_item_status', {
|
|
422
|
-
p_id: item.id,
|
|
423
|
-
p_status: 'in_progress'
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
### Mark Epic Done with Notes
|
|
429
|
-
|
|
430
|
-
```ts
|
|
431
|
-
const { data } = await supabase.rpc('update_work_item_status', {
|
|
432
|
-
p_id: epicId,
|
|
433
|
-
p_status: 'done',
|
|
434
|
-
p_notes_append: [
|
|
435
|
-
'All child tasks completed',
|
|
436
|
-
'Code reviewed and merged to main',
|
|
437
|
-
'Deployed to production'
|
|
438
|
-
]
|
|
439
|
-
});
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
### List All Open Work, Filter by Priority
|
|
443
|
-
|
|
444
|
-
```ts
|
|
445
|
-
const { data: epics } = await supabase.rpc('get_open_epics', {
|
|
446
|
-
p_priority_filter: 'urgent'
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
for (const epic of epics) {
|
|
450
|
-
const { data: items } = await supabase.rpc('get_work_items_by_epic', {
|
|
451
|
-
p_epic_id: epic.id
|
|
452
|
-
});
|
|
453
|
-
// process items...
|
|
454
|
-
}
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
---
|
|
458
|
-
|
|
459
|
-
## Supabase Project Reference
|
|
460
|
-
|
|
461
|
-
In production, you'll need:
|
|
462
|
-
|
|
463
|
-
**Environment variables (in .env.local):**
|
|
464
|
-
```bash
|
|
465
|
-
NEXT_PUBLIC_SUPABASE_URL=https://<project-ref>.supabase.co
|
|
466
|
-
NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon-key>
|
|
467
|
-
SUPABASE_SERVICE_ROLE_KEY=<service-role-key> # Server-side only
|
|
468
|
-
```
|
|
469
|
-
|
|
470
|
-
Replace `<project-ref>` with your actual Supabase project reference (e.g., `uvojezuorjgqzmhhgluu`).
|
|
471
|
-
|
|
472
|
-
**Project-specific data (from docs/guides/agent-bootstrap.md):**
|
|
473
|
-
- SUPABASE_PROJECT_ID (if required by your project)
|
|
474
|
-
- Any custom schema names (if work_items lives in non-public schema)
|
|
475
|
-
- Related table names (companies, customers, contacts, campaigns, etc.)
|
|
476
|
-
|
|
477
|
-
---
|
|
478
|
-
|
|
479
|
-
## Error Handling
|
|
480
|
-
|
|
481
|
-
### RPC Not Found
|
|
482
|
-
If `get_open_epics` returns a 404, the function doesn't exist on your Supabase instance.
|
|
483
|
-
Run migration to add the function, or contact your DBA.
|
|
484
|
-
|
|
485
|
-
### Invalid UUID
|
|
486
|
-
```ts
|
|
487
|
-
// Wrong — string passed directly
|
|
488
|
-
p_id: "item-id"
|
|
489
|
-
|
|
490
|
-
// Correct — cast to uuid
|
|
491
|
-
p_id: itemId
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
### Status Not in Enum
|
|
495
|
-
Check `p_status` against allowed values. Will raise a constraint error if invalid.
|
|
496
|
-
|
|
497
|
-
### Item Not Found
|
|
498
|
-
`update_work_item_status` and `bump_epic_version` will raise an exception if ID doesn't exist.
|
|
499
|
-
Always catch or check first:
|
|
500
|
-
```ts
|
|
501
|
-
const { data: items } = await supabase.rpc('get_work_items_by_epic', { p_epic_id: id });
|
|
502
|
-
if (!items || items.length === 0) {
|
|
503
|
-
// Epic not found
|
|
504
|
-
}
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
---
|
|
508
|
-
|
|
509
|
-
## Analytics (Raw SQL)
|
|
510
|
-
|
|
511
|
-
Direct SELECT is acceptable for read-only analytics:
|
|
512
|
-
|
|
513
|
-
```sql
|
|
514
|
-
SELECT status, count(*) as cnt FROM work_items GROUP BY status;
|
|
515
|
-
SELECT priority, count(*) FROM work_items WHERE labels @> ARRAY['urgent'] GROUP BY priority;
|
|
516
|
-
SELECT avg(EXTRACT(EPOCH FROM (completed_at - created_at))/3600)::numeric(10,2) as avg_hours
|
|
517
|
-
FROM work_items WHERE status = 'done' AND item_type = 'task';
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
For INSERT/UPDATE/DELETE: always use the RPC functions above.
|
|
1
|
+
# Work Items RPC Reference
|
|
2
|
+
|
|
3
|
+
> Complete reference for work_items table operations via Supabase RPC functions.
|
|
4
|
+
> Use these functions for ALL CRUD operations. Never write raw INSERT/UPDATE/SELECT against work_items.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Core Rule
|
|
9
|
+
|
|
10
|
+
**Always use RPC functions.** They handle defaults, check constraints, timestamps, sorting, and return structured JSONB.
|
|
11
|
+
|
|
12
|
+
Exception: Ad-hoc analytics queries (e.g., `SELECT count(*)`) are acceptable as raw SQL.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Valid Enum Values
|
|
17
|
+
|
|
18
|
+
| Column | Allowed Values |
|
|
19
|
+
|--------|---|
|
|
20
|
+
| `status` | `todo` · `in_progress` · `blocked` · `review` · `done` · `archived` |
|
|
21
|
+
| `priority` | `urgent` · `high` · `normal` · `low` |
|
|
22
|
+
| `item_type` | `epic` · `task` · `subtask` · `bug` · `spike` |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## RPC Functions
|
|
27
|
+
|
|
28
|
+
### 1. get_open_epics — List open epics
|
|
29
|
+
|
|
30
|
+
Returns all non-done/archived epics sorted by priority, then created_at.
|
|
31
|
+
|
|
32
|
+
**Supabase SQL:**
|
|
33
|
+
```sql
|
|
34
|
+
SELECT get_open_epics();
|
|
35
|
+
SELECT get_open_epics('urgent');
|
|
36
|
+
SELECT get_open_epics(p_label_filter := 'feature-x');
|
|
37
|
+
SELECT get_open_epics('high', 'backend');
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Supabase JS Client:**
|
|
41
|
+
```ts
|
|
42
|
+
const { data } = await supabase.rpc('get_open_epics');
|
|
43
|
+
const { data } = await supabase.rpc('get_open_epics', {
|
|
44
|
+
p_priority_filter: 'urgent'
|
|
45
|
+
});
|
|
46
|
+
const { data } = await supabase.rpc('get_open_epics', {
|
|
47
|
+
p_label_filter: 'cs2'
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Parameters:**
|
|
52
|
+
|
|
53
|
+
| Name | Type | Required | Notes |
|
|
54
|
+
|------|------|----------|-------|
|
|
55
|
+
| `p_priority_filter` | text | no | NULL = all priorities. One of: `urgent`, `high`, `normal`, `low` |
|
|
56
|
+
| `p_label_filter` | text | no | NULL = all labels. Uses array containment (`@>`) for matching |
|
|
57
|
+
|
|
58
|
+
**Returns:**
|
|
59
|
+
- JSONB array of epic objects (sorted by priority then created_at)
|
|
60
|
+
- Empty `[]` if none found
|
|
61
|
+
- Each epic has: `id`, `title`, `status`, `priority`, `item_type`, `labels`, `created_at`, `updated_at`
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### 2. insert_work_item — Create a work item
|
|
66
|
+
|
|
67
|
+
Create a new task, epic, subtask, bug, or spike.
|
|
68
|
+
|
|
69
|
+
**Supabase SQL:**
|
|
70
|
+
```sql
|
|
71
|
+
SELECT insert_work_item(
|
|
72
|
+
p_title := 'Build user authentication',
|
|
73
|
+
p_description := 'Implement OAuth2 flow...',
|
|
74
|
+
p_status := 'todo',
|
|
75
|
+
p_priority := 'high',
|
|
76
|
+
p_item_type := 'task',
|
|
77
|
+
p_parent_id := 'epic-uuid'::uuid,
|
|
78
|
+
p_labels := ARRAY['backend', 'auth'],
|
|
79
|
+
p_source := 'agent'
|
|
80
|
+
);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Supabase JS Client:**
|
|
84
|
+
```ts
|
|
85
|
+
const { data } = await supabase.rpc('insert_work_item', {
|
|
86
|
+
p_title: 'Build user authentication',
|
|
87
|
+
p_description: 'Implement OAuth2 flow...',
|
|
88
|
+
p_status: 'todo',
|
|
89
|
+
p_priority: 'high',
|
|
90
|
+
p_item_type: 'task',
|
|
91
|
+
p_parent_id: epicId,
|
|
92
|
+
p_labels: ['backend', 'auth'],
|
|
93
|
+
p_source: 'agent'
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**All Parameters:**
|
|
98
|
+
|
|
99
|
+
| Name | Type | Default | Notes |
|
|
100
|
+
|------|------|---------|-------|
|
|
101
|
+
| `p_title` | text | *required* | Work item name (max 255 chars) |
|
|
102
|
+
| `p_description` | text | NULL | Long-form description |
|
|
103
|
+
| `p_status` | text | `'todo'` | One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
|
|
104
|
+
| `p_priority` | text | `'normal'` | One of: `urgent`, `high`, `normal`, `low` |
|
|
105
|
+
| `p_item_type` | text | `'task'` | One of: `epic`, `task`, `subtask`, `bug`, `spike` |
|
|
106
|
+
| `p_parent_id` | uuid | NULL | Parent epic UUID for hierarchy (for subtasks) |
|
|
107
|
+
| `p_company_id` | uuid | NULL | Foreign key to companies table |
|
|
108
|
+
| `p_customer_id` | uuid | NULL | Foreign key to customers table |
|
|
109
|
+
| `p_campaign_id` | uuid | NULL | Foreign key to campaigns table |
|
|
110
|
+
| `p_contact_id` | uuid | NULL | Foreign key to contacts table |
|
|
111
|
+
| `p_project_id` | uuid | NULL | Project identifier (project-specific) |
|
|
112
|
+
| `p_assignee` | text | NULL | Assigned person name or email |
|
|
113
|
+
| `p_assigned_to` | text | NULL | Same as assignee (alternate field) |
|
|
114
|
+
| `p_due_date` | date | NULL | Due date for the task |
|
|
115
|
+
| `p_tags` | text[] | `'{}'` | Array of tags |
|
|
116
|
+
| `p_labels` | text[] | `'{}'` | Array of labels (used for filtering) |
|
|
117
|
+
| `p_linked_table` | text | NULL | Name of external table to link (if any) |
|
|
118
|
+
| `p_linked_id` | uuid | NULL | ID in linked_table |
|
|
119
|
+
| `p_created_by` | text | NULL | Who created this item |
|
|
120
|
+
| `p_estimated_hours` | numeric | NULL | Time estimate in hours |
|
|
121
|
+
| `p_notes` | jsonb | `'[]'` | Array of note objects `[{ text, author, timestamp }]` |
|
|
122
|
+
| `p_session_id` | text | NULL | Session UUID (for audit trail) |
|
|
123
|
+
| `p_package` | text | NULL | Package/module name (e.g., '@regen/ui') |
|
|
124
|
+
| `p_source` | text | `'manual'` | How was this created: `manual`, `agent`, `api`, `import` |
|
|
125
|
+
| `p_checklist` | jsonb | `NULL` | Checklist items. If NULL and parent has `definition_of_done`, auto-inherited with all `checked: false` |
|
|
126
|
+
| `p_definition_of_done` | jsonb | `NULL` | DoD template (epics only). Child tasks inherit this as their checklist at insert time |
|
|
127
|
+
|
|
128
|
+
**Returns:**
|
|
129
|
+
- Full inserted work_item row as JSONB
|
|
130
|
+
- Includes auto-generated `id`, `created_at`, `updated_at`
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
### 3. update_work_item_status — Change status
|
|
135
|
+
|
|
136
|
+
Transition a work item's status. Auto-manages `completed_at`.
|
|
137
|
+
|
|
138
|
+
**Hard gate:** implementation agents do not set non-epic work directly to `done`.
|
|
139
|
+
They submit a report and move the item to `review`. A validator closes it as
|
|
140
|
+
`done` only after fresh verification.
|
|
141
|
+
|
|
142
|
+
**Supabase SQL:**
|
|
143
|
+
```sql
|
|
144
|
+
SELECT update_work_item_status(
|
|
145
|
+
'work-item-uuid'::uuid,
|
|
146
|
+
'in_progress'
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
SELECT update_work_item_status(
|
|
150
|
+
'work-item-uuid'::uuid,
|
|
151
|
+
'review',
|
|
152
|
+
'["Implementation complete; ready for validator"]'::jsonb,
|
|
153
|
+
'agent-session-id',
|
|
154
|
+
'agent'
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
SELECT update_work_item_status(
|
|
158
|
+
'work-item-uuid'::uuid,
|
|
159
|
+
'done',
|
|
160
|
+
'["Validator verified implementation report, CodeFlow post, and checklist evidence"]'::jsonb,
|
|
161
|
+
'validator-session-id',
|
|
162
|
+
'validator'
|
|
163
|
+
);
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Supabase JS Client:**
|
|
167
|
+
```ts
|
|
168
|
+
const { data } = await supabase.rpc('update_work_item_status', {
|
|
169
|
+
p_id: itemId,
|
|
170
|
+
p_status: 'in_progress'
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const { data } = await supabase.rpc('update_work_item_status', {
|
|
174
|
+
p_id: itemId,
|
|
175
|
+
p_status: 'review',
|
|
176
|
+
p_notes_append: ['Implementation complete; ready for validator'],
|
|
177
|
+
p_actor_session_id: agentSessionId,
|
|
178
|
+
p_actor_role: 'agent'
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const { data } = await supabase.rpc('update_work_item_status', {
|
|
182
|
+
p_id: itemId,
|
|
183
|
+
p_status: 'done',
|
|
184
|
+
p_notes_append: ['Validator verified implementation report, CodeFlow post, and checklist evidence'],
|
|
185
|
+
p_actor_session_id: validatorSessionId,
|
|
186
|
+
p_actor_role: 'validator'
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Parameters:**
|
|
191
|
+
|
|
192
|
+
| Name | Type | Required | Notes |
|
|
193
|
+
|------|------|----------|-------|
|
|
194
|
+
| `p_id` | uuid | yes | work_item ID |
|
|
195
|
+
| `p_status` | text | yes | One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
|
|
196
|
+
| `p_notes_append` | jsonb | no | Array of strings appended to existing notes |
|
|
197
|
+
| `p_actor_session_id` | text | review/done | Current agent or validator session ID |
|
|
198
|
+
| `p_actor_role` | text | review/done | `agent` for `review`, `validator` for `done` |
|
|
199
|
+
|
|
200
|
+
**Behavior:**
|
|
201
|
+
- Setting `done` auto-sets `completed_at = now()`
|
|
202
|
+
- Setting non-epic work to `review` raises EXCEPTION unless `implementation_report.codeflow_post` exists and caller role is `agent`
|
|
203
|
+
- Setting non-epic work to `done` raises EXCEPTION unless current status is `review`, caller role is `validator`, `implementation_report.codeflow_post` exists, every required checklist item is checked, and required checklist evidence was ticked by the originating agent session
|
|
204
|
+
- Setting `todo`, `in_progress`, `blocked`, or `review` clears `completed_at`
|
|
205
|
+
- `updated_at` always refreshed to current timestamp
|
|
206
|
+
- Raises exception if ID not found
|
|
207
|
+
|
|
208
|
+
**Returns:**
|
|
209
|
+
- Full updated work_item row as JSONB
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
### 4. update_checklist_item — Tick off a checklist item
|
|
214
|
+
|
|
215
|
+
**Supabase SQL:**
|
|
216
|
+
```sql
|
|
217
|
+
SELECT update_checklist_item(
|
|
218
|
+
'work-item-uuid'::uuid,
|
|
219
|
+
'tsc-clean', -- string id of the checklist item
|
|
220
|
+
true, -- checked state
|
|
221
|
+
'agent-session-id',
|
|
222
|
+
'agent',
|
|
223
|
+
'rpc'
|
|
224
|
+
);
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Parameters:**
|
|
228
|
+
|
|
229
|
+
| Name | Type | Required | Notes |
|
|
230
|
+
|------|------|----------|-------|
|
|
231
|
+
| `p_work_item_id` | uuid | yes | the work item ID |
|
|
232
|
+
| `p_item_id` | text | yes | the `id` field of the checklist item |
|
|
233
|
+
| `p_checked` | boolean | yes | `true` = checked, `false` = unchecked |
|
|
234
|
+
| `p_actor_session_id` | text | yes for checked=true | originating implementation agent session ID |
|
|
235
|
+
| `p_actor_role` | text | yes for checked=true | must be `agent` for completion evidence ticks |
|
|
236
|
+
| `p_event_source` | text | no | source label, default `rpc` |
|
|
237
|
+
|
|
238
|
+
Call this as each checklist item is completed — not all at once at the end.
|
|
239
|
+
The tick is written to `work_item_checklist_events`; supervisor or validator
|
|
240
|
+
re-ticks are rejected by the exit gate.
|
|
241
|
+
|
|
242
|
+
**Returns:** updated checklist JSONB array.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
### 5. submit_implementation_report — File agent completion narrative
|
|
247
|
+
|
|
248
|
+
MUST be called BEFORE `update_work_item_status(..., 'review', ...)`.
|
|
249
|
+
|
|
250
|
+
**Supabase SQL:**
|
|
251
|
+
```sql
|
|
252
|
+
SELECT submit_implementation_report(
|
|
253
|
+
'work-item-uuid'::uuid,
|
|
254
|
+
'{
|
|
255
|
+
"tldr": "One-sentence summary",
|
|
256
|
+
"assumptions": [],
|
|
257
|
+
"deviations": [],
|
|
258
|
+
"uncertainty": [],
|
|
259
|
+
"detail": "Full narrative",
|
|
260
|
+
"flags": [],
|
|
261
|
+
"codeflow_post": {
|
|
262
|
+
"agent_session_id": "agent-session-id",
|
|
263
|
+
"summary": "What changed and why",
|
|
264
|
+
"files_changed": ["path/to/file"],
|
|
265
|
+
"verification": ["command or evidence"],
|
|
266
|
+
"commit": "optional commit hash"
|
|
267
|
+
}
|
|
268
|
+
}'::jsonb
|
|
269
|
+
);
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Parameters:**
|
|
273
|
+
|
|
274
|
+
| Name | Type | Required | Notes |
|
|
275
|
+
|------|------|----------|-------|
|
|
276
|
+
| `p_work_item_id` | uuid | yes | the work item ID |
|
|
277
|
+
| `p_report` | jsonb | yes | implementation report (shape below) |
|
|
278
|
+
|
|
279
|
+
**Returns:** `{ "flags_count": N, "deviations_count": N, "has_deviations": bool }` — signal only.
|
|
280
|
+
|
|
281
|
+
**`implementation_report` shape:**
|
|
282
|
+
```json
|
|
283
|
+
{
|
|
284
|
+
"tldr": "string",
|
|
285
|
+
"assumptions": ["string", "..."],
|
|
286
|
+
"deviations": ["string — deviation from plan", "..."],
|
|
287
|
+
"uncertainty": ["string — anything unclear", "..."],
|
|
288
|
+
"detail": "string — full narrative",
|
|
289
|
+
"flags": ["string — supervisor attention needed", "..."],
|
|
290
|
+
"codeflow_post": {
|
|
291
|
+
"agent_session_id": "string — originating implementation session",
|
|
292
|
+
"summary": "string — agent-authored CodeFlow post",
|
|
293
|
+
"files_changed": ["string", "..."],
|
|
294
|
+
"verification": ["string", "..."],
|
|
295
|
+
"commit": "string — optional"
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
If `has_deviations` is true or `flags_count > 0`, supervisor pulls full report from DB.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
### 6. get_work_items_by_epic — Fetch epic + children
|
|
305
|
+
|
|
306
|
+
Get an epic and all its child tasks/subtasks, sorted by priority.
|
|
307
|
+
|
|
308
|
+
**Supabase SQL:**
|
|
309
|
+
```sql
|
|
310
|
+
SELECT get_work_items_by_epic('epic-uuid'::uuid);
|
|
311
|
+
SELECT get_work_items_by_epic('epic-uuid'::uuid, 'todo');
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Supabase JS Client:**
|
|
315
|
+
```ts
|
|
316
|
+
const { data } = await supabase.rpc('get_work_items_by_epic', {
|
|
317
|
+
p_epic_id: epicId
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
const { data } = await supabase.rpc('get_work_items_by_epic', {
|
|
321
|
+
p_epic_id: epicId,
|
|
322
|
+
p_status_filter: 'todo'
|
|
323
|
+
});
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Parameters:**
|
|
327
|
+
|
|
328
|
+
| Name | Type | Required | Notes |
|
|
329
|
+
|------|------|----------|-------|
|
|
330
|
+
| `p_epic_id` | uuid | yes | The epic's work_item ID |
|
|
331
|
+
| `p_status_filter` | text | no | NULL = all statuses. One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
|
|
332
|
+
|
|
333
|
+
**Returns:**
|
|
334
|
+
- JSONB array with parent epic first, then children
|
|
335
|
+
- Sorted by: priority (urgent > high > normal > low), then created_at
|
|
336
|
+
- Each item has same structure as returned from insert_work_item
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
### 7. bump_epic_version — Version with history
|
|
341
|
+
|
|
342
|
+
Snapshot an epic's current state and assign a version number.
|
|
343
|
+
|
|
344
|
+
**Supabase SQL:**
|
|
345
|
+
```sql
|
|
346
|
+
SELECT bump_epic_version(
|
|
347
|
+
'epic-uuid'::uuid,
|
|
348
|
+
'0.2.0',
|
|
349
|
+
'Added async task execution',
|
|
350
|
+
'agent'
|
|
351
|
+
);
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**Supabase JS Client:**
|
|
355
|
+
```ts
|
|
356
|
+
const { data } = await supabase.rpc('bump_epic_version', {
|
|
357
|
+
p_epic_id: epicId,
|
|
358
|
+
p_version: '0.2.0',
|
|
359
|
+
p_change_summary: 'Added async task execution',
|
|
360
|
+
p_changed_by: 'agent'
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Parameters:**
|
|
365
|
+
|
|
366
|
+
| Name | Type | Required | Notes |
|
|
367
|
+
|------|------|----------|-------|
|
|
368
|
+
| `p_epic_id` | uuid | yes | Must be item_type = `'epic'` |
|
|
369
|
+
| `p_version` | text | yes | Semantic version string (e.g., `'0.1.0'`, `'1.0.0'`) |
|
|
370
|
+
| `p_change_summary` | text | no | What changed in this version |
|
|
371
|
+
| `p_changed_by` | text | no | Who bumped the version |
|
|
372
|
+
|
|
373
|
+
**Behavior:**
|
|
374
|
+
- Snapshots the epic's current state into work_item_versions table
|
|
375
|
+
- Updates the epic's `version` column
|
|
376
|
+
- Raises exception if item is not an epic (item_type != 'epic')
|
|
377
|
+
|
|
378
|
+
**Returns:**
|
|
379
|
+
- JSONB object: `{ epic_id, version, version_record_id, change_summary, changed_by, bumped_at }`
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## Common Patterns
|
|
384
|
+
|
|
385
|
+
### Create an Epic + Child Tasks
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
// 1. Create epic
|
|
389
|
+
const { data: epic } = await supabase.rpc('insert_work_item', {
|
|
390
|
+
p_title: 'Implement feature X',
|
|
391
|
+
p_item_type: 'epic',
|
|
392
|
+
p_status: 'todo',
|
|
393
|
+
p_priority: 'high',
|
|
394
|
+
p_source: 'agent'
|
|
395
|
+
});
|
|
396
|
+
const epicId = epic[0].id;
|
|
397
|
+
|
|
398
|
+
// 2. Create child tasks
|
|
399
|
+
for (const task of tasks) {
|
|
400
|
+
await supabase.rpc('insert_work_item', {
|
|
401
|
+
p_title: task.title,
|
|
402
|
+
p_item_type: 'task',
|
|
403
|
+
p_priority: task.priority,
|
|
404
|
+
p_parent_id: epicId,
|
|
405
|
+
p_source: 'agent'
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Fetch Epic Tree, Filter by Status, Update Each
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
const { data: tree } = await supabase.rpc('get_work_items_by_epic', {
|
|
414
|
+
p_epic_id: epicId,
|
|
415
|
+
p_status_filter: 'todo'
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
for (const item of tree) {
|
|
419
|
+
if (item.item_type === 'epic') continue; // skip parent
|
|
420
|
+
|
|
421
|
+
await supabase.rpc('update_work_item_status', {
|
|
422
|
+
p_id: item.id,
|
|
423
|
+
p_status: 'in_progress'
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### Mark Epic Done with Notes
|
|
429
|
+
|
|
430
|
+
```ts
|
|
431
|
+
const { data } = await supabase.rpc('update_work_item_status', {
|
|
432
|
+
p_id: epicId,
|
|
433
|
+
p_status: 'done',
|
|
434
|
+
p_notes_append: [
|
|
435
|
+
'All child tasks completed',
|
|
436
|
+
'Code reviewed and merged to main',
|
|
437
|
+
'Deployed to production'
|
|
438
|
+
]
|
|
439
|
+
});
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### List All Open Work, Filter by Priority
|
|
443
|
+
|
|
444
|
+
```ts
|
|
445
|
+
const { data: epics } = await supabase.rpc('get_open_epics', {
|
|
446
|
+
p_priority_filter: 'urgent'
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
for (const epic of epics) {
|
|
450
|
+
const { data: items } = await supabase.rpc('get_work_items_by_epic', {
|
|
451
|
+
p_epic_id: epic.id
|
|
452
|
+
});
|
|
453
|
+
// process items...
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
## Supabase Project Reference
|
|
460
|
+
|
|
461
|
+
In production, you'll need:
|
|
462
|
+
|
|
463
|
+
**Environment variables (in .env.local):**
|
|
464
|
+
```bash
|
|
465
|
+
NEXT_PUBLIC_SUPABASE_URL=https://<project-ref>.supabase.co
|
|
466
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon-key>
|
|
467
|
+
SUPABASE_SERVICE_ROLE_KEY=<service-role-key> # Server-side only
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Replace `<project-ref>` with your actual Supabase project reference (e.g., `uvojezuorjgqzmhhgluu`).
|
|
471
|
+
|
|
472
|
+
**Project-specific data (from docs/guides/agent-bootstrap.md):**
|
|
473
|
+
- SUPABASE_PROJECT_ID (if required by your project)
|
|
474
|
+
- Any custom schema names (if work_items lives in non-public schema)
|
|
475
|
+
- Related table names (companies, customers, contacts, campaigns, etc.)
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Error Handling
|
|
480
|
+
|
|
481
|
+
### RPC Not Found
|
|
482
|
+
If `get_open_epics` returns a 404, the function doesn't exist on your Supabase instance.
|
|
483
|
+
Run migration to add the function, or contact your DBA.
|
|
484
|
+
|
|
485
|
+
### Invalid UUID
|
|
486
|
+
```ts
|
|
487
|
+
// Wrong — string passed directly
|
|
488
|
+
p_id: "item-id"
|
|
489
|
+
|
|
490
|
+
// Correct — cast to uuid
|
|
491
|
+
p_id: itemId
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Status Not in Enum
|
|
495
|
+
Check `p_status` against allowed values. Will raise a constraint error if invalid.
|
|
496
|
+
|
|
497
|
+
### Item Not Found
|
|
498
|
+
`update_work_item_status` and `bump_epic_version` will raise an exception if ID doesn't exist.
|
|
499
|
+
Always catch or check first:
|
|
500
|
+
```ts
|
|
501
|
+
const { data: items } = await supabase.rpc('get_work_items_by_epic', { p_epic_id: id });
|
|
502
|
+
if (!items || items.length === 0) {
|
|
503
|
+
// Epic not found
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## Analytics (Raw SQL)
|
|
510
|
+
|
|
511
|
+
Direct SELECT is acceptable for read-only analytics:
|
|
512
|
+
|
|
513
|
+
```sql
|
|
514
|
+
SELECT status, count(*) as cnt FROM work_items GROUP BY status;
|
|
515
|
+
SELECT priority, count(*) FROM work_items WHERE labels @> ARRAY['urgent'] GROUP BY priority;
|
|
516
|
+
SELECT avg(EXTRACT(EPOCH FROM (completed_at - created_at))/3600)::numeric(10,2) as avg_hours
|
|
517
|
+
FROM work_items WHERE status = 'done' AND item_type = 'task';
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
For INSERT/UPDATE/DELETE: always use the RPC functions above.
|