agentxchain 2.155.30 → 2.155.32

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.30",
3
+ "version": "2.155.32",
4
4
  "description": "CLI for AgentXchain — governed multi-agent software delivery",
5
5
  "type": "module",
6
6
  "bin": {
@@ -4701,29 +4701,51 @@ function _acceptGovernedTurnLocked(root, config, opts) {
4701
4701
 
4702
4702
  const gateSemanticMode = config.gate_semantic_coverage_mode || 'strict';
4703
4703
  if (uncoveredFiles.length > 0 && gateSemanticMode === 'strict') {
4704
- const coverageError = `Gate "${exitGateId}" is failing on ${uncoveredFiles.join(', ')}. Your turn did not modify ${uncoveredFiles.length === 1 ? 'that file' : 'those files'}. Either edit the file(s) to satisfy the gate, or remove the phase transition request.`;
4705
- transitionToFailedAcceptance(root, state, currentTurn, coverageError, {
4706
- error_code: 'gate_semantic_coverage',
4707
- stage: 'gate_semantic_coverage',
4708
- extra: {
4709
- gate_id: exitGateId,
4710
- uncovered_files: uncoveredFiles,
4711
- declared_files: [...declaredFiles],
4712
- gate_reasons: preGateResult.reasons,
4713
- },
4714
- });
4715
- return {
4716
- ok: false,
4717
- error: coverageError,
4718
- validation: {
4719
- ...validation,
4720
- ok: false,
4704
+ // BUG-81: In planning phase only, auto-strip the phase transition request
4705
+ // instead of permanently blocking. PM's partial planning work is preserved;
4706
+ // the phase stays in "planning" and the continuous loop re-dispatches PM to
4707
+ // complete gate artifacts. In implementation+ phases, gate failures still
4708
+ // reject — dev/qa claiming readiness without updating gate files is a real error.
4709
+ if (turnResult.phase_transition_request && state.phase === 'planning') {
4710
+ emitRunEvent(root, 'gate_transition_request_auto_stripped', {
4711
+ run_id: state.run_id,
4712
+ phase: state.phase,
4713
+ status: state.status,
4714
+ turn: { turn_id: currentTurn.turn_id, role_id: currentTurn.assigned_role },
4715
+ payload: {
4716
+ gate_id: exitGateId,
4717
+ uncovered_files: uncoveredFiles,
4718
+ declared_files: [...declaredFiles],
4719
+ rationale: 'Turn did not modify gate-required files; phase transition stripped to preserve partial planning work',
4720
+ },
4721
+ });
4722
+ delete turnResult.phase_transition_request;
4723
+ // Fall through — continue with acceptance without the phase transition
4724
+ } else {
4725
+ const coverageError = `Gate "${exitGateId}" is failing on ${uncoveredFiles.join(', ')}. Your turn did not modify ${uncoveredFiles.length === 1 ? 'that file' : 'those files'}. Either edit the file(s) to satisfy the gate, or remove the phase transition request.`;
4726
+ transitionToFailedAcceptance(root, state, currentTurn, coverageError, {
4727
+ error_code: 'gate_semantic_coverage',
4721
4728
  stage: 'gate_semantic_coverage',
4722
- error_class: 'gate_coverage_error',
4723
- errors: uncoveredFiles.map(f => `Gate "${exitGateId}" is failing on "${f}". Your turn did not modify that file.`),
4724
- warnings: [],
4725
- },
4726
- };
4729
+ extra: {
4730
+ gate_id: exitGateId,
4731
+ uncovered_files: uncoveredFiles,
4732
+ declared_files: [...declaredFiles],
4733
+ gate_reasons: preGateResult.reasons,
4734
+ },
4735
+ });
4736
+ return {
4737
+ ok: false,
4738
+ error: coverageError,
4739
+ validation: {
4740
+ ...validation,
4741
+ ok: false,
4742
+ stage: 'gate_semantic_coverage',
4743
+ error_class: 'gate_coverage_error',
4744
+ errors: uncoveredFiles.map(f => `Gate "${exitGateId}" is failing on "${f}". Your turn did not modify that file.`),
4745
+ warnings: [],
4746
+ },
4747
+ };
4748
+ }
4727
4749
  }
4728
4750
  }
4729
4751
  }
@@ -6967,6 +6989,12 @@ function evaluateIntentCoverage(turnResult, intakeContext, { state = null, confi
6967
6989
  continue;
6968
6990
  }
6969
6991
 
6992
+ const roadmapCoverage = evaluateRoadmapDerivedConditionalCoverage(item, turnResult, intakeContext, state);
6993
+ if (roadmapCoverage === true) {
6994
+ addressed.push(item);
6995
+ continue;
6996
+ }
6997
+
6970
6998
  // Check 1: Structural — intent_response field with explicit status
6971
6999
  const structuralEntry = responseMap.get(normalizedItem);
6972
7000
  if (structuralEntry && ['addressed', 'deferred', 'rejected'].includes(structuralEntry.status)) {
@@ -7050,6 +7078,68 @@ function evaluateIdleExpansionConditionalCoverage(item, turnResult, intakeContex
7050
7078
  return null;
7051
7079
  }
7052
7080
 
7081
+ // ── Roadmap-derived intent conditional coverage (BUG-80) ────────────────────
7082
+ //
7083
+ // Roadmap-derived intents (charter starts with "[roadmap]") include literal
7084
+ // implementation text as acceptance items. PM turns in planning phase produce
7085
+ // charter/scoping artifacts, not implementation code, so the generic 50%
7086
+ // keyword-overlap check fails. This function provides phase-aware evaluation:
7087
+ // - "Evidence source:" items are metadata provenance → always addressed
7088
+ // - "Unchecked roadmap item completed:" in planning phase → milestone-mention check
7089
+ // - In implementation+ phases → falls through to normal semantic matching
7090
+
7091
+ function evaluateRoadmapDerivedConditionalCoverage(item, turnResult, intakeContext, state) {
7092
+ const charter = intakeContext?.charter || '';
7093
+ if (!charter.startsWith('[roadmap]')) {
7094
+ return null;
7095
+ }
7096
+
7097
+ const normalizedItem = typeof item === 'string' ? item.toLowerCase().trim() : '';
7098
+
7099
+ // "Evidence source:" items are provenance metadata, not deliverables.
7100
+ // No turn of any role can "address" a file path reference.
7101
+ if (normalizedItem.startsWith('evidence source:')) {
7102
+ return true;
7103
+ }
7104
+
7105
+ // "Unchecked roadmap item completed:" contains literal implementation text.
7106
+ // In planning phase, PM scopes the milestone — check for milestone mention
7107
+ // rather than requiring implementation-keyword overlap.
7108
+ // In implementation/qa/launch phases, fall through to normal semantic matching
7109
+ // so dev turns are still evaluated against actual implementation keywords.
7110
+ if (normalizedItem.startsWith('unchecked roadmap item completed:')) {
7111
+ const currentPhase = state?.phase || '';
7112
+ if (currentPhase !== 'planning') {
7113
+ return null;
7114
+ }
7115
+
7116
+ // Extract milestone section identifier from charter: "[roadmap] M28: ..."
7117
+ const sectionMatch = charter.match(/\[roadmap\]\s*(M\d+)/i);
7118
+ if (!sectionMatch) {
7119
+ return null;
7120
+ }
7121
+
7122
+ const milestoneId = sectionMatch[1].toLowerCase();
7123
+
7124
+ // Build a searchable corpus from the turn result
7125
+ const corpus = [
7126
+ turnResult.summary || '',
7127
+ ...(turnResult.decisions || []).map(d => `${d.statement || ''} ${d.rationale || ''}`),
7128
+ ...(turnResult.objections || []).map(o => o.statement || ''),
7129
+ ...(turnResult.files_changed || []),
7130
+ ...(turnResult.artifacts_created || []),
7131
+ ...(Array.isArray(turnResult.intent_response)
7132
+ ? turnResult.intent_response.map(r => `${r.item || ''} ${r.detail || ''}`)
7133
+ : []),
7134
+ ].join('\n').toLowerCase();
7135
+
7136
+ // If the turn mentions the milestone section ID, the item is addressed
7137
+ return corpus.includes(milestoneId);
7138
+ }
7139
+
7140
+ return null;
7141
+ }
7142
+
7053
7143
  export {
7054
7144
  STATE_PATH,
7055
7145
  HISTORY_PATH,