taskforce-loop-engineering 0.15.7 → 0.15.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.15.9 - 2026-08-25
|
|
6
|
+
|
|
7
|
+
- Clarify that the disposable OpenClaw smoke may write required checkpoint and verification artifacts only inside its temporary Loop runtime queue while user/project files, configuration, credentials, and external state remain read-only.
|
|
8
|
+
- Add regression coverage that rejects contradictory smoke permission wording or a missing checkpoint requirement.
|
|
9
|
+
|
|
10
|
+
## 0.15.8 - 2026-08-25
|
|
11
|
+
|
|
12
|
+
- Preserve every non-blocking risk from the effective terminal checkpoint in `final_judgement.residual_risks`, including accepted project completions without a continuation action.
|
|
13
|
+
- Deduplicate repeated terminal risks while retaining the accepted completion outcome.
|
|
14
|
+
- Add regression coverage proving accepted terminal checkpoints keep their operational risks visible.
|
|
15
|
+
|
|
5
16
|
## 0.15.7 - 2026-08-24
|
|
6
17
|
|
|
7
18
|
- Prevent accepted phase checkpoints from producing `ready_to_apply` when they explicitly mark project completion as `in_progress`, including both string and object completion forms.
|
package/lib/core.mjs
CHANGED
|
@@ -3852,6 +3852,7 @@ export function buildFinalJudgement(contract, acceptancePlan, devPlan, checkpoin
|
|
|
3852
3852
|
const explicitContinuationReviews = effectiveReviews.filter((review) =>
|
|
3853
3853
|
(review.checkpointRisks?.length ?? 0) > 0 && continuationNextAction(review.checkpointNextAction)
|
|
3854
3854
|
);
|
|
3855
|
+
const effectiveResidualRisks = [...new Set(effectiveReviews.flatMap((review) => review.checkpointRisks ?? []))];
|
|
3855
3856
|
const deferredGateCount = effectiveReviews.reduce((count, review) => count + (review.deferredGates?.length ?? 0), 0);
|
|
3856
3857
|
let outcome = 'needs_revision';
|
|
3857
3858
|
|
|
@@ -3954,7 +3955,7 @@ export function buildFinalJudgement(contract, acceptancePlan, devPlan, checkpoin
|
|
|
3954
3955
|
residual_risks: [
|
|
3955
3956
|
...(contract.requires_human_gate ? ['Human gate still required before external or high-risk action.'] : []),
|
|
3956
3957
|
...(context.verificationFailed ? ['Configured verification has failing commands.'] : []),
|
|
3957
|
-
...
|
|
3958
|
+
...effectiveResidualRisks
|
|
3958
3959
|
],
|
|
3959
3960
|
created_at: new Date().toISOString()
|
|
3960
3961
|
};
|
package/package.json
CHANGED
|
@@ -175,7 +175,13 @@ assert.equal(inferTaskScope({ body: 'Continue the overall project with a product
|
|
|
175
175
|
|
|
176
176
|
{
|
|
177
177
|
const devPlan = { checkpoints: [{ id: 'cp1' }] };
|
|
178
|
-
const reviews = { reviews: [{
|
|
178
|
+
const reviews = { reviews: [{
|
|
179
|
+
checkpointId: 'cp6', sequence: 6, status: 'accepted', projectCompletion: { status: 'accepted' },
|
|
180
|
+
checkpointRisks: [
|
|
181
|
+
'A non-blocking operational risk remains after acceptance.',
|
|
182
|
+
'A non-blocking operational risk remains after acceptance.'
|
|
183
|
+
]
|
|
184
|
+
}] };
|
|
179
185
|
const judgement = buildFinalJudgement(
|
|
180
186
|
{ ...baseContract, task_scope: 'project' },
|
|
181
187
|
basePlan,
|
|
@@ -185,6 +191,7 @@ assert.equal(inferTaskScope({ body: 'Continue the overall project with a product
|
|
|
185
191
|
{ dispatchStatus: 'completed' }
|
|
186
192
|
);
|
|
187
193
|
assert.equal(judgement.outcome, 'ready_to_apply');
|
|
194
|
+
assert.deepEqual(judgement.residual_risks, ['A non-blocking operational risk remains after acceptance.']);
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
console.log('final judgement self-test passed');
|
|
@@ -128,6 +128,13 @@ if (doctorResult.code !== 0) throw new Error(`doctor failed: ${doctorResult.stde
|
|
|
128
128
|
const doctorReport = JSON.parse(doctorResult.stdout);
|
|
129
129
|
if (doctorReport.status !== 'ok' || doctorReport.externalWrite !== false || !doctorReport.checks.some((check) => check.id === 'notification_dry_run' && check.ok)) throw new Error('doctor did not complete a safe notification dry-run');
|
|
130
130
|
const smoke = new URL('./openclaw-smoke.mjs', import.meta.url).pathname;
|
|
131
|
+
const smokeSource = await readFile(smoke, 'utf8');
|
|
132
|
+
if (!smokeSource.includes('Do not change user or project files, configuration, credentials, or external state.')
|
|
133
|
+
|| !smokeSource.includes('Writing the required Loop checkpoint and verification evidence under')
|
|
134
|
+
|| !smokeSource.includes('is allowed and required; do not write anywhere else.')
|
|
135
|
+
|| !smokeSource.includes('path.relative(args.root, smokeRuntime)')) {
|
|
136
|
+
throw new Error('OpenClaw smoke permission boundary or checkpoint requirement is missing');
|
|
137
|
+
}
|
|
131
138
|
const loopBin = new URL('../bin/loop-engineering.mjs', import.meta.url).pathname;
|
|
132
139
|
const smokeResult = await new Promise((resolve) => {
|
|
133
140
|
const child = spawn(process.execPath, [smoke, '--root', root, '--queue', 'test-tasks', '--worker-agent', 'builder', '--openclaw-bin', mockOpenClaw, '--loop-bin', loopBin, '--json'], { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
@@ -59,7 +59,8 @@ async function main() {
|
|
|
59
59
|
config.retry = { ...(config.retry || {}), maxAttempts: 1 };
|
|
60
60
|
await mkdir(path.dirname(smokeConfig), { recursive: true });
|
|
61
61
|
await writeFile(smokeConfig, `${JSON.stringify(config, null, 2)}\n`);
|
|
62
|
-
const
|
|
62
|
+
const smokeRuntimeRel = path.relative(args.root, smokeRuntime);
|
|
63
|
+
const message = `走 loop:Perform a read-only integration smoke. Do not change user or project files, configuration, credentials, or external state. Writing the required Loop checkpoint and verification evidence under ${smokeRuntimeRel}/ is allowed and required; do not write anywhere else. Report SMOKE_OK with verification evidence.`;
|
|
63
64
|
const route = await run(args.loopBin, ['route-message', '--root', args.root, '--queue', smokeQueue, '--message', message, '--route', '--confirm-execute', '--source-channel', 'feishu', '--source-target', 'user:loop-smoke-dry-run', '--source-account', 'doctor', '--source-message-id', `smoke-${runToken}`, '--source-reply-to', `smoke-${runToken}`, '--json'], { cwd: args.root });
|
|
64
65
|
steps.push({ id: 'route', ok: route.code === 0 });
|
|
65
66
|
if (route.code !== 0) throw new Error(`route failed: ${route.stderr || route.stdout}`);
|