agentxchain 2.155.33 → 2.155.35

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentxchain",
3
- "version": "2.155.33",
3
+ "version": "2.155.35",
4
4
  "description": "CLI for AgentXchain — governed multi-agent software delivery",
5
5
  "type": "module",
6
6
  "bin": {
@@ -63,6 +63,19 @@ function getRoadmapReplenishmentTriageHints(root) {
63
63
  };
64
64
  }
65
65
 
66
+ function formatVisionSectionScope(sections, { limit = 5 } = {}) {
67
+ const names = Array.isArray(sections)
68
+ ? sections.map((section) => String(section || '').trim()).filter(Boolean)
69
+ : [];
70
+ if (names.length === 0) {
71
+ return 'remaining VISION.md scope';
72
+ }
73
+ if (names.length <= limit) {
74
+ return names.join(', ');
75
+ }
76
+ return `${names.slice(0, limit).join(', ')} (+${names.length - limit} more)`;
77
+ }
78
+
66
79
  // ---------------------------------------------------------------------------
67
80
  // Session state
68
81
  // ---------------------------------------------------------------------------
@@ -734,7 +747,8 @@ export function seedFromVision(root, visionPath, options = {}) {
734
747
  // generic vision candidates can bypass PM roadmap replenishment.
735
748
  const exhaustion = detectRoadmapExhaustedVisionOpen(root, visionPath);
736
749
  if (exhaustion.open) {
737
- const sectionNames = exhaustion.unplanned_sections.join(', ');
750
+ const sectionNames = formatVisionSectionScope(exhaustion.unplanned_sections);
751
+ const fullSectionNames = exhaustion.unplanned_sections.join(', ');
738
752
  const replenishmentEvent = recordEvent(root, {
739
753
  source: 'vision_scan',
740
754
  category: 'roadmap_exhausted_vision_open',
@@ -745,7 +759,7 @@ export function seedFromVision(root, visionPath, options = {}) {
745
759
  derived: true,
746
760
  },
747
761
  evidence: [
748
- { type: 'text', value: `All ${exhaustion.total_milestones} roadmap milestones checked. VISION sections not yet planned: ${sectionNames}` },
762
+ { type: 'text', value: `All ${exhaustion.total_milestones} roadmap milestones checked. VISION sections not yet planned: ${fullSectionNames}` },
749
763
  ],
750
764
  });
751
765
 
@@ -767,10 +781,10 @@ export function seedFromVision(root, visionPath, options = {}) {
767
781
  template: 'generic',
768
782
  ...(replenishmentHints.preferred_role ? { preferred_role: replenishmentHints.preferred_role } : {}),
769
783
  ...(replenishmentHints.phase_scope ? { phase_scope: replenishmentHints.phase_scope } : {}),
770
- charter: `[roadmap-replenishment] Derive next bounded roadmap increment from VISION.md. Unplanned scope: ${sectionNames}. Current roadmap checked through ${exhaustion.latest_milestone}. Read .planning/VISION.md and .planning/ROADMAP.md to select the next testable milestone. Produce concrete unchecked M${exhaustion.total_milestones + 1} items. Do not re-verify previous completed milestones.`,
784
+ charter: `[roadmap-replenishment] Derive next bounded roadmap increment from VISION.md. Candidate pool: ${sectionNames}. Current roadmap checked through ${exhaustion.latest_milestone}. Read .planning/VISION.md and .planning/ROADMAP.md to select one next testable milestone. Produce concrete unchecked M${exhaustion.total_milestones + 1} items. Do not re-verify previous completed milestones.`,
771
785
  acceptance_contract: [
772
786
  `New unchecked milestone items added to .planning/ROADMAP.md`,
773
- `Milestone scope derived from VISION.md sections: ${sectionNames}`,
787
+ `Milestone cites at least one concrete VISION.md source section from the unplanned backlog`,
774
788
  `Milestone is bounded, testable, and does not duplicate existing checked milestones`,
775
789
  ],
776
790
  });
@@ -795,7 +809,7 @@ export function seedFromVision(root, visionPath, options = {}) {
795
809
  idle: false,
796
810
  intentId: replenishmentIntentId,
797
811
  section: 'Roadmap replenishment',
798
- goal: `Derive next increment from: ${sectionNames}`,
812
+ goal: `Derive next increment from unplanned VISION scope: ${sectionNames}`,
799
813
  source: 'roadmap_replenishment',
800
814
  };
801
815
  }
@@ -6021,7 +6021,7 @@ function _acceptGovernedTurnLocked(root, config, opts) {
6021
6021
  category: 'non_progress',
6022
6022
  recovery: {
6023
6023
  typed_reason: `Non-progress detected: ${newCount} accepted turns have not reduced gate failure "${gateId}".`,
6024
- recovery_action: 'agentxchain resume --acknowledge-non-progress',
6024
+ recovery_action: 'agentxchain resume',
6025
6025
  detail: `Gate "${gateId}" has been failing on ${failingFiles.join(', ')} for ${newCount} consecutive turns. The gated file(s) were never modified.`,
6026
6026
  },
6027
6027
  turnId: currentTurn.turn_id,
@@ -6995,6 +6995,12 @@ function evaluateIntentCoverage(turnResult, intakeContext, { state = null, confi
6995
6995
  continue;
6996
6996
  }
6997
6997
 
6998
+ const roadmapReplenishmentCoverage = evaluateRoadmapReplenishmentConditionalCoverage(item, turnResult, intakeContext);
6999
+ if (roadmapReplenishmentCoverage === true) {
7000
+ addressed.push(item);
7001
+ continue;
7002
+ }
7003
+
6998
7004
  // Check 1: Structural — intent_response field with explicit status
6999
7005
  const structuralEntry = responseMap.get(normalizedItem);
7000
7006
  if (structuralEntry && ['addressed', 'deferred', 'rejected'].includes(structuralEntry.status)) {
@@ -7140,6 +7146,59 @@ function evaluateRoadmapDerivedConditionalCoverage(item, turnResult, intakeConte
7140
7146
  return null;
7141
7147
  }
7142
7148
 
7149
+ // ── Roadmap-replenishment conditional coverage (BUG-85) ───────────────────
7150
+ //
7151
+ // BUG-77's replenishment path originally generated one acceptance item
7152
+ // containing every unplanned VISION heading. A valid PM turn only binds one
7153
+ // next milestone, so requiring semantic coverage of the whole backlog is
7154
+ // overbroad. Accept both the new scoped item and the legacy broad item when
7155
+ // the result cites VISION.md and at least one concrete listed section.
7156
+
7157
+ function evaluateRoadmapReplenishmentConditionalCoverage(item, turnResult, intakeContext) {
7158
+ const charter = intakeContext?.charter || '';
7159
+ if (!charter.startsWith('[roadmap-replenishment]')) {
7160
+ return null;
7161
+ }
7162
+
7163
+ const normalizedItem = typeof item === 'string' ? item.toLowerCase().trim() : '';
7164
+ const isScopedTraceabilityItem =
7165
+ normalizedItem.startsWith('milestone cites at least one concrete vision.md source section')
7166
+ || normalizedItem.startsWith('milestone scope derived from vision.md sections:');
7167
+ if (!isScopedTraceabilityItem) {
7168
+ return null;
7169
+ }
7170
+
7171
+ const corpus = [
7172
+ turnResult.summary || '',
7173
+ ...(turnResult.decisions || []).map(d => `${d.statement || ''} ${d.rationale || ''}`),
7174
+ ...(turnResult.objections || []).map(o => o.statement || ''),
7175
+ ...(turnResult.files_changed || []),
7176
+ ...(turnResult.artifacts_created || []),
7177
+ ...(Array.isArray(turnResult.intent_response)
7178
+ ? turnResult.intent_response.map(r => `${r.item || ''} ${r.detail || ''}`)
7179
+ : []),
7180
+ ].join('\n').toLowerCase();
7181
+
7182
+ if (!corpus.includes('vision.md')) {
7183
+ return false;
7184
+ }
7185
+
7186
+ if (normalizedItem.startsWith('milestone cites at least one concrete vision.md source section')) {
7187
+ return true;
7188
+ }
7189
+
7190
+ const sectionList = String(item).split(':').slice(1).join(':');
7191
+ const sectionNames = sectionList
7192
+ .split(',')
7193
+ .map((section) => section.trim().toLowerCase())
7194
+ .filter((section) => section.length >= 4);
7195
+ if (sectionNames.length === 0) {
7196
+ return true;
7197
+ }
7198
+
7199
+ return sectionNames.some((section) => corpus.includes(section));
7200
+ }
7201
+
7143
7202
  export {
7144
7203
  STATE_PATH,
7145
7204
  HISTORY_PATH,