taskforce-loop-engineering 0.13.0 → 0.15.0

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.
@@ -0,0 +1,107 @@
1
+ import assert from 'node:assert/strict';
2
+ import { mkdtemp, mkdir, readFile, rename, writeFile } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { doctorReport, enqueueTask, notifyHumanInputRequests, projectStatus, queueStatus, reconcileProjectGates, routeLoopMessage, taskRuntimeDirFor } from '../lib/core.mjs';
6
+
7
+ const root = await mkdtemp(path.join(os.tmpdir(), 'loop-project-gates-'));
8
+ const queue = 'shared';
9
+ const projectFile = path.join(root, 'configs', 'loops', 'projects', 'openreel.json');
10
+ const spec = { schemaVersion: 1, project: 'openreel', type: 'code_project', queues: [{ queue, kind: 'standard' }], backlog: [
11
+ { id: 'B-01', required: true, status: 'human_gated', dependsOn: [] },
12
+ { id: 'S-01', required: true, status: 'human_gated', dependsOn: [] }
13
+ ] };
14
+ await mkdir(path.dirname(projectFile), { recursive: true });
15
+ await writeFile(projectFile, `${JSON.stringify(spec, null, 2)}\n`);
16
+
17
+ const b = await enqueueTask(root, { queue, title: 'OpenReel B-01', task: 'Project openreel requirement B-01', projectId: 'openreel', sourceChannel: 'test', sourceTarget: 'owner' });
18
+ const checkpointDir = path.join(taskRuntimeDirFor(root, queue, b.task.id), 'checkpoints');
19
+ await mkdir(checkpointDir, { recursive: true });
20
+ await writeFile(path.join(checkpointDir, 'cp1.json'), `${JSON.stringify({ version: 1, task_id: b.task.id, checkpoint_id: 'cp1', milestone_id: 'B-01', requirement_ids: ['B-01'], status: 'needs_human_input', blockers: ['Authorize B-01'] }, null, 2)}\n`);
21
+ const notified = await notifyHumanInputRequests(root, { queue, notifyCommand: '/bin/true' });
22
+ assert.equal(notified.sent, 1);
23
+ assert.equal((await queueStatus(root, queue)).waiting, 1);
24
+ const gateFile = path.join(root, notified.results[0].ledger);
25
+ const gate = JSON.parse(await readFile(gateFile, 'utf8'));
26
+ assert.equal(gate.project_id, 'openreel');
27
+ assert.equal(gate.milestone_id, 'B-01');
28
+ assert.deepEqual(gate.requirement_ids, ['B-01']);
29
+ assert.equal(typeof gate.contract_hash, 'string');
30
+
31
+ spec.backlog[0] = { ...spec.backlog[0], required: false, status: 'out_of_scope', disposition: 'canceled_by_owner' };
32
+ await writeFile(projectFile, `${JSON.stringify(spec, null, 2)}\n`);
33
+ const status = await queueStatus(root, queue);
34
+ assert.equal(status.waiting, 0, 'B-01 waiting gate must disappear after B-01 leaves project scope');
35
+ assert.equal(status.canceled, 1);
36
+ assert.equal(JSON.parse(await readFile(gateFile, 'utf8')).status, 'canceled');
37
+
38
+ const other = await enqueueTask(root, { queue, title: 'Other project task', task: 'Project other', projectId: 'other' });
39
+ const openreel = await enqueueTask(root, { queue, title: 'OpenReel target', task: 'Project openreel', projectId: 'openreel' });
40
+ await rename(path.join(root, other.file), path.join(root, 'runtime', 'loops', queue, 'active', path.basename(other.file)));
41
+ await rename(path.join(root, openreel.file), path.join(root, 'runtime', 'loops', queue, 'active', path.basename(openreel.file)));
42
+ const replacement = await routeLoopMessage(root, { route: true, confirmExecute: true, supersedeActive: true, queue, message: '走 loop:继续 openreel 项目' });
43
+ assert.equal(replacement.supersededTaskId, openreel.task.id);
44
+ assert.equal(await readFile(path.join(taskRuntimeDirFor(root, queue, other.task.id), 'supersede_request.json'), 'utf8').then(() => true, () => false), false);
45
+
46
+ const invalidGate = { ...gate, gate_id: `${openreel.task.id}:bad`, task_id: openreel.task.id, checkpoint_id: 'bad', status: 'waiting_for_human', requirement_ids: ['MISSING'] };
47
+ const invalidFile = path.join(root, 'runtime', 'loops', queue, 'human-input', 'gates', `${openreel.task.id}.bad.json`);
48
+ await writeFile(invalidFile, `${JSON.stringify(invalidGate, null, 2)}\n`);
49
+ const doctor = await doctorReport(root);
50
+ assert.equal(doctor.ok, false);
51
+ assert(doctor.checks.some((check) => check.id === `human-gate:${invalidGate.gate_id}` && !check.ok));
52
+ await reconcileProjectGates(root, { queue });
53
+
54
+ // project-status treats the configured ledger/backlog as authoritative and
55
+ // exposes registry drift instead of silently reporting stale completion data.
56
+ const authoritativeBacklog = path.join(root, 'project', 'backlog.json');
57
+ const authoritativeLedger = path.join(root, 'project', 'acceptance-ledger.json');
58
+ await mkdir(path.dirname(authoritativeBacklog), { recursive: true });
59
+ await writeFile(authoritativeBacklog, `${JSON.stringify({ status: 'ongoing', items: [{ id: 'S-01', required: true, status: 'accepted' }] }, null, 2)}\n`);
60
+ await writeFile(authoritativeLedger, `${JSON.stringify({ status: 'ongoing', unmet: ['S-01'], blockers: [{ id: 'S-01' }] }, null, 2)}\n`);
61
+ await writeFile(projectFile, `${JSON.stringify({ ...spec, backlogSource: 'project/backlog.json', acceptanceLedger: 'project/acceptance-ledger.json', terminalContract: 'project/terminal.md' }, null, 2)}\n`);
62
+ const drifted = await projectStatus(root, { project: 'openreel' });
63
+ assert.equal(drifted.projectCompletion, 'in_progress');
64
+ assert.equal(drifted.authority.acceptanceLedger, 'project/acceptance-ledger.json');
65
+ assert.equal(drifted.consistency.ok, false);
66
+ assert(drifted.needsAttention.includes('authoritative_source_drift'));
67
+
68
+ // A ready milestone with project in progress and a deferred authorization is
69
+ // converted into a structured waiting gate, not left as prose on a done task.
70
+ const deferred = await enqueueTask(root, { queue, title: 'OpenReel deferred S-01', task: 'Project openreel S-01', projectId: 'openreel', sourceChannel: 'test', sourceTarget: 'owner' });
71
+ const deferredDir = path.join(taskRuntimeDirFor(root, queue, deferred.task.id), 'checkpoints');
72
+ await mkdir(deferredDir, { recursive: true });
73
+ await writeFile(path.join(deferredDir, 'cp-ready.json'), `${JSON.stringify({
74
+ version: 1, task_id: deferred.task.id, checkpoint_id: 'cp-ready', milestone_id: 'S-01', requirement_ids: ['S-01'],
75
+ status: 'ready_for_acceptance', blockers: [], verification: ['local phase passed'], risks: [],
76
+ project_completion: { status: 'in_progress' },
77
+ deferred_gates: [{ id: 'S-01-production', action: 'production_rollback_drill', required_authority: 'Owner authorization for the exact production rollback drill scope.' }]
78
+ }, null, 2)}\n`);
79
+ const deferredNotice = await notifyHumanInputRequests(root, { queue, notifyCommand: '/bin/true' });
80
+ const deferredResult = deferredNotice.results.find((item) => item.taskId === deferred.task.id);
81
+ assert.equal(deferredResult.outcome, 'sent');
82
+ const deferredGate = JSON.parse(await readFile(path.join(root, deferredResult.ledger), 'utf8'));
83
+ assert.equal(deferredGate.gate_kind, 'deferred_authorization');
84
+ assert.equal(deferredGate.authorization_requirements[0].action, 'production_rollback_drill');
85
+ assert.match(deferredGate.authorization_requirements[0].required_authority, /Owner authorization/);
86
+ assert.equal((await queueStatus(root, queue)).waiting >= 1, true);
87
+
88
+ // Once the authoritative project ledger accepts the terminal contract, an
89
+ // optional post-completion deferred action stays in operations backlog and
90
+ // neither creates nor retains a project-queue waiting gate.
91
+ await writeFile(authoritativeLedger, `${JSON.stringify({ status: 'accepted', unmet: [], blockers: [] }, null, 2)}\n`);
92
+ await reconcileProjectGates(root, { queue });
93
+ assert.equal((await queueStatus(root, queue)).waiting, 0);
94
+ assert.equal(JSON.parse(await readFile(path.join(root, deferredResult.ledger), 'utf8')).status, 'superseded');
95
+ const acceptedOptional = await enqueueTask(root, { queue, title: 'OpenReel optional operations transfer', task: 'Project openreel optional post-completion transfer', projectId: 'openreel', sourceChannel: 'test', sourceTarget: 'owner' });
96
+ const acceptedOptionalDir = path.join(taskRuntimeDirFor(root, queue, acceptedOptional.task.id), 'checkpoints');
97
+ await mkdir(acceptedOptionalDir, { recursive: true });
98
+ await writeFile(path.join(acceptedOptionalDir, 'cp1.json'), `${JSON.stringify({
99
+ version: 1, task_id: acceptedOptional.task.id, checkpoint_id: 'cp1', milestone_id: 'cp1',
100
+ status: 'ready_for_acceptance', blockers: [], project_completion: { status: 'accepted' },
101
+ deferred_gates: [{ id: 'optional-transfer', required_authority: 'Separate authorization for optional production transfer.' }]
102
+ }, null, 2)}\n`);
103
+ const acceptedNotice = await notifyHumanInputRequests(root, { queue, notifyCommand: '/bin/true' });
104
+ assert.equal(acceptedNotice.results.some((item) => item.taskId === acceptedOptional.task.id), false);
105
+ assert.equal((await queueStatus(root, queue)).waiting, 0);
106
+
107
+ console.log(JSON.stringify({ status: 'ok', assertions: ['structured gate context', 'B-01 waiting to zero', 'project-isolated supersede', 'doctor strong validation', 'authoritative ledger drift', 'ready milestone deferred gate', 'accepted project optional deferred gate stays out of queue'] }));
@@ -89,6 +89,27 @@ const contract = await readJson(path.join(taskRuntimeDirFor(root, queue, routed.
89
89
  assert.equal(contract.risk_level, 'model_assessed');
90
90
  assert.equal(contract.requires_human_gate, false);
91
91
 
92
+ const largeBodyQueue = 'large-body-smoke';
93
+ const largeBody = `走 loop 验证超长任务正文\n${'checkpoint evidence '.repeat(10_000)}`;
94
+ const largeBodyRouted = await routeLoopMessage(root, {
95
+ route: true,
96
+ confirmExecute: true,
97
+ queue: largeBodyQueue,
98
+ message: largeBody,
99
+ sourceChannel: 'feishu',
100
+ sourceTarget: 'user-1'
101
+ });
102
+ const largeBodyRun = await runQueueOnce(root, {
103
+ queue: largeBodyQueue,
104
+ dispatcher: `node -e "const fs=require('fs');const t=JSON.parse(fs.readFileSync(process.env.LOOP_TASK_FILE,'utf8'));if(process.env.LOOP_TASK_BODY!==undefined||process.env.LOOP_TASK_BODY_MODE!=='task_file'||t.body.length<100000)process.exit(7)"`,
105
+ progressNotifyCommand: '/bin/true',
106
+ timeoutMs: 10_000,
107
+ leaseMs: 20_000,
108
+ staleActiveMs: 60_000
109
+ });
110
+ assert.equal(largeBodyRun.processed, true);
111
+ assert.equal(largeBodyRun.run.dispatch.exitCode, 0);
112
+
92
113
  const orphanQueue = 'orphan-recovery-smoke';
93
114
  const orphanRouted = await routeLoopMessage(root, {
94
115
  route: true,
@@ -483,5 +504,35 @@ assert.equal(sent.sent, 1);
483
504
  const repeated = await notifyTerminalTasks(root, { queue, notifyCommand: '/bin/true' });
484
505
  assert.equal(repeated.results[0].outcome, 'already_notified');
485
506
 
507
+ // Real directory-level regression: terminal history plus the newest project
508
+ // carrier yields exactly one durable gate, one waiting task, and zero replay.
509
+ const regressionRoot = await mkdtemp(path.join(tmpdir(), 'loop-gate-regression-'));
510
+ const regressionQueue = 'project-regression';
511
+ await writeJson(path.join(regressionRoot, 'configs', 'loops', 'projects', 'demo.json'), {
512
+ schemaVersion: 1, project: 'demo', queues: [{ queue: regressionQueue }],
513
+ backlog: [{ id: 'R-1', status: 'human_gated', required: true }]
514
+ });
515
+ for (const [id, enqueuedAt] of [['history-done', '2026-01-01T00:00:00Z'], ['latest-done', '2026-01-02T00:00:00Z']]) {
516
+ await writeJson(path.join(queueSubdirFor(regressionRoot, regressionQueue, 'done'), `${id}.json`), {
517
+ id, title: `demo ${id}`, body: 'demo R-1', projectId: 'demo', status: 'completed', enqueuedAt,
518
+ source: { channel: 'test', target: 'owner' }
519
+ });
520
+ await writeJson(path.join(taskRuntimeDirFor(regressionRoot, regressionQueue, id), 'checkpoints', 'cp1.json'), {
521
+ version: 1, task_id: id, checkpoint_id: 'cp1', milestone_id: 'R-1', sequence: 1,
522
+ status: 'ready_for_acceptance', blockers: [], deferred_gates: [{ id: 'R-1', required_authority: 'Approve R-1.' }],
523
+ verification: [], risks: [], project_completion: 'in_progress', next_action: 'wait'
524
+ });
525
+ await writeJson(path.join(taskRuntimeDirFor(regressionRoot, regressionQueue, id), 'final_judgement.json'), {
526
+ version: 1, task_id: id, outcome: 'project_in_progress', coverage: { effective_review_ids: ['cp1'] }
527
+ });
528
+ }
529
+ const regressionFirst = await notifyHumanInputRequests(regressionRoot, { queue: regressionQueue, notifyCommand: '/bin/true' });
530
+ assert.equal(regressionFirst.sent, 1);
531
+ assert.equal((await queueStatus(regressionRoot, regressionQueue)).waiting, 1);
532
+ assert.equal((await readdir(path.join(queueDirFor(regressionRoot, regressionQueue), 'human-input', 'gates'))).length, 1);
533
+ assert.equal((await readdir(queueSubdirFor(regressionRoot, regressionQueue, 'done'))).length, 1);
534
+ const regressionRepeated = await notifyHumanInputRequests(regressionRoot, { queue: regressionQueue, notifyCommand: '/bin/true' });
535
+ assert.equal(regressionRepeated.sent, 0);
536
+
486
537
  console.log('route/notify self-test passed');
487
538
  await import('./config-drift-self-test.mjs');
@@ -0,0 +1,21 @@
1
+ import assert from 'node:assert/strict';
2
+ import { AdapterError, createClaudeCodeAdapter, createCodexCliAdapter, createHermesAdapter, createMemoryTransport, createOpenClawAdapter, validateAdapter } from '../lib/runtime-adapter-sdk.mjs';
3
+
4
+ export async function conform(factory) {
5
+ const transport = createMemoryTransport(); const adapter = validateAdapter(factory(transport));
6
+ const session = await adapter.createSession({ key: 'offline-demo', metadata: { apiKey: 'must-not-leak' } });
7
+ const run = await adapter.startRun({ sessionId: session.sessionId, requestId: 'request-1', input: { prompt: 'local only' } });
8
+ await adapter.recordStep({ runId: run.runId, stepId: 'step-1', evidence: [{ local: true, token: 'hidden' }] });
9
+ await assert.rejects(adapter.prepareEffect({ runId: run.runId, effectId: 'send', idempotencyKey: 'send:1' }), (error) => error instanceof AdapterError && error.code === 'EFFECT_NOT_AUTHORIZED');
10
+ const effect = await adapter.prepareEffect({ runId: run.runId, effectId: 'write-local', idempotencyKey: 'write:1', authorized: true, payload: { password: 'hidden' } });
11
+ assert.equal(effect.state, 'authorized'); assert.equal(effect.payload.password, '[REDACTED]');
12
+ await adapter.resolveGate({ gateId: 'gate-1', decision: 'approved', responseRef: 'local-ref' });
13
+ const beat = await adapter.heartbeat({ runId: run.runId });
14
+ assert.equal((await adapter.continueRun({ runId: run.runId, continuationToken: beat.continuationToken })).status, 'running');
15
+ assert.equal(JSON.stringify(adapter.telemetry).includes('must-not-leak'), false);
16
+ return { runtime: adapter.runtime, version: adapter.version, capabilities: adapter.capabilities, assertions: 11 };
17
+ }
18
+
19
+ const results = [];
20
+ for (const factory of [createOpenClawAdapter, createHermesAdapter, createCodexCliAdapter, createClaudeCodeAdapter]) results.push(await conform(factory));
21
+ console.log(JSON.stringify({ status: 'passed', boundary: 'credential-free simulated transport', results }));
@@ -0,0 +1,20 @@
1
+ name: production-trust
2
+ on:
3
+ pull_request:
4
+ workflow_dispatch:
5
+ jobs:
6
+ deterministic-canary:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v4
10
+ - uses: actions/setup-node@v4
11
+ with:
12
+ node-version: 22
13
+ - run: npm install --ignore-scripts --no-audit --no-fund
14
+ working-directory: packages/loop-engineering
15
+ - run: npm run check:production-trust
16
+ working-directory: packages/loop-engineering
17
+ - uses: actions/upload-artifact@v4
18
+ with:
19
+ name: production-trust-evidence
20
+ path: packages/loop-engineering/.production-evidence/
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/ambitioncn/taskforce-loop-engineering/schemas/production-evidence-v1.json",
4
+ "title": "Loop Engineering production trust evidence",
5
+ "type": "object",
6
+ "required": ["schema", "schema_version", "generated_at", "scenarios", "compatibility", "metrics", "thresholds", "evaluation", "integrity", "passed"],
7
+ "properties": {
8
+ "schema": { "const": "loop.production_trust_evidence" },
9
+ "schema_version": { "const": 1 },
10
+ "generated_at": { "type": "string", "format": "date-time" },
11
+ "scenarios": { "type": "array", "minItems": 8 },
12
+ "compatibility": { "type": "array", "minItems": 3 },
13
+ "metrics": { "type": "object" },
14
+ "thresholds": { "type": "object" },
15
+ "evaluation": { "type": "object", "required": ["checks", "trend", "passed"] },
16
+ "integrity": { "type": "object", "required": ["algorithm", "digest"] },
17
+ "passed": { "type": "boolean" }
18
+ },
19
+ "additionalProperties": true
20
+ }