* Inspect a candidate final assistant message. If it claims completion while * the active contract still has blockers, return an injection payload the * caller can splice into history. Otherwise return null. * * Caller wires in the agent loop (bin/smallcode.js): * const guard = checkDoneGuard
(content, cwd)
| 55 | * } |
| 56 | */ |
| 57 | function checkDoneGuard(content, cwd) { |
| 58 | if (process.env.SMALLCODE_CONTRACT === 'false') return null; |
| 59 | if (!looksLikeDoneClaim(content)) return null; |
| 60 | |
| 61 | let store, c; |
| 62 | try { |
| 63 | store = getStore(cwd || process.cwd()); |
| 64 | c = store.active(); |
| 65 | } catch { |
| 66 | return null; |
| 67 | } |
| 68 | if (!c) return null; // no active contract → guard inactive |
| 69 | |
| 70 | const ds = c.doneStatus(); |
| 71 | if (ds.done) return null; // contract is fully resolved — let the response through |
| 72 | |
| 73 | const blockerLines = ds.blockers |
| 74 | .map((b) => ` - ${b.id} (${b.state}) ${b.text}`) |
| 75 | .join('\n'); |
| 76 | |
| 77 | const injection = |
| 78 | `[CONTRACT-GUARD] You claimed the task is complete, but the active contract "${c.title}" (${c.id}) still has unresolved assertions: |
| 79 | |
| 80 | ${blockerLines} |
| 81 | |
| 82 | You cannot deliver a final response while assertions are pending or failed. Do one of the following before claiming done: |
| 83 | |
| 84 | 1. Run the right command(s) and call contract_assert_pass <id> with evidence |
| 85 | 2. Call contract_assert_fail <id> with the actual failure (if it really is broken) |
| 86 | 3. Call contract_assert_skip <id> with a reason (if it is genuinely out of scope) |
| 87 | 4. Call contract_status to refresh the assertion list |
| 88 | |
| 89 | If you are blocked from completing an assertion, explain the specific blocker and ask the user — do not claim completion. Disable this guard with SMALLCODE_CONTRACT=false.`; |
| 90 | |
| 91 | return { |
| 92 | injection, |
| 93 | contractId: c.id, |
| 94 | blockers: ds.blockers, |
| 95 | }; |
| 96 | } |
| 97 | |
| 98 | module.exports = { checkDoneGuard, looksLikeDoneClaim, DONE_PATTERNS }; |
no test coverage detected