Repository navigation
feat(task-bridge): task overlap classifier — independence detection layer (#1487 layer 1) - #1656
Conversation
Adds `src/task-overlap.ts` with three exported helpers:
- `classifyTaskCategory(body)` — keyword-based categorisation into
cancel / code / research / email / calendar / file / unknown
- `hasSerialDependency(body)` — detects "after you finish", "depends on",
"once it's done", etc. — always serialises
- `areSafeToOverlap(raw1, raw2)` — combines the above into a boolean
the proactive-loop can use when deciding whether to start task N+1
while task N is in-flight
Conservative rules (first pass per issue sonichi#1487):
- Serial-dependency language in either task → serialize
- Either is a CANCEL_INSTRUCTION → serialize (must interrupt)
- Either is "code" category → serialize (shared git/filesystem state)
- Same category → serialize (may share external state)
- Different non-code, non-cancel categories → safe to overlap (1 max)
50 unit tests cover extractTaskBody, classifyTaskCategory,
hasSerialDependency, and areSafeToOverlap including header-field
non-interference (source: discord must not skew task-body classification).
The orchestration layer (proactive-loop using areSafeToOverlap to spawn a
concurrent background Agent) is a follow-up commit; this PR lands the
classifier independently so it can be reviewed and merged first.
Closes sonichi#1487 (layer 1 of 2)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
604807b to
7f8501f
Compare
sonichi
left a comment
There was a problem hiding this comment.
Cold review by Sutando agents (review only — merge stays with the owner).
Should-fix (correctness vs. its own docstring) — extractTaskBody keeps the trailing headers and the injected tier-instructions block. The docstring says classifiers see "only the actual request text — not source: voice etc.", but the bridge writes headers on both sides of the body: discord-bridge.py:2966-2976 emits task: … then source:, channel_name:, guild_name:, user_id:, access_tier:, priority:, then the ===SUTANDO SYSTEM INSTRUCTIONS=== block for non-owner tiers. Slicing "from task: onward" strips only id:/timestamp: and feeds everything else to the regexes. Concretely:
channel_name/guild_nameare user-influenced strings inside the classified text. The category check is first-match-wins (email → calendar → code → file → research), so a code task arriving from a guild named e.g. "inbox zero" matches the email regex first and classifiesemail— making it overlap-eligible against a research task. That's the unsafe direction (two concurrent tasks, one mutating git), not the conservative one.- Team/other-tier task files carry the whole codex instructions block; today's keywords happen not to trip on it, but that's luck, not a contract.
Fix is small: bound the slice at the next \nsource: line (every bridge writes source: immediately after the task text — discord-bridge.py:2967, and the chat-path/voice formats match), falling back to end-of-string. One regression test with a full real-shaped task file (headers both sides + tier block) would pin it.
Should-fix — hasSerialDependency only matches single-token subjects in the "once X is done" form. once\s+\S+('s?\s+|\s+is\s+)(done|complete|finished) matches "once it's done" but not "once the deploy is done" / "once the email is sent" (multi-word subject; also "sent" absent). Misses here flip serial intent to overlap — again the unsafe direction. once\s+.{1,40}?\s+is\s+(done|complete|finished|sent) (plus the existing 's form) closes the common cases.
Nits:
- Stale comment: "'code' is last among specific categories" — it's third of five (email, calendar, code, file, research).
after finishing Xdoesn't match (finish\bvs "finishing"); cheap to addfinish(ing)?.
The overall shape is right — conservative default, cancel/code always serialize, same-category serializes, 50 tests, and layer-splitting the classifier from orchestration is the correct call. Both should-fixes bias the unsafe direction though, which is exactly what this layer exists to prevent.
Merge-readiness: not quite — fix the extractTaskBody bound (and ideally the serial-dependency subject gap) before layer 2 consumes this; both are small, self-contained changes.
Stand: Echo Act IV (Mini)
|
Routing/dedup note: see #1666 (comment) — #1666 and this PR are one feature in two PRs; please consolidate to one (single concern, single tracking issue) and it needs the owner's feature go/no-go before depth review. — Lucy (Mac Studio bot) |
liususan091219
left a comment
There was a problem hiding this comment.
APPROVE.
- Clean standalone layer: no behavior change yet (classifier + tests only), conservative defaults (serialize on same-category, code, cancel, or dependency language), and extractTaskBody respects the #982 header-forge boundary.
- One suggested tightening before layer 3 wires this in: rule 5 currently lets
unknownoverlap with any different known category — but unknown means the keywords failed, and a missed code task overlapping an email task is the expensive failure. Treatingunknownas non-overlappable would make the conservative claim complete. - Test suite covers the matrix well incl. negative dependency phrases.
|
Post-approve addendum (applies here and to the #1666 port): |
|
@cla-assistant check |
… 2) (#1666) Python port of `src/task-overlap.ts` (PR #1656) so the proactive-loop (Python) can call `are_safe_to_overlap(raw1, raw2)` without shelling out to Node. Same conservative heuristics: code/cancel always serialize; serial-dependency language forces ordering; same-category serializes; different non-code categories may overlap. 20 tests covering extract_task_body, classify_task_category, has_serial_dependency, and are_safe_to_overlap — mirrors the TS test suite so divergence between implementations surfaces immediately. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Susan Xueqing Liu <xliu127@stevens.edu>
What
Adds
src/task-overlap.ts— the classification layer needed before theconcurrent-execution step of #1487 can land.
Three exported helpers:
classifyTaskCategory(body)cancel | code | research | email | calendar | file | unknownhasSerialDependency(body)areSafeToOverlap(raw1, raw2)Independence rules (conservative first pass)
Per issue #1487's stated heuristics:
CANCEL_INSTRUCTION→ serialize (must interrupt in-flight work)codecategory → serialize (shared git / filesystem state)Tests
50 unit tests in
tests/task-overlap.test.tscovering:extractTaskBodydelimiter handling (header fields must not skew classification)classifyTaskCategory— 19 labelled cases including CANCEL_INSTRUCTION, contractions ("it's done"), plurals ("appointments")hasSerialDependency— 6 positive / 5 negative cases including "once it's done"areSafeToOverlap— 10 cases: research+email, code+anything, cancel+anything, serial dep, unknown pairsWhat's next (layer 2)
A follow-up PR adds the orchestration: when the proactive-loop's task watcher emits a second
TASK_FILE:notification while task N is in-flight, callareSafeToOverlap(task_N_body, task_N1_body)and, if true, start task N+1 as a backgroundAgentrather than queuing it. Concurrency cap: 2 simultaneous tasks.This PR is intentionally the classifier only so it can be reviewed and merged before the more complex orchestration change lands.
Closes #1487 (layer 1 of 2)
🤖 Generated with Claude Code