nubos-pilot 0.9.4 → 0.9.5
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.
|
@@ -11,27 +11,53 @@ const { deleteCheckpoint, readCheckpoint } = require('../../lib/checkpoint.cjs')
|
|
|
11
11
|
|
|
12
12
|
const BYPASS_FLAG = '--bypass-nubosloop';
|
|
13
13
|
|
|
14
|
+
// Evidence-based gate: a complete Nubosloop run accumulates fields on the
|
|
15
|
+
// checkpoint envelope (cache_hit from preflight, verify_exit_code from
|
|
16
|
+
// post-executor, findings from post-critics, committed_at from commit). A
|
|
17
|
+
// gamed run that only invokes `loop-run-round --phase commit` directly leaves
|
|
18
|
+
// verify_exit_code and findings undefined. Checking last_phase alone is not
|
|
19
|
+
// enough — we require the cumulative signature.
|
|
14
20
|
function _assertLoopGate(taskId, cwd, bypass, stderr) {
|
|
15
21
|
const cp = readCheckpoint(taskId, cwd);
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
22
|
+
const np = (cp && cp.nubosloop) || null;
|
|
23
|
+
const last = np && np.last_phase;
|
|
24
|
+
const checks = [
|
|
25
|
+
{ ok: !!cp, reason: 'no-checkpoint', missing: 'checkpoint', observed: 'no-checkpoint' },
|
|
26
|
+
{ ok: last === 'commit', reason: 'last-phase-mismatch', missing: 'last_phase=commit', observed: last || 'none' },
|
|
27
|
+
{ ok: np && np.verify_exit_code === 0, reason: 'post-executor-not-green', missing: 'verify_exit_code=0', observed: np && np.verify_exit_code !== undefined ? String(np.verify_exit_code) : 'undefined' },
|
|
28
|
+
{ ok: np && Array.isArray(np.findings), reason: 'post-critics-missing', missing: 'findings (array)', observed: np && np.findings !== undefined ? JSON.stringify(np.findings).slice(0, 60) : 'undefined' },
|
|
29
|
+
{ ok: np && !!np.committed_at, reason: 'commit-phase-not-stamped', missing: 'committed_at', observed: (np && np.committed_at) || 'undefined' },
|
|
30
|
+
];
|
|
31
|
+
const failed = checks.find((c) => !c.ok);
|
|
32
|
+
if (!failed) {
|
|
33
|
+
return { bypassed: false, last_phase: last, forced_commit_phase: !!(np && np.forced_commit_phase) };
|
|
34
|
+
}
|
|
20
35
|
if (bypass) {
|
|
21
36
|
stderr.write(
|
|
22
37
|
'[nubos-pilot] WARNING: commit-task ' + taskId +
|
|
23
|
-
' bypassing Nubosloop gate (' + BYPASS_FLAG +
|
|
38
|
+
' bypassing Nubosloop gate (' + BYPASS_FLAG +
|
|
39
|
+
'; reason=' + failed.reason + '; missing=' + failed.missing +
|
|
40
|
+
'; observed=' + failed.observed +
|
|
24
41
|
'). Single-pass commit, no critic review enforced.\n',
|
|
25
42
|
);
|
|
26
|
-
return { bypassed: true, last_phase: last || null };
|
|
43
|
+
return { bypassed: true, last_phase: last || null, forced_commit_phase: !!(np && np.forced_commit_phase) };
|
|
27
44
|
}
|
|
28
45
|
throw new NubosPilotError(
|
|
29
46
|
'commit-task-loop-bypass-violation',
|
|
30
|
-
'commit-task refused: Nubosloop
|
|
31
|
-
' (
|
|
32
|
-
'
|
|
47
|
+
'commit-task refused: Nubosloop sequence incomplete for ' + taskId +
|
|
48
|
+
' (reason=' + failed.reason + '; missing=' + failed.missing +
|
|
49
|
+
'; observed=' + failed.observed + '). ' +
|
|
50
|
+
'Run the full loop (preflight → post-executor verify-green → post-critics → commit) first, or pass ' + BYPASS_FLAG +
|
|
33
51
|
' for an explicit single-pass override.',
|
|
34
|
-
{
|
|
52
|
+
{
|
|
53
|
+
taskId,
|
|
54
|
+
reason: failed.reason,
|
|
55
|
+
missing: failed.missing,
|
|
56
|
+
observed_last_phase: last || null,
|
|
57
|
+
observed_verify_exit_code: np && np.verify_exit_code !== undefined ? np.verify_exit_code : null,
|
|
58
|
+
observed_findings_is_array: !!(np && Array.isArray(np.findings)),
|
|
59
|
+
observed_committed_at: (np && np.committed_at) || null,
|
|
60
|
+
},
|
|
35
61
|
);
|
|
36
62
|
}
|
|
37
63
|
|
|
@@ -141,6 +167,7 @@ function run(args, ctx) {
|
|
|
141
167
|
files: safeFiles,
|
|
142
168
|
files_source: filesSource,
|
|
143
169
|
nubosloop_bypassed: gate.bypassed,
|
|
170
|
+
nubosloop_forced_commit_phase: !!gate.forced_commit_phase,
|
|
144
171
|
};
|
|
145
172
|
stdout.write(JSON.stringify(payload));
|
|
146
173
|
return payload;
|
|
@@ -82,9 +82,10 @@ function _capture() {
|
|
|
82
82
|
return { stub, get: () => buf };
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
// Seed a checkpoint that satisfies the Nubosloop gate (
|
|
86
|
-
//
|
|
87
|
-
//
|
|
85
|
+
// Seed a checkpoint that satisfies the full Nubosloop gate (sequence-integrity).
|
|
86
|
+
// A real loop accumulates evidence on the envelope; the gate refuses unless
|
|
87
|
+
// every required marker is present. Tests that exercise game-paths build their
|
|
88
|
+
// own partial fixtures.
|
|
88
89
|
function seedLoopReadyCheckpoint(root, taskId, extra) {
|
|
89
90
|
const cpPath = path.join(root, '.nubos-pilot', 'checkpoints', taskId + '.json');
|
|
90
91
|
fs.mkdirSync(path.dirname(cpPath), { recursive: true });
|
|
@@ -94,12 +95,21 @@ function seedLoopReadyCheckpoint(root, taskId, extra) {
|
|
|
94
95
|
status: 'pre-commit',
|
|
95
96
|
files_touched: [],
|
|
96
97
|
nubosloop: {
|
|
98
|
+
round: 1,
|
|
99
|
+
cache_hit: false,
|
|
97
100
|
last_phase: 'commit',
|
|
98
101
|
last_action: 'commit',
|
|
102
|
+
verify_exit_code: 0,
|
|
103
|
+
findings: [],
|
|
99
104
|
committed_at: '2026-05-04T12:00:00Z',
|
|
100
105
|
},
|
|
101
106
|
};
|
|
102
|
-
|
|
107
|
+
// Allow the test to override individual fields (incl. nubosloop sub-fields).
|
|
108
|
+
const merged = Object.assign({}, base, extra || {});
|
|
109
|
+
if (extra && extra.nubosloop) {
|
|
110
|
+
merged.nubosloop = Object.assign({}, base.nubosloop, extra.nubosloop);
|
|
111
|
+
}
|
|
112
|
+
fs.writeFileSync(cpPath, JSON.stringify(merged), 'utf-8');
|
|
103
113
|
return cpPath;
|
|
104
114
|
}
|
|
105
115
|
|
|
@@ -249,10 +259,112 @@ test('CT-9: refuse commit when nubosloop.last_phase ≠ commit', () => {
|
|
|
249
259
|
() => subcmd.run(['M006-S001-T0021'], { cwd: root, stdout: cap.stub, stderr: stderr.stub }),
|
|
250
260
|
(err) => err && err.code === 'commit-task-loop-bypass-violation'
|
|
251
261
|
&& err.details && err.details.reason === 'last-phase-mismatch'
|
|
252
|
-
&& err.details.
|
|
262
|
+
&& err.details.observed_last_phase === 'verifying',
|
|
263
|
+
);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test('CT-12: refuse gamed commit (last_phase=commit but no verify_exit_code)', () => {
|
|
267
|
+
const root = makeRepo();
|
|
268
|
+
seedPlanAndTask(root, '06-01', 'M006-S001-T0030', ['src/g.ts']);
|
|
269
|
+
fs.mkdirSync(path.join(root, 'src'), { recursive: true });
|
|
270
|
+
fs.writeFileSync(path.join(root, 'src', 'g.ts'), 'export const g = 7;\n', 'utf-8');
|
|
271
|
+
// Simulates an agent that ran ONLY `loop-run-round --phase commit` to game
|
|
272
|
+
// the gate, without going through preflight/post-executor/post-critics.
|
|
273
|
+
// verify_exit_code is undefined → post-executor never ran.
|
|
274
|
+
const cpPath = path.join(root, '.nubos-pilot', 'checkpoints', 'M006-S001-T0030.json');
|
|
275
|
+
fs.mkdirSync(path.dirname(cpPath), { recursive: true });
|
|
276
|
+
fs.writeFileSync(cpPath, JSON.stringify({
|
|
277
|
+
schema_version: 1,
|
|
278
|
+
task_id: 'M006-S001-T0030',
|
|
279
|
+
status: 'pre-commit',
|
|
280
|
+
files_touched: [],
|
|
281
|
+
nubosloop: { last_phase: 'commit', last_action: 'commit', committed_at: '2026-05-04T12:00:00Z' },
|
|
282
|
+
}), 'utf-8');
|
|
283
|
+
const cap = _capture();
|
|
284
|
+
const stderr = _capture();
|
|
285
|
+
assert.throws(
|
|
286
|
+
() => subcmd.run(['M006-S001-T0030'], { cwd: root, stdout: cap.stub, stderr: stderr.stub }),
|
|
287
|
+
(err) => err && err.code === 'commit-task-loop-bypass-violation'
|
|
288
|
+
&& err.details && err.details.reason === 'post-executor-not-green',
|
|
289
|
+
);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test('CT-13: refuse gamed commit when verify ran but post-critics findings missing', () => {
|
|
293
|
+
const root = makeRepo();
|
|
294
|
+
seedPlanAndTask(root, '06-01', 'M006-S001-T0031', ['src/h.ts']);
|
|
295
|
+
fs.mkdirSync(path.join(root, 'src'), { recursive: true });
|
|
296
|
+
fs.writeFileSync(path.join(root, 'src', 'h.ts'), 'export const h = 8;\n', 'utf-8');
|
|
297
|
+
// verify ran (exit_code=0) but critics never produced findings — agent
|
|
298
|
+
// skipped the critic-schwarm step.
|
|
299
|
+
const cpPath = path.join(root, '.nubos-pilot', 'checkpoints', 'M006-S001-T0031.json');
|
|
300
|
+
fs.mkdirSync(path.dirname(cpPath), { recursive: true });
|
|
301
|
+
fs.writeFileSync(cpPath, JSON.stringify({
|
|
302
|
+
schema_version: 1,
|
|
303
|
+
task_id: 'M006-S001-T0031',
|
|
304
|
+
status: 'pre-commit',
|
|
305
|
+
files_touched: [],
|
|
306
|
+
nubosloop: {
|
|
307
|
+
last_phase: 'commit', last_action: 'commit',
|
|
308
|
+
verify_exit_code: 0, // post-executor ran
|
|
309
|
+
committed_at: '2026-05-04T12:00:00Z',
|
|
310
|
+
// findings: missing → post-critics never ran
|
|
311
|
+
},
|
|
312
|
+
}), 'utf-8');
|
|
313
|
+
const cap = _capture();
|
|
314
|
+
const stderr = _capture();
|
|
315
|
+
assert.throws(
|
|
316
|
+
() => subcmd.run(['M006-S001-T0031'], { cwd: root, stdout: cap.stub, stderr: stderr.stub }),
|
|
317
|
+
(err) => err && err.code === 'commit-task-loop-bypass-violation'
|
|
318
|
+
&& err.details && err.details.reason === 'post-critics-missing',
|
|
319
|
+
);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
test('CT-14: refuse when verify-red was recorded (post-executor failed)', () => {
|
|
323
|
+
const root = makeRepo();
|
|
324
|
+
seedPlanAndTask(root, '06-01', 'M006-S001-T0032', ['src/i.ts']);
|
|
325
|
+
fs.mkdirSync(path.join(root, 'src'), { recursive: true });
|
|
326
|
+
fs.writeFileSync(path.join(root, 'src', 'i.ts'), 'export const i = 9;\n', 'utf-8');
|
|
327
|
+
// Loop reached commit-stamp somehow but verify was red — must refuse.
|
|
328
|
+
seedLoopReadyCheckpoint(root, 'M006-S001-T0032', {
|
|
329
|
+
nubosloop: { verify_exit_code: 1 },
|
|
330
|
+
});
|
|
331
|
+
const cap = _capture();
|
|
332
|
+
const stderr = _capture();
|
|
333
|
+
assert.throws(
|
|
334
|
+
() => subcmd.run(['M006-S001-T0032'], { cwd: root, stdout: cap.stub, stderr: stderr.stub }),
|
|
335
|
+
(err) => err && err.code === 'commit-task-loop-bypass-violation'
|
|
336
|
+
&& err.details && err.details.reason === 'post-executor-not-green'
|
|
337
|
+
&& err.details.observed_verify_exit_code === 1,
|
|
253
338
|
);
|
|
254
339
|
});
|
|
255
340
|
|
|
341
|
+
test('CT-15: bypass on gamed commit logs precise reason in stderr', () => {
|
|
342
|
+
const root = makeRepo();
|
|
343
|
+
seedPlanAndTask(root, '06-01', 'M006-S001-T0033', ['src/j.ts']);
|
|
344
|
+
fs.mkdirSync(path.join(root, 'src'), { recursive: true });
|
|
345
|
+
fs.writeFileSync(path.join(root, 'src', 'j.ts'), 'export const j = 10;\n', 'utf-8');
|
|
346
|
+
const cpPath = path.join(root, '.nubos-pilot', 'checkpoints', 'M006-S001-T0033.json');
|
|
347
|
+
fs.mkdirSync(path.dirname(cpPath), { recursive: true });
|
|
348
|
+
fs.writeFileSync(cpPath, JSON.stringify({
|
|
349
|
+
schema_version: 1, task_id: 'M006-S001-T0033', status: 'pre-commit', files_touched: [],
|
|
350
|
+
nubosloop: { last_phase: 'commit', last_action: 'commit', committed_at: 'z' },
|
|
351
|
+
}), 'utf-8');
|
|
352
|
+
const prev = process.cwd();
|
|
353
|
+
process.chdir(root);
|
|
354
|
+
const cap = _capture();
|
|
355
|
+
const stderr = _capture();
|
|
356
|
+
try {
|
|
357
|
+
subcmd.run(['M006-S001-T0033', '--bypass-nubosloop'], { cwd: root, stdout: cap.stub, stderr: stderr.stub });
|
|
358
|
+
} finally {
|
|
359
|
+
process.chdir(prev);
|
|
360
|
+
}
|
|
361
|
+
const payload = JSON.parse(cap.get());
|
|
362
|
+
assert.equal(payload.ok, true);
|
|
363
|
+
assert.equal(payload.nubosloop_bypassed, true);
|
|
364
|
+
assert.match(stderr.get(), /reason=post-executor-not-green/);
|
|
365
|
+
assert.match(stderr.get(), /missing=verify_exit_code=0/);
|
|
366
|
+
});
|
|
367
|
+
|
|
256
368
|
test('CT-10: --bypass-nubosloop allows single-pass commit and warns on stderr', () => {
|
|
257
369
|
const root = makeRepo();
|
|
258
370
|
seedPlanAndTask(root, '06-01', 'M006-S001-T0022', ['src/e.ts']);
|
|
@@ -467,6 +467,79 @@ test('LCLI-RR-7: loop-run-round rejects unknown --phase', () => {
|
|
|
467
467
|
);
|
|
468
468
|
});
|
|
469
469
|
|
|
470
|
+
test('LCLI-RR-8: phase=commit refuses without verify_exit_code (post-executor never ran)', () => {
|
|
471
|
+
const r = _mkRoot();
|
|
472
|
+
checkpoint.startTask({ id: 'M001-S001-T0001' }, r);
|
|
473
|
+
const loopRunRound = require('./loop-run-round.cjs');
|
|
474
|
+
assert.throws(
|
|
475
|
+
() => loopRunRound.run(
|
|
476
|
+
['M001-S001-T0001', '--phase', 'commit'],
|
|
477
|
+
{ cwd: r, stdout: _cap().stub },
|
|
478
|
+
),
|
|
479
|
+
(err) => err && err.code === 'loop-commit-precondition-missing'
|
|
480
|
+
&& err.details && err.details.missing === 'verify_exit_code',
|
|
481
|
+
);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
test('LCLI-RR-9: phase=commit refuses without findings (post-critics never ran)', () => {
|
|
485
|
+
const r = _mkRoot();
|
|
486
|
+
checkpoint.startTask({ id: 'M001-S001-T0001' }, r);
|
|
487
|
+
const nubosloop = require('../../lib/nubosloop.cjs');
|
|
488
|
+
// post-executor ran (verify-green) but critics never produced findings.
|
|
489
|
+
nubosloop.recordLoopState('M001-S001-T0001', { round: 1 }, r);
|
|
490
|
+
checkpoint.mergeCheckpoint('M001-S001-T0001', (cur) => ({
|
|
491
|
+
nubosloop: Object.assign({}, (cur && cur.nubosloop) || {}, { verify_exit_code: 0 }),
|
|
492
|
+
}), r);
|
|
493
|
+
const loopRunRound = require('./loop-run-round.cjs');
|
|
494
|
+
assert.throws(
|
|
495
|
+
() => loopRunRound.run(
|
|
496
|
+
['M001-S001-T0001', '--phase', 'commit'],
|
|
497
|
+
{ cwd: r, stdout: _cap().stub },
|
|
498
|
+
),
|
|
499
|
+
(err) => err && err.code === 'loop-commit-precondition-missing'
|
|
500
|
+
&& err.details && err.details.missing === 'findings',
|
|
501
|
+
);
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
test('LCLI-RR-10: phase=commit accepts complete loop state (verify-green + findings array)', () => {
|
|
505
|
+
const r = _mkRoot();
|
|
506
|
+
checkpoint.startTask({ id: 'M001-S001-T0001' }, r);
|
|
507
|
+
const nubosloop = require('../../lib/nubosloop.cjs');
|
|
508
|
+
nubosloop.recordLoopState('M001-S001-T0001', { round: 1 }, r);
|
|
509
|
+
checkpoint.mergeCheckpoint('M001-S001-T0001', (cur) => ({
|
|
510
|
+
nubosloop: Object.assign({}, (cur && cur.nubosloop) || {}, {
|
|
511
|
+
verify_exit_code: 0,
|
|
512
|
+
findings: [],
|
|
513
|
+
}),
|
|
514
|
+
}), r);
|
|
515
|
+
const cap = _cap();
|
|
516
|
+
const loopRunRound = require('./loop-run-round.cjs');
|
|
517
|
+
loopRunRound.run(['M001-S001-T0001', '--phase', 'commit'], { cwd: r, stdout: cap.stub });
|
|
518
|
+
const out = JSON.parse(cap.get());
|
|
519
|
+
assert.equal(out.next_action, 'commit-task');
|
|
520
|
+
assert.equal(out.forced, false);
|
|
521
|
+
const cp = checkpoint.readCheckpoint('M001-S001-T0001', r);
|
|
522
|
+
assert.equal(cp.nubosloop.last_phase, 'commit');
|
|
523
|
+
assert.equal(cp.nubosloop.forced_commit_phase, false);
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
test('LCLI-RR-11: phase=commit --force-commit-phase bypasses preconditions and stamps the override', () => {
|
|
527
|
+
const r = _mkRoot();
|
|
528
|
+
checkpoint.startTask({ id: 'M001-S001-T0001' }, r);
|
|
529
|
+
// Empty checkpoint — no verify, no findings. Force should still allow.
|
|
530
|
+
const cap = _cap();
|
|
531
|
+
const loopRunRound = require('./loop-run-round.cjs');
|
|
532
|
+
loopRunRound.run(
|
|
533
|
+
['M001-S001-T0001', '--phase', 'commit', '--force-commit-phase'],
|
|
534
|
+
{ cwd: r, stdout: cap.stub },
|
|
535
|
+
);
|
|
536
|
+
const out = JSON.parse(cap.get());
|
|
537
|
+
assert.equal(out.next_action, 'commit-task');
|
|
538
|
+
assert.equal(out.forced, true);
|
|
539
|
+
const cp = checkpoint.readCheckpoint('M001-S001-T0001', r);
|
|
540
|
+
assert.equal(cp.nubosloop.forced_commit_phase, true);
|
|
541
|
+
});
|
|
542
|
+
|
|
470
543
|
test('LCLI-22: learning-match queries the local store', () => {
|
|
471
544
|
const r = _mkRoot();
|
|
472
545
|
const lr = require('../../lib/learnings.cjs');
|
|
@@ -164,6 +164,43 @@ function _runPostCritics(taskId, list, cwd) {
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
function _runCommit(taskId, list, cwd) {
|
|
167
|
+
// Sequence-integrity guard: the commit phase MUST follow a complete loop run.
|
|
168
|
+
// Stamping last_phase='commit' is what unlocks commit-task, so without this
|
|
169
|
+
// check an agent could shell out `loop-run-round --phase commit` directly,
|
|
170
|
+
// skip preflight/executor/critics, and bypass the entire Nubosloop. The
|
|
171
|
+
// commit-task gate then sees a satisfied last_phase and lets the commit
|
|
172
|
+
// through. Defense-in-depth: refuse here AND in commit-task.
|
|
173
|
+
//
|
|
174
|
+
// Required evidence on the checkpoint envelope:
|
|
175
|
+
// - verify_exit_code === 0 → post-executor ran AND verify was green
|
|
176
|
+
// - findings is an array → post-critics ran (empty array = passed)
|
|
177
|
+
//
|
|
178
|
+
// Bypass for legitimate test fixtures / migration: --force-commit-phase.
|
|
179
|
+
const force = list.includes('--force-commit-phase');
|
|
180
|
+
if (!force) {
|
|
181
|
+
const cur = checkpoint.readCheckpoint(taskId, cwd) || {};
|
|
182
|
+
const np = (cur && cur.nubosloop) || {};
|
|
183
|
+
if (np.verify_exit_code !== 0) {
|
|
184
|
+
throw new NubosPilotError(
|
|
185
|
+
'loop-commit-precondition-missing',
|
|
186
|
+
'phase=commit refused: post-executor did not record a verify-green run for ' + taskId +
|
|
187
|
+
' (observed verify_exit_code=' + (np.verify_exit_code === undefined ? 'undefined' : np.verify_exit_code) + '). ' +
|
|
188
|
+
'Run `loop-run-round ' + taskId + ' --phase post-executor --verify-exit-code 0 --verify-output-path ...` first, ' +
|
|
189
|
+
'or pass --force-commit-phase for an explicit override.',
|
|
190
|
+
{ taskId, missing: 'verify_exit_code', observed: np.verify_exit_code === undefined ? null : np.verify_exit_code },
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
if (!Array.isArray(np.findings)) {
|
|
194
|
+
throw new NubosPilotError(
|
|
195
|
+
'loop-commit-precondition-missing',
|
|
196
|
+
'phase=commit refused: post-critics did not produce a findings array for ' + taskId +
|
|
197
|
+
' (observed findings=' + (np.findings === undefined ? 'undefined' : JSON.stringify(np.findings)) + '). ' +
|
|
198
|
+
'Run `loop-run-round ' + taskId + ' --phase post-critics --critic-outputs <json>` first, ' +
|
|
199
|
+
'or pass --force-commit-phase for an explicit override.',
|
|
200
|
+
{ taskId, missing: 'findings', observed: np.findings === undefined ? null : np.findings },
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
167
204
|
const pattern = args.getFlag(list, '--learning-pattern') || null;
|
|
168
205
|
const outcome = args.getFlag(list, '--learning-outcome') || 'verified';
|
|
169
206
|
let logged = null;
|
|
@@ -184,6 +221,7 @@ function _runCommit(taskId, list, cwd) {
|
|
|
184
221
|
last_phase: 'commit',
|
|
185
222
|
last_action: 'commit',
|
|
186
223
|
committed_at: new Date().toISOString(),
|
|
224
|
+
forced_commit_phase: force ? true : (cur && cur.nubosloop && cur.nubosloop.forced_commit_phase) || false,
|
|
187
225
|
}),
|
|
188
226
|
}),
|
|
189
227
|
cwd,
|
|
@@ -192,6 +230,7 @@ function _runCommit(taskId, list, cwd) {
|
|
|
192
230
|
phase: 'commit',
|
|
193
231
|
next_action: 'commit-task',
|
|
194
232
|
learning_logged: logged,
|
|
233
|
+
forced: force,
|
|
195
234
|
};
|
|
196
235
|
}
|
|
197
236
|
|