looply-cli 0.5.10 → 0.5.12

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 (126) hide show
  1. package/dist/.src-hash +1 -1
  2. package/dist/autonomy-controller.d.ts +23 -1
  3. package/dist/autonomy-controller.d.ts.map +1 -1
  4. package/dist/autonomy-controller.js +50 -9
  5. package/dist/autonomy-controller.js.map +1 -1
  6. package/dist/autonomy-store.d.ts +33 -1
  7. package/dist/autonomy-store.d.ts.map +1 -1
  8. package/dist/autonomy-store.js +58 -8
  9. package/dist/autonomy-store.js.map +1 -1
  10. package/dist/autonomy-tick.d.ts +23 -1
  11. package/dist/autonomy-tick.d.ts.map +1 -1
  12. package/dist/autonomy-tick.js +80 -14
  13. package/dist/autonomy-tick.js.map +1 -1
  14. package/dist/bin.d.ts.map +1 -1
  15. package/dist/bin.js +34 -5
  16. package/dist/bin.js.map +1 -1
  17. package/dist/branch-delivery-wiring.d.ts +4 -1
  18. package/dist/branch-delivery-wiring.d.ts.map +1 -1
  19. package/dist/branch-delivery-wiring.js +39 -12
  20. package/dist/branch-delivery-wiring.js.map +1 -1
  21. package/dist/branch-delivery.d.ts +157 -8
  22. package/dist/branch-delivery.d.ts.map +1 -1
  23. package/dist/branch-delivery.js +580 -82
  24. package/dist/branch-delivery.js.map +1 -1
  25. package/dist/branch-replay.d.ts +45 -0
  26. package/dist/branch-replay.d.ts.map +1 -0
  27. package/dist/branch-replay.js +123 -0
  28. package/dist/branch-replay.js.map +1 -0
  29. package/dist/commit-ownership.d.ts +102 -0
  30. package/dist/commit-ownership.d.ts.map +1 -0
  31. package/dist/commit-ownership.js +97 -0
  32. package/dist/commit-ownership.js.map +1 -0
  33. package/dist/coordinator-state.d.ts.map +1 -1
  34. package/dist/coordinator-state.js +23 -1
  35. package/dist/coordinator-state.js.map +1 -1
  36. package/dist/daemon-cmd.d.ts.map +1 -1
  37. package/dist/daemon-cmd.js +47 -4
  38. package/dist/daemon-cmd.js.map +1 -1
  39. package/dist/deliver-cmd.d.ts +18 -0
  40. package/dist/deliver-cmd.d.ts.map +1 -1
  41. package/dist/deliver-cmd.js +71 -5
  42. package/dist/deliver-cmd.js.map +1 -1
  43. package/dist/delivery-settings-cache.d.ts +15 -1
  44. package/dist/delivery-settings-cache.d.ts.map +1 -1
  45. package/dist/delivery-settings-cache.js +31 -3
  46. package/dist/delivery-settings-cache.js.map +1 -1
  47. package/dist/environment-hold.d.ts +69 -0
  48. package/dist/environment-hold.d.ts.map +1 -0
  49. package/dist/environment-hold.js +120 -0
  50. package/dist/environment-hold.js.map +1 -0
  51. package/dist/gate.d.ts.map +1 -1
  52. package/dist/gate.js +15 -1
  53. package/dist/gate.js.map +1 -1
  54. package/dist/github-api.d.ts +19 -0
  55. package/dist/github-api.d.ts.map +1 -1
  56. package/dist/github-api.js +26 -0
  57. package/dist/github-api.js.map +1 -1
  58. package/dist/goal-adaptive.d.ts +1 -0
  59. package/dist/goal-adaptive.d.ts.map +1 -1
  60. package/dist/goal-adaptive.js +26 -13
  61. package/dist/goal-adaptive.js.map +1 -1
  62. package/dist/goal-compile.d.ts +37 -0
  63. package/dist/goal-compile.d.ts.map +1 -1
  64. package/dist/goal-compile.js +25 -1
  65. package/dist/goal-compile.js.map +1 -1
  66. package/dist/goal-replay.d.ts +83 -0
  67. package/dist/goal-replay.d.ts.map +1 -0
  68. package/dist/goal-replay.js +121 -0
  69. package/dist/goal-replay.js.map +1 -0
  70. package/dist/goal-reproof.d.ts +5 -0
  71. package/dist/goal-reproof.d.ts.map +1 -1
  72. package/dist/goal-reproof.js +11 -4
  73. package/dist/goal-reproof.js.map +1 -1
  74. package/dist/grant-pause.d.ts +48 -0
  75. package/dist/grant-pause.d.ts.map +1 -0
  76. package/dist/grant-pause.js +103 -0
  77. package/dist/grant-pause.js.map +1 -0
  78. package/dist/grant-reconcile.d.ts +8 -2
  79. package/dist/grant-reconcile.d.ts.map +1 -1
  80. package/dist/grant-reconcile.js +9 -2
  81. package/dist/grant-reconcile.js.map +1 -1
  82. package/dist/grant-waiting-wiring.d.ts +49 -0
  83. package/dist/grant-waiting-wiring.d.ts.map +1 -0
  84. package/dist/grant-waiting-wiring.js +77 -0
  85. package/dist/grant-waiting-wiring.js.map +1 -0
  86. package/dist/machine-run-slots.d.ts +10 -2
  87. package/dist/machine-run-slots.d.ts.map +1 -1
  88. package/dist/machine-run-slots.js +15 -4
  89. package/dist/machine-run-slots.js.map +1 -1
  90. package/dist/maintenance-cmd.d.ts +44 -0
  91. package/dist/maintenance-cmd.d.ts.map +1 -0
  92. package/dist/maintenance-cmd.js +132 -0
  93. package/dist/maintenance-cmd.js.map +1 -0
  94. package/dist/maintenance-facts.d.ts +52 -0
  95. package/dist/maintenance-facts.d.ts.map +1 -0
  96. package/dist/maintenance-facts.js +256 -0
  97. package/dist/maintenance-facts.js.map +1 -0
  98. package/dist/maintenance-tick.d.ts +51 -0
  99. package/dist/maintenance-tick.d.ts.map +1 -0
  100. package/dist/maintenance-tick.js +156 -0
  101. package/dist/maintenance-tick.js.map +1 -0
  102. package/dist/planner-timeouts.d.ts +14 -0
  103. package/dist/planner-timeouts.d.ts.map +1 -0
  104. package/dist/planner-timeouts.js +51 -0
  105. package/dist/planner-timeouts.js.map +1 -0
  106. package/dist/run-cmd.d.ts +12 -1
  107. package/dist/run-cmd.d.ts.map +1 -1
  108. package/dist/run-cmd.js +146 -10
  109. package/dist/run-cmd.js.map +1 -1
  110. package/dist/run-launcher.d.ts +3 -0
  111. package/dist/run-launcher.d.ts.map +1 -1
  112. package/dist/run-launcher.js +3 -2
  113. package/dist/run-launcher.js.map +1 -1
  114. package/dist/run-refusal-marks.d.ts +7 -1
  115. package/dist/run-refusal-marks.d.ts.map +1 -1
  116. package/dist/run-refusal-marks.js +4 -0
  117. package/dist/run-refusal-marks.js.map +1 -1
  118. package/dist/server-client.d.ts +39 -1
  119. package/dist/server-client.d.ts.map +1 -1
  120. package/dist/server-client.js +28 -0
  121. package/dist/server-client.js.map +1 -1
  122. package/dist/start-attempts.d.ts +4 -2
  123. package/dist/start-attempts.d.ts.map +1 -1
  124. package/dist/start-attempts.js +6 -1
  125. package/dist/start-attempts.js.map +1 -1
  126. package/package.json +2 -2
@@ -0,0 +1,51 @@
1
+ import { type MaintenancePlan, type MaintenanceSettings, type PackageRootFacts } from '@looply/core';
2
+ /**
3
+ * THE WEEKLY MAINTENANCE PLAN, MADE BY THE DAEMON THAT DRIVES THE REPOSITORY.
4
+ *
5
+ * On the daemon's five-minute settings cadence: pull the project's maintenance
6
+ * setting (set in AutoRyn or the console) into `maintenance-settings.json`, and
7
+ * when the weekly slot has passed and no plan was made since, read the repository
8
+ * (`maintenance-facts.ts`), plan (`planMaintenance`), and propose the plan to the
9
+ * server. AutoRyn turns proposals into tickets and goals; this machine never
10
+ * creates a goal by itself.
11
+ *
12
+ * ⚠️ ONE PLAN PER SLOT. `maintenance-state.json` records when the last plan was
13
+ * proposed; a failure to reach the server leaves it unrecorded, so the next
14
+ * cadence tries again — but reading the repository again costs a few `npm`
15
+ * calls, so a failed plan waits 30 minutes before the next try.
16
+ *
17
+ * ⚠️ NEVER TWO AT ONCE, AND NEVER BLOCKING. The plan runs in the background of
18
+ * the cadence; a second cadence that finds one going does nothing.
19
+ */
20
+ export declare const MAINTENANCE_SETTINGS_FILE = "maintenance-settings.json";
21
+ export declare const MAINTENANCE_STATE_FILE = "maintenance-state.json";
22
+ export interface MaintenanceState {
23
+ /** When the last plan reached the server (ms). */
24
+ lastPlannedAt: number | null;
25
+ week: string | null;
26
+ proposed: number;
27
+ skipped: string[];
28
+ /** The last failure and when, for a retry delay and a person reading the file. */
29
+ lastFailureAt: number | null;
30
+ lastFailure: string | null;
31
+ }
32
+ /** The project's maintenance setting as this machine last heard it; null when off or never heard. */
33
+ export declare function readMaintenanceSettings(stateDir: string): MaintenanceSettings | null;
34
+ export declare function readMaintenanceState(stateDir: string): MaintenanceState;
35
+ export interface MaintenanceTickDeps {
36
+ stateDir: string;
37
+ fetchSettings(): Promise<unknown>;
38
+ propose(body: {
39
+ week: string;
40
+ items: MaintenancePlan['items'];
41
+ }): Promise<unknown>;
42
+ gather(opts: {
43
+ deadCode: boolean;
44
+ }): Promise<PackageRootFacts[]>;
45
+ log(line: string): void;
46
+ now(): number;
47
+ }
48
+ export type MaintenanceTickOutcome = 'off' | 'not-due' | 'busy' | 'waiting-retry' | 'proposed' | 'failed';
49
+ /** One cadence: refresh the setting, plan when due. Never throws. Returns what happened (tests). */
50
+ export declare function makeMaintenanceTick(deps: MaintenanceTickDeps): () => Promise<MaintenanceTickOutcome>;
51
+ //# sourceMappingURL=maintenance-tick.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maintenance-tick.d.ts","sourceRoot":"","sources":["../src/maintenance-tick.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AAGtB;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,yBAAyB,8BAA8B,CAAC;AACrE,eAAO,MAAM,sBAAsB,2BAA2B,CAAC;AAG/D,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kFAAkF;IAClF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAkBD,qGAAqG;AACrG,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAKpF;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAWvE;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnF,MAAM,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACjE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,IAAI,MAAM,CAAC;CACf;AAED,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,eAAe,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE1G,oGAAoG;AACpG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,OAAO,CAAC,sBAAsB,CAAC,CA+EpG"}
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAINTENANCE_STATE_FILE = exports.MAINTENANCE_SETTINGS_FILE = void 0;
4
+ exports.readMaintenanceSettings = readMaintenanceSettings;
5
+ exports.readMaintenanceState = readMaintenanceState;
6
+ exports.makeMaintenanceTick = makeMaintenanceTick;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = require("node:path");
9
+ const core_1 = require("@looply/core");
10
+ const server_client_1 = require("./server-client");
11
+ /**
12
+ * THE WEEKLY MAINTENANCE PLAN, MADE BY THE DAEMON THAT DRIVES THE REPOSITORY.
13
+ *
14
+ * On the daemon's five-minute settings cadence: pull the project's maintenance
15
+ * setting (set in AutoRyn or the console) into `maintenance-settings.json`, and
16
+ * when the weekly slot has passed and no plan was made since, read the repository
17
+ * (`maintenance-facts.ts`), plan (`planMaintenance`), and propose the plan to the
18
+ * server. AutoRyn turns proposals into tickets and goals; this machine never
19
+ * creates a goal by itself.
20
+ *
21
+ * ⚠️ ONE PLAN PER SLOT. `maintenance-state.json` records when the last plan was
22
+ * proposed; a failure to reach the server leaves it unrecorded, so the next
23
+ * cadence tries again — but reading the repository again costs a few `npm`
24
+ * calls, so a failed plan waits 30 minutes before the next try.
25
+ *
26
+ * ⚠️ NEVER TWO AT ONCE, AND NEVER BLOCKING. The plan runs in the background of
27
+ * the cadence; a second cadence that finds one going does nothing.
28
+ */
29
+ exports.MAINTENANCE_SETTINGS_FILE = 'maintenance-settings.json';
30
+ exports.MAINTENANCE_STATE_FILE = 'maintenance-state.json';
31
+ const RETRY_AFTER_MS = 30 * 60_000;
32
+ function readJson(path) {
33
+ try {
34
+ const v = JSON.parse((0, node_fs_1.readFileSync)(path, 'utf8'));
35
+ return typeof v === 'object' && v !== null && !Array.isArray(v) ? v : null;
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ }
41
+ function writeJson(path, dir, value) {
42
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
43
+ const tmp = `${path}.${process.pid}.tmp`;
44
+ (0, node_fs_1.writeFileSync)(tmp, JSON.stringify(value, null, 2) + '\n', 'utf8');
45
+ (0, node_fs_1.renameSync)(tmp, path);
46
+ }
47
+ /** The project's maintenance setting as this machine last heard it; null when off or never heard. */
48
+ function readMaintenanceSettings(stateDir) {
49
+ const raw = readJson((0, node_path_1.join)(stateDir, exports.MAINTENANCE_SETTINGS_FILE));
50
+ if (raw === null || raw['settings'] === null || raw['settings'] === undefined)
51
+ return null;
52
+ const v = (0, core_1.validateMaintenanceSettings)(raw['settings']);
53
+ return v.ok ? v.settings : null;
54
+ }
55
+ function readMaintenanceState(stateDir) {
56
+ const raw = readJson((0, node_path_1.join)(stateDir, exports.MAINTENANCE_STATE_FILE)) ?? {};
57
+ const num = (k) => (typeof raw[k] === 'number' && Number.isFinite(raw[k]) ? raw[k] : null);
58
+ return {
59
+ lastPlannedAt: num('lastPlannedAt'),
60
+ week: typeof raw['week'] === 'string' ? raw['week'] : null,
61
+ proposed: num('proposed') ?? 0,
62
+ skipped: Array.isArray(raw['skipped']) ? raw['skipped'].filter((s) => typeof s === 'string') : [],
63
+ lastFailureAt: num('lastFailureAt'),
64
+ lastFailure: typeof raw['lastFailure'] === 'string' ? raw['lastFailure'] : null,
65
+ };
66
+ }
67
+ /** One cadence: refresh the setting, plan when due. Never throws. Returns what happened (tests). */
68
+ function makeMaintenanceTick(deps) {
69
+ let running = false;
70
+ let reportedPullFailure = false;
71
+ const pull = async () => {
72
+ let body;
73
+ try {
74
+ body = await deps.fetchSettings();
75
+ }
76
+ catch (e) {
77
+ if (!(e instanceof server_client_1.ServerError && (e.isOffline || e.isAuth)) && !reportedPullFailure) {
78
+ reportedPullFailure = true;
79
+ deps.log(`maint : could not refresh the maintenance setting — ${e.message}`);
80
+ }
81
+ return;
82
+ }
83
+ reportedPullFailure = false;
84
+ const b = body;
85
+ if (typeof b !== 'object' || b === null || !('settings' in b))
86
+ return;
87
+ let settings = null;
88
+ if (b.settings !== null) {
89
+ const v = (0, core_1.validateMaintenanceSettings)(b.settings);
90
+ if (!v.ok) {
91
+ deps.log(`maint : the server sent a maintenance setting this build refuses (${v.key}: ${v.because})`);
92
+ return;
93
+ }
94
+ settings = v.settings;
95
+ }
96
+ const path = (0, node_path_1.join)(deps.stateDir, exports.MAINTENANCE_SETTINGS_FILE);
97
+ const before = readJson(path);
98
+ if (before !== null && JSON.stringify(before['settings'] ?? null) === JSON.stringify(settings))
99
+ return;
100
+ try {
101
+ writeJson(path, deps.stateDir, { settings, updatedAt: typeof b.updatedAt === 'string' ? b.updatedAt : null, fetchedAt: new Date(deps.now()).toISOString() });
102
+ deps.log(`maint : maintenance is ${settings?.enabled ? 'on' : 'off'} for this project`);
103
+ }
104
+ catch (e) {
105
+ deps.log(`maint : could not write the maintenance setting (${e.message})`);
106
+ }
107
+ };
108
+ const plan = async (settings, week) => {
109
+ const state = readMaintenanceState(deps.stateDir);
110
+ const save = (patch) => {
111
+ try {
112
+ writeJson((0, node_path_1.join)(deps.stateDir, exports.MAINTENANCE_STATE_FILE), deps.stateDir, { ...state, ...patch });
113
+ }
114
+ catch {
115
+ /* the next cadence plans again; a duplicate plan is upserted, not doubled */
116
+ }
117
+ };
118
+ try {
119
+ deps.log(`maint : making this week's maintenance plan (${week})`);
120
+ const facts = await deps.gather({ deadCode: settings.deadCode.enabled });
121
+ const result = (0, core_1.planMaintenance)({ settings, week, roots: facts });
122
+ await deps.propose({ week, items: result.items });
123
+ save({ lastPlannedAt: deps.now(), week, proposed: result.items.length, skipped: result.skipped.slice(0, 50), lastFailure: null, lastFailureAt: null });
124
+ deps.log(`maint : proposed ${result.items.length} maintenance goal(s) for ${week}${result.skipped.length ? `; ${result.skipped.length} thing(s) left for later (${exports.MAINTENANCE_STATE_FILE})` : ''}`);
125
+ return 'proposed';
126
+ }
127
+ catch (e) {
128
+ const why = e.message.slice(0, 300);
129
+ save({ lastFailureAt: deps.now(), lastFailure: why });
130
+ deps.log(`maint : the maintenance plan failed — ${why}; trying again in 30 minutes`);
131
+ return 'failed';
132
+ }
133
+ };
134
+ return async () => {
135
+ await pull();
136
+ const settings = readMaintenanceSettings(deps.stateDir);
137
+ const state = readMaintenanceState(deps.stateDir);
138
+ const due = (0, core_1.maintenanceDue)(settings, state.lastPlannedAt, deps.now());
139
+ if (settings === null || !settings.enabled)
140
+ return 'off';
141
+ if (!due.due)
142
+ return 'not-due';
143
+ if (running)
144
+ return 'busy';
145
+ if (state.lastFailureAt !== null && deps.now() - state.lastFailureAt < RETRY_AFTER_MS)
146
+ return 'waiting-retry';
147
+ running = true;
148
+ try {
149
+ return await plan(settings, due.week);
150
+ }
151
+ finally {
152
+ running = false;
153
+ }
154
+ };
155
+ }
156
+ //# sourceMappingURL=maintenance-tick.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maintenance-tick.js","sourceRoot":"","sources":["../src/maintenance-tick.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * HOW MANY TIMES ONE PLANNING HAS TIMED OUT ON THIS MACHINE — the count `goal-compile.ts`'s
3
+ * `compileTierFor` turns into a longer limit and a smaller plan (TAB-B-57, 2026-10-16: two Starts
4
+ * lost to a ten-minute planner timeout before the third compiled).
5
+ *
6
+ * Keyed by whatever the caller names one planning by (`<id>@<version>`), in the PROJECT's state
7
+ * directory, so a later Start placed in another checkout still knows. Separate from the compiler
8
+ * on purpose: the compiler writes nothing.
9
+ */
10
+ export declare const PLANNER_TIMEOUTS_FILE = "planner-timeouts.json";
11
+ export declare function plannerTimeoutsFor(stateDir: string, key: string): number;
12
+ /** Count one more timeout for `key`; returns the new count. Never throws: the count only lengthens a limit. */
13
+ export declare function notePlannerTimeout(stateDir: string, key: string): number;
14
+ //# sourceMappingURL=planner-timeouts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner-timeouts.d.ts","sourceRoot":"","sources":["../src/planner-timeouts.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAQxE;AAED,+GAA+G;AAC/G,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAmBxE"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PLANNER_TIMEOUTS_FILE = void 0;
4
+ exports.plannerTimeoutsFor = plannerTimeoutsFor;
5
+ exports.notePlannerTimeout = notePlannerTimeout;
6
+ const node_fs_1 = require("node:fs");
7
+ const node_path_1 = require("node:path");
8
+ /**
9
+ * HOW MANY TIMES ONE PLANNING HAS TIMED OUT ON THIS MACHINE — the count `goal-compile.ts`'s
10
+ * `compileTierFor` turns into a longer limit and a smaller plan (TAB-B-57, 2026-10-16: two Starts
11
+ * lost to a ten-minute planner timeout before the third compiled).
12
+ *
13
+ * Keyed by whatever the caller names one planning by (`<id>@<version>`), in the PROJECT's state
14
+ * directory, so a later Start placed in another checkout still knows. Separate from the compiler
15
+ * on purpose: the compiler writes nothing.
16
+ */
17
+ exports.PLANNER_TIMEOUTS_FILE = 'planner-timeouts.json';
18
+ function plannerTimeoutsFor(stateDir, key) {
19
+ try {
20
+ const raw = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(stateDir, exports.PLANNER_TIMEOUTS_FILE), 'utf8'));
21
+ const n = raw[key];
22
+ return typeof n === 'number' && Number.isFinite(n) && n > 0 ? Math.floor(n) : 0;
23
+ }
24
+ catch {
25
+ return 0;
26
+ }
27
+ }
28
+ /** Count one more timeout for `key`; returns the new count. Never throws: the count only lengthens a limit. */
29
+ function notePlannerTimeout(stateDir, key) {
30
+ const path = (0, node_path_1.join)(stateDir, exports.PLANNER_TIMEOUTS_FILE);
31
+ try {
32
+ let raw = {};
33
+ try {
34
+ raw = JSON.parse((0, node_fs_1.readFileSync)(path, 'utf8'));
35
+ }
36
+ catch {
37
+ raw = {};
38
+ }
39
+ const next = (typeof raw[key] === 'number' ? raw[key] : 0) + 1;
40
+ raw[key] = next;
41
+ (0, node_fs_1.mkdirSync)(stateDir, { recursive: true });
42
+ const tmp = `${path}.${process.pid}.tmp`;
43
+ (0, node_fs_1.writeFileSync)(tmp, `${JSON.stringify(raw)}\n`, 'utf8');
44
+ (0, node_fs_1.renameSync)(tmp, path);
45
+ return next;
46
+ }
47
+ catch {
48
+ return 0;
49
+ }
50
+ }
51
+ //# sourceMappingURL=planner-timeouts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner-timeouts.js","sourceRoot":"","sources":["../src/planner-timeouts.ts"],"names":[],"mappings":";;;AAeA,gDAQC;AAGD,gDAmBC;AA7CD,qCAA6E;AAC7E,yCAAiC;AAEjC;;;;;;;;GAQG;AAEU,QAAA,qBAAqB,GAAG,uBAAuB,CAAC;AAE7D,SAAgB,kBAAkB,CAAC,QAAgB,EAAE,GAAW;IAC9D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,IAAA,gBAAI,EAAC,QAAQ,EAAE,6BAAqB,CAAC,EAAE,MAAM,CAAC,CAA4B,CAAC;QAC/G,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,+GAA+G;AAC/G,SAAgB,kBAAkB,CAAC,QAAgB,EAAE,GAAW;IAC9D,MAAM,IAAI,GAAG,IAAA,gBAAI,EAAC,QAAQ,EAAE,6BAAqB,CAAC,CAAC;IACnD,IAAI,CAAC;QACH,IAAI,GAAG,GAA2B,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAA2B,CAAC;QACzE,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,GAAG,EAAE,CAAC;QACX,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC/D,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;QAChB,IAAA,mBAAS,EAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;QACzC,IAAA,uBAAa,EAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvD,IAAA,oBAAU,EAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
package/dist/run-cmd.d.ts CHANGED
@@ -6,6 +6,7 @@ import { type RepairContext, type RunSummary } from './round-runner';
6
6
  import type { AnsweredQuestionView, PartialQuestionBody } from '@looply/core';
7
7
  import { type ApprovalResolutionContext } from './approval-resolution';
8
8
  import { type RepositorySpan } from '@looply/core';
9
+ import type { EnvironmentCode } from '@looply/core';
9
10
  import { type GovernedActionResultContext } from './governed-run';
10
11
  /**
11
12
  * The composition root for `looply run`.
@@ -154,6 +155,11 @@ export declare class RunRefused extends Error {
154
155
  * the mark so the daemon can settle the pursuit with facts, not a sentence.
155
156
  */
156
157
  readonly delivery?: RunDelivery | undefined;
158
+ /**
159
+ * Which machine fault, on an `environment` refusal only — carried to the mark so the
160
+ * controller's hold names it (`environment-hold.ts`).
161
+ */
162
+ readonly environment?: EnvironmentCode | undefined;
157
163
  /**
158
164
  * The same refusal, for a machine.
159
165
  *
@@ -178,7 +184,12 @@ export declare class RunRefused extends Error {
178
184
  * delivering run, the commit, and each required step's outcome. Carried to
179
185
  * the mark so the daemon can settle the pursuit with facts, not a sentence.
180
186
  */
181
- delivery?: RunDelivery | undefined);
187
+ delivery?: RunDelivery | undefined,
188
+ /**
189
+ * Which machine fault, on an `environment` refusal only — carried to the mark so the
190
+ * controller's hold names it (`environment-hold.ts`).
191
+ */
192
+ environment?: EnvironmentCode | undefined);
182
193
  }
183
194
  /** What `looply run` exits with when it refuses for good. */
184
195
  export declare const EXIT_REFUSED = 3;
@@ -1 +1 @@
1
- {"version":3,"file":"run-cmd.d.ts","sourceRoot":"","sources":["../src/run-cmd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAOvD,OAAO,EAGL,KAAK,cAAc,EAKnB,KAAK,IAAI,EAaT,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAA6B,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAiC/E,OAAO,EAGL,KAAK,aAAa,EAIlB,KAAK,UAAU,EAChB,MAAM,gBAAgB,CAAC;AAoBxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAmB9E,OAAO,EAGL,KAAK,yBAAyB,EAE/B,MAAM,uBAAuB,CAAC;AAe/B,OAAO,EAaL,KAAK,cAAc,EAEpB,MAAM,cAAc,CAAC;AAiCtB,OAAO,EAIL,KAAK,2BAA2B,EAEjC,MAAM,gBAAgB,CAAC;AAIxB;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,YAAY,GACpB,iBAAiB,GACjB,YAAY,GACZ,gBAAgB,GAChB,eAAe,GACf,iBAAiB,GACjB,qBAAqB,CAAC;AAE1B,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;IACrB;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAAC;IAC5D,oEAAoE;IACpE,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;;;;;;;OAiBG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;;;;;;OAUG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,qBAAa,UAAW,SAAQ,KAAK;IAcjC,QAAQ,CAAC,IAAI,EAAE,cAAc;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;IACxB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,WAAW;IA1BjC;;;;;;;;;;OAUG;gBAED,OAAO,EAAE,MAAM,EACN,IAAI,GAAE,cAA8B;IAC7C;;;;;OAKG;IACM,MAAM,CAAC,EAAE,MAAM,YAAA;IACxB;;;;OAIG;IACM,QAAQ,CAAC,EAAE,WAAW,YAAA;CAIlC;AAED,6DAA6D;AAC7D,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE;IAAE,MAAM,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,EACxD,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAE,EAC5G,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC1B,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAYtC,4EAA4E;AAC5E,eAAO,MAAM,8BAA8B,QAAY,CAAC;AACxD,iGAAiG;AACjG,eAAO,MAAM,6BAA6B,QAAY,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CA+D5D;AA6MD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,YAAY;AACjB;;;;;;;;GAQG;AACH,UAAU,CAAC,EAAE,yBAAyB;AACtC;;;;;;GAMG;AACH,QAAQ,CAAC,EAAE,2BAA2B;AACtC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;AACtB;;;;;;;;GAQG;AACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;AACzB;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,EAAE,aAAa;AACtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;AACpB;;;;;;;;;;;;GAYG;AACH,IAAI,CAAC,EAAE,cAAc,GACpB,MAAM,CA4FR;AAED;;;;;;;;;;;GAWG;AACH;;;;;;GAMG;AACH,MAAM,WAAW,yBAAyB;IACxC,GAAG,CAAC,IAAI,EAAE,mBAAmB,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChF,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;CACnF;AAiID;;;GAGG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAs8HnE"}
1
+ {"version":3,"file":"run-cmd.d.ts","sourceRoot":"","sources":["../src/run-cmd.ts"],"names":[],"mappings":"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"}
package/dist/run-cmd.js CHANGED
@@ -63,9 +63,13 @@ const programme_mode_1 = require("./programme-mode");
63
63
  const partial_asker_1 = require("./partial-asker");
64
64
  const goal_ownership_1 = require("./goal-ownership");
65
65
  const goal_compile_1 = require("./goal-compile");
66
+ const planner_timeouts_1 = require("./planner-timeouts");
66
67
  const plan_recovery_1 = require("./plan-recovery");
67
68
  const goal_execution_evidence_1 = require("./goal-execution-evidence");
68
69
  const goal_reproof_1 = require("./goal-reproof");
70
+ const goal_replay_1 = require("./goal-replay");
71
+ const branch_replay_1 = require("./branch-replay");
72
+ const run_base_2 = require("./run-base");
69
73
  const round_records_1 = require("./round-records");
70
74
  const goal_gap_1 = require("./goal-gap");
71
75
  const goal_adaptive_1 = require("./goal-adaptive");
@@ -128,6 +132,7 @@ class RunRefused extends Error {
128
132
  code;
129
133
  branch;
130
134
  delivery;
135
+ environment;
131
136
  /**
132
137
  * The same refusal, for a machine.
133
138
  *
@@ -152,11 +157,17 @@ class RunRefused extends Error {
152
157
  * delivering run, the commit, and each required step's outcome. Carried to
153
158
  * the mark so the daemon can settle the pursuit with facts, not a sentence.
154
159
  */
155
- delivery) {
160
+ delivery,
161
+ /**
162
+ * Which machine fault, on an `environment` refusal only — carried to the mark so the
163
+ * controller's hold names it (`environment-hold.ts`).
164
+ */
165
+ environment) {
156
166
  super(message);
157
167
  this.code = code;
158
168
  this.branch = branch;
159
169
  this.delivery = delivery;
170
+ this.environment = environment;
160
171
  }
161
172
  }
162
173
  exports.RunRefused = RunRefused;
@@ -1024,6 +1035,9 @@ async function runLoop(opts) {
1024
1035
  * ⚠️ AN ARROW, for the same flow-analysis reason as `recordDelivery` below.
1025
1036
  */
1026
1037
  const deliveringBranch = async () => {
1038
+ // The branch this goal's work was REBUILT onto, when it was: that is the tree that was proved.
1039
+ if (rebuiltAs !== null)
1040
+ return rebuiltAs.branch;
1027
1041
  if (deliveringRunId === null)
1028
1042
  return branch;
1029
1043
  const cut = (0, run_delivery_1.deliveringBranchOf)((0, lane_claims_1.readLaneClaims)(cwd), deliveringRunId);
@@ -2802,7 +2816,31 @@ async function runLoop(opts) {
2802
2816
  * would put sixty minutes of verifier inside a sixty-minute window. They draw
2803
2817
  * from one budget instead.
2804
2818
  */
2805
- let verifyBudget = verify_cmd_2.VERIFY_MAX_PER_RUN;
2819
+ /**
2820
+ * THE PLANNING TIER (`goal-compile.ts`, COMPILE_TIERS): after a timed-out planning of this goal
2821
+ * version, a longer limit and a smaller plan, so the worst case stays inside the window. The
2822
+ * verify budget shrinks with the plan — that is what pays for the longer compile.
2823
+ */
2824
+ // PROJECT-scoped: a goal's next Start may be placed in another checkout, and must still know.
2825
+ const plannedTimeouts = binding.kind === 'bound' ? (0, planner_timeouts_1.plannerTimeoutsFor)(projectStateDirPath, `${binding.goal.id}@${binding.goal.version}`) : 0;
2826
+ const compileTier = (0, goal_compile_1.compileTierFor)(plannedTimeouts);
2827
+ const adaptiveTier = (0, goal_compile_1.compileTierFor)(plannedTimeouts, goal_compile_1.ADAPTIVE_COMPILE_TIERS);
2828
+ let compileTimedOut = false;
2829
+ /**
2830
+ * A PLANNER THAT RAN OUT OF TIME IS THE MACHINE'S LIMIT, NOT THE GOAL'S FAULT: the run leaves
2831
+ * with `environment` / `planner_timeout`, so the controller voids this Start (it costs no try),
2832
+ * and the timeout is counted so the next Start plans with the next tier. Null when no planning
2833
+ * timed out in this run — the exit is then whatever it was.
2834
+ */
2835
+ const plannerTimedOut = (message) => {
2836
+ if (!compileTimedOut || binding.kind !== 'bound')
2837
+ return null;
2838
+ const n = (0, planner_timeouts_1.notePlannerTimeout)(projectStateDirPath, `${binding.goal.id}@${binding.goal.version}`);
2839
+ const next = (0, goal_compile_1.compileTierFor)(n);
2840
+ return new RunRefused(`${message} — planning took longer than its limit; the next Start plans with ${Math.round(next.timeoutMs / 60000)} minutes ` +
2841
+ `for at most ${next.maxSteps} steps, and this Start does not count`, 'environment', undefined, undefined, 'planner_timeout');
2842
+ };
2843
+ let verifyBudget = Math.min(verify_cmd_2.VERIFY_MAX_PER_RUN, compileTier.maxSteps);
2806
2844
  /**
2807
2845
  * EVERYTHING A START DOES BEFORE THE RUN, under one guard.
2808
2846
  *
@@ -2882,6 +2920,10 @@ async function runLoop(opts) {
2882
2920
  let deliveringRunId = null;
2883
2921
  // L4b: the commit key 2 confirmed HEAD on, beside the run that delivered it.
2884
2922
  let deliveringSha = null;
2923
+ /** This goal's work, rebuilt onto the base for the goal check (`goal-replay.ts`), when it was. */
2924
+ let rebuiltAs = null;
2925
+ /** Why it could not be rebuilt, when that was tried and failed: what the next revision plans around. */
2926
+ let replayTrouble = null;
2885
2927
  /** F27: the tree this Start's evaluator judged, when a programme moved HEAD to the tree the lane holds. */
2886
2928
  let judged = { kind: 'as-is', because: 'no goal-met check ran' };
2887
2929
  /** The first compile's authority answer, kept so its reason is the acted-on one. */
@@ -2927,11 +2969,16 @@ async function runLoop(opts) {
2927
2969
  checks: config.gates.map((g) => g.name),
2928
2970
  }),
2929
2971
  }, {
2930
- compile: (i) => (0, goal_compile_1.compileGoal)(i, { invoke: planAgent }),
2972
+ compile: async (i) => {
2973
+ const out = await (0, goal_compile_1.compileGoal)(i, { invoke: planAgent, timeoutMs: compileTier.timeoutMs, maxSteps: compileTier.maxSteps });
2974
+ if (!out.ok && out.failure === 'timed-out')
2975
+ compileTimedOut = true;
2976
+ return out;
2977
+ },
2931
2978
  // M3-2: checked at the committed tree before any step becomes an item; the compile recorded either way.
2932
2979
  check: (steps) => (0, compile_check_1.checkCompiledPlan)(steps, compileReaders, compiledAt),
2933
2980
  log: (line) => log(`compile : ${line}`),
2934
- }, goal_compile_1.COMPILE_MAX_STEPS);
2981
+ }, compileTier.maxSteps);
2935
2982
  // A step whose citation did not hold is re-planned, an empty plan is asked again as an instruction,
2936
2983
  // and only then does a ticket get one direct step (`plan-recovery.ts`) — never a hand-back.
2937
2984
  const compiled = recovered.compiled;
@@ -3193,6 +3240,53 @@ async function runLoop(opts) {
3193
3240
  }
3194
3241
  log(`goal : judging ${(0, goal_met_target_1.describeTarget)(judged)}`);
3195
3242
  }
3243
+ /**
3244
+ * THE CODE MOVED AWAY FROM THIS GOAL'S WORK: REBUILD IT ONTO THE BASE, THEN JUDGE THAT TREE
3245
+ * (`goal-replay.ts`, owner ruling 2026-10-16). In a checkout Looply made, when HEAD holds none
3246
+ * of this plan's commits, they are replayed onto the base as a fresh run branch BEFORE the
3247
+ * evaluator looks — so the verdict and the gates are about the same tree, and the branch holds
3248
+ * only this goal's work. A replay that does not apply puts HEAD back; KEY 2 then plans what is
3249
+ * missing instead of refusing (`replan`).
3250
+ */
3251
+ if (judged.kind === 'as-is' && (0, reaper_1.hasProvisionedMarker)(cwd)) {
3252
+ const rounds = await (0, round_records_1.readRoundRecords)(stateDir, ledger_store_1.nodeLedgerFs);
3253
+ if (rounds.ok) {
3254
+ const committed = (0, goal_execution_evidence_1.committedShasOf)({ scope: askedScope, items: owned, rounds: rounds.rounds });
3255
+ const aligned = await (0, goal_replay_1.alignWithOwnWork)({
3256
+ headSha: () => git.headSha(),
3257
+ changedPaths: () => git.changedPaths(),
3258
+ isAncestor: (a, of) => git.isAncestor(a, of),
3259
+ baseRef: async () => (await (0, run_base_2.resolveBaseBranch)(git, config.run.baseBranch).catch(() => null))?.ref ?? null,
3260
+ commitOf: (ref) => git.commitOf(ref),
3261
+ // The same patch replay the delivery rebuild uses: never a 3-way merge (`branch-replay.ts`).
3262
+ replay: (base, shas) => (0, branch_replay_1.replayOnto)((0, git_driver_1.nodeGitExec)(cwd), (dir) => (0, git_driver_1.nodeGitExec)(dir), base, shas),
3263
+ commitsBetween: async (base, sha) => (await (0, git_driver_1.nodeGitExec)(cwd)(['rev-list', '--reverse', `${base}..${sha}`])).stdout.split(/\r?\n/).filter((l) => l.trim() !== ''),
3264
+ createBranch: (name, from) => git.createBranch(name, from),
3265
+ }, { committed, branch: `${branch}-rebuilt`, aliases: (0, goal_replay_1.replayedAs)(projectStateDirPath, goalId) });
3266
+ if (aligned.kind === 'rebuilt') {
3267
+ (0, goal_replay_1.recordReplay)(projectStateDirPath, goalId, aligned.picked);
3268
+ (0, run_base_1.writeCheckoutGoal)(stateDir, { goalId, branch: aligned.branch, at: new Date().toISOString() });
3269
+ (0, lane_claims_1.recordLaneClaim)(cwd, {
3270
+ schema: lane_claims_1.LANE_CLAIMS_SCHEMA,
3271
+ kind: 'claims',
3272
+ at: new Date().toISOString(),
3273
+ branch: aligned.branch,
3274
+ runId,
3275
+ goalId,
3276
+ goalVersion: bound.version,
3277
+ planRevision: revision,
3278
+ servings: [],
3279
+ workspace: cwd,
3280
+ });
3281
+ rebuiltAs = { branch: aligned.branch, head: aligned.head };
3282
+ log(`goal : this goal's ${committed.length} commit(s) were not in the tree here — rebuilt onto ${aligned.base} as ${aligned.branch}; judging that`);
3283
+ }
3284
+ else if (aligned.kind === 'failed') {
3285
+ replayTrouble = aligned.because;
3286
+ log(`goal : ${aligned.because}`);
3287
+ }
3288
+ }
3289
+ }
3196
3290
  adaptive = await (0, goal_adaptive_1.decideAdaptive)({
3197
3291
  goalId: scope.goalId,
3198
3292
  goalVersion: bound.version,
@@ -3233,10 +3327,19 @@ async function runLoop(opts) {
3233
3327
  compile: async (i, maxSteps) => {
3234
3328
  const at = await git.headTreeSha().catch(() => null);
3235
3329
  const recovered = await (0, plan_recovery_1.compileWithRecovery)(i, {
3236
- compile: (j) => (0, goal_compile_1.compileGoal)(j, { invoke: planAgent, maxSteps }),
3330
+ compile: async (j) => {
3331
+ const out = await (0, goal_compile_1.compileGoal)(j, {
3332
+ invoke: planAgent,
3333
+ maxSteps: Math.min(maxSteps, adaptiveTier.maxSteps),
3334
+ timeoutMs: adaptiveTier.timeoutMs,
3335
+ });
3336
+ if (!out.ok && out.failure === 'timed-out')
3337
+ compileTimedOut = true;
3338
+ return out;
3339
+ },
3237
3340
  check: (steps) => (0, compile_check_1.checkCompiledPlan)(steps, compileReaders, at),
3238
3341
  log: (line) => log(`goal : ${line}`),
3239
- }, maxSteps);
3342
+ }, Math.min(maxSteps, adaptiveTier.maxSteps));
3240
3343
  return recovered.compiled;
3241
3344
  },
3242
3345
  changedPaths: () => git.changedPaths(),
@@ -3272,16 +3375,47 @@ async function runLoop(opts) {
3272
3375
  */
3273
3376
  if (!confirmed.ok && confirmed.moved === true && judged.kind !== 'carried') {
3274
3377
  log('goal : the code moved on since this plan was delivered — running the gates again at the current tree');
3378
+ let reproofVerdict = null;
3275
3379
  const again = await (0, goal_reproof_1.reproveAtHead)(head, (0, goal_execution_evidence_1.committedShasOf)(key2Input), {
3276
3380
  changedPaths: () => git.changedPaths(),
3277
3381
  isAncestor: (a, of) => git.isAncestor(a, of),
3278
3382
  changedPathsBetween: (from, to) => git.changedPathsBetween(from, to),
3279
- runGates: async (paths) => (await (0, gate_1.runGate)({ steps: config.gates, changedPaths: paths, runner: (0, untrusted_gate_1.makeUntrustedGateRunner)(cwd) })).steps,
3383
+ runGates: async (paths) => {
3384
+ const gate = await (0, gate_1.runGate)({ steps: config.gates, changedPaths: paths, runner: (0, untrusted_gate_1.makeUntrustedGateRunner)(cwd) });
3385
+ reproofVerdict = gate.verdict;
3386
+ return gate.steps;
3387
+ },
3388
+ aliases: (0, goal_replay_1.replayedAs)(projectStateDirPath, goalId),
3280
3389
  });
3281
3390
  confirmed = again.ok
3282
3391
  ? (0, goal_execution_evidence_1.confirmGoalExecutionEvidence)({ ...key2Input, rechecked: { contains: again.contains, steps: again.steps } })
3283
3392
  : { ok: false, because: `${goal_execution_evidence_1.CODE_MOVED_ON}, and it could not be checked again: ${again.because}` };
3284
3393
  log(`goal : ${confirmed.ok ? 'the gates pass at the current tree, and this plan’s work is in it' : confirmed.because}`);
3394
+ if (!confirmed.ok) {
3395
+ /**
3396
+ * NEVER A HAND-BACK FOR THIS (owner ruling 2026-10-16). Three answers, none of them a
3397
+ * person's question:
3398
+ * - the gate could not RUN here (sandbox, tool): the machine's fault — retryable, and
3399
+ * the run's words name it, so the Start is voided (`environment`);
3400
+ * - the tree has uncommitted changes: not this run's to judge — retryable;
3401
+ * - the gates are red here, or the work is not in this tree (and could not be
3402
+ * rebuilt onto the base): a gap the work can close — the next revision plans it.
3403
+ */
3404
+ if (reproofVerdict === 'blocked') {
3405
+ return {
3406
+ ok: false,
3407
+ reason: `gate blocked: step could not run — the environment is unavailable, not the change (${confirmed.because})`,
3408
+ unknown: true,
3409
+ };
3410
+ }
3411
+ if (!again.ok && /uncommitted change/.test(again.because))
3412
+ return { ok: false, reason: again.because, unknown: true };
3413
+ return {
3414
+ ok: false,
3415
+ reason: replayTrouble === null ? confirmed.because : `${confirmed.because} (${replayTrouble})`,
3416
+ replan: true,
3417
+ };
3418
+ }
3285
3419
  }
3286
3420
  /**
3287
3421
  * 🔴 WHAT KEY 2 SAW, KEPT FOR THE FOURTH KEY.
@@ -3295,7 +3429,8 @@ async function runLoop(opts) {
3295
3429
  */
3296
3430
  if (confirmed.ok) {
3297
3431
  deliveringRunId = confirmed.round.runId;
3298
- deliveringSha = confirmed.round.sha ?? null;
3432
+ // A REBUILT tree delivers its own tip: the original round's commit is not in it.
3433
+ deliveringSha = rebuiltAs !== null ? rebuiltAs.head : (confirmed.round.sha ?? null);
3299
3434
  key2Saw = {
3300
3435
  delivered: new Set(confirmed.delivered),
3301
3436
  checks: new Map((confirmed.reproved ?? confirmed.round.gate?.steps ?? []).map((st) => [
@@ -3575,7 +3710,7 @@ async function runLoop(opts) {
3575
3710
  await releaseHold();
3576
3711
  // The branch the controller will ask the lane about: the one that delivered (F20).
3577
3712
  const refusedOn = deliveredOn;
3578
- throw said.terminal ? new RunRefused(said.message, said.code, refusedOn, delivery) : new Error(said.message);
3713
+ throw said.terminal ? new RunRefused(said.message, said.code, refusedOn, delivery) : (plannerTimedOut(said.message) ?? new Error(said.message));
3579
3714
  }
3580
3715
  }
3581
3716
  const left = scope === null ? null : (0, core_1.workLeft)(runQueue.list());
@@ -3603,7 +3738,8 @@ async function runLoop(opts) {
3603
3738
  throw new RunRefused(`nothing here can move without you — ${(0, queue_summary_1.describeNoReady)(runQueue.list())}`, 'human_required');
3604
3739
  }
3605
3740
  await releaseHold();
3606
- throw new Error(`nothing to do — ${(0, queue_summary_1.describeNoReady)(runQueue.list())}`);
3741
+ const nothing = `nothing to do — ${(0, queue_summary_1.describeNoReady)(runQueue.list())}`;
3742
+ throw plannerTimedOut(compileNote === null ? nothing : `${nothing} (${compileNote})`) ?? new Error(nothing);
3607
3743
  }
3608
3744
  /**
3609
3745
  * THE APPROVAL BOUNDARY, AND THE ONLY PLACE IT COULD LIVE.