@nathapp/nax 0.68.4 → 0.68.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.
Files changed (2) hide show
  1. package/dist/nax.js +75 -46
  2. package/package.json +1 -1
package/dist/nax.js CHANGED
@@ -16837,6 +16837,7 @@ var init_schemas_execution = __esm(() => {
16837
16837
  fullSuiteTimeoutSeconds: exports_external.number().int().min(10).max(600).default(120),
16838
16838
  maxFailureSummaryChars: exports_external.number().int().min(500).max(1e4).default(2000),
16839
16839
  abortOnIncreasingFailures: exports_external.boolean().default(true),
16840
+ consecutiveIncreasesToBail: exports_external.number().int().min(1).max(10).default(2),
16840
16841
  escalateOnExhaustion: exports_external.boolean().optional().default(true),
16841
16842
  rethinkAtAttempt: exports_external.number().int().min(1).default(2),
16842
16843
  urgencyAtAttempt: exports_external.number().int().min(1).default(3)
@@ -17321,6 +17322,7 @@ var init_schemas3 = __esm(() => {
17321
17322
  fullSuiteTimeoutSeconds: 300,
17322
17323
  maxFailureSummaryChars: 2000,
17323
17324
  abortOnIncreasingFailures: true,
17325
+ consecutiveIncreasesToBail: 2,
17324
17326
  escalateOnExhaustion: true,
17325
17327
  rethinkAtAttempt: 2,
17326
17328
  urgencyAtAttempt: 3
@@ -19086,6 +19088,12 @@ function resolveTestStrategy(raw) {
19086
19088
  return "three-session-tdd-lite";
19087
19089
  return "test-after";
19088
19090
  }
19091
+ function isThreeSessionStrategy(strategy) {
19092
+ return strategy !== undefined && THREE_SESSION_STRATEGIES.has(strategy);
19093
+ }
19094
+ function isSingleSessionTestOwningStrategy(strategy) {
19095
+ return strategy !== undefined && SINGLE_SESSION_TEST_OWNING_STRATEGIES.has(strategy);
19096
+ }
19089
19097
  function getAcQualityRules(profile) {
19090
19098
  const langSection = profile?.language ? LANGUAGE_PATTERNS[profile.language] : undefined;
19091
19099
  const typeSection = profile?.type ? TYPE_PATTERNS[profile.type] : undefined;
@@ -19098,7 +19106,7 @@ function getAcQualityRules(profile) {
19098
19106
 
19099
19107
  ${extras}`;
19100
19108
  }
19101
- var VALID_TEST_STRATEGIES, COMPLEXITY_GUIDE = `## Complexity Classification Guide
19109
+ var VALID_TEST_STRATEGIES, THREE_SESSION_STRATEGIES, SINGLE_SESSION_TEST_OWNING_STRATEGIES, COMPLEXITY_GUIDE = `## Complexity Classification Guide
19102
19110
 
19103
19111
  Classify each story's complexity based on scope and risk \u2014 NOT acceptance criteria count.
19104
19112
  A story with 10 simple "add field" ACs is simpler than one with 3 ACs involving concurrent
@@ -19239,6 +19247,11 @@ var init_test_strategy = __esm(() => {
19239
19247
  "three-session-tdd",
19240
19248
  "three-session-tdd-lite"
19241
19249
  ];
19250
+ THREE_SESSION_STRATEGIES = new Set([
19251
+ "three-session-tdd",
19252
+ "three-session-tdd-lite"
19253
+ ]);
19254
+ SINGLE_SESSION_TEST_OWNING_STRATEGIES = new Set(["tdd-simple", "test-after"]);
19242
19255
  LANGUAGE_PATTERNS = {
19243
19256
  go: `### Go-Specific AC Patterns
19244
19257
 
@@ -36046,7 +36059,7 @@ var init_autofix_test_writer = __esm(() => {
36046
36059
  kind: "run",
36047
36060
  name: "autofix-test-writer",
36048
36061
  stage: "rectification",
36049
- session: { role: "test-writer", lifetime: "fresh" },
36062
+ session: { role: "test-writer", lifetime: "warm" },
36050
36063
  config: autofixConfigSelector,
36051
36064
  build(input, _ctx) {
36052
36065
  const prompt = RectifierPromptBuilder.testWriterRectification(input.failedChecks, input.story, {
@@ -36838,18 +36851,36 @@ var init__session_output = __esm(() => {
36838
36851
  EMPTY = { success: false, filesChanged: [], output: "", parsed: false };
36839
36852
  });
36840
36853
 
36854
+ // src/operations/execution-gates.ts
36855
+ function shouldRunReview(config2) {
36856
+ return config2.review?.enabled === true;
36857
+ }
36858
+ function shouldRunRectification(config2) {
36859
+ return config2.execution?.rectification?.enabled === true;
36860
+ }
36861
+ function shouldKeepSessionOpen(config2, role) {
36862
+ return SESSION_CONTINUITY_ROLES.has(role) && (shouldRunReview(config2) || shouldRunRectification(config2));
36863
+ }
36864
+ var SESSION_CONTINUITY_ROLES;
36865
+ var init_execution_gates = __esm(() => {
36866
+ init_config();
36867
+ SESSION_CONTINUITY_ROLES = new Set(["implementer", "test-writer"]);
36868
+ });
36869
+
36841
36870
  // src/operations/write-test.ts
36842
36871
  var testWriterOp;
36843
36872
  var init_write_test = __esm(() => {
36844
36873
  init_config();
36845
36874
  init_isolation();
36846
36875
  init__session_output();
36876
+ init_execution_gates();
36847
36877
  testWriterOp = {
36848
36878
  kind: "run",
36849
36879
  name: "test-writer",
36850
36880
  stage: "run",
36851
- session: { role: "test-writer", lifetime: "fresh" },
36881
+ session: { role: "test-writer", lifetime: "warm" },
36852
36882
  config: tddConfigSelector,
36883
+ keepOpen: (_input, ctx) => shouldKeepSessionOpen(ctx.config, "test-writer"),
36853
36884
  build(input, _ctx) {
36854
36885
  if (input.promptMarkdown?.trim()) {
36855
36886
  return {
@@ -36896,20 +36927,6 @@ var init_write_test = __esm(() => {
36896
36927
  };
36897
36928
  });
36898
36929
 
36899
- // src/operations/execution-gates.ts
36900
- function shouldRunReview(config2) {
36901
- return config2.review?.enabled === true;
36902
- }
36903
- function shouldRunRectification(config2) {
36904
- return config2.execution?.rectification?.enabled === true;
36905
- }
36906
- function shouldKeepSessionOpen(config2, role) {
36907
- return role === "implementer" && (shouldRunReview(config2) || shouldRunRectification(config2));
36908
- }
36909
- var init_execution_gates = __esm(() => {
36910
- init_config();
36911
- });
36912
-
36913
36930
  // src/operations/implement.ts
36914
36931
  var implementerOp;
36915
36932
  var init_implement = __esm(() => {
@@ -38416,10 +38433,11 @@ var init__finding_to_check = __esm(() => {
38416
38433
  });
38417
38434
 
38418
38435
  // src/operations/autofix-implementer-strategy.ts
38419
- function makeAutofixImplementerStrategy(story, config2, sink) {
38436
+ function makeAutofixImplementerStrategy(story, config2, sink, opts = {}) {
38437
+ const claimsAdversarial = opts.includeAdversarialReview === true;
38420
38438
  return {
38421
38439
  name: "autofix-implementer",
38422
- appliesTo: (f) => f.fixTarget === "source" && IMPLEMENTER_SOURCES.has(f.source),
38440
+ appliesTo: (f) => f.fixTarget === "source" && IMPLEMENTER_SOURCES.has(f.source) || claimsAdversarial && f.source === "adversarial-review",
38423
38441
  fixOp: implementerRectifyOp,
38424
38442
  buildInput: (findings, _prior, _cycleCtx) => ({
38425
38443
  failedChecks: findingsToFailedChecks(findings),
@@ -41078,18 +41096,18 @@ ${exceptions.join(`
41078
41096
  `)}`;
41079
41097
  }
41080
41098
  function implementerOwnsTests(story) {
41081
- return SINGLE_SESSION_TEST_OWNING_STRATEGIES.has(story.routing?.testStrategy ?? "");
41099
+ return isSingleSessionTestOwningStrategy(story.routing?.testStrategy);
41082
41100
  }
41083
41101
  function testEditHeadline(story, prohibition) {
41084
41102
  return implementerOwnsTests(story) ? SINGLE_SESSION_PERMIT_HEADLINE : prohibition;
41085
41103
  }
41086
41104
  function exceptionCountWord(story) {
41087
- return THREE_SESSION_STRATEGIES.has(story.routing?.testStrategy ?? "") ? "four" : "three";
41105
+ return isThreeSessionStrategy(story.routing?.testStrategy) ? "four" : "three";
41088
41106
  }
41089
41107
  function escapeHatchFor(story) {
41090
41108
  if (implementerOwnsTests(story))
41091
41109
  return SINGLE_SESSION_TEST_EDIT_POLICY;
41092
- const isTdd = THREE_SESSION_STRATEGIES.has(story.routing?.testStrategy ?? "");
41110
+ const isTdd = isThreeSessionStrategy(story.routing?.testStrategy);
41093
41111
  return buildEscapeHatch({ includeMockHandoff: isTdd });
41094
41112
  }
41095
41113
  function noTestIsolationBlock(story) {
@@ -41294,7 +41312,7 @@ REASON: <one paragraph: which mock is wrong vs which dispatch the new code uses,
41294
41312
  Rules:
41295
41313
  - Do NOT make any edits yourself; the test-writer will fulfill.
41296
41314
  - Do NOT also emit \`UNRESOLVED:\` in the same turn \u2014 this declaration IS the handoff.
41297
- - FILES must list real test files. Each path must exist and be a test file.`, THREE_SESSION_STRATEGIES, SINGLE_SESSION_TEST_OWNING_STRATEGIES, SINGLE_SESSION_PERMIT_HEADLINE = "You authored these tests in the same session as the implementation, so you MAY edit test files \u2014 but ONLY to resolve a genuine contradiction between a test and this story's acceptance criteria (or between two acceptance criteria). NEVER weaken, delete, loosen, or skip a test merely to make it pass. See the test-edit guidance appended below.", SINGLE_SESSION_TEST_EDIT_POLICY = `
41315
+ - FILES must list real test files. Each path must exist and be a test file.`, SINGLE_SESSION_PERMIT_HEADLINE = "You authored these tests in the same session as the implementation, so you MAY edit test files \u2014 but ONLY to resolve a genuine contradiction between a test and this story's acceptance criteria (or between two acceptance criteria). NEVER weaken, delete, loosen, or skip a test merely to make it pass. See the test-edit guidance appended below.", SINGLE_SESSION_TEST_EDIT_POLICY = `
41298
41316
 
41299
41317
  ## Test-edit guidance (single-session implementer)
41300
41318
 
@@ -41313,10 +41331,9 @@ If two findings or two acceptance criteria contradict each other and you cannot
41313
41331
  both even after adjusting tests, do not guess. Emit:
41314
41332
  UNRESOLVED: <which findings/ACs conflicted and why they cannot both be satisfied>`, CONTRADICTION_ESCAPE_HATCH, MAX_STRUCTURED_FINDINGS = 10, RAW_WITH_FINDINGS_LIMIT = 1000, RAW_FALLBACK_LIMIT = 4000;
41315
41333
  var init_rectifier_builder_helpers = __esm(() => {
41334
+ init_config();
41316
41335
  init_review();
41317
41336
  init_sections2();
41318
- THREE_SESSION_STRATEGIES = new Set(["three-session-tdd", "three-session-tdd-lite"]);
41319
- SINGLE_SESSION_TEST_OWNING_STRATEGIES = new Set(["tdd-simple", "test-after"]);
41320
41337
  CONTRADICTION_ESCAPE_HATCH = buildEscapeHatch({ includeMockHandoff: false });
41321
41338
  });
41322
41339
 
@@ -53430,6 +53447,11 @@ function phasesToRevalidate(strategiesRun, allPhases) {
53430
53447
  }
53431
53448
  return allPhases.filter((p) => needed.has(p.kind));
53432
53449
  }
53450
+ function orderGateLast(phases) {
53451
+ const rest = phases.filter((p) => p.kind !== "full-suite-gate");
53452
+ const gates = phases.filter((p) => p.kind === "full-suite-gate");
53453
+ return [...rest, ...gates];
53454
+ }
53433
53455
  function toReviewDecisionPayload(opName, output) {
53434
53456
  if (output === null || output === undefined || typeof output !== "object")
53435
53457
  return null;
@@ -53644,18 +53666,24 @@ async function runPhase(ctx, slot, phaseCosts, phaseOutputs, isThreeSession = fa
53644
53666
  scope.close();
53645
53667
  }
53646
53668
  }
53647
- function withIncreasingFailuresBail(strategies, enabled) {
53669
+ function withIncreasingFailuresBail(strategies, enabled, consecutiveIncreases) {
53648
53670
  if (!enabled)
53649
53671
  return strategies;
53672
+ const threshold = Math.max(1, consecutiveIncreases);
53650
53673
  return strategies.map((strategy) => ({
53651
53674
  ...strategy,
53652
53675
  bailWhen: (iterations) => {
53653
53676
  const userReason = strategy.bailWhen?.(iterations) ?? null;
53654
53677
  if (userReason !== null)
53655
53678
  return userReason;
53656
- const last = iterations[iterations.length - 1];
53657
- if (last && last.findingsAfter.length > last.findingsBefore.length) {
53658
- return `failure count increased: ${last.findingsBefore.length} -> ${last.findingsAfter.length}`;
53679
+ if (iterations.length < threshold)
53680
+ return null;
53681
+ const trailing = iterations.slice(-threshold);
53682
+ const allRegressed = trailing.every((it) => it.findingsAfter.length > it.findingsBefore.length);
53683
+ if (allRegressed) {
53684
+ const first = trailing[0];
53685
+ const last = trailing[trailing.length - 1];
53686
+ return `failure count increased for ${threshold} consecutive iteration(s): ${first.findingsBefore.length} -> ${last.findingsAfter.length}`;
53659
53687
  }
53660
53688
  return null;
53661
53689
  }
@@ -53685,13 +53713,14 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs) {
53685
53713
  const cycle = {
53686
53714
  findings: [...initialFindings],
53687
53715
  iterations: [],
53688
- strategies: withIncreasingFailuresBail(rectification.strategies, rectification.abortOnIncreasingFailures),
53716
+ strategies: withIncreasingFailuresBail(rectification.strategies, rectification.abortOnIncreasingFailures, rectification.consecutiveIncreasesToBail ?? 1),
53689
53717
  config: { maxAttemptsTotal: rectification.maxAttempts, validatorRetries: 1 },
53690
53718
  validate: async (_validateCtx, opts) => {
53691
53719
  if (ctx.runtime.signal?.aborted)
53692
53720
  return { findings: [], shortCircuited: false };
53693
53721
  const lite = (opts?.mode ?? "full") === "lite";
53694
- const phases = phasesToRevalidate(opts?.strategiesRun, validationPhases);
53722
+ const selected = phasesToRevalidate(opts?.strategiesRun, validationPhases);
53723
+ const phases = lite ? orderGateLast(selected) : selected;
53695
53724
  getSafeLogger()?.debug("story-orchestrator", "rectification validate scope", {
53696
53725
  storyId: ctx.storyId,
53697
53726
  mode: opts?.mode ?? "full",
@@ -53701,9 +53730,6 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs) {
53701
53730
  const findings = [];
53702
53731
  let shortCircuited = false;
53703
53732
  for (const phase of phases) {
53704
- if (lite && phase.kind === "full-suite-gate") {
53705
- continue;
53706
- }
53707
53733
  await runPhase(ctx, phase.slot, phaseCosts, phaseOutputs);
53708
53734
  if (shouldSkipPhaseForRectification(phase, state, phaseOutputs))
53709
53735
  continue;
@@ -54019,9 +54045,6 @@ var init_story_orchestrator = __esm(() => {
54019
54045
 
54020
54046
  // src/execution/build-plan-for-strategy.ts
54021
54047
  import { join as join46 } from "path";
54022
- function isThreeSessionStrategy(strategy) {
54023
- return THREE_SESSION_STRATEGIES2.has(strategy);
54024
- }
54025
54048
  function requiresInitialRefCapture(strategy) {
54026
54049
  return isThreeSessionStrategy(strategy);
54027
54050
  }
@@ -54080,8 +54103,12 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
54080
54103
  strategies.push(makeFullSuiteRectifyStrategy(story, config2));
54081
54104
  }
54082
54105
  if (config2.quality.autofix?.enabled !== false) {
54083
- strategies.push(makeAutofixImplementerStrategy(story, config2, sink));
54084
- strategies.push(makeAutofixTestWriterStrategy(story, config2, sink));
54106
+ strategies.push(makeAutofixImplementerStrategy(story, config2, sink, {
54107
+ includeAdversarialReview: !isThreeSession
54108
+ }));
54109
+ if (isThreeSession) {
54110
+ strategies.push(makeAutofixTestWriterStrategy(story, config2, sink));
54111
+ }
54085
54112
  }
54086
54113
  const postValidate = async (findings, _validateCtx) => {
54087
54114
  if (sink.testEdits.length === 0 && sink.mockHandoffs.length === 0)
@@ -54107,14 +54134,13 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
54107
54134
  }
54108
54135
  return builder.build(ctx, { isThreeSession });
54109
54136
  }
54110
- var THREE_SESSION_STRATEGIES2;
54111
54137
  var init_build_plan_for_strategy = __esm(() => {
54138
+ init_config();
54112
54139
  init_operations();
54113
54140
  init_execution_gates();
54114
54141
  init_full_suite_rectify();
54115
54142
  init_test_runners();
54116
54143
  init_story_orchestrator();
54117
- THREE_SESSION_STRATEGIES2 = new Set(["three-session-tdd", "three-session-tdd-lite"]);
54118
54144
  });
54119
54145
 
54120
54146
  // src/execution/plan-inputs.ts
@@ -54314,7 +54340,8 @@ async function assemblePlanInputsFromCtx(ctx) {
54314
54340
  const rectificationInput = ctx.config.execution?.rectification?.enabled === true ? {
54315
54341
  maxAttempts: ctx.config.execution.rectification.maxAttemptsTotal,
54316
54342
  strategies: [],
54317
- abortOnIncreasingFailures: ctx.config.execution.rectification.abortOnIncreasingFailures
54343
+ abortOnIncreasingFailures: ctx.config.execution.rectification.abortOnIncreasingFailures,
54344
+ consecutiveIncreasesToBail: ctx.config.execution.rectification.consecutiveIncreasesToBail
54318
54345
  } : undefined;
54319
54346
  return {
54320
54347
  story,
@@ -54333,12 +54360,12 @@ async function assemblePlanInputsFromCtx(ctx) {
54333
54360
  };
54334
54361
  }
54335
54362
  var init_plan_inputs = __esm(() => {
54363
+ init_config();
54336
54364
  init_context();
54337
54365
  init_errors();
54338
54366
  init_prompts();
54339
54367
  init_review();
54340
54368
  init_resolver();
54341
- init_build_plan_for_strategy();
54342
54369
  });
54343
54370
 
54344
54371
  // src/pipeline/stages/execution-helpers.ts
@@ -54865,6 +54892,7 @@ var init_post_run = __esm(() => {
54865
54892
  // src/pipeline/stages/execution.ts
54866
54893
  var RUNTIME_CRASH_CODES, executionStage, _executionDeps;
54867
54894
  var init_execution = __esm(() => {
54895
+ init_config();
54868
54896
  init_agents();
54869
54897
  init_errors();
54870
54898
  init_build_plan_for_strategy();
@@ -58383,7 +58411,7 @@ var package_default;
58383
58411
  var init_package = __esm(() => {
58384
58412
  package_default = {
58385
58413
  name: "@nathapp/nax",
58386
- version: "0.68.4",
58414
+ version: "0.68.5",
58387
58415
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
58388
58416
  type: "module",
58389
58417
  bin: {
@@ -58478,8 +58506,8 @@ var init_version = __esm(() => {
58478
58506
  NAX_VERSION = package_default.version;
58479
58507
  NAX_COMMIT = (() => {
58480
58508
  try {
58481
- if (/^[0-9a-f]{6,10}$/.test("197c6530"))
58482
- return "197c6530";
58509
+ if (/^[0-9a-f]{6,10}$/.test("1056817e"))
58510
+ return "1056817e";
58483
58511
  } catch {}
58484
58512
  try {
58485
58513
  const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
@@ -96937,6 +96965,7 @@ var FIELD_DESCRIPTIONS = {
96937
96965
  "execution.rectification.fullSuiteTimeoutSeconds": "Timeout for full test suite run in seconds",
96938
96966
  "execution.rectification.maxFailureSummaryChars": "Max characters in failure summary",
96939
96967
  "execution.rectification.abortOnIncreasingFailures": "Abort if failure count increases",
96968
+ "execution.rectification.consecutiveIncreasesToBail": "Consecutive regressing iterations required before abortOnIncreasingFailures bails (default: 2; 1 = legacy behaviour)",
96940
96969
  "execution.rectification.escalateOnExhaustion": "Enable model tier escalation when attempts are exhausted with remaining failures",
96941
96970
  "execution.rectification.rethinkAtAttempt": "Attempt number at which 'rethink your approach' language is injected into the prompt (default: 2)",
96942
96971
  "execution.rectification.urgencyAtAttempt": "Attempt number at which 'final chance before escalation' urgency is added (default: 3)",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nathapp/nax",
3
- "version": "0.68.4",
3
+ "version": "0.68.5",
4
4
  "description": "AI Coding Agent Orchestrator — loops until done",
5
5
  "type": "module",
6
6
  "bin": {