@nathapp/nax 0.34.0 → 0.35.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.
@@ -162,6 +162,24 @@ async function runRectificationLoop(
162
162
  await cleanupProcessTree(rectifyResult.pid);
163
163
  }
164
164
 
165
+ if (rectifyResult.success) {
166
+ logger.info("tdd", "Rectification agent session complete", {
167
+ storyId: story.id,
168
+ attempt: rectificationState.attempt,
169
+ cost: rectifyResult.estimatedCost,
170
+ });
171
+ } else {
172
+ logger.warn("tdd", "Rectification agent session failed", {
173
+ storyId: story.id,
174
+ attempt: rectificationState.attempt,
175
+ exitCode: rectifyResult.exitCode,
176
+ });
177
+ }
178
+
179
+ // BUG-063: Auto-commit after rectification agent — prevents uncommitted changes
180
+ // from leaking into verifier/review stages. Same pattern as session-runner.ts.
181
+ await autoCommitIfDirty(workdir, "rectification", story.id, logger);
182
+
165
183
  const rectifyIsolation = lite ? undefined : await verifyImplementerIsolation(workdir, rectifyBeforeRef);
166
184
 
167
185
  if (rectifyIsolation && !rectifyIsolation.passed) {
@@ -191,6 +209,12 @@ async function runRectificationLoop(
191
209
  testSummary.failed = newTestSummary.failed;
192
210
  testSummary.passed = newTestSummary.passed;
193
211
  }
212
+
213
+ logger.warn("tdd", "Full suite still failing after rectification attempt", {
214
+ storyId: story.id,
215
+ attempt: rectificationState.attempt,
216
+ remainingFailures: rectificationState.currentFailures,
217
+ });
194
218
  }
195
219
 
196
220
  const finalFullSuite = await executeWithTimeout(testCmd, fullSuiteTimeout, undefined, { cwd: workdir });
@@ -207,3 +231,47 @@ async function runRectificationLoop(
207
231
  logger.info("tdd", "Full suite gate passed", { storyId: story.id });
208
232
  return true;
209
233
  }
234
+
235
+ /**
236
+ * BUG-063: Auto-commit safety net for rectification agent sessions.
237
+ *
238
+ * Rectification runs agent.run() directly (not via runTddSession), so it
239
+ * needs its own auto-commit. Without this, uncommitted changes from
240
+ * rectification leak into verifier/review stages causing spurious failures.
241
+ */
242
+ async function autoCommitIfDirty(
243
+ workdir: string,
244
+ role: string,
245
+ storyId: string,
246
+ logger: ReturnType<typeof getLogger>,
247
+ ): Promise<void> {
248
+ try {
249
+ const statusProc = Bun.spawn(["git", "status", "--porcelain"], {
250
+ cwd: workdir,
251
+ stdout: "pipe",
252
+ stderr: "pipe",
253
+ });
254
+ const statusOutput = await new Response(statusProc.stdout).text();
255
+ await statusProc.exited;
256
+
257
+ if (!statusOutput.trim()) return;
258
+
259
+ logger.warn("tdd", `Agent did not commit after ${role} session — auto-committing`, {
260
+ role,
261
+ storyId,
262
+ dirtyFiles: statusOutput.trim().split("\n").length,
263
+ });
264
+
265
+ const addProc = Bun.spawn(["git", "add", "-A"], { cwd: workdir, stdout: "pipe", stderr: "pipe" });
266
+ await addProc.exited;
267
+
268
+ const commitProc = Bun.spawn(["git", "commit", "-m", `chore(${storyId}): auto-commit after ${role} session`], {
269
+ cwd: workdir,
270
+ stdout: "pipe",
271
+ stderr: "pipe",
272
+ });
273
+ await commitProc.exited;
274
+ } catch {
275
+ // Silently ignore — auto-commit is best-effort
276
+ }
277
+ }
@@ -129,6 +129,22 @@ export async function runTddSession(
129
129
  await cleanupProcessTree(result.pid);
130
130
  }
131
131
 
132
+ if (result.success) {
133
+ logger.info("tdd", `Session complete: ${role}`, {
134
+ role,
135
+ storyId: story.id,
136
+ durationMs: Date.now() - startTime,
137
+ cost: result.estimatedCost,
138
+ });
139
+ } else {
140
+ logger.warn("tdd", `Session failed: ${role}`, {
141
+ role,
142
+ storyId: story.id,
143
+ durationMs: Date.now() - startTime,
144
+ exitCode: result.exitCode,
145
+ });
146
+ }
147
+
132
148
  // BUG-058: Auto-commit if agent left uncommitted changes
133
149
  await autoCommitIfDirty(workdir, role, story.id);
134
150
 
@@ -153,6 +153,7 @@ export async function readVerdict(workdir: string): Promise<VerifierVerdict | nu
153
153
  if (!isValidVerdict(parsed)) {
154
154
  logger.warn("tdd", "Verifier verdict file missing required fields — ignoring", {
155
155
  path: verdictPath,
156
+ content: JSON.stringify(parsed).slice(0, 500),
156
157
  });
157
158
  return null;
158
159
  }
@@ -78,10 +78,17 @@ export async function runRectificationLoop(opts: RectificationLoopOptions): Prom
78
78
  dangerouslySkipPermissions: config.execution.dangerouslySkipPermissions,
79
79
  });
80
80
 
81
- if (!agentResult.success) {
81
+ if (agentResult.success) {
82
+ logger?.info("rectification", `Agent ${label} session complete`, {
83
+ storyId: story.id,
84
+ attempt: rectificationState.attempt,
85
+ cost: agentResult.estimatedCost,
86
+ });
87
+ } else {
82
88
  logger?.warn("rectification", `Agent ${label} session failed`, {
83
89
  storyId: story.id,
84
90
  attempt: rectificationState.attempt,
91
+ exitCode: agentResult.exitCode,
85
92
  });
86
93
  }
87
94
 
@@ -116,6 +123,12 @@ export async function runRectificationLoop(opts: RectificationLoopOptions): Prom
116
123
  testSummary.failed = newTestSummary.failed;
117
124
  testSummary.passed = newTestSummary.passed;
118
125
  }
126
+
127
+ logger?.warn("rectification", `${label} still failing after attempt`, {
128
+ storyId: story.id,
129
+ attempt: rectificationState.attempt,
130
+ remainingFailures: rectificationState.currentFailures,
131
+ });
119
132
  }
120
133
 
121
134
  if (rectificationState.attempt >= rectificationConfig.maxRetries) {