@xn-intenton-z2a/agentic-lib 7.1.69 → 7.1.71

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.
@@ -13,8 +13,6 @@ name: agentic-lib-init
13
13
  run-name: "agentic-lib-init [${{ github.ref_name }}]"
14
14
 
15
15
  on:
16
- #@dist schedule:
17
- #@dist - cron: "0 5 * * *"
18
16
  workflow_call:
19
17
  inputs:
20
18
  mode:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xn-intenton-z2a/agentic-lib",
3
- "version": "7.1.69",
3
+ "version": "7.1.71",
4
4
  "description": "Agentic-lib Agentic Coding Systems SDK powering automated GitHub workflows.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -9,7 +9,7 @@ import * as core from "@actions/core";
9
9
  import * as github from "@actions/github";
10
10
  import { loadConfig, getWritablePaths } from "./config-loader.js";
11
11
  import { logActivity, generateClosingNotes } from "./logging.js";
12
- import { readFileSync } from "fs";
12
+ import { readFileSync, existsSync, readdirSync } from "fs";
13
13
 
14
14
  // Task implementations
15
15
  import { resolveIssue } from "./tasks/resolve-issue.js";
@@ -99,15 +99,63 @@ async function run() {
99
99
  if (result.action) core.setOutput("action", result.action);
100
100
  if (result.actionArg) core.setOutput("action-arg", result.actionArg);
101
101
 
102
- // Compute limits status for enriched logging
102
+ const profileName = config.tuning?.profileName || "unknown";
103
+
104
+ // Transformation cost: 1 for code-changing tasks, 0 otherwise
105
+ const COST_TASKS = ["transform", "fix-code", "maintain-features", "maintain-library"];
106
+ const isNop = result.outcome === "nop" || result.outcome === "error";
107
+ const transformationCost = COST_TASKS.includes(task) && !isNop ? 1 : 0;
108
+
109
+ // Read cumulative transformation cost from the activity log
110
+ const intentionFilepath = config.intentionBot?.intentionFilepath;
111
+ let cumulativeCost = 0;
112
+ if (intentionFilepath && existsSync(intentionFilepath)) {
113
+ const logContent = readFileSync(intentionFilepath, "utf8");
114
+ const costMatches = logContent.matchAll(/\*\*agentic-lib transformation cost:\*\* (\d+)/g);
115
+ cumulativeCost = [...costMatches].reduce((sum, m) => sum + parseInt(m[1], 10), 0);
116
+ }
117
+ cumulativeCost += transformationCost;
118
+
119
+ // Count features and library docs on disk
120
+ const featuresPath = config.paths?.features?.path;
121
+ const featuresUsed = featuresPath && existsSync(featuresPath)
122
+ ? readdirSync(featuresPath).filter((f) => f.endsWith(".md")).length
123
+ : 0;
124
+ const libraryPath = config.paths?.library?.path;
125
+ const libraryUsed = libraryPath && existsSync(libraryPath)
126
+ ? readdirSync(libraryPath).filter((f) => f.endsWith(".md")).length
127
+ : 0;
128
+
129
+ // Count open automated issues (feature vs maintenance)
130
+ let featureIssueCount = 0;
131
+ let maintenanceIssueCount = 0;
132
+ try {
133
+ const { data: openAutoIssues } = await context.octokit.rest.issues.listForRepo({
134
+ ...context.repo,
135
+ state: "open",
136
+ labels: "automated",
137
+ per_page: 50,
138
+ });
139
+ for (const oi of openAutoIssues.filter((i) => !i.pull_request)) {
140
+ const lbls = oi.labels.map((l) => l.name);
141
+ if (lbls.includes("maintenance")) maintenanceIssueCount++;
142
+ else featureIssueCount++;
143
+ }
144
+ } catch (_) { /* API not available */ }
145
+
146
+ const budgetCap = config.transformationBudget || 0;
147
+ const featCap = config.paths?.features?.limit || 4;
148
+ const libCap = config.paths?.library?.limit || 32;
149
+
150
+ // Compute limits status with actual values
103
151
  const limitsStatus = [
104
- { name: "transformation-budget", valueNum: 0, capacityNum: config.transformationBudget || 0, value: `0/${config.transformationBudget || 0}`, remaining: `${config.transformationBudget || 0}`, status: "" },
105
- { name: "max-feature-issues", valueNum: 0, capacityNum: config.featureDevelopmentIssuesWipLimit, value: `?/${config.featureDevelopmentIssuesWipLimit}`, remaining: "?", status: "" },
106
- { name: "max-maintenance-issues", valueNum: 0, capacityNum: config.maintenanceIssuesWipLimit, value: `?/${config.maintenanceIssuesWipLimit}`, remaining: "?", status: "" },
152
+ { name: "transformation-budget", valueNum: cumulativeCost, capacityNum: budgetCap, value: `${cumulativeCost}/${budgetCap}`, remaining: `${Math.max(0, budgetCap - cumulativeCost)}`, status: cumulativeCost >= budgetCap && budgetCap > 0 ? "EXHAUSTED" : "" },
153
+ { name: "max-feature-issues", valueNum: featureIssueCount, capacityNum: config.featureDevelopmentIssuesWipLimit, value: `${featureIssueCount}/${config.featureDevelopmentIssuesWipLimit}`, remaining: `${Math.max(0, config.featureDevelopmentIssuesWipLimit - featureIssueCount)}`, status: "" },
154
+ { name: "max-maintenance-issues", valueNum: maintenanceIssueCount, capacityNum: config.maintenanceIssuesWipLimit, value: `${maintenanceIssueCount}/${config.maintenanceIssuesWipLimit}`, remaining: `${Math.max(0, config.maintenanceIssuesWipLimit - maintenanceIssueCount)}`, status: "" },
107
155
  { name: "max-attempts-per-issue", valueNum: 0, capacityNum: config.attemptsPerIssue, value: `?/${config.attemptsPerIssue}`, remaining: "?", status: task === "resolve-issue" ? "" : "n/a" },
108
156
  { name: "max-attempts-per-branch", valueNum: 0, capacityNum: config.attemptsPerBranch, value: `?/${config.attemptsPerBranch}`, remaining: "?", status: task === "fix-code" ? "" : "n/a" },
109
- { name: "features", valueNum: 0, capacityNum: config.paths?.features?.limit || 4, value: `?/${config.paths?.features?.limit || 4}`, remaining: "?", status: ["maintain-features", "transform"].includes(task) ? "" : "n/a" },
110
- { name: "library", valueNum: 0, capacityNum: config.paths?.library?.limit || 32, value: `?/${config.paths?.library?.limit || 32}`, remaining: "?", status: task === "maintain-library" ? "" : "n/a" },
157
+ { name: "features", valueNum: featuresUsed, capacityNum: featCap, value: `${featuresUsed}/${featCap}`, remaining: `${Math.max(0, featCap - featuresUsed)}`, status: ["maintain-features", "transform"].includes(task) ? "" : "n/a" },
158
+ { name: "library", valueNum: libraryUsed, capacityNum: libCap, value: `${libraryUsed}/${libCap}`, remaining: `${Math.max(0, libCap - libraryUsed)}`, status: task === "maintain-library" ? "" : "n/a" },
111
159
  ];
112
160
 
113
161
  // Merge task-reported limits if available
@@ -119,15 +167,8 @@ async function run() {
119
167
  }
120
168
 
121
169
  const closingNotes = result.closingNotes || generateClosingNotes(limitsStatus);
122
- const profileName = config.tuning?.profileName || "unknown";
123
-
124
- // Transformation cost: 1 for code-changing tasks, 0 otherwise
125
- const COST_TASKS = ["transform", "fix-code", "maintain-features", "maintain-library"];
126
- const isNop = result.outcome === "nop" || result.outcome === "error";
127
- const transformationCost = COST_TASKS.includes(task) && !isNop ? 1 : 0;
128
170
 
129
171
  // Log to intentïon.md (commit-if-changed excludes this on non-default branches)
130
- const intentionFilepath = config.intentionBot?.intentionFilepath;
131
172
  if (intentionFilepath) {
132
173
  logActivity({
133
174
  filepath: intentionFilepath,
@@ -191,6 +191,50 @@ export async function discussions(context) {
191
191
  core.info("Mission complete signal written (MISSION_COMPLETE.md)");
192
192
  }
193
193
 
194
+ // Create issue when bot requests it
195
+ if (action === "create-issue" && actionArg) {
196
+ try {
197
+ const { data: issue } = await octokit.rest.issues.create({
198
+ ...context.repo,
199
+ title: actionArg,
200
+ labels: ["automated", "enhancement"],
201
+ });
202
+ core.info(`Created issue #${issue.number}: ${actionArg}`);
203
+ } catch (err) {
204
+ core.warning(`Failed to create issue: ${err.message}`);
205
+ }
206
+ }
207
+
208
+ // Request supervisor evaluation
209
+ if (action === "request-supervisor") {
210
+ try {
211
+ await octokit.rest.actions.createWorkflowDispatch({
212
+ ...context.repo,
213
+ workflow_id: "agentic-lib-workflow.yml",
214
+ ref: "main",
215
+ inputs: { message: actionArg || "Discussion bot referral" },
216
+ });
217
+ core.info(`Dispatched supervisor with message: ${actionArg}`);
218
+ } catch (err) {
219
+ core.warning(`Failed to dispatch supervisor: ${err.message}`);
220
+ }
221
+ }
222
+
223
+ // Stop automation
224
+ if (action === "stop") {
225
+ try {
226
+ await octokit.rest.actions.createWorkflowDispatch({
227
+ ...context.repo,
228
+ workflow_id: "agentic-lib-schedule.yml",
229
+ ref: "main",
230
+ inputs: { frequency: "off" },
231
+ });
232
+ core.info("Automation stopped via discussions bot");
233
+ } catch (err) {
234
+ core.warning(`Failed to stop automation: ${err.message}`);
235
+ }
236
+ }
237
+
194
238
  await postReply(octokit, discussion.nodeId, replyBody);
195
239
 
196
240
  const argSuffix = actionArg ? ` (${actionArg})` : "";
@@ -6,12 +6,17 @@
6
6
  // asks the Copilot SDK to choose multiple concurrent actions, then dispatches them.
7
7
 
8
8
  import * as core from "@actions/core";
9
- import { existsSync, readFileSync } from "fs";
9
+ import { existsSync, readFileSync, writeFileSync } from "fs";
10
10
  import { runCopilotTask, readOptionalFile, scanDirectory, filterIssues } from "../copilot.js";
11
11
 
12
12
  async function gatherContext(octokit, repo, config, t) {
13
13
  const mission = readOptionalFile(config.paths.mission.path);
14
- const recentActivity = readOptionalFile(config.intentionBot.intentionFilepath).split("\n").slice(-20).join("\n");
14
+ const intentionLogFull = readOptionalFile(config.intentionBot.intentionFilepath);
15
+ const recentActivity = intentionLogFull.split("\n").slice(-20).join("\n");
16
+
17
+ // Read cumulative transformation cost from the activity log
18
+ const costMatches = intentionLogFull.matchAll(/\*\*agentic-lib transformation cost:\*\* (\d+)/g);
19
+ const cumulativeTransformationCost = [...costMatches].reduce((sum, m) => sum + parseInt(m[1], 10), 0);
15
20
 
16
21
  // Check mission-complete signal
17
22
  const missionComplete = existsSync("MISSION_COMPLETE.md");
@@ -20,6 +25,13 @@ async function gatherContext(octokit, repo, config, t) {
20
25
  missionCompleteInfo = readFileSync("MISSION_COMPLETE.md", "utf8").substring(0, 500);
21
26
  }
22
27
 
28
+ // Check mission-failed signal
29
+ const missionFailed = existsSync("MISSION_FAILED.md");
30
+ let missionFailedInfo = "";
31
+ if (missionFailed) {
32
+ missionFailedInfo = readFileSync("MISSION_FAILED.md", "utf8").substring(0, 500);
33
+ }
34
+
23
35
  // Check transformation budget
24
36
  const transformationBudget = config.transformationBudget || 0;
25
37
 
@@ -55,6 +67,36 @@ async function gatherContext(octokit, repo, config, t) {
55
67
  return `#${i.number}: ${i.title} [${labels || "no labels"}] (${age}d old)`;
56
68
  });
57
69
 
70
+ // Fetch recently-closed issues for mission-complete detection and dedup
71
+ let recentlyClosedSummary = [];
72
+ try {
73
+ const { data: closedIssuesRaw } = await octokit.rest.issues.listForRepo({
74
+ ...repo,
75
+ state: "closed",
76
+ per_page: 5,
77
+ sort: "updated",
78
+ direction: "desc",
79
+ });
80
+ for (const ci of closedIssuesRaw.filter((i) => !i.pull_request)) {
81
+ let closeReason = "closed";
82
+ try {
83
+ const { data: comments } = await octokit.rest.issues.listComments({
84
+ ...repo,
85
+ issue_number: ci.number,
86
+ per_page: 1,
87
+ sort: "created",
88
+ direction: "desc",
89
+ });
90
+ if (comments.length > 0 && comments[0].body?.includes("Automated Review Result")) {
91
+ closeReason = "closed by review as RESOLVED";
92
+ }
93
+ } catch (_) { /* ignore */ }
94
+ recentlyClosedSummary.push(`#${ci.number}: ${ci.title} — ${closeReason}`);
95
+ }
96
+ } catch (err) {
97
+ core.warning(`Could not fetch recently closed issues: ${err.message}`);
98
+ }
99
+
58
100
  const { data: openPRs } = await octokit.rest.pulls.list({
59
101
  ...repo,
60
102
  state: "open",
@@ -98,7 +140,11 @@ async function gatherContext(octokit, repo, config, t) {
98
140
  activeDiscussionUrl,
99
141
  missionComplete,
100
142
  missionCompleteInfo,
143
+ missionFailed,
144
+ missionFailedInfo,
101
145
  transformationBudget,
146
+ cumulativeTransformationCost,
147
+ recentlyClosedSummary,
102
148
  };
103
149
  }
104
150
 
@@ -114,6 +160,9 @@ function buildPrompt(ctx, agentInstructions) {
114
160
  `### Open Issues (${ctx.issuesSummary.length})`,
115
161
  ctx.issuesSummary.join("\n") || "none",
116
162
  "",
163
+ `### Recently Closed Issues (${ctx.recentlyClosedSummary.length})`,
164
+ ctx.recentlyClosedSummary.join("\n") || "none",
165
+ "",
117
166
  `### Open PRs (${ctx.prsSummary.length})`,
118
167
  ctx.prsSummary.join("\n") || "none",
119
168
  "",
@@ -150,8 +199,17 @@ function buildPrompt(ctx, agentInstructions) {
150
199
  "",
151
200
  ]
152
201
  : []),
202
+ ...(ctx.missionFailed
203
+ ? [
204
+ `### Mission Status: FAILED`,
205
+ ctx.missionFailedInfo,
206
+ "The mission has been declared failed. The schedule should be set to off.",
207
+ "You may still: review/close issues, respond to discussions.",
208
+ "",
209
+ ]
210
+ : []),
153
211
  ...(ctx.transformationBudget > 0
154
- ? [`### Transformation Budget: ${ctx.transformationBudget} cycles per run`, ""]
212
+ ? [`### Transformation Budget: ${ctx.cumulativeTransformationCost}/${ctx.transformationBudget} used (${Math.max(0, ctx.transformationBudget - ctx.cumulativeTransformationCost)} remaining)`, ""]
155
213
  : []),
156
214
  `### Issue Limits`,
157
215
  `Feature development WIP limit: ${ctx.featureIssuesWipLimit}`,
@@ -176,6 +234,10 @@ function buildPrompt(ctx, agentInstructions) {
176
234
  "### Communication",
177
235
  "- `respond:discussions | message: <text> | discussion-url: <url>` — Reply via discussions bot",
178
236
  "",
237
+ "### Mission Lifecycle",
238
+ "- `mission-complete | reason: <text>` — Declare mission accomplished. Writes MISSION_COMPLETE.md and sets schedule to off. Use when: all acceptance criteria in MISSION.md are satisfied, tests pass, and recently-closed issues confirm resolution.",
239
+ "- `mission-failed | reason: <text>` — Declare mission failed. Writes MISSION_FAILED.md and sets schedule to off. Use when: transformation budget is exhausted with no progress, pipeline is stuck in a loop, or the mission is unachievable.",
240
+ "",
179
241
  "### Schedule Control",
180
242
  "- `set-schedule:<frequency>` — Change supervisor schedule (off, weekly, daily, hourly, continuous). Use `set-schedule:weekly` when mission is substantially complete, `set-schedule:continuous` to ramp up.",
181
243
  "",
@@ -253,6 +315,31 @@ async function executeDispatch(octokit, repo, actionName, params) {
253
315
  async function executeCreateIssue(octokit, repo, params) {
254
316
  const title = params.title || "Untitled issue";
255
317
  const labels = params.labels ? params.labels.split(",").map((l) => l.trim()) : ["automated"];
318
+
319
+ // Dedup guard: skip if a similarly-titled issue was closed in the last hour
320
+ try {
321
+ const { data: recent } = await octokit.rest.issues.listForRepo({
322
+ ...repo,
323
+ state: "closed",
324
+ sort: "updated",
325
+ direction: "desc",
326
+ per_page: 5,
327
+ });
328
+ const titlePrefix = title.toLowerCase().substring(0, 30);
329
+ const duplicate = recent.find(
330
+ (i) =>
331
+ !i.pull_request &&
332
+ i.title.toLowerCase().includes(titlePrefix) &&
333
+ Date.now() - new Date(i.closed_at).getTime() < 3600000,
334
+ );
335
+ if (duplicate) {
336
+ core.info(`Skipping duplicate issue (similar to recently closed #${duplicate.number})`);
337
+ return `skipped:duplicate-of-#${duplicate.number}`;
338
+ }
339
+ } catch (err) {
340
+ core.warning(`Dedup check failed: ${err.message}`);
341
+ }
342
+
256
343
  core.info(`Creating issue: ${title}`);
257
344
  const { data: issue } = await octokit.rest.issues.create({ ...repo, title, labels });
258
345
  return `created-issue:#${issue.number}`;
@@ -297,11 +384,65 @@ async function executeRespondDiscussions(octokit, repo, params) {
297
384
  return "skipped:respond-no-message";
298
385
  }
299
386
 
387
+ async function executeMissionComplete(octokit, repo, params) {
388
+ const reason = params.reason || "All acceptance criteria satisfied";
389
+ const signal = [
390
+ "# Mission Complete",
391
+ "",
392
+ `- **Timestamp:** ${new Date().toISOString()}`,
393
+ `- **Detected by:** supervisor`,
394
+ `- **Reason:** ${reason}`,
395
+ "",
396
+ "This file was created automatically. To restart transformations, delete this file or run `npx @xn-intenton-z2a/agentic-lib init --reseed`.",
397
+ ].join("\n");
398
+ writeFileSync("MISSION_COMPLETE.md", signal);
399
+ core.info(`Mission complete signal written: ${reason}`);
400
+ try {
401
+ await octokit.rest.actions.createWorkflowDispatch({
402
+ ...repo,
403
+ workflow_id: "agentic-lib-schedule.yml",
404
+ ref: "main",
405
+ inputs: { frequency: "off" },
406
+ });
407
+ } catch (err) {
408
+ core.warning(`Could not set schedule to off: ${err.message}`);
409
+ }
410
+ return `mission-complete:${reason.substring(0, 100)}`;
411
+ }
412
+
413
+ async function executeMissionFailed(octokit, repo, params) {
414
+ const reason = params.reason || "Mission could not be completed";
415
+ const signal = [
416
+ "# Mission Failed",
417
+ "",
418
+ `- **Timestamp:** ${new Date().toISOString()}`,
419
+ `- **Detected by:** supervisor`,
420
+ `- **Reason:** ${reason}`,
421
+ "",
422
+ "This file was created automatically. To restart, delete this file and run `npx @xn-intenton-z2a/agentic-lib init --reseed`.",
423
+ ].join("\n");
424
+ writeFileSync("MISSION_FAILED.md", signal);
425
+ core.info(`Mission failed signal written: ${reason}`);
426
+ try {
427
+ await octokit.rest.actions.createWorkflowDispatch({
428
+ ...repo,
429
+ workflow_id: "agentic-lib-schedule.yml",
430
+ ref: "main",
431
+ inputs: { frequency: "off" },
432
+ });
433
+ } catch (err) {
434
+ core.warning(`Could not set schedule to off: ${err.message}`);
435
+ }
436
+ return `mission-failed:${reason.substring(0, 100)}`;
437
+ }
438
+
300
439
  const ACTION_HANDLERS = {
301
440
  "github:create-issue": executeCreateIssue,
302
441
  "github:label-issue": executeLabelIssue,
303
442
  "github:close-issue": executeCloseIssue,
304
443
  "respond:discussions": executeRespondDiscussions,
444
+ "mission-complete": executeMissionComplete,
445
+ "mission-failed": executeMissionFailed,
305
446
  };
306
447
 
307
448
  async function executeSetSchedule(octokit, repo, frequency) {
@@ -370,6 +511,17 @@ export async function supervise(context) {
370
511
  }
371
512
  }
372
513
 
514
+ // Build changes list from executed actions
515
+ const changes = results
516
+ .filter((r) => r.startsWith("created-issue:") || r.startsWith("mission-complete:") || r.startsWith("mission-failed:"))
517
+ .map((r) => {
518
+ if (r.startsWith("created-issue:")) return { action: "created-issue", file: r.replace("created-issue:", ""), sizeInfo: "" };
519
+ if (r.startsWith("mission-complete:")) return { action: "mission-complete", file: "MISSION_COMPLETE.md", sizeInfo: r.replace("mission-complete:", "") };
520
+ if (r.startsWith("mission-failed:")) return { action: "mission-failed", file: "MISSION_FAILED.md", sizeInfo: r.replace("mission-failed:", "") };
521
+ return null;
522
+ })
523
+ .filter(Boolean);
524
+
373
525
  return {
374
526
  outcome: actions.length === 0 ? "nop" : `supervised:${actions.length}-actions`,
375
527
  tokensUsed,
@@ -378,5 +530,7 @@ export async function supervise(context) {
378
530
  cost,
379
531
  model,
380
532
  details: `Actions: ${results.join(", ")}\nReasoning: ${reasoning.substring(0, 300)}`,
533
+ narrative: reasoning.substring(0, 500),
534
+ changes,
381
535
  };
382
536
  }
@@ -1,11 +1,14 @@
1
1
  Does the combination source file, test file, website files, README file and dependencies file resolve the following issue? Check that the solution satisfies the issue's acceptance criteria and moves the mission toward complete.
2
2
 
3
- If the mission could have been fully accomplished in this transform but the solution only partially addresses it, note this gap and suggest a follow-up issue for the remaining work.
3
+ An issue is NOT resolved unless ALL of the following are true:
4
+ 1. The implementation exists and matches what the issue asks for
5
+ 2. Tests exist that specifically test the implemented functionality (seed-only identity tests do NOT count)
6
+ 3. Tests match the acceptance criteria in MISSION.md — the mission is the source of truth
7
+ 4. Tests and implementation are consistent — test expectations must match what the code actually returns (casing, types, formats)
8
+
9
+ If any of these are missing, the issue is NOT resolved — keep it open or create a follow-up issue for the gap. Do not close an issue just because implementation code exists without matching tests.
4
10
 
5
- When reviewing, check that:
6
- - Tests and implementation are consistent — test expectations must match what the code actually returns (casing, types, formats)
7
- - Tests match the acceptance criteria in MISSION.md — the mission is the source of truth
8
- - If tests expect different values than the code produces, create an issue to fix the mismatch
11
+ If the mission could have been fully accomplished in this transform but the solution only partially addresses it, note this gap and suggest a follow-up issue for the remaining work.
9
12
 
10
13
  Note: The repository has a website in `src/web/` that uses the JS library. When reviewing, check that website files are updated alongside library changes.
11
14
 
@@ -27,6 +27,8 @@ You are the supervisor of an autonomous coding repository. Your job is to advanc
27
27
  - **github:close-issue** — When an issue is clearly resolved or no longer relevant.
28
28
  - **respond:discussions** — When replying to a user request that came through the discussions bot. Include the discussion URL and a clear message.
29
29
  - **set-schedule:\<frequency\>** — Change the workflow schedule. Use `weekly` when mission is substantially achieved, `continuous` to ramp up for active development.
30
+ - **mission-complete** — When all MISSION.md acceptance criteria are verified as satisfied. Review the Recently Closed Issues — if the last 2+ issues were closed by review as RESOLVED, 0 open issues remain, and the acceptance criteria in MISSION.md match the implemented code, declare mission complete. This writes MISSION_COMPLETE.md and sets the schedule to off. Always include a reason summarising what was achieved.
31
+ - **mission-failed** — When the mission cannot be completed. Use when: transformation budget is exhausted with acceptance criteria still unmet, the pipeline is stuck in a create-close loop with no code changes, or 3+ consecutive transforms failed to produce working code. This writes MISSION_FAILED.md and sets the schedule to off. Always include a reason explaining what went wrong.
30
32
  - **nop** — When everything is running optimally: transform is active, issues are flowing, no failures.
31
33
 
32
34
  ## Stale Issue Detection
@@ -42,15 +44,16 @@ Include the website URL in the announcement — the site is at `https://<owner>.
42
44
 
43
45
  ### Mission Accomplished (bounded missions)
44
46
  When ALL of the following conditions are met, the mission is accomplished:
45
- 1. All open issues are closed
47
+ 1. All open issues are closed (check Recently Closed Issues — if the last 2+ were closed by review as RESOLVED, this is strong evidence)
46
48
  2. Tests pass (CI gates commits, so this is usually the case)
47
- 3. The MISSION.md acceptance criteria are all satisfied
48
- 4. Evidence artifacts exist under `docs/` (example outputs, test results, or walkthroughs)
49
+ 3. The MISSION.md acceptance criteria are all satisfied (verify each criterion against the Recently Closed Issues and Recent Activity)
50
+ 4. Do not create an issue if a similar issue was recently closed as resolved — check the Recently Closed Issues section
49
51
 
50
- When all conditions are met:
51
- 1. `dispatch:agentic-lib-bot` announce mission accomplished in the discussions thread. Include the website URL (`https://<owner>.github.io/<repo>/`) where users can see the finished product.
52
- 2. `set-schedule:off` — stop the workflow. The mission is done.
53
- 3. Log `mission-accomplished` in the activity log.
52
+ When all conditions are met, use the `mission-complete` action:
53
+ 1. `mission-complete | reason: <summary of what was achieved>` this writes MISSION_COMPLETE.md and sets the schedule to off
54
+ 2. `dispatch:agentic-lib-bot` — announce mission accomplished in the discussions thread. Include the website URL (`https://<owner>.github.io/<repo>/`) where users can see the finished product.
55
+
56
+ Do NOT create another issue when the mission is already accomplished. If the Recently Closed Issues show 2+ issues closed by review as RESOLVED and 0 open issues remain, the mission is done.
54
57
 
55
58
  ### Ongoing Missions
56
59
  If MISSION.md explicitly says "do not set schedule to off" or "ongoing mission", the mission never completes.
@@ -64,14 +67,33 @@ When the transform agent has implemented all major features but minor polish rem
64
67
  2. `set-schedule:weekly` — reduce to weekly maintenance check-ins
65
68
  3. Check that `docs/` contains evidence of the library working before declaring done
66
69
 
70
+ ### Mission Failed
71
+ When the mission cannot be completed, use the `mission-failed` action. Indicators of failure:
72
+ 1. **Budget exhausted** — Transformation Budget shows usage at or near capacity with acceptance criteria still unmet
73
+ 2. **Pipeline stuck** — 3+ consecutive supervisor cycles created issues that were immediately closed by review as RESOLVED, but the acceptance criteria are NOT actually met (false positives in review)
74
+ 3. **No progress** — the last 3+ transforms produced no code changes (all nop outcomes) and acceptance criteria remain unmet
75
+ 4. **Repeated failures** — transforms keep producing code that fails tests, and fix-code cannot resolve the failures
76
+ 5. **Consuming budget without results** — transformation budget is being spent but the codebase is not converging toward the acceptance criteria
77
+
78
+ When declaring mission failed:
79
+ 1. `mission-failed | reason: <what went wrong and what was achieved>` — this writes MISSION_FAILED.md and sets the schedule to off
80
+ 2. `dispatch:agentic-lib-bot` — announce the failure in the discussions thread with details of what was accomplished and what remains
81
+
67
82
  ## Prerequisites
68
83
 
69
84
  - The `set-schedule` action requires a `WORKFLOW_TOKEN` secret (classic PAT with `workflow` scope) to push workflow file changes to main.
70
85
 
71
86
  ## Stability Detection
72
87
 
73
- Check the Recent Activity log for patterns that indicate the mission is done:
74
- - If the last 2+ workflow runs produced no transform commits (only maintain-only or nop outcomes), AND all open issues are closed, the mission is likely accomplished. Follow the "Mission Accomplished" protocol above.
88
+ Check the Recent Activity log and Recently Closed Issues for patterns:
89
+
90
+ **Mission complete signals:**
91
+ - If the last 2+ issues were closed by review as RESOLVED, AND 0 open issues remain, the mission is likely accomplished. Verify against MISSION.md acceptance criteria, then use `mission-complete`.
92
+ - If the last 2+ workflow runs produced no transform commits (only maintain-only or nop outcomes), AND all open issues are closed, follow the "Mission Accomplished" protocol.
93
+
94
+ **Mission failed signals:**
95
+ - If the Transformation Budget shows usage near capacity (e.g. 28/32) and acceptance criteria are still unmet, the mission is failing. Use `mission-failed`.
96
+ - If the last 3+ cycles show the pattern: create issue → review closes as resolved → no transform → create identical issue, the pipeline is stuck. Check if acceptance criteria are truly met (use `mission-complete`) or if review is wrong (create a more specific issue). If neither works, use `mission-failed`.
75
97
  - Look for `transform: nop` or `transform: transformed` patterns in the activity log to distinguish productive iterations from idle ones.
76
98
 
77
99
  ## Discussions Awareness
@@ -16,7 +16,7 @@
16
16
  "author": "",
17
17
  "license": "MIT",
18
18
  "dependencies": {
19
- "@xn-intenton-z2a/agentic-lib": "^7.1.69"
19
+ "@xn-intenton-z2a/agentic-lib": "^7.1.71"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@vitest/coverage-v8": "^4.0.18",