@xn-intenton-z2a/agentic-lib 7.4.32 → 7.4.34

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.
@@ -19,7 +19,7 @@ on:
19
19
  mode:
20
20
  type: string
21
21
  required: false
22
- default: "update"
22
+ default: "purge"
23
23
  dry-run:
24
24
  type: string
25
25
  required: false
@@ -27,7 +27,7 @@ on:
27
27
  mission-seed:
28
28
  type: string
29
29
  required: false
30
- default: "6-kyu-understand-hamming-distance"
30
+ default: "7-kyu-understand-fizz-buzz"
31
31
  mission-text:
32
32
  type: string
33
33
  required: false
@@ -58,11 +58,11 @@ on:
58
58
  description: "Init mode"
59
59
  type: choice
60
60
  required: false
61
- default: "update"
61
+ default: "purge"
62
62
  options:
63
- - update
64
- - reseed
65
63
  - purge
64
+ - reseed
65
+ - update
66
66
  dry-run:
67
67
  description: "Preview changes without writing files"
68
68
  type: boolean
@@ -72,8 +72,10 @@ on:
72
72
  description: "Mission seed name (purge only)"
73
73
  type: choice
74
74
  required: false
75
- default: "6-kyu-understand-hamming-distance"
75
+ default: "7-kyu-understand-fizz-buzz"
76
76
  options:
77
+ - random
78
+ - generate
77
79
  - 8-kyu-remember-empty
78
80
  - 8-kyu-remember-hello-world
79
81
  - 7-kyu-understand-fizz-buzz
@@ -158,7 +160,7 @@ jobs:
158
160
  with:
159
161
  script: |
160
162
  core.setOutput('dry-run', context.payload.inputs?.['dry-run'] || 'false');
161
- core.setOutput('mission', context.payload.inputs?.['mission-seed'] || '6-kyu-understand-hamming-distance');
163
+ core.setOutput('mission', context.payload.inputs?.['mission-seed'] || '7-kyu-understand-fizz-buzz');
162
164
  core.setOutput('profile', context.payload.inputs?.['profile'] || '');
163
165
  core.setOutput('model', context.payload.inputs?.['model'] || '');
164
166
  core.setOutput('create-seed-issues', context.payload.inputs?.['create-seed-issues'] || 'false');
@@ -171,18 +173,18 @@ jobs:
171
173
  with:
172
174
  ref: ${{ inputs.ref }}
173
175
  dry-run: ${{ inputs.dry-run || 'false' }}
174
- skip-tests: ${{ inputs.mode == 'reseed' || inputs.mode == 'purge' }}
176
+ skip-tests: ${{ inputs.mode != 'update' }}
175
177
  secrets: inherit
176
178
 
177
179
  # Step 2: Reseed/purge and configure (only if mode != update)
178
180
  # Use !cancelled() so purge runs even if update's npm test failed
179
181
  init:
180
182
  needs: [params, update]
181
- if: "!cancelled() && (inputs.mode == 'reseed' || inputs.mode == 'purge')"
183
+ if: "!cancelled() && inputs.mode != 'update'"
182
184
  runs-on: ubuntu-latest
183
185
  env:
184
186
  INIT_MODE: ${{ inputs.mode }}
185
- INIT_MISSION_SEED: ${{ inputs.mission-seed || '6-kyu-understand-hamming-distance' }}
187
+ INIT_MISSION_SEED: ${{ inputs.mission-seed || '7-kyu-understand-fizz-buzz' }}
186
188
  INIT_MISSION_TEXT: ${{ inputs.mission-text }}
187
189
  steps:
188
190
  - uses: actions/checkout@v6
@@ -18,9 +18,10 @@ on:
18
18
  required: false
19
19
  default: ""
20
20
  frequency:
21
- description: "How often the workflow should run"
22
- required: true
21
+ description: "How often the workflow should run (empty = read from agentic-lib.toml)"
22
+ required: false
23
23
  type: string
24
+ default: ""
24
25
  model:
25
26
  description: "Copilot SDK model to use"
26
27
  required: false
@@ -39,16 +40,27 @@ on:
39
40
  workflow_dispatch:
40
41
  inputs:
41
42
  frequency:
42
- description: "How often the workflow should run (maintenance = weekly + remove mission-complete + unlimited budget)"
43
- required: true
43
+ description: "How often the workflow should run (empty = read from agentic-lib.toml, maintenance = weekly + remove mission-complete + unlimited budget)"
44
+ required: false
44
45
  type: choice
46
+ default: ""
45
47
  options:
48
+ - ""
46
49
  - "off"
47
50
  - "maintenance"
48
51
  - "weekly"
49
52
  - "daily"
50
53
  - "hourly"
51
54
  - "continuous"
55
+ focus:
56
+ description: "Focus mode (empty = read from agentic-lib.toml)"
57
+ required: false
58
+ type: choice
59
+ default: ""
60
+ options:
61
+ - ""
62
+ - "mission"
63
+ - "maintenance"
52
64
  model:
53
65
  description: "Copilot SDK model to use (empty = read from agentic-lib.toml)"
54
66
  required: false
@@ -85,16 +97,36 @@ jobs:
85
97
  frequency: ${{ steps.resolve.outputs.frequency }}
86
98
  model: ${{ steps.resolve.outputs.model }}
87
99
  profile: ${{ steps.resolve.outputs.profile }}
100
+ focus: ${{ steps.resolve.outputs.focus }}
88
101
  maintenance: ${{ steps.resolve.outputs.maintenance }}
89
102
  steps:
103
+ - uses: actions/checkout@v6
104
+ with:
105
+ sparse-checkout: agentic-lib.toml
106
+ sparse-checkout-cone-mode: false
90
107
  - id: resolve
91
108
  uses: actions/github-script@v8
92
109
  with:
93
110
  script: |
94
- const frequency = context.payload.inputs?.['frequency'] || 'off';
111
+ const fs = require('fs');
112
+ const tomlPath = 'agentic-lib.toml';
113
+ let tomlContent = '';
114
+ if (fs.existsSync(tomlPath)) tomlContent = fs.readFileSync(tomlPath, 'utf8');
115
+ const readToml = (key) => {
116
+ const m = tomlContent.match(new RegExp(`^\\s*${key}\\s*=\\s*"([^"]*)"`, 'm'));
117
+ return m ? m[1] : '';
118
+ };
119
+ let frequency = context.payload.inputs?.['frequency'] || '';
120
+ if (!frequency) frequency = readToml('supervisor') || 'off';
121
+ const model = context.payload.inputs?.['model'] || '';
122
+ const profile = context.payload.inputs?.['profile'] || '';
123
+ let focus = context.payload.inputs?.['focus'] || '';
124
+ if (!focus) focus = readToml('focus') || 'mission';
125
+ if (frequency === 'maintenance') focus = 'maintenance';
95
126
  core.setOutput('frequency', frequency);
96
- core.setOutput('model', context.payload.inputs?.['model'] || '');
97
- core.setOutput('profile', context.payload.inputs?.['profile'] || '');
127
+ core.setOutput('model', model);
128
+ core.setOutput('profile', profile);
129
+ core.setOutput('focus', focus);
98
130
  core.setOutput('maintenance', frequency === 'maintenance' ? 'true' : 'false');
99
131
 
100
132
  update-schedule:
@@ -116,8 +148,8 @@ jobs:
116
148
  with:
117
149
  script: |
118
150
  const fs = require('fs');
119
- const frequency = '${{ inputs.frequency }}';
120
- const workflowPath = '.github/workflows/agentic-lib-workflow.yml';
151
+ const frequency = '${{ needs.params.outputs.frequency }}';
152
+ const focus = '${{ needs.params.outputs.focus }}';
121
153
  const tomlPath = 'agentic-lib.toml';
122
154
  let model = '${{ inputs.model }}';
123
155
  if (!model && fs.existsSync(tomlPath)) {
@@ -126,75 +158,107 @@ jobs:
126
158
  if (m) model = m[1];
127
159
  }
128
160
  if (!model) model = 'gpt-5-mini';
129
- const profile = '${{ inputs.profile }}';
161
+ let profile = '${{ inputs.profile }}';
162
+ if (!profile && fs.existsSync(tomlPath)) {
163
+ const toml = fs.readFileSync(tomlPath, 'utf8');
164
+ const m = toml.match(/^\s*profile\s*=\s*"([^"]*)"/m);
165
+ if (m) profile = m[1];
166
+ }
130
167
 
131
168
  const isMaintenance = frequency === 'maintenance';
132
169
  const effectiveFrequency = isMaintenance ? 'weekly' : frequency;
133
170
 
134
- // Problem 4 fix: Use a "never fires" cron for off instead of removing the block.
135
- // Keeping the schedule: block permanently avoids GitHub cron de-registration issues.
136
- const SCHEDULE_MAP = {
171
+ // Proportional schedule maps for each workflow
172
+ const WORKFLOW_SCHEDULE_MAP = {
173
+ off: '0 0 31 2 *',
174
+ weekly: '25 6 * * 1', // Monday 6:25am
175
+ daily: '25 6 * * *', // Every day 6:25am
176
+ hourly: '25 * * * *', // Every hour at :25
177
+ continuous: '5,25,45 * * * *', // Every 20 min
178
+ };
179
+ const INIT_SCHEDULE_MAP = {
180
+ off: '0 0 31 2 *',
181
+ weekly: '0 4 1 * *', // 1st of month 4:00am
182
+ daily: '0 4 * * 1', // Monday 4:00am
183
+ hourly: '0 4 * * *', // Every day 4:00am
184
+ continuous: '0 1,5,9,13,17,21 * * *', // Every 4 hours
185
+ };
186
+ const TEST_SCHEDULE_MAP = {
137
187
  off: '0 0 31 2 *',
138
- weekly: '25 6 * * 1',
139
- daily: '25 6 * * *',
140
- hourly: '25 * * * *',
141
- continuous: '5,25,45 * * * *',
188
+ weekly: '40 6 * * 1', // Monday 6:40am
189
+ daily: '40 6 * * *', // Every day 6:40am
190
+ hourly: '40 0,4,8,12,16,20 * * *', // Every 4 hours at :40
191
+ continuous: '40 * * * *', // Every hour at :40
142
192
  };
143
193
 
144
- // Update agentic-lib-workflow.yml schedule
145
- let content = fs.readFileSync(workflowPath, 'utf8');
146
- const cron = SCHEDULE_MAP[effectiveFrequency];
194
+ // Helper: update cron in a workflow file
195
+ function updateWorkflowCron(path, cron, label) {
196
+ if (!fs.existsSync(path)) {
197
+ core.info(`${label}: file not found at ${path}, skipping`);
198
+ return;
199
+ }
200
+ let content = fs.readFileSync(path, 'utf8');
201
+ // Remove any duplicate schedule: blocks (keep only the first)
202
+ const dupScheduleRegex = /(\n schedule:\n - cron: "[^"]*"\n)(\s*schedule:\n\s*- cron: "[^"]*"\n)/;
203
+ if (dupScheduleRegex.test(content)) {
204
+ content = content.replace(dupScheduleRegex, '$1');
205
+ core.info(`${label}: removed duplicate schedule block`);
206
+ }
207
+ const cronRegex = /- cron: "[^"]*"/;
208
+ if (cronRegex.test(content)) {
209
+ content = content.replace(cronRegex, `- cron: "${cron}"`);
210
+ } else {
211
+ const scheduleBlock = `\n schedule:\n - cron: "${cron}"\n`;
212
+ content = content.replace(/\non:\n/, `\non:${scheduleBlock}`);
213
+ }
214
+ fs.writeFileSync(path, content);
215
+ core.info(`${label}: set cron to "${cron}"`);
216
+ }
217
+
218
+ const workflowPath = '.github/workflows/agentic-lib-workflow.yml';
219
+ const initPath = '.github/workflows/agentic-lib-init.yml';
220
+ const testPath = '.github/workflows/agentic-lib-test.yml';
221
+
222
+ const workflowCron = WORKFLOW_SCHEDULE_MAP[effectiveFrequency];
223
+ const initCron = INIT_SCHEDULE_MAP[effectiveFrequency];
224
+ const testCron = TEST_SCHEDULE_MAP[effectiveFrequency];
147
225
 
148
226
  // Check if the frequency is already set — skip if no-op (but never skip maintenance)
149
- // Must check BOTH the config file AND the workflow file to avoid desynchronisation
150
227
  const supervisorRegex2 = /^\s*supervisor\s*=\s*"([^"]*)"/m;
151
228
  if (!isMaintenance && fs.existsSync(tomlPath)) {
152
229
  const currentToml = fs.readFileSync(tomlPath, 'utf8');
153
230
  const currentMatch = currentToml.match(supervisorRegex2);
154
231
  const currentFreq = currentMatch ? currentMatch[1] : '';
155
- // Also check the workflow file has the expected cron schedule
232
+ const wfContent = fs.existsSync(workflowPath) ? fs.readFileSync(workflowPath, 'utf8') : '';
156
233
  const cronRegex = /- cron: "([^"]*)"/;
157
- const workflowCronMatch = content.match(cronRegex);
234
+ const workflowCronMatch = wfContent.match(cronRegex);
158
235
  const currentCron = workflowCronMatch ? workflowCronMatch[1] : null;
159
- const expectedCron = cron; // from SCHEDULE_MAP
160
236
  const configMatches = currentFreq === frequency;
161
- const workflowMatches = currentCron === expectedCron;
237
+ const workflowMatches = currentCron === workflowCron;
162
238
  if (configMatches && workflowMatches) {
163
239
  core.info(`Schedule already set to ${frequency} — no change needed`);
164
240
  return;
165
241
  }
166
- if (configMatches && !workflowMatches) {
167
- core.info(`Config says ${frequency} but workflow cron is "${currentCron}" (expected "${expectedCron}") — updating workflow`);
168
- }
169
242
  }
170
243
 
171
- // Replace existing schedule cron or insert a new block
172
- const cronRegexReplace = /- cron: "[^"]*"/;
173
- if (cronRegexReplace.test(content)) {
174
- content = content.replace(cronRegexReplace, `- cron: "${cron}"`);
175
- } else {
176
- // No schedule block exists — insert one after 'on:'
177
- const scheduleBlock = `\n schedule:\n - cron: "${cron}"\n`;
178
- content = content.replace(
179
- /\non:\n/,
180
- `\non:${scheduleBlock}`
181
- );
182
- }
244
+ // Update all three workflow files proportionally
245
+ updateWorkflowCron(workflowPath, workflowCron, 'workflow');
246
+ updateWorkflowCron(initPath, initCron, 'init');
247
+ updateWorkflowCron(testPath, testCron, 'test');
183
248
 
184
- // Stamp the file with current date so the commit is never empty
185
- const dateStamp = `# Schedule updated: ${new Date().toISOString()}`;
186
- const stampRegex = /^# Schedule updated: .*/m;
187
- if (stampRegex.test(content)) {
188
- content = content.replace(stampRegex, dateStamp);
189
- } else {
190
- content = content.replace(
191
- /^(# .*\n)+/m,
192
- (match) => match + dateStamp + '\n'
193
- );
249
+ // Stamp the workflow file with current date
250
+ if (fs.existsSync(workflowPath)) {
251
+ let content = fs.readFileSync(workflowPath, 'utf8');
252
+ const dateStamp = `# Schedule updated: ${new Date().toISOString()}`;
253
+ const stampRegex = /^# Schedule updated: .*/m;
254
+ if (stampRegex.test(content)) {
255
+ content = content.replace(stampRegex, dateStamp);
256
+ } else {
257
+ content = content.replace(/^(# .*\n)+/m, (match) => match + dateStamp + '\n');
258
+ }
259
+ fs.writeFileSync(workflowPath, content);
194
260
  }
195
-
196
- fs.writeFileSync(workflowPath, content);
197
- core.info(`Updated workflow schedule to: ${effectiveFrequency} (cron: ${cron || 'none'})`);
261
+ core.info(`Updated proportional schedules: workflow=${effectiveFrequency}, init=${effectiveFrequency}(proportional), test=${effectiveFrequency}(proportional)`);
198
262
 
199
263
  // Maintenance mode: remove mission-complete/failed signals
200
264
  if (isMaintenance) {
@@ -206,7 +270,7 @@ jobs:
206
270
  }
207
271
  }
208
272
 
209
- // Update agentic-lib.toml with model and supervisor settings
273
+ // Update agentic-lib.toml with model, supervisor, focus, and profile settings
210
274
  if (fs.existsSync(tomlPath)) {
211
275
  let toml = fs.readFileSync(tomlPath, 'utf8');
212
276
 
@@ -227,6 +291,14 @@ jobs:
227
291
  toml = toml.replace(scheduleSupervisorRegex, `$1supervisor = "${frequency}"`);
228
292
  }
229
293
 
294
+ // Update focus
295
+ const focusRegex = /^(\s*focus\s*=\s*)"[^"]*"/m;
296
+ if (focusRegex.test(toml)) {
297
+ toml = toml.replace(focusRegex, `$1"${focus}"`);
298
+ } else if (toml.match(/^\[schedule\]/m)) {
299
+ toml = toml.replace(/^(\s*supervisor\s*=\s*"[^"]*".*$)/m, `$1\nfocus = "${focus}"`);
300
+ }
301
+
230
302
  if (profile) {
231
303
  const profileRegex = /(\[tuning\][^\[]*?)(^\s*profile\s*=\s*"[^"]*")/m;
232
304
  if (profileRegex.test(toml)) {
@@ -244,7 +316,7 @@ jobs:
244
316
  }
245
317
 
246
318
  fs.writeFileSync(tomlPath, toml);
247
- core.info(`Updated agentic-lib.toml: model=${model}, supervisor=${frequency}${profile ? ', profile=' + profile : ''}`);
319
+ core.info(`Updated agentic-lib.toml: model=${model}, supervisor=${frequency}, focus=${focus}${profile ? ', profile=' + profile : ''}`);
248
320
  } else {
249
321
  core.warning('agentic-lib.toml not found — skipping config update');
250
322
  }
@@ -260,7 +332,7 @@ jobs:
260
332
  git config user.email "${TOKEN_ID}+${TOKEN_USER}@users.noreply.github.com"
261
333
  FREQUENCY="${{ inputs.frequency }}"
262
334
  MODEL="${{ inputs.model }}"
263
- git add .github/workflows/agentic-lib-workflow.yml agentic-lib.toml
335
+ git add .github/workflows/agentic-lib-workflow.yml .github/workflows/agentic-lib-init.yml .github/workflows/agentic-lib-test.yml agentic-lib.toml
264
336
  # Stage removed mission files ONLY if maintenance mode deleted them
265
337
  if [ "$FREQUENCY" = "maintenance" ]; then
266
338
  git rm --ignore-unmatch MISSION_COMPLETE.md MISSION_FAILED.md 2>/dev/null || true
@@ -17,7 +17,7 @@ run-name: "agentic-lib-test [${{ github.ref_name }}]"
17
17
 
18
18
  on:
19
19
  #@dist schedule:
20
- #@dist - cron: "40 * * * *"
20
+ #@dist - cron: "0 0 31 2 *"
21
21
  #@dist push:
22
22
  #@dist branches: [main]
23
23
  #@dist paths:
@@ -17,7 +17,7 @@ run-name: "agentic-lib-workflow [${{ github.ref_name }}]"
17
17
 
18
18
  on:
19
19
  #@dist schedule:
20
- #@dist - cron: "0 6 * * 1"
20
+ #@dist - cron: "0 0 31 2 *"
21
21
  workflow_call:
22
22
  inputs:
23
23
  ref:
@@ -729,11 +729,30 @@ jobs:
729
729
  echo "- **Features:** ${{ steps.maintain-features.outputs.narrative }}" >> $GITHUB_STEP_SUMMARY
730
730
  echo "- **Library:** ${{ steps.maintain-library.outputs.narrative }}" >> $GITHUB_STEP_SUMMARY
731
731
 
732
+ - name: Check health for commit message
733
+ id: health
734
+ if: github.repository != 'xn-intenton-z2a/agentic-lib' && needs.params.outputs.dry-run != 'true'
735
+ run: |
736
+ if npm ci --ignore-scripts 2>/dev/null; then
737
+ TEST_OUTPUT=$(npm test 2>&1) || true
738
+ PASS_COUNT=$(echo "$TEST_OUTPUT" | grep -oP '\d+ passing' | head -1 || echo "")
739
+ FAIL_COUNT=$(echo "$TEST_OUTPUT" | grep -oP '\d+ failing' | head -1 || echo "")
740
+ if [ -n "$FAIL_COUNT" ]; then
741
+ echo "summary=maintain(features+library): ${PASS_COUNT:-0 passing}, ${FAIL_COUNT} [unstable]" >> $GITHUB_OUTPUT
742
+ elif [ -n "$PASS_COUNT" ]; then
743
+ echo "summary=maintain(features+library): ${PASS_COUNT} [healthy]" >> $GITHUB_OUTPUT
744
+ else
745
+ echo "summary=maintain(features+library): tests completed [healthy]" >> $GITHUB_OUTPUT
746
+ fi
747
+ else
748
+ echo "summary=maintain(features+library): [broken: npm ci failed]" >> $GITHUB_OUTPUT
749
+ fi
750
+
732
751
  - name: Commit and push changes
733
752
  if: github.repository != 'xn-intenton-z2a/agentic-lib' && needs.params.outputs.dry-run != 'true'
734
753
  uses: ./.github/agentic-lib/actions/commit-if-changed
735
754
  with:
736
- commit-message: "agentic-step: maintain features and library"
755
+ commit-message: "${{ steps.health.outputs.summary || 'agentic-step: maintain features and library' }}"
737
756
  push-ref: ${{ github.ref_name }}
738
757
  fail-on-conflict: "false"
739
758
 
@@ -1621,6 +1640,15 @@ jobs:
1621
1640
  # echo "tests-passed=true" >> $GITHUB_OUTPUT
1622
1641
  # echo "Behaviour tests passed"
1623
1642
 
1643
+ - name: Sync lockfile if package.json changed
1644
+ if: github.repository != 'xn-intenton-z2a/agentic-lib' && steps.issue.outputs.issue-number != '' && needs.params.outputs.dry-run != 'true'
1645
+ run: |
1646
+ if git diff --name-only | grep -q 'package.json'; then
1647
+ echo "package.json changed — syncing lockfile"
1648
+ npm install --package-lock-only || echo "::warning::Lockfile sync failed"
1649
+ git add package-lock.json 2>/dev/null || true
1650
+ fi
1651
+
1624
1652
  - name: Commit and push
1625
1653
  if: github.repository != 'xn-intenton-z2a/agentic-lib' && steps.issue.outputs.issue-number != '' && needs.params.outputs.dry-run != 'true' && steps.pre-commit-test.outputs.tests-passed == 'true' && steps.pre-commit-behaviour-test.outputs.tests-passed != 'false'
1626
1654
  uses: ./.github/agentic-lib/actions/commit-if-changed
package/agentic-lib.toml CHANGED
@@ -6,7 +6,8 @@
6
6
  # During init: #@dist transforms restore standard paths for consumer repos.
7
7
 
8
8
  [schedule]
9
- supervisor = "daily" # off | weekly | daily | hourly | continuous
9
+ supervisor = "daily" #@dist "off" # off | weekly | daily | hourly | continuous
10
+ focus = "mission" # mission | maintenance
10
11
 
11
12
  [paths]
12
13
  mission = "test/MISSION.md" #@dist "MISSION.md"
@@ -89,6 +90,11 @@ max-test-output = 4000 # max chars of test output in prompts
89
90
  max-file-listing = 30 # max files in directory listings (0 = unlimited)
90
91
  max-library-index = 2000 # max chars for library index in prompts
91
92
  max-fix-test-output = 8000 # max chars of failed run log in fix-code
93
+ review-issues-cap = 2 # max issues reviewed per batch (conservative for 10 min timeout)
94
+ min-resolved-issues = 1 # mission-complete: minimum closed-as-RESOLVED issues
95
+ min-cumulative-transforms = 1 # mission-complete: minimum transform cycles
96
+ max-source-todos = 2 # mission-complete: max TODO comments in src
97
+ acceptance-criteria-threshold = 30 # mission-complete: % acceptance criteria required
92
98
 
93
99
  [profiles.med]
94
100
  # Balanced — good results, middle ground.
@@ -111,6 +117,11 @@ max-test-output = 10000 # max chars of test output in prompts
111
117
  max-file-listing = 100 # max files in directory listings (0 = unlimited)
112
118
  max-library-index = 5000 # max chars for library index in prompts
113
119
  max-fix-test-output = 15000 # max chars of failed run log in fix-code
120
+ review-issues-cap = 3 # max issues reviewed per batch
121
+ min-resolved-issues = 2 # mission-complete: minimum closed-as-RESOLVED issues
122
+ min-cumulative-transforms = 1 # mission-complete: minimum transform cycles
123
+ max-source-todos = 1 # mission-complete: max TODO comments in src
124
+ acceptance-criteria-threshold = 50 # mission-complete: % acceptance criteria required
114
125
 
115
126
  [profiles.max]
116
127
  # Thorough — maximum context for complex missions.
@@ -133,6 +144,11 @@ max-test-output = 20000 # max chars of test output in prompts
133
144
  max-file-listing = 0 # max files in directory listings (0 = unlimited)
134
145
  max-library-index = 10000 # max chars for library index in prompts
135
146
  max-fix-test-output = 30000 # max chars of failed run log in fix-code
147
+ review-issues-cap = 4 # max issues reviewed per batch (may need step timeout awareness)
148
+ min-resolved-issues = 3 # mission-complete: minimum closed-as-RESOLVED issues
149
+ min-cumulative-transforms = 2 # mission-complete: minimum transform cycles
150
+ max-source-todos = 0 # mission-complete: max TODO comments in src
151
+ acceptance-criteria-threshold = 75 # mission-complete: % acceptance criteria required
136
152
 
137
153
  [goals]
138
154
  # W12/W13: Code coverage thresholds — stated in all code-changing prompts
@@ -144,7 +160,11 @@ min-branch-coverage = 30 # minimum % branch coverage required
144
160
  # All conditions must be met simultaneously.
145
161
  min-resolved-issues = 1 # minimum closed-as-RESOLVED issues since init
146
162
  max-source-todos = 0 # max TODO comments allowed in ./src (0 = none)
147
- # C6: Removed min-dedicated-tests (replaced by cumulative transforms and acceptance criteria)
163
+ acceptance-criteria-threshold = 50 # percentage of acceptance criteria that must be met (0-100)
164
+ min-cumulative-transforms = 1 # minimum transform cycles completed
165
+ require-no-open-issues = true # all issues must be closed
166
+ require-no-open-prs = true # all PRs must be merged/closed
167
+ require-no-critical-gaps = true # no critical implementation gaps
148
168
 
149
169
  [bot]
150
170
  log-prefix = "tmp/agent-log-" #@dist "agent-log-"