Concurrency guards: single-flight, semaphore and timeouts (#61)
CI / ci (push) Successful in 1m35s
CI / ci (pull_request) Successful in 1m35s

Co-authored-by: dev_agent <dev_agent@cubecraftlabs.com>
This commit was merged in pull request #61.
This commit is contained in:
2026-10-05 10:42:18 -04:00
committed by approver_agent
parent 87316d8b70
commit a8b0c7894f
10 changed files with 662 additions and 17 deletions
+10
View File
@@ -162,6 +162,16 @@ automatic** (D-021).
with key-like query parameters are removed, inside JSON strings too.
`harness.Purge` deletes rows older than `harness.RunRetention` (30 days),
clearing the `suggestion_batches` and `week_plans` references first.
- **Concurrency guards** (`harness.Guard`, one per process): `harness.Run`
takes a scope key, and concurrent runs of one skill with one scope share a
single in-flight run and its result, error included (single-flight); runs
with different scopes are independent. A semaphore lets at most
`harness.DefaultMaxCalls` (2, set by `NewGuard`) LLM calls run at once;
waiting for a slot honours the context. Each skill declares a timeout
(`harness.DefaultTimeout`, 60 s, unless it needs another) bounding the
whole run, slot waits and repair turn included; a run past it fails with
`llm.ErrTimeout`. A caller whose context ends gets the context error; the
shared run is cancelled, freeing its slot, once no caller waits for it.
- **Prompt layering** (D-007): each skill version's prompt is a
`text/template` file embedded from `ai/skills/prompts/`
(`<skill>.v<version>.tmpl`). The system prompt is always, in order: