taskchef 5.3.0 → 5.4.0

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "5.3.0",
3
+ "version": "5.4.0",
4
4
  "description": "Dispatch work from a data-only workspace to visible Codex project tasks.",
5
5
  "author": {
6
6
  "name": "Favo Yang",
package/SPEC.md CHANGED
@@ -179,9 +179,11 @@ cases.
179
179
  For each assignment, `$taskchef-delegate`:
180
180
 
181
181
  1. runs `dispatch prepare` and native Codex project discovery concurrently;
182
- the preparation command resolves the canonical workspace, loads and
183
- validates configured projects, and generates the full UUID, preparation
184
- timestamp, and exact marker in one process
182
+ only when neither a native provisional-ID resolver nor programmatic tool
183
+ orchestration is available, it also takes one recent-thread baseline
184
+ snapshot in that parallel group. The preparation command resolves the
185
+ canonical workspace, loads and validates configured projects, and generates
186
+ the full UUID, preparation timestamp, and exact marker in one process
185
187
  2. selects one unambiguous configured target and matches its exact path against
186
188
  the already-loaded native projects
187
189
  3. prefixes the instruction with the prepared exact
@@ -195,22 +197,27 @@ For each assignment, `$taskchef-delegate`:
195
197
  6. when creation returns only a provisional client ID, immediately appends the
196
198
  marked entry with `threadId: null`, then prefers one native client-ID wait or
197
199
  resolution call with a 30-second timeout when Codex exposes one
198
- 7. when no native operation is available, takes at most two recent-thread
200
+ 7. when no native operation is available, excludes durable Codex IDs from the
201
+ successful pre-creation baseline, then takes at most two recent-thread
199
202
  snapshots on a nominal 10- and 30-second schedule after the provisional
200
203
  result; a late first checkpoint runs immediately, and the second starts at
201
204
  least 20 seconds after the first actually started. It filters candidates by
202
205
  available host/project/time/worktree metadata, uses title only as an advisory
203
- ordering hint, and accepts only one thread whose structured delegated input
204
- starts with the exact marker
206
+ ordering hint, batches independent reads programmatically when supported,
207
+ and accepts only one thread whose structured delegated input starts with the
208
+ exact marker
205
209
  8. atomically fills the nullable thread ID after an exact match
206
210
  9. returns after recording or after reporting that bounded resolution was
207
211
  unresolved, without waiting for executor work completion.
208
212
 
209
- The exact random marker makes a pre-creation thread snapshot unnecessary.
210
- Creation-time filtering allows five seconds of clock skew. Candidate reads run
211
- concurrently where the host permits and inspect only structured
212
- `codexDelegation.input`, never untrusted title, summary, preview, or plain-text
213
- marker echoes. A native resolver result is verified against the same structured
213
+ The exact random marker remains the sole correlation proof. A successful
214
+ pre-creation snapshot is only a candidate-elimination baseline; its failure
215
+ does not block creation or weaken the marker check. Creation-time filtering
216
+ allows five seconds of clock skew. Candidate reads run concurrently where the
217
+ host permits, use one programmatic batch when available, and inspect only
218
+ structured `codexDelegation.input`, never untrusted title, summary, preview, or
219
+ plain-text marker echoes. A native resolver result is verified against the same
220
+ structured
214
221
  marker before persistence. Zero exact matches remain unresolved; multiple exact
215
222
  matches are ambiguous. Snapshot, candidate-read, native-resolution, or
216
223
  task-resolution errors leave the already-recorded nullable entry intact. The
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "5.3.0",
3
+ "version": "5.4.0",
4
4
  "description": "A non-blocking interactive dispatcher for visible Codex tasks.",
5
5
  "license": "MIT",
6
6
  "author": "Favo Yang",
@@ -27,15 +27,21 @@ for all deterministic workspace and task-record operations.
27
27
 
28
28
  ## Dispatch
29
29
 
30
- 1. In parallel, run `<plugin-root>/bin/taskchef.js dispatch prepare --json`
31
- and list the native Codex projects once. The prepare command resolves the
30
+ 1. In parallel, run `<plugin-root>/bin/taskchef.js dispatch prepare --json`,
31
+ list the native Codex projects once, and, only when neither a dedicated
32
+ provisional-ID resolver nor programmatic tool orchestration is available,
33
+ take one pre-creation `list_threads` snapshot with limit 50. Do not add this
34
+ snapshot when candidate reads can be issued in one programmatic batch. The
35
+ prepare command resolves the
32
36
  canonical workspace, loads and validates the configured routing targets,
33
37
  generates the lowercase full UUID task ID, and returns `preparedAt` plus the
34
38
  exact first-line marker. Use
35
39
  `$taskchef-bootstrap` if the workspace is missing or unhealthy.
36
40
  The CLI resolves `--workspace`, then `TASKCHEF_WORKSPACE`, then
37
41
  `~/.agents/taskchef`; do not substitute the current project. Reject the
38
- dispatcher workspace itself as a target.
42
+ dispatcher workspace itself as a target. From the pre-creation snapshot,
43
+ retain only durable Codex thread IDs as a candidate-elimination baseline.
44
+ Snapshot failure must not block creation; continue without a baseline.
39
45
  2. Split the request into the smallest independently useful outcomes. Include
40
46
  constraints, expected testing, and reporting in every instruction.
41
47
  3. Classify against configured `name`, every URL in the `githubRepos` list, and
@@ -54,9 +60,9 @@ for all deterministic workspace and task-record operations.
54
60
  Prefix the complete executor instruction with
55
61
  exactly `<!-- taskchef_id=<full UUID> -->` as the first line, followed by a
56
62
  blank line and the instruction body. Preserve this
57
- marked instruction for recording, and note the creation time.
58
- Do not take a pre-creation thread snapshot; the exact random marker is the
59
- correlation key.
63
+ marked instruction for recording, and note the creation time. The exact
64
+ random marker remains the sole correlation proof; the pre-creation IDs only
65
+ eliminate threads that already existed.
60
66
  6. Create one real Codex task using the exact configured project, a local
61
67
  environment on its executor host, the marked instruction, and a short title.
62
68
  7. When `create_thread` returns a durable `threadId`, immediately run
@@ -81,8 +87,10 @@ for all deterministic workspace and task-record operations.
81
87
  accepts the provisional ID and waits for or resolves its durable thread
82
88
  ID, call it exactly once with a timeout of at most 30 seconds. Do not invent
83
89
  an operation or pass the provisional ID to tools that require `threadId`.
84
- - When no native operation is available, take at most two `list_threads`
85
- snapshots with limit 50. The nominal schedule is 10 and 30 seconds after
90
+ - When no native operation is available, take at most two post-creation
91
+ `list_threads` snapshots with limit 50. Exclude every durable Codex ID from
92
+ the successful pre-creation baseline before reading candidates. The
93
+ nominal schedule is 10 and 30 seconds after
86
94
  the provisional result. Treat the first checkpoint as due, not expired: if
87
95
  nullable recording or other required work finishes after 10 seconds, take
88
96
  the first snapshot immediately. Start the second snapshot no sooner than
@@ -96,7 +104,9 @@ for all deterministic workspace and task-record operations.
96
104
  may normalize it, so never exclude a candidate because its title differs.
97
105
  - Read every remaining candidate with `read_thread`, requesting one turn and
98
106
  no command output. Read candidates concurrently when the tool surface
99
- permits. Inspect only the structured
107
+ permits; when programmatic tool orchestration is available, issue the
108
+ independent reads together in one programmatic batch. Inspect only the
109
+ structured
100
110
  `userMessage.content[].codexDelegation.input`; do not trust titles,
101
111
  summaries, previews, plain-text echoes, or assistant output as proof.
102
112
  - Accept a candidate only when the structured input's first line is exactly
package/src/delegation.js CHANGED
@@ -250,6 +250,7 @@ export async function createAndRecordDelegation({
250
250
  recordTask,
251
251
  resolveRecordedTask = null,
252
252
  resolveProvisionalThread = null,
253
+ baselineThreadIds = new Set(),
253
254
  taskId = randomUUID(),
254
255
  checkpointsMs = THREAD_RESOLUTION_CHECKPOINTS_MS,
255
256
  timeoutMs = THREAD_RESOLUTION_TIMEOUT_MS,
@@ -274,6 +275,9 @@ export async function createAndRecordDelegation({
274
275
  if (resolveRecordedTask !== null && typeof resolveRecordedTask !== "function") {
275
276
  throw new Error("resolveRecordedTask must be a function or null");
276
277
  }
278
+ if (!(baselineThreadIds instanceof Set)) {
279
+ throw new Error("baselineThreadIds must be a Set");
280
+ }
277
281
  validateResolutionSchedule(checkpointsMs, timeoutMs);
278
282
 
279
283
  const prepared = prepareDelegation(instruction, { taskId });
@@ -507,6 +511,7 @@ export async function createAndRecordDelegation({
507
511
  try {
508
512
  const snapshot = await listThreads({ limit: recentLimit });
509
513
  candidates = filterThreadCandidates(snapshot, {
514
+ baselineThreadIds,
510
515
  excludedThreadIds: provisionalIds,
511
516
  hostId: expected.hostId ?? null,
512
517
  projectId: expected.projectId ?? target.projectId ?? null,