atris 3.74.28 → 3.74.29
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/lib/fleet.js +39 -29
- package/package.json +1 -1
package/lib/fleet.js
CHANGED
|
@@ -53,18 +53,27 @@ const {
|
|
|
53
53
|
} = require('./secret-gateway');
|
|
54
54
|
const { appendEngineLiveLogChunk, createEngineLiveLog, engineTerminalReason } = require('./engine-job-lifecycle');
|
|
55
55
|
const { recordEngineResource } = require('./engine-resource');
|
|
56
|
+
const {
|
|
57
|
+
taskTagTokens,
|
|
58
|
+
isDecisionHoldTag,
|
|
59
|
+
isDecisionTask,
|
|
60
|
+
DECISION_REFUSE_REASON,
|
|
61
|
+
} = require('./task-decision');
|
|
56
62
|
|
|
57
63
|
// Lanes a fleet may never staff on its own: the human keeps irreversible
|
|
58
64
|
// calls. Mirrors the autoland denied lanes.
|
|
59
65
|
const DENIED_TAGS = ['billing', 'money', 'payments', 'deploy', 'security', 'customer', 'external', 'feedback'];
|
|
60
66
|
|
|
61
|
-
// The protected lane a task sits in
|
|
62
|
-
//
|
|
63
|
-
//
|
|
67
|
+
// The protected lane a task sits in, or null. This is the one place that
|
|
68
|
+
// decides protection: staffing (isSafeLane), the ship gate, the dispatch flight
|
|
69
|
+
// and the builder prompt all ask it, so a task one of them holds back as
|
|
70
|
+
// protected is never one that another would merge. A task's tags are its tag,
|
|
71
|
+
// its tags list, the tags `atris task tag` adds later and hashtags in its
|
|
72
|
+
// title (all through taskTagTokens), plus the todo tags it was imported with.
|
|
64
73
|
function protectedLaneOfTask(task) {
|
|
65
74
|
if (!task || typeof task !== 'object') return null;
|
|
66
75
|
const todoTags = task.metadata && Array.isArray(task.metadata.todo_tags) ? task.metadata.todo_tags : [];
|
|
67
|
-
const tags = [task
|
|
76
|
+
const tags = [...taskTagTokens(task), ...todoTags.filter(Boolean).map((tag) => String(tag).trim().toLowerCase())];
|
|
68
77
|
return tags.find((tag) => DENIED_TAGS.includes(tag)) || null;
|
|
69
78
|
}
|
|
70
79
|
|
|
@@ -126,7 +135,8 @@ function shellQuote(value) {
|
|
|
126
135
|
|
|
127
136
|
// The bounded prompt every engine gets: isolated worktree, MAP first, the
|
|
128
137
|
// task's own check, one landing order per mode. Yolo: the engine lands it
|
|
129
|
-
// itself with worktree ship
|
|
138
|
+
// itself with worktree ship, unless the task is in a protected lane. Otherwise:
|
|
139
|
+
// commit only, the conductor lands it.
|
|
130
140
|
function buildFleetPrompt(task, { worktreePath, yolo = false } = {}) {
|
|
131
141
|
const ref = task.display_id || task.id || 'TASK';
|
|
132
142
|
const title = String(task.title || '').trim();
|
|
@@ -134,11 +144,27 @@ function buildFleetPrompt(task, { worktreePath, yolo = false } = {}) {
|
|
|
134
144
|
const done = titleDone || String((task.metadata && task.metadata.done_looks_like) || '').trim();
|
|
135
145
|
const check = taskDispatchCheck(task, worktreePath || process.cwd());
|
|
136
146
|
const shipMessage = title.split(/[.:](?:\s|$)/)[0].replace(/"/g, "'").slice(0, 90) || ref;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
147
|
+
// A protected-lane task is never shipped by its builder, yolo or not. The
|
|
148
|
+
// builder commits and stops, and the dispatch flight ships that commit once,
|
|
149
|
+
// without --merge, so a pull request opens and a person lands it. A builder
|
|
150
|
+
// that shipped too would open the pull request before the flight's own
|
|
151
|
+
// check, and if the flight's check or ship then failed, the claim would be
|
|
152
|
+
// released with that pull request open and unrecorded. Yolo still gives the
|
|
153
|
+
// builder its network for running checks.
|
|
154
|
+
const lane = yolo ? protectedLaneOfTask(task) : null;
|
|
155
|
+
let commitRule;
|
|
156
|
+
if (lane) {
|
|
157
|
+
commitRule = `This task is in the protected ${lane} lane, so a person lands it, not you. Commit on the current branch with a plain-English message. Do not push, do not run \`atris worktree ship\`, and do not create branches; the conductor ships your commit for a person to review.`;
|
|
158
|
+
} else if (yolo) {
|
|
159
|
+
commitRule = `Land it yourself. Commit on the current branch with a plain-English message, then run: atris worktree ship --message "${shipMessage} (${ref})" --verify ${shellQuote(check)} --merge, and report the PR URL. That ship command is the only push allowed. If it reports a conflict or a failed check, stop and report; never resolve conflicts yourself.`;
|
|
160
|
+
} else {
|
|
161
|
+
commitRule = 'Commit on the current branch with a clear message. Do not push and do not create branches; the conductor lands your commit.';
|
|
162
|
+
}
|
|
163
|
+
// The guard refuses a checkout that has edits in it, so it can only pass at
|
|
164
|
+
// the start. A builder that re-ran it in its review step, after its edits,
|
|
165
|
+
// took the failure as a stop order and left finished work uncommitted.
|
|
140
166
|
const lines = [
|
|
141
|
-
'
|
|
167
|
+
'Before your first edit, run `atris worktree guard` once; if it fails then, stop immediately, report back, and do not edit anything. It checks for a clean start, so it fails once edits exist: never run it again after editing.',
|
|
142
168
|
'',
|
|
143
169
|
ATRIS_BUILD_PROCESS_PREAMBLE,
|
|
144
170
|
'',
|
|
@@ -162,7 +188,7 @@ function buildFleetPrompt(task, { worktreePath, yolo = false } = {}) {
|
|
|
162
188
|
`- ${commitRule}`,
|
|
163
189
|
...METHOD_KERNEL.map((rule) => `- ${rule}`),
|
|
164
190
|
'',
|
|
165
|
-
`Final report (plain text): files changed, check command + result, commit sha${yolo ? ', PR URL' : ''} (or say what failed and why).`
|
|
191
|
+
`Final report (plain text): files changed, check command + result, commit sha${yolo && !lane ? ', PR URL' : ''} (or say what failed and why).`
|
|
166
192
|
);
|
|
167
193
|
const lessonFiles = [
|
|
168
194
|
...(Array.isArray(task.files) ? task.files : []),
|
|
@@ -1358,20 +1384,6 @@ function dispatchToEngine({ task, engine, worktreePath, root = process.cwd(), ti
|
|
|
1358
1384
|
// ---------------------------------------------------------------------------
|
|
1359
1385
|
// T2: staffing
|
|
1360
1386
|
|
|
1361
|
-
const {
|
|
1362
|
-
taskTagTokens,
|
|
1363
|
-
isDecisionHoldTag,
|
|
1364
|
-
isDecisionTask,
|
|
1365
|
-
DECISION_REFUSE_REASON,
|
|
1366
|
-
} = require('./task-decision');
|
|
1367
|
-
|
|
1368
|
-
function taskTags(task) {
|
|
1369
|
-
// Tags added after creation live in metadata.tags (`atris task tag`); a
|
|
1370
|
-
// fleet that only read task.tags/title hashtags would ignore an owner-hold
|
|
1371
|
-
// flag stamped on a live task and keep restaffing it (CLI-879).
|
|
1372
|
-
return taskTagTokens(task);
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
1387
|
// A task flagged for a human decision is never fleet-staffable, whatever its
|
|
1376
1388
|
// lane. Mirrors the sweep's needs-human hold so both loops agree. Also honors
|
|
1377
1389
|
// the clearer `decision` tag so policy questions stay off autonomous lanes.
|
|
@@ -1379,10 +1391,10 @@ function isHumanHoldTag(tag) {
|
|
|
1379
1391
|
return isDecisionHoldTag(tag);
|
|
1380
1392
|
}
|
|
1381
1393
|
|
|
1394
|
+
// The fleet may staff a task only when no person has to decide it and it sits
|
|
1395
|
+
// in no protected lane. Protection is protectedLaneOfTask's call alone.
|
|
1382
1396
|
function isSafeLane(task) {
|
|
1383
|
-
|
|
1384
|
-
const tags = taskTags(task);
|
|
1385
|
-
return !tags.some((t) => DENIED_TAGS.includes(t));
|
|
1397
|
+
return !isDecisionTask(task) && !protectedLaneOfTask(task);
|
|
1386
1398
|
}
|
|
1387
1399
|
|
|
1388
1400
|
// Rough file-surface guess from a task's text: paths and bare `commands/x.js`
|
|
@@ -1713,12 +1725,10 @@ module.exports = {
|
|
|
1713
1725
|
assertIsolatedWorktree,
|
|
1714
1726
|
buildEngineCommand,
|
|
1715
1727
|
isSafeLane,
|
|
1716
|
-
taskTags,
|
|
1717
1728
|
nextInstalledFleetEngine,
|
|
1718
1729
|
rankFleetEnginesDetailed,
|
|
1719
1730
|
dispatchToEngine,
|
|
1720
1731
|
recordDispatchOutcome,
|
|
1721
|
-
taskTags,
|
|
1722
1732
|
isHumanHoldTag,
|
|
1723
1733
|
isDecisionTask,
|
|
1724
1734
|
DECISION_REFUSE_REASON,
|
package/package.json
CHANGED