agentxchain 2.155.56 → 2.155.58

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.56",
3
+ "version": "2.155.58",
4
4
  "description": "CLI for AgentXchain — governed multi-agent software delivery",
5
5
  "type": "module",
6
6
  "bin": {
@@ -498,7 +498,7 @@ function renderPrompt(role, roleId, turn, state, config, root) {
498
498
  lines.push('- `files_changed`: **REQUIRED** array of **strings** (file paths only). Do NOT use `files_modified` — the field name is `files_changed`. Do NOT use objects like `{path, change_type}` — just the path string (e.g. `["src/cli.js", "tests/smoke.mjs"]`).');
499
499
  lines.push('- `proposed_next_role`: **REQUIRED**. Must be in allowed_next_roles for the current phase, or `"human"`.');
500
500
  lines.push('- `decisions[].id`: pattern `DEC-NNN` where NNN is digits only (e.g. `DEC-001`, `DEC-002`). Do NOT use `D1`, `D2`, or freeform IDs.');
501
- lines.push('- `decisions[].statement`: non-empty string describing the decision. Do NOT use `decision`, `description`, or `summary` as the field name — the field is `statement`.');
501
+ lines.push('- `decisions[].statement`: non-empty string describing the decision. Do NOT use `decision`, `description`, `summary`, or `title` as the field name — the field is `statement`.');
502
502
  lines.push('- `decisions[].rationale`: REQUIRED non-empty string explaining why the decision was made. Do NOT omit this field.');
503
503
  lines.push('- `decisions[].category`: one of `implementation`, `architecture`, `scope`, `process`, `quality`, `release`');
504
504
  lines.push('- `objections[].id`: pattern `OBJ-NNN` where NNN is digits only (e.g. `OBJ-001`, `OBJ-002`). Do NOT append extra suffixes like `-M31` or use non-numeric characters after `OBJ-`.');
@@ -506,6 +506,7 @@ function renderPrompt(role, roleId, turn, state, config, root) {
506
506
  lines.push('- `verification.status`: **REQUIRED**. One of `pass`, `fail`, `skipped`. Always include this field in the `verification` object.');
507
507
  lines.push('- `verification.status: "pass"` is valid only when every `verification.machine_evidence[].exit_code` is `0`, unless a negative-case command explicitly sets `expected_exit_code` to the same non-zero value.');
508
508
  lines.push('- Expected-failure checks should be wrapped in a verifier that exits `0` when the failure occurs as expected. If you must record a raw non-zero negative-case command on a passing turn, set `verification.machine_evidence[].expected_exit_code` to the expected non-zero code and explain it in `evidence_summary`.');
509
+ lines.push('- `verification.machine_evidence[]` is only for executable command records with both `command` and `exit_code`. Put typed marker checks, file-grep observations, bucket summaries, and acceptance-contract summaries in `verification.evidence_summary`, not in `machine_evidence`.');
509
510
  lines.push('- If verification commands produce side-effect files (e.g., `.tusq/plan.json`, `coverage/`, `.cache/`), declare each in `verification.produced_files` with `disposition: "ignore"` (temporary output to clean up) or `disposition: "artifact"` (output to checkpoint as a turn deliverable). Undeclared dirty files with declared verification will be auto-cleaned but declaring them is preferred.');
510
511
  lines.push('- `artifact.type`: **REQUIRED**. One of `workspace`, `patch`, `commit`, `review`.');
511
512
  lines.push('- If you make zero repo file edits, set `artifact.type` to `"review"` and `files_changed` to `[]`.');
@@ -1285,10 +1285,12 @@ export function normalizeTurnResult(tr, config, context = {}) {
1285
1285
  if (!stmt) {
1286
1286
  const alt = typeof patched.decision === 'string' ? patched.decision.trim()
1287
1287
  : typeof patched.description === 'string' ? patched.description.trim()
1288
- : typeof patched.summary === 'string' ? patched.summary.trim() : '';
1288
+ : typeof patched.summary === 'string' ? patched.summary.trim()
1289
+ : typeof patched.title === 'string' ? patched.title.trim() : '';
1289
1290
  if (alt) {
1290
1291
  const srcField = typeof patched.decision === 'string' && patched.decision.trim() ? 'decision'
1291
- : typeof patched.description === 'string' && patched.description.trim() ? 'description' : 'summary';
1292
+ : typeof patched.description === 'string' && patched.description.trim() ? 'description'
1293
+ : typeof patched.summary === 'string' && patched.summary.trim() ? 'summary' : 'title';
1292
1294
  corrections.push(`decisions[${index}].statement: copied from ${srcField}`);
1293
1295
  normalizationEvents.push({
1294
1296
  field: `decisions[${index}].statement`,
@@ -1362,6 +1364,63 @@ export function normalizeTurnResult(tr, config, context = {}) {
1362
1364
  normalized.verification = { ...normalized.verification, status: inferredStatus };
1363
1365
  }
1364
1366
 
1367
+ // ── BUG-104: typed marker evidence belongs in evidence_summary ───────
1368
+ // machine_evidence is reserved for executable command records. Some model
1369
+ // turns emit useful structured observations in that array (for example
1370
+ // file_marker_grep objects) without command/exit_code fields. Preserve that
1371
+ // information as summary evidence instead of fabricating shell commands.
1372
+ if (
1373
+ normalized.verification
1374
+ && typeof normalized.verification === 'object'
1375
+ && !Array.isArray(normalized.verification)
1376
+ && Array.isArray(normalized.verification.machine_evidence)
1377
+ ) {
1378
+ const keptMachineEvidence = [];
1379
+ const structuredEvidenceSummaries = [];
1380
+ normalized.verification.machine_evidence.forEach((entry, index) => {
1381
+ if (
1382
+ entry
1383
+ && typeof entry === 'object'
1384
+ && !Array.isArray(entry)
1385
+ && typeof entry.command === 'string'
1386
+ && entry.command.trim()
1387
+ && Number.isInteger(entry.exit_code)
1388
+ ) {
1389
+ keptMachineEvidence.push(entry);
1390
+ return;
1391
+ }
1392
+
1393
+ const summary = summarizeStructuredMachineEvidence(entry);
1394
+ if (!summary) {
1395
+ keptMachineEvidence.push(entry);
1396
+ return;
1397
+ }
1398
+
1399
+ structuredEvidenceSummaries.push(summary);
1400
+ corrections.push(`verification.machine_evidence[${index}]: moved structured ${summary.type} evidence into evidence_summary`);
1401
+ normalizationEvents.push({
1402
+ field: `verification.machine_evidence[${index}]`,
1403
+ original_value: entry,
1404
+ normalized_value: summary.text,
1405
+ rationale: 'structured_machine_evidence_moved_to_evidence_summary',
1406
+ });
1407
+ });
1408
+
1409
+ if (structuredEvidenceSummaries.length > 0) {
1410
+ const existingSummary = typeof normalized.verification.evidence_summary === 'string'
1411
+ ? normalized.verification.evidence_summary.trim()
1412
+ : '';
1413
+ const appendedSummary = structuredEvidenceSummaries.map((summary) => summary.text).join('; ');
1414
+ normalized.verification = {
1415
+ ...normalized.verification,
1416
+ machine_evidence: keptMachineEvidence,
1417
+ evidence_summary: existingSummary
1418
+ ? `${existingSummary}\nStructured evidence: ${appendedSummary}`
1419
+ : `Structured evidence: ${appendedSummary}`,
1420
+ };
1421
+ }
1422
+ }
1423
+
1365
1424
  // ── BUG-90: normalize missing artifact.type ─────────────────────────
1366
1425
  if (
1367
1426
  normalized.artifact
@@ -1740,6 +1799,42 @@ export function normalizeTurnResult(tr, config, context = {}) {
1740
1799
  return { normalized, corrections, normalizationEvents };
1741
1800
  }
1742
1801
 
1802
+ function summarizeStructuredMachineEvidence(entry) {
1803
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
1804
+ return null;
1805
+ }
1806
+ if (typeof entry.type !== 'string' || entry.type.trim().length === 0) {
1807
+ return null;
1808
+ }
1809
+
1810
+ const type = entry.type.trim();
1811
+ const parts = [`type=${type}`];
1812
+ for (const key of ['path', 'marker', 'section', 'result']) {
1813
+ if (typeof entry[key] === 'string' && entry[key].trim()) {
1814
+ parts.push(`${key}=${truncateEvidenceValue(entry[key].trim())}`);
1815
+ }
1816
+ }
1817
+ if (Array.isArray(entry.contract) && entry.contract.length > 0) {
1818
+ parts.push(`contract=${truncateEvidenceValue(entry.contract.join(' | '))}`);
1819
+ }
1820
+ if (
1821
+ entry.buckets_observed
1822
+ && typeof entry.buckets_observed === 'object'
1823
+ && !Array.isArray(entry.buckets_observed)
1824
+ ) {
1825
+ parts.push(`buckets_observed=${truncateEvidenceValue(JSON.stringify(entry.buckets_observed))}`);
1826
+ }
1827
+
1828
+ return {
1829
+ type,
1830
+ text: `[${parts.join(', ')}]`,
1831
+ };
1832
+ }
1833
+
1834
+ function truncateEvidenceValue(value, max = 220) {
1835
+ return value.length > max ? `${value.slice(0, max - 3)}...` : value;
1836
+ }
1837
+
1743
1838
  function normalizeIdleExpansionMutualExclusionSentinel(result) {
1744
1839
  if (!result || typeof result !== 'object' || Array.isArray(result)) {
1745
1840
  return { changed: false, value: result, correction: '' };