@nathapp/nax 0.78.0 → 0.79.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.
- package/dist/nax.js +756 -415
- package/flows/nax-finish/nax-finish.flow.ts +21 -12
- package/flows/nax-finish/steps/commit-round.ts +8 -8
- package/flows/nax-finish/types.ts +23 -9
- package/package.json +7 -2
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
* the `acceptance` node last passed, and the repo-root `test` command does
|
|
32
32
|
* not cover per-feature acceptance tests — so without this a fix could break
|
|
33
33
|
* the contract the first gate proved and still ship.
|
|
34
|
-
* - `commit_gate` re-enters `review_quality`
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
34
|
+
* - `commit_gate` re-enters `review_quality` whenever its fix committed — the
|
|
35
|
+
* gate loop was otherwise the one editing loop whose output faced only
|
|
36
|
+
* mechanical checks, which a fix that degrades the tests it repairs will
|
|
37
|
+
* satisfy. A test-only fix used to skip the re-review as a cost tradeoff;
|
|
38
|
+
* #1510 closed that hole. See `gateCommitRoute`.
|
|
39
39
|
* - `load_ctx` and `open_pr` both route to `escalate` rather than throwing on
|
|
40
40
|
* their own failures. acpx has no error edge, so a throw ends the run with no
|
|
41
41
|
* result file for the plugin to read or notify from — the one outcome that
|
|
@@ -103,14 +103,23 @@ export const _openPrDeps = {
|
|
|
103
103
|
*
|
|
104
104
|
* - `unchanged` — nothing committed; no new diff, so nothing to review.
|
|
105
105
|
* - `tests-only` — every touched path matched the repo's test-file patterns.
|
|
106
|
-
* Skipped by explicit choice: the re-review is the flow's most expensive node
|
|
107
|
-
* and a gate fix is usually a mechanical test repair. **This is a real hole.**
|
|
108
|
-
* The defect that motivated the re-entry (rs-stock `b6fb66dd`) was itself
|
|
109
|
-
* test-only — 8 copy-pasted stubs across 3 test files — so this route would
|
|
110
|
-
* not have caught it. Widen it here if test-quality regressions start
|
|
111
|
-
* shipping — the audit's `review-skipped` rounds are the evidence.
|
|
112
106
|
* - `changed` — production code was touched, or the paths could not be
|
|
113
107
|
* classified at all. "Cannot classify" reviews rather than skips.
|
|
108
|
+
*
|
|
109
|
+
* `tests-only` and `changed` both re-enter `review_quality` (#1510). They used
|
|
110
|
+
* to diverge: `tests-only` skipped the re-review as a cost tradeoff, on the
|
|
111
|
+
* reasoning that a gate fix is usually a mechanical test repair. That was a
|
|
112
|
+
* real hole — the defect that motivated the re-entry was itself test-only, 8
|
|
113
|
+
* copy-pasted stubs across 3 test files, so the skip would not have caught the
|
|
114
|
+
* very thing it was built for. A gate fix can turn a red suite green by
|
|
115
|
+
* degrading the tests it repairs, and `quality_gates` is satisfied by exactly
|
|
116
|
+
* that; nothing else read that diff. The audit settled the cost side: across
|
|
117
|
+
* every finish recorded, exactly one `gate` round has ever fired, so the skip
|
|
118
|
+
* was saving a review that almost never runs.
|
|
119
|
+
*
|
|
120
|
+
* The classification is kept even though both routes now review. It is what a
|
|
121
|
+
* cheaper test-quality-scoped reviewer would key off if gate rounds ever become
|
|
122
|
+
* frequent enough for the full re-review to hurt.
|
|
114
123
|
*/
|
|
115
124
|
async function gateCommitRoute(
|
|
116
125
|
i: FinishInput,
|
|
@@ -509,7 +518,7 @@ export default defineFlow({
|
|
|
509
518
|
from: "commit_gate",
|
|
510
519
|
switch: {
|
|
511
520
|
on: "$.route",
|
|
512
|
-
cases: { changed: "review_quality", "tests-only": "
|
|
521
|
+
cases: { changed: "review_quality", "tests-only": "review_quality", unchanged: "quality_gates" },
|
|
513
522
|
},
|
|
514
523
|
},
|
|
515
524
|
// The narrative runs only once the PR exists. acpx has no error edge, so an
|
|
@@ -16,16 +16,15 @@ const REVIEWED_PHASES: FinishPhase[] = ["spec", "quality"];
|
|
|
16
16
|
/**
|
|
17
17
|
* What produced this round, given the successor the commit routed to.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* `route` no longer changes the answer, and that is the point: since #1510
|
|
20
|
+
* every committed gate fix re-enters `review_quality`, so no route can skip an
|
|
21
|
+
* owed re-review. The parameter stays because the round is still keyed on the
|
|
22
|
+
* successor conceptually, and a future route that *does* bypass a reviewer
|
|
23
|
+
* would need to be reflected here rather than silently inheriting
|
|
24
|
+
* `no-reviewer`.
|
|
23
25
|
*/
|
|
24
|
-
export function commitRoundOutcome(phase: FinishPhase,
|
|
26
|
+
export function commitRoundOutcome(phase: FinishPhase, _route: string): FinishRoundOutcome {
|
|
25
27
|
if (REVIEWED_PHASES.includes(phase)) return "fixed";
|
|
26
|
-
// Only `gate` can skip an owed re-review; `acceptance` has no reviewer to
|
|
27
|
-
// skip, so its `tests-only`-shaped routes (it has none today) stay honest.
|
|
28
|
-
if (phase === "gate" && route === "tests-only") return "review-skipped";
|
|
29
28
|
return "no-reviewer";
|
|
30
29
|
}
|
|
31
30
|
|
|
@@ -58,6 +57,7 @@ export function buildCommitRound(i: CommitRoundInput): FinishRound {
|
|
|
58
57
|
committed: i.committed,
|
|
59
58
|
outcome: commitRoundOutcome(i.phase, i.route),
|
|
60
59
|
findings: i.findings,
|
|
60
|
+
route: i.route,
|
|
61
61
|
...(i.failing ? { failing: i.failing } : {}),
|
|
62
62
|
...(i.committed && i.shaAfter ? { sha: i.shaAfter } : {}),
|
|
63
63
|
};
|
|
@@ -80,16 +80,17 @@ export type FinishRoundOutcome =
|
|
|
80
80
|
*/
|
|
81
81
|
| "no-reviewer"
|
|
82
82
|
/**
|
|
83
|
-
* A re-review was owed and deliberately skipped
|
|
84
|
-
* that touched test files exclusively (`gateCommitRoute` → `tests-only`).
|
|
83
|
+
* A re-review was owed and deliberately skipped.
|
|
85
84
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
85
|
+
* **No longer emitted.** It described the `gate` → `tests-only` route, which
|
|
86
|
+
* skipped `review_quality` as a cost tradeoff; #1510 closed that hole, so
|
|
87
|
+
* every committed gate fix is now re-reviewed and nothing writes this.
|
|
88
|
+
*
|
|
89
|
+
* Retained because the audit trail is read, not just written: a project that
|
|
90
|
+
* ran an earlier nax can hold rounds carrying this outcome, and dropping it
|
|
91
|
+
* from the union would make those unrenderable. Do not reuse the name for a
|
|
92
|
+
* new meaning — a reader hitting it in an old artifact must still be told
|
|
93
|
+
* what it meant when it was written.
|
|
93
94
|
*/
|
|
94
95
|
| "review-skipped";
|
|
95
96
|
|
|
@@ -106,6 +107,19 @@ export interface FinishRound {
|
|
|
106
107
|
findings: Finding[];
|
|
107
108
|
/** Gate commands that were red this round (gate phase). */
|
|
108
109
|
failing?: string[];
|
|
110
|
+
/**
|
|
111
|
+
* The successor this round's commit routed to — `changed` / `tests-only` /
|
|
112
|
+
* `unchanged` for `gate`, `changed` / `unchanged` elsewhere.
|
|
113
|
+
*
|
|
114
|
+
* Recorded because `outcome` stopped carrying it. Until #1510 a tests-only
|
|
115
|
+
* gate fix was the only round writing `review-skipped`, so the outcome
|
|
116
|
+
* doubled as the classification; now every committed gate fix is reviewed
|
|
117
|
+
* and writes `no-reviewer`, which would leave "what did this fix touch?"
|
|
118
|
+
* unanswerable from the trail. That question is the input to deciding
|
|
119
|
+
* whether the re-review ever needs a cheaper, test-scoped form, so it has to
|
|
120
|
+
* survive the round it was computed in.
|
|
121
|
+
*/
|
|
122
|
+
route?: string;
|
|
109
123
|
/**
|
|
110
124
|
* `HEAD` SHA after this round's commit (set only when `committed`); absent
|
|
111
125
|
* on no-op rounds so a reader can distinguish "no commit" from "record lost".
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nathapp/nax",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.79.0",
|
|
4
4
|
"description": "AI Coding Agent Orchestrator — loops until done",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -47,9 +47,14 @@
|
|
|
47
47
|
"check:dispatch-context": "bash scripts/check-dispatch-context.sh",
|
|
48
48
|
"check:naxconfig-cast": "bash scripts/check-no-silent-naxconfig-cast.sh",
|
|
49
49
|
"check:runtime-cleanup": "bash scripts/check-runtime-cleanup.sh",
|
|
50
|
+
"check:scripts": "bash scripts/check-scripts.sh",
|
|
50
51
|
"check:adapter-no-config-import": "bash scripts/check-adapter-no-config-import.sh",
|
|
52
|
+
"check:test-typecheck": "bun run scripts/check-test-typecheck.ts",
|
|
53
|
+
"check:test-typecheck:update": "bun run scripts/check-test-typecheck.ts --update-baseline",
|
|
54
|
+
"check:test-as-unknown-as": "bun run scripts/check-test-as-unknown-as.ts",
|
|
55
|
+
"check:test-as-unknown-as:update": "bun run scripts/check-test-as-unknown-as.ts --update-baseline",
|
|
51
56
|
"check:gate-reachability": "bun run scripts/check-gate-reachability.ts",
|
|
52
|
-
"check:all": "bun run lint && bun run check:test-mocks && bun run check:process-cwd && bun run check:no-adapter-wrap && bun run check:dispatch-context && bun run check:naxconfig-cast && bun run check:runtime-cleanup && bun run check:adapter-no-config-import && bun run check:gate-reachability",
|
|
57
|
+
"check:all": "bun run lint && bun run check:test-mocks && bun run check:process-cwd && bun run check:no-adapter-wrap && bun run check:scripts && bun run check:dispatch-context && bun run check:naxconfig-cast && bun run check:runtime-cleanup && bun run check:adapter-no-config-import && bun run check:test-typecheck && bun run check:test-as-unknown-as && bun run check:gate-reachability",
|
|
53
58
|
"prepublishOnly": "bun run build",
|
|
54
59
|
"test:full": "FULL=1 NAX_PRECHECK=1 bun test test/ --timeout=60000"
|
|
55
60
|
},
|