From de22e4784f70ccb6bb3155babdd1ac17459302ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20TEKTA=C5=9E?= Date: Fri, 21 Aug 2026 09:27:14 +0300 Subject: [PATCH 1/4] refactor: extract goal evidence helpers --- src/source/runtime/goal-evidence.js | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/source/runtime/goal-evidence.js diff --git a/src/source/runtime/goal-evidence.js b/src/source/runtime/goal-evidence.js new file mode 100644 index 00000000..d4e88fa6 --- /dev/null +++ b/src/source/runtime/goal-evidence.js @@ -0,0 +1,39 @@ +export function hasConcreteGoalEvidence(value) { + const text = String(value || "").trim() + if (text.length < 24) return false + const normalized = text.toLowerCase().replace(/\s+/g, " ") + const weak = new Set(["done", "complete", "completed", "ok", "looks good", "n/a", "none", "no evidence", "no evidence provided", "goal completed", "marked complete"]) + if (weak.has(normalized) || normalized.startsWith("marked complete by /loop-goal-done")) return false + return /(\b(npm|pnpm|yarn|bun|node|pytest|cargo|dotnet|go test|tsc|typecheck|test|tests|lint|build|check|checks|exit\s*\d|passed|verified|changed|updated|created|fixed|file|files|diff|commit)\b|[`\\/][\w./:-]+)/i.test(text) || text.length >= 80 +} + +export function goalChecksPassed(job) { + return Array.isArray(job?.lastGoalChecks) && job.lastGoalChecks.length > 0 && job.lastGoalChecks.every((item) => Number(item?.code) === 0) +} + +export function goalRequiresPassingChecks(job) { + return job?.goalRequireChecksPass !== false && Array.isArray(job?.goalChecks) && job.goalChecks.length > 0 +} + +export function goalProgressSnapshot(job) { + return { + status: job?.goalStatus || "", + progressCount: Array.isArray(job?.goalProgress) ? job.goalProgress.length : 0, + evidence: String(job?.goalEvidence || ""), + checksPassedAt: Number(job?.goalChecksPassedAt || 0), + lastGoalCheckAt: Number(job?.lastGoalCheckAt || 0), + lastVerifyAt: Number(job?.lastVerifyAt || 0), + lastVerifyCode: Number.isFinite(Number(job?.lastVerifyCode)) ? Number(job.lastVerifyCode) : undefined, + } +} + +export function goalMadeMeaningfulProgress(beforeJob, afterJob) { + const before = goalProgressSnapshot(beforeJob || {}) + const after = goalProgressSnapshot(afterJob || {}) + if (["completed", "blocked"].includes(after.status) && after.status !== before.status) return true + if (after.progressCount > before.progressCount) return true + if (after.evidence !== before.evidence && hasConcreteGoalEvidence(after.evidence)) return true + if (after.checksPassedAt > before.checksPassedAt || goalChecksPassed(afterJob) && after.lastGoalCheckAt > before.lastGoalCheckAt) return true + if (after.lastVerifyAt > before.lastVerifyAt && after.lastVerifyCode === 0) return true + return false +} From 9a29efc3a5ea6d3508797e6479fcf867f4688d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20TEKTA=C5=9E?= Date: Fri, 21 Aug 2026 09:27:38 +0300 Subject: [PATCH 2/4] refactor: compose goal evidence helpers --- src/source/runtime/goal-runtime.js | 42 ++---------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/src/source/runtime/goal-runtime.js b/src/source/runtime/goal-runtime.js index 0d739db3..ca7388ae 100644 --- a/src/source/runtime/goal-runtime.js +++ b/src/source/runtime/goal-runtime.js @@ -3,9 +3,11 @@ import { matchJob, isGoalJob } from "../core/jobs.js" import { readState, writeState } from "../core/state.js" import { appendLoopLog } from "../core/process.js" import { writeGoalReport } from "./goal-report.js" +import { hasConcreteGoalEvidence, goalChecksPassed, goalRequiresPassingChecks } from "./goal-evidence.js" export { buildGoalPrompt } from "./goal-prompt.js" export { goalReportPath, goalReportText, writeGoalReport } from "./goal-report.js" +export { hasConcreteGoalEvidence, goalChecksPassed, goalRequiresPassingChecks, goalProgressSnapshot, goalMadeMeaningfulProgress } from "./goal-evidence.js" export function pickGoalJob(state, target = "") { const goals = (state.jobs || []).filter(isGoalJob) @@ -21,46 +23,6 @@ export function parseGoalToolText(args, fields) { return result } -export function hasConcreteGoalEvidence(value) { - const text = String(value || "").trim() - if (text.length < 24) return false - const normalized = text.toLowerCase().replace(/\s+/g, " ") - const weak = new Set(["done", "complete", "completed", "ok", "looks good", "n/a", "none", "no evidence", "no evidence provided", "goal completed", "marked complete"]) - if (weak.has(normalized) || normalized.startsWith("marked complete by /loop-goal-done")) return false - return /(\b(npm|pnpm|yarn|bun|node|pytest|cargo|dotnet|go test|tsc|typecheck|test|tests|lint|build|check|checks|exit\s*\d|passed|verified|changed|updated|created|fixed|file|files|diff|commit)\b|[`\\/][\w./:-]+)/i.test(text) || text.length >= 80 -} - -export function goalChecksPassed(job) { - return Array.isArray(job?.lastGoalChecks) && job.lastGoalChecks.length > 0 && job.lastGoalChecks.every((item) => Number(item?.code) === 0) -} - -export function goalRequiresPassingChecks(job) { - return job?.goalRequireChecksPass !== false && Array.isArray(job?.goalChecks) && job.goalChecks.length > 0 -} - -export function goalProgressSnapshot(job) { - return { - status: job?.goalStatus || "", - progressCount: Array.isArray(job?.goalProgress) ? job.goalProgress.length : 0, - evidence: String(job?.goalEvidence || ""), - checksPassedAt: Number(job?.goalChecksPassedAt || 0), - lastGoalCheckAt: Number(job?.lastGoalCheckAt || 0), - lastVerifyAt: Number(job?.lastVerifyAt || 0), - lastVerifyCode: Number.isFinite(Number(job?.lastVerifyCode)) ? Number(job.lastVerifyCode) : undefined, - } -} - -export function goalMadeMeaningfulProgress(beforeJob, afterJob) { - const before = goalProgressSnapshot(beforeJob || {}) - const after = goalProgressSnapshot(afterJob || {}) - if (["completed", "blocked"].includes(after.status) && after.status !== before.status) return true - if (after.progressCount > before.progressCount) return true - if (after.evidence !== before.evidence && hasConcreteGoalEvidence(after.evidence)) return true - if (after.checksPassedAt > before.checksPassedAt || goalChecksPassed(afterJob) && after.lastGoalCheckAt > before.lastGoalCheckAt) return true - if (after.lastVerifyAt > before.lastVerifyAt && after.lastVerifyCode === 0) return true - return false -} - export async function rejectGoalCompletion(directory, sessionID, state, job, reason) { job.goalCompletionRejectedAt = now() job.goalCompletionRejectedReason = reason From 2ee6ead22f710b2fe0920cc5aefe0c4f6eef7f95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20TEKTA=C5=9E?= Date: Fri, 21 Aug 2026 09:28:11 +0300 Subject: [PATCH 3/4] test: syntax-check goal evidence runtime --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9200508d..b33f6ffe 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "build:plugin": "bun build src/source/v1.js --outfile=src/index.js --target=bun --format=esm --external=@opencode-ai/plugin/tool", "build:plugin:npm": "npm run build:plugin", "prepack": "node --check src/index.js", - "check": "node --check src/source/v1.js && node --check src/source/core/args.js && node --check src/source/core/state.js && node --check src/source/core/jobs.js && node --check src/source/core/process.js && node --check src/source/opencode/sdk.js && node --check src/source/opencode/session-context.js && node --check src/source/opencode/command-router.js && node --check src/source/opencode/goal-commands.js && node --check src/source/opencode/loop-commands.js && node --check src/source/opencode/loop-registration.js && node --check src/source/runtime/session-activity.js && node --check src/source/runtime/session-status.js && node --check src/source/runtime/compaction.js && node --check src/source/runtime/action-dispatch.js && node --check src/source/runtime/run-finalization.js && node --check src/source/runtime/run-admission.js && node --check src/source/runtime/executor.js && node --check src/source/runtime/scheduler.js && node --check src/source/runtime/goal-prompt.js && node --check src/source/runtime/goal-report.js && node --check src/source/runtime/goal-runtime.js && node --check src/source/runtime/goal-policy.js && node --check src/source/runtime/goal-steering.js && node --check src/source/runtime/job-workspace.js && node --check src/source/opencode2/prompt-runtime.js && node --check src/source/opencode2/diagnostics.js && node --check src/source/opencode2/logging.js && node --check src/source/legacy-v1.js && node --check src/index.js && node --check scripts/install-node.mjs && node --check scripts/install-with-goals.mjs && node --check scripts/loopd.mjs && node --check scripts/install-test.mjs && node --check scripts/goal-companion-test.mjs && node --check scripts/loopd-test.mjs && node --check scripts/smoke-test.mjs && node --check scripts/host-adapter-contract-test.mjs && node --check scripts/command-router-test.mjs && node --check scripts/goal-command-handlers-test.mjs && node --check scripts/loop-command-handlers-test.mjs && node --check scripts/loop-registration-test.mjs && node --check scripts/session-activity-test.mjs && node --check scripts/session-status-test.mjs && node --check scripts/compaction-runtime-test.mjs && node --check scripts/executor-runtime-test.mjs && node --check scripts/scheduler-runtime-test.mjs && node --check scripts/goal-runtime-test.mjs && node --check scripts/goal-policy-test.mjs && node --check scripts/goal-steering-test.mjs && node --check scripts/job-workspace-test.mjs && node --check scripts/v2-prompt-runtime-test.mjs && node --check scripts/v2-prompt-interval-test.mjs && node --check scripts/v2-command-runtime-test.mjs && node --check scripts/v2-command-adapter-test.mjs && node --check scripts/v2-diagnostics-test.mjs && node --check scripts/v2-logging-test.mjs && node --check scripts/comprehensive-watchdog.mjs && node --check scripts/comprehensive-test.mjs && node --check scripts/host-loop-canary.mjs && node --check scripts/host-goal-steering-canary.mjs && node --check scripts/publish-workflow-test.mjs", + "check": "node --check src/source/v1.js && node --check src/source/core/args.js && node --check src/source/core/state.js && node --check src/source/core/jobs.js && node --check src/source/core/process.js && node --check src/source/opencode/sdk.js && node --check src/source/opencode/session-context.js && node --check src/source/opencode/command-router.js && node --check src/source/opencode/goal-commands.js && node --check src/source/opencode/loop-commands.js && node --check src/source/opencode/loop-registration.js && node --check src/source/runtime/session-activity.js && node --check src/source/runtime/session-status.js && node --check src/source/runtime/compaction.js && node --check src/source/runtime/action-dispatch.js && node --check src/source/runtime/run-finalization.js && node --check src/source/runtime/run-admission.js && node --check src/source/runtime/executor.js && node --check src/source/runtime/scheduler.js && node --check src/source/runtime/goal-prompt.js && node --check src/source/runtime/goal-report.js && node --check src/source/runtime/goal-evidence.js && node --check src/source/runtime/goal-runtime.js && node --check src/source/runtime/goal-policy.js && node --check src/source/runtime/goal-steering.js && node --check src/source/runtime/job-workspace.js && node --check src/source/opencode2/prompt-runtime.js && node --check src/source/opencode2/diagnostics.js && node --check src/source/opencode2/logging.js && node --check src/source/legacy-v1.js && node --check src/index.js && node --check scripts/install-node.mjs && node --check scripts/install-with-goals.mjs && node --check scripts/loopd.mjs && node --check scripts/install-test.mjs && node --check scripts/goal-companion-test.mjs && node --check scripts/loopd-test.mjs && node --check scripts/smoke-test.mjs && node --check scripts/host-adapter-contract-test.mjs && node --check scripts/command-router-test.mjs && node --check scripts/goal-command-handlers-test.mjs && node --check scripts/loop-command-handlers-test.mjs && node --check scripts/loop-registration-test.mjs && node --check scripts/session-activity-test.mjs && node --check scripts/session-status-test.mjs && node --check scripts/compaction-runtime-test.mjs && node --check scripts/executor-runtime-test.mjs && node --check scripts/scheduler-runtime-test.mjs && node --check scripts/goal-runtime-test.mjs && node --check scripts/goal-policy-test.mjs && node --check scripts/goal-steering-test.mjs && node --check scripts/job-workspace-test.mjs && node --check scripts/v2-prompt-runtime-test.mjs && node --check scripts/v2-prompt-interval-test.mjs && node --check scripts/v2-command-runtime-test.mjs && node --check scripts/v2-command-adapter-test.mjs && node --check scripts/v2-diagnostics-test.mjs && node --check scripts/v2-logging-test.mjs && node --check scripts/comprehensive-watchdog.mjs && node --check scripts/comprehensive-test.mjs && node --check scripts/host-loop-canary.mjs && node --check scripts/host-goal-steering-canary.mjs && node --check scripts/publish-workflow-test.mjs", "test": "node scripts/publish-workflow-test.mjs && node scripts/command-router-test.mjs && node scripts/goal-command-handlers-test.mjs && node scripts/loop-command-handlers-test.mjs && node scripts/loop-registration-test.mjs && node scripts/session-activity-test.mjs && node scripts/session-status-test.mjs && node scripts/compaction-runtime-test.mjs && node scripts/action-dispatch-test.mjs && node scripts/run-finalization-test.mjs && node scripts/run-admission-test.mjs && node scripts/executor-runtime-test.mjs && node scripts/scheduler-runtime-test.mjs && node scripts/goal-runtime-test.mjs && node scripts/goal-policy-test.mjs && node scripts/goal-steering-test.mjs && node scripts/job-workspace-test.mjs && node scripts/v2-prompt-runtime-test.mjs && node scripts/v2-prompt-interval-test.mjs && node scripts/v2-command-runtime-test.mjs && node scripts/v2-command-adapter-test.mjs && node scripts/v2-diagnostics-test.mjs && node scripts/v2-logging-test.mjs && node scripts/install-test.mjs && node scripts/goal-companion-test.mjs && node scripts/loopd-test.mjs && node scripts/smoke-test.mjs && node scripts/host-adapter-contract-test.mjs && node scripts/comprehensive-watchdog.mjs", "canary:host": "node scripts/host-loop-canary.mjs && node scripts/host-goal-steering-canary.mjs", "install:global": "node scripts/install-with-goals.mjs", From a8256b7f58057b54483f3b6335c0bbaf620bf60f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20TEKTA=C5=9E?= Date: Fri, 21 Aug 2026 09:30:14 +0300 Subject: [PATCH 4/4] refactor: depend directly on goal evidence helpers --- src/source/runtime/goal-policy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source/runtime/goal-policy.js b/src/source/runtime/goal-policy.js index 797b5d31..d8d1a843 100644 --- a/src/source/runtime/goal-policy.js +++ b/src/source/runtime/goal-policy.js @@ -1,7 +1,7 @@ import { DEFAULT_GOAL_MAX_NO_PROGRESS, now as defaultNow } from "../core/args.js" import { isGoalJob } from "../core/jobs.js" import { appendLoopLog as defaultAppendLoopLog } from "../core/process.js" -import { goalMadeMeaningfulProgress } from "./goal-runtime.js" +import { goalMadeMeaningfulProgress } from "./goal-evidence.js" function requireFunction(value, name) { if (typeof value !== "function") throw new TypeError(`createGoalExecutionPolicy requires ${name}`)