Maestro task: 8f533721-32c9-4f73-af9f-9a9f0e94abf8 (Feature 09 - AI Harness and Skills Framework, final task).
Done-condition
harness.Run accepts a scope key; concurrent runs with the same (skill, scope) share one in-flight execution and result; a global semaphore limits concurrent LLM calls to 2 (configurable) with context-aware waiting; each skill declares a timeout (default 60 s) enforced via context. Blocking-Fake tests prove: two same-scope calls produce one Generate call and identical results; different scopes run independently; a third concurrent call waits for a slot; a cancelled context releases its slot; timeout returns ErrTimeout. Go quality floor passes with -race.
gofmt/vet/go test -race/build pass; no new dependency (go.mod/go.sum unchanged).
Documented trade-offs: a scope must identify the input (joiners share the first result); shared output is handed to callers as-is; the semaphore limits each Generate call, not each run.
Maestro task: 8f533721-32c9-4f73-af9f-9a9f0e94abf8 (Feature 09 - AI Harness and Skills Framework, final task).
## Done-condition
harness.Run accepts a scope key; concurrent runs with the same (skill, scope) share one in-flight execution and result; a global semaphore limits concurrent LLM calls to 2 (configurable) with context-aware waiting; each skill declares a timeout (default 60 s) enforced via context. Blocking-Fake tests prove: two same-scope calls produce one Generate call and identical results; different scopes run independently; a third concurrent call waits for a slot; a cancelled context releases its slot; timeout returns ErrTimeout. Go quality floor passes with -race.
## Evidence
- New internal/ai/harness/guard.go + guard_test.go; harness.go wires scope/semaphore/timeout; llm/fake.go gained blocking support.
- gofmt/vet/go test -race/build pass; no new dependency (go.mod/go.sum unchanged).
Documented trade-offs: a scope must identify the input (joiners share the first result); shared output is handed to callers as-is; the semaphore limits each Generate call, not each run.
harness.Run now takes a scope key. Concurrent runs of one skill with one
scope share a single in-flight run and its result, errors included, so
only one Generate call is made; different scopes run independently. A
process-wide Guard (NewGuard, DefaultMaxCalls = 2) bounds concurrent LLM
calls with a context-aware semaphore. Each skill declares Timeout()
(DefaultTimeout = 60 s), enforced via context over the whole run; a run
past it fails with an error matching llm.ErrTimeout. A caller whose
context ends gets the context error; the shared run is cancelled, and
its slot freed, once no caller waits for it.
llm.Fake results can now block (Release) and signal entry (Started), so
tests hold calls in flight.
Maestro task: 8f533721-32c9-4f73-af9f-9a9f0e94abf8
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
runOnce only mapped an expired context to llm.ErrTimeout when execute
returned an error, so a PostProcess that succeeded after the deadline was
reported as a success. Check the deadline after execution (context cause
or the clock, since the timer may not have fired yet) and fail such a run
with llm.ErrTimeout and a provider_error ai_runs row.
Adds a TestRunTimeout case with a skill whose PostProcess succeeds only
after its timeout.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
runOnce checked the deadline only before saving the row. The save can
wait for the store's single writer, so a run whose work ended in time
could return success after its timeout. Check the deadline again once
the row is saved and return llm.ErrTimeout when it has passed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The row-saved-late test only checked that one ai_runs row existed, so it
would also pass if the work itself had timed out before the save. It now
requires the row to be ok with no error, which holds only when the work
ended in time and the save alone ran past the deadline.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Maestro task: 8f533721-32c9-4f73-af9f-9a9f0e94abf8 (Feature 09 - AI Harness and Skills Framework, final task).
Done-condition
harness.Run accepts a scope key; concurrent runs with the same (skill, scope) share one in-flight execution and result; a global semaphore limits concurrent LLM calls to 2 (configurable) with context-aware waiting; each skill declares a timeout (default 60 s) enforced via context. Blocking-Fake tests prove: two same-scope calls produce one Generate call and identical results; different scopes run independently; a third concurrent call waits for a slot; a cancelled context releases its slot; timeout returns ErrTimeout. Go quality floor passes with -race.
Evidence
Documented trade-offs: a scope must identify the input (joiners share the first result); shared output is handed to callers as-is; the semaphore limits each Generate call, not each run.
Independent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.
Independent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.
Independent Codex gpt-6-sol review: BLOCKED for this exact commit.
Independent Codex gpt-6-sol review: APPROVED for this exact commit.