agentic-workflow-manager 9.12.0 → 9.12.2

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.
@@ -416,9 +416,12 @@ describe('supervisor loop', () => {
416
416
  });
417
417
  let spawned = 0;
418
418
  const sup = new supervisor_1.Supervisor(repo, 'main', supervisor_1.DEFAULT_SUPERVISOR_CONFIG, () => { spawned += 1; }, undefined, notCertified);
419
+ let now = Date.now();
420
+ jest.spyOn(Date, 'now').mockImplementation(() => now);
419
421
  for (let i = 0; i < supervisor_1.MAX_SENSOR_DEFERRALS; i += 1) {
420
422
  expect(await sup.tick()).toBe('continue');
421
423
  expect((0, store_1.readJournal)(repo, 'main').state.cycle.status).toBe('IN_PROGRESS');
424
+ now += 5000;
422
425
  }
423
426
  // The verdict never settled, so the supervisor must stop pretending it might.
424
427
  expect(await sup.tick()).toBe('custody');
@@ -443,6 +446,91 @@ describe('supervisor loop', () => {
443
446
  // Deferring dispatch was right throughout, and stays right.
444
447
  expect(spawned).toBe(0);
445
448
  });
449
+ test('unverifiable currentness retries durably across supervisor restart and does not spawn before admitted', async () => {
450
+ initUnattendedFixture(repo);
451
+ let now = Date.now();
452
+ jest.spyOn(Date, 'now').mockImplementation(() => now);
453
+ let verdict = 'unverifiable';
454
+ const observe = async () => verdict === 'unverifiable'
455
+ ? { state: 'blocked', planState: 'valid', executionMode: 'desatendido', journal: 'not-required', currentness: 'unverifiable', sensors: 'not-required', diagnostics: [{ code: 'ADMISSION_CURRENTNESS_BLOCKED', message: 'registry:baseline' }] }
456
+ : admitted();
457
+ let spawned = 0;
458
+ const spawn = () => { spawned += 1; };
459
+ expect(await new supervisor_1.Supervisor(repo, 'main', supervisor_1.DEFAULT_SUPERVISOR_CONFIG, spawn, undefined, observe, true).tick()).toBe('continue');
460
+ expect((0, store_1.readJournal)(repo, 'main').state).toHaveProperty('admissionRetry.attempts', 1);
461
+ expect((0, store_1.readJournal)(repo, 'main').state.generations).toHaveLength(0);
462
+ expect(spawned).toBe(0);
463
+ // New supervisor instance represents a process restart. Repeated early
464
+ // ticks cannot spend or reset the durable retry budget.
465
+ const restarted = new supervisor_1.Supervisor(repo, 'main', supervisor_1.DEFAULT_SUPERVISOR_CONFIG, spawn, undefined, observe, true);
466
+ expect(await restarted.tick()).toBe('continue');
467
+ expect((0, store_1.readJournal)(repo, 'main').state).toHaveProperty('admissionRetry.attempts', 1);
468
+ now += 5000;
469
+ verdict = 'current';
470
+ expect(await restarted.tick()).toBe('continue');
471
+ expect((0, store_1.readJournal)(repo, 'main').state).not.toHaveProperty('admissionRetry');
472
+ expect((0, store_1.readJournal)(repo, 'main').state.cycle.status).toBe('IN_PROGRESS');
473
+ expect((0, store_1.readJournal)(repo, 'main').state.generations).toHaveLength(1);
474
+ expect(spawned).toBeGreaterThan(0);
475
+ });
476
+ test('stale currentness is conclusive and never receives transient retry budget', async () => {
477
+ initUnattendedFixture(repo);
478
+ const blocked = async () => ({ state: 'blocked', planState: 'valid', executionMode: 'desatendido', journal: 'current', currentness: 'stale', sensors: 'not-required', diagnostics: [{ code: 'ADMISSION_CURRENTNESS_BLOCKED', message: 'stale' }] });
479
+ let spawned = 0;
480
+ expect(await new supervisor_1.Supervisor(repo, 'main', supervisor_1.DEFAULT_SUPERVISOR_CONFIG, () => { spawned++; }, undefined, blocked).tick()).toBe('custody');
481
+ const state = (0, store_1.readJournal)(repo, 'main').state;
482
+ expect(state.cycle.status).toBe('BLOCKED');
483
+ expect(state).not.toHaveProperty('admissionRetry');
484
+ expect(state.generations).toHaveLength(0);
485
+ expect(spawned).toBe(0);
486
+ });
487
+ test('first admission observation binds provider, runtime and autonomy; changed restart identity never dispatches', async () => {
488
+ initUnattendedFixture(repo);
489
+ const identity = { kind: 'native', version: '1.0.0', accountScopeDigest: 'a'.repeat(64) };
490
+ const cfg = { ...supervisor_1.DEFAULT_SUPERVISOR_CONFIG, routingIdentity: identity, controllerAutonomy: 'approval-free' };
491
+ const notCurrent = async () => ({ state: 'blocked', planState: 'valid', executionMode: 'desatendido', journal: 'not-required', currentness: 'unverifiable', sensors: 'not-required', diagnostics: [{ code: 'ADMISSION_CURRENTNESS_BLOCKED', message: 'temporary' }] });
492
+ let spawns = 0;
493
+ expect(await new supervisor_1.Supervisor(repo, 'main', cfg, () => { spawns++; }, undefined, notCurrent).tick()).toBe('continue');
494
+ expect((0, store_1.readJournal)(repo, 'main').state).toHaveProperty('admissionContext', { provider: 'codex', runtime: identity, controllerAutonomy: 'approval-free' });
495
+ const changed = { ...cfg, routingIdentity: { ...identity, accountScopeDigest: 'b'.repeat(64) } };
496
+ expect(await new supervisor_1.Supervisor(repo, 'main', changed, () => { spawns++; }, undefined, admitted).tick()).toBe('custody');
497
+ expect((0, store_1.readJournal)(repo, 'main').state.cycle.status).toBe('BLOCKED');
498
+ expect(spawns).toBe(0);
499
+ });
500
+ test('alternating transient causes share one durable retry budget', async () => {
501
+ initUnattendedFixture(repo);
502
+ let now = Date.now();
503
+ jest.spyOn(Date, 'now').mockImplementation(() => now);
504
+ let reads = 0;
505
+ const alternating = async () => {
506
+ const sensor = reads++ % 2 === 1;
507
+ return sensor
508
+ ? { state: 'blocked', planState: 'valid', executionMode: 'desatendido', journal: 'not-required', currentness: 'current', sensors: 'not-certified', diagnostics: [{ code: 'ADMISSION_SENSORS_BLOCKED', message: 'temporary' }] }
509
+ : { state: 'blocked', planState: 'valid', executionMode: 'desatendido', journal: 'not-required', currentness: 'unverifiable', sensors: 'not-required', diagnostics: [{ code: 'ADMISSION_CURRENTNESS_BLOCKED', message: 'temporary' }] };
510
+ };
511
+ let spawns = 0;
512
+ for (let i = 0; i < supervisor_1.MAX_SENSOR_DEFERRALS + 1; i++) {
513
+ const outcome = await new supervisor_1.Supervisor(repo, 'main', supervisor_1.DEFAULT_SUPERVISOR_CONFIG, () => { spawns++; }, undefined, alternating).tick();
514
+ expect(outcome).toBe(i < supervisor_1.MAX_SENSOR_DEFERRALS ? 'continue' : 'custody');
515
+ now += 5000;
516
+ }
517
+ expect(reads).toBe(supervisor_1.MAX_SENSOR_DEFERRALS + 1);
518
+ expect(spawns).toBe(0);
519
+ expect((0, store_1.readJournal)(repo, 'main').state.generations).toHaveLength(0);
520
+ });
521
+ test('an incomplete first configuration can be corrected before dispatch without trapping the cycle', async () => {
522
+ initUnattendedFixture(repo);
523
+ const notCurrent = async () => ({ state: 'blocked', planState: 'valid', executionMode: 'desatendido', journal: 'not-required', currentness: 'unverifiable', sensors: 'not-required', diagnostics: [{ code: 'ADMISSION_CURRENTNESS_BLOCKED', message: 'temporary' }] });
524
+ let spawned = 0;
525
+ expect(await new supervisor_1.Supervisor(repo, 'main', supervisor_1.DEFAULT_SUPERVISOR_CONFIG, () => { spawned++; }, undefined, notCurrent).tick()).toBe('continue');
526
+ expect((0, store_1.readJournal)(repo, 'main').state).not.toHaveProperty('admissionContext');
527
+ const cfg = { ...supervisor_1.DEFAULT_SUPERVISOR_CONFIG, routingIdentity: { kind: 'native', version: '1.0.0', accountScopeDigest: 'a'.repeat(64) }, controllerAutonomy: 'approval-free' };
528
+ const retry = (0, store_1.readJournal)(repo, 'main').state.admissionRetry;
529
+ jest.spyOn(Date, 'now').mockReturnValue(Date.parse(retry.nextRetryAt));
530
+ expect(await new supervisor_1.Supervisor(repo, 'main', cfg, () => { spawned++; }, undefined, admitted, true).tick()).toBe('continue');
531
+ expect((0, store_1.readJournal)(repo, 'main').state).toHaveProperty('admissionContext', { provider: 'codex', runtime: cfg.routingIdentity, controllerAutonomy: 'approval-free' });
532
+ expect(spawned).toBeGreaterThan(0);
533
+ });
446
534
  test('una admisión compacta bloqueada no lanza controlador ni wrappers', async () => {
447
535
  initUnattendedFixture(repo);
448
536
  const state = (0, store_1.readJournal)(repo, 'main').state;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-workflow-manager",
3
- "version": "9.12.0",
3
+ "version": "9.12.2",
4
4
  "main": "dist/src/index.js",
5
5
  "bin": {
6
6
  "awm": "./dist/src/index.js"
Binary file
Binary file