create-principles-disciple 1.132.6 → 1.133.1

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.
Files changed (134) hide show
  1. package/codex-adapter/dist/ingestion/ingestion.js +3 -3
  2. package/codex-adapter/dist/ingestion/transcript-locate.d.ts +6 -11
  3. package/codex-adapter/dist/ingestion/transcript-locate.js +5 -73
  4. package/codex-adapter/dist/ingestion/transcript-path.d.ts +2 -2
  5. package/codex-adapter/dist/ingestion/transcript-path.js +4 -21
  6. package/codex-adapter/dist/worker/workspace-worker.d.ts +1 -12
  7. package/codex-adapter/dist/worker/workspace-worker.js +4 -34
  8. package/codex-adapter/package.json +1 -1
  9. package/console/dist/server/models/CodexGovernanceHealthModel.d.ts +97 -0
  10. package/console/dist/server/models/CodexGovernanceHealthModel.js +81 -0
  11. package/console/dist/server/models/EvidenceChainConsoleModel.js +16 -2
  12. package/console/dist/server/routes/health.js +59 -3
  13. package/console/dist/server/routes/update.js +105 -1
  14. package/console/dist/ui/i18n/en.json +4 -0
  15. package/console/dist/ui/i18n/zh-CN.json +4 -0
  16. package/console/dist/ui/pages/pain/PainPage.js +1 -1
  17. package/console/dist/ui/utils/validators.d.ts +2 -0
  18. package/console/dist/ui/utils/validators.js +7 -0
  19. package/console/dist/web/assets/app.js +15 -1
  20. package/core/dist/host/index.d.ts +2 -0
  21. package/core/dist/host/index.d.ts.map +1 -1
  22. package/core/dist/host/index.js +3 -0
  23. package/core/dist/host/index.js.map +1 -1
  24. package/core/dist/host/legacy-registration.d.ts +28 -0
  25. package/core/dist/host/legacy-registration.d.ts.map +1 -0
  26. package/core/dist/host/legacy-registration.js +49 -0
  27. package/core/dist/host/legacy-registration.js.map +1 -0
  28. package/core/dist/runtime-v2/__tests__/evidence-chain-host-kind.test.d.ts +2 -0
  29. package/core/dist/runtime-v2/__tests__/evidence-chain-host-kind.test.d.ts.map +1 -0
  30. package/core/dist/runtime-v2/__tests__/evidence-chain-host-kind.test.js +49 -0
  31. package/core/dist/runtime-v2/__tests__/evidence-chain-host-kind.test.js.map +1 -0
  32. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +7 -0
  33. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
  34. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
  35. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +17 -6
  36. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
  37. package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.d.ts.map +1 -1
  38. package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js +14 -6
  39. package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js.map +1 -1
  40. package/core/dist/runtime-v2/types/evidence-chain-contract.d.ts +6 -0
  41. package/core/dist/runtime-v2/types/evidence-chain-contract.d.ts.map +1 -1
  42. package/core/dist/runtime-v2/types/evidence-chain-contract.js +12 -0
  43. package/core/dist/runtime-v2/types/evidence-chain-contract.js.map +1 -1
  44. package/core/package.json +1 -1
  45. package/dist/installer.d.ts +9 -3
  46. package/dist/installer.d.ts.map +1 -1
  47. package/dist/installer.js +37 -28
  48. package/dist/installer.js.map +1 -1
  49. package/dist/installers/codex-host-installer.d.ts +17 -7
  50. package/dist/installers/codex-host-installer.d.ts.map +1 -1
  51. package/dist/installers/codex-host-installer.js +78 -194
  52. package/dist/installers/codex-host-installer.js.map +1 -1
  53. package/dist/update/apply-payload.d.ts +88 -0
  54. package/dist/update/apply-payload.d.ts.map +1 -0
  55. package/dist/update/apply-payload.js +166 -0
  56. package/dist/update/apply-payload.js.map +1 -0
  57. package/dist/update/bootstrap-protocol.d.ts.map +1 -1
  58. package/dist/update/bootstrap-protocol.js +14 -2
  59. package/dist/update/bootstrap-protocol.js.map +1 -1
  60. package/dist/update/release-manager-authority.d.ts +15 -0
  61. package/dist/update/release-manager-authority.d.ts.map +1 -1
  62. package/dist/update/release-manager-authority.js +35 -7
  63. package/dist/update/release-manager-authority.js.map +1 -1
  64. package/dist/update/release-manager.d.ts +74 -6
  65. package/dist/update/release-manager.d.ts.map +1 -1
  66. package/dist/update/release-manager.js +272 -36
  67. package/dist/update/release-manager.js.map +1 -1
  68. package/dist/update/transaction-journal.d.ts +3 -1
  69. package/dist/update/transaction-journal.d.ts.map +1 -1
  70. package/dist/update/transaction-journal.js +3 -1
  71. package/dist/update/transaction-journal.js.map +1 -1
  72. package/host-runtime/dist/codex-disclosure.d.ts +23 -0
  73. package/host-runtime/dist/codex-disclosure.js +60 -0
  74. package/host-runtime/dist/codex-ingestion-consent.d.ts +111 -0
  75. package/host-runtime/dist/codex-ingestion-consent.js +223 -0
  76. package/host-runtime/dist/codex-legacy-registration.d.ts +18 -0
  77. package/host-runtime/dist/codex-legacy-registration.js +34 -0
  78. package/host-runtime/dist/codex-transcript-locate.d.ts +16 -0
  79. package/host-runtime/dist/codex-transcript-locate.js +106 -0
  80. package/host-runtime/dist/codex-worker-status.d.ts +24 -0
  81. package/host-runtime/dist/codex-worker-status.js +52 -0
  82. package/host-runtime/dist/governance-observation-store.d.ts +77 -1
  83. package/host-runtime/dist/governance-observation-store.js +188 -3
  84. package/host-runtime/dist/governance-signal-admission.d.ts +26 -0
  85. package/host-runtime/dist/governance-signal-admission.js +47 -0
  86. package/host-runtime/dist/index.d.ts +5 -0
  87. package/host-runtime/dist/index.js +14 -0
  88. package/host-runtime/package.json +1 -1
  89. package/package.json +1 -1
  90. package/pd-cli/dist/commands/codex-ingest-quarantine.d.ts +12 -0
  91. package/pd-cli/dist/commands/codex-ingest-quarantine.d.ts.map +1 -0
  92. package/pd-cli/dist/commands/codex-ingest-quarantine.js +116 -0
  93. package/pd-cli/dist/commands/codex-ingest-quarantine.js.map +1 -0
  94. package/pd-cli/dist/commands/codex-setup.d.ts +46 -0
  95. package/pd-cli/dist/commands/codex-setup.d.ts.map +1 -0
  96. package/pd-cli/dist/commands/codex-setup.js +423 -0
  97. package/pd-cli/dist/commands/codex-setup.js.map +1 -0
  98. package/pd-cli/dist/commands/health-codex.d.ts.map +1 -1
  99. package/pd-cli/dist/commands/health-codex.js +350 -67
  100. package/pd-cli/dist/commands/health-codex.js.map +1 -1
  101. package/pd-cli/dist/index.js +51 -0
  102. package/pd-cli/dist/index.js.map +1 -1
  103. package/pd-cli/package.json +1 -1
  104. package/plugin/dist/bundle.js +331 -331
  105. package/plugin/dist/governance-audit.js +1 -1
  106. package/plugin/dist/rulehost-evidence.js +1 -1
  107. package/release-manager/dist/installer.d.ts +9 -3
  108. package/release-manager/dist/installer.d.ts.map +1 -1
  109. package/release-manager/dist/installer.js +37 -28
  110. package/release-manager/dist/installer.js.map +1 -1
  111. package/release-manager/dist/installers/codex-host-installer.d.ts +17 -7
  112. package/release-manager/dist/installers/codex-host-installer.d.ts.map +1 -1
  113. package/release-manager/dist/installers/codex-host-installer.js +78 -194
  114. package/release-manager/dist/installers/codex-host-installer.js.map +1 -1
  115. package/release-manager/dist/update/apply-payload.d.ts +88 -0
  116. package/release-manager/dist/update/apply-payload.d.ts.map +1 -0
  117. package/release-manager/dist/update/apply-payload.js +166 -0
  118. package/release-manager/dist/update/apply-payload.js.map +1 -0
  119. package/release-manager/dist/update/bootstrap-protocol.d.ts.map +1 -1
  120. package/release-manager/dist/update/bootstrap-protocol.js +14 -2
  121. package/release-manager/dist/update/bootstrap-protocol.js.map +1 -1
  122. package/release-manager/dist/update/release-manager-authority.d.ts +15 -0
  123. package/release-manager/dist/update/release-manager-authority.d.ts.map +1 -1
  124. package/release-manager/dist/update/release-manager-authority.js +35 -7
  125. package/release-manager/dist/update/release-manager-authority.js.map +1 -1
  126. package/release-manager/dist/update/release-manager.d.ts +74 -6
  127. package/release-manager/dist/update/release-manager.d.ts.map +1 -1
  128. package/release-manager/dist/update/release-manager.js +272 -36
  129. package/release-manager/dist/update/release-manager.js.map +1 -1
  130. package/release-manager/dist/update/transaction-journal.d.ts +3 -1
  131. package/release-manager/dist/update/transaction-journal.d.ts.map +1 -1
  132. package/release-manager/dist/update/transaction-journal.js +3 -1
  133. package/release-manager/dist/update/transaction-journal.js.map +1 -1
  134. package/release-manager/package.json +1 -1
@@ -1666,6 +1666,16 @@ function releaseManagerFlagEnabled(workspaceDir) {
1666
1666
  const flags = computeFlagsFromLoadResult(loadPdConfig(workspaceDir));
1667
1667
  return isFeatureEnabled(flags, 'release_manager_shadow');
1668
1668
  }
1669
+ /**
1670
+ * PRI-698 Phase 1: gates routing /apply-full to the ReleaseManager write
1671
+ * orchestration. Default off — the legacy updater serves with an explicit
1672
+ * `release_manager_write_disabled` fallback reason. Requires the shadow flag
1673
+ * too (the whole authority layer is gated on it first).
1674
+ */
1675
+ function releaseManagerWriteFlagEnabled(workspaceDir) {
1676
+ const flags = computeFlagsFromLoadResult(loadPdConfig(workspaceDir));
1677
+ return isFeatureEnabled(flags, 'release_manager_write_authority');
1678
+ }
1669
1679
  function fallbackToLegacyForAllKinds(reason) {
1670
1680
  for (const kind of MUTATION_KINDS) {
1671
1681
  updateMutationController.unregister(kind, RELEASE_MANAGER_AUTHORITY);
@@ -1745,6 +1755,87 @@ async function runReleaseManagerCheckDispatch(mod, req, res, ctx) {
1745
1755
  sendError(res, 500, 'update_check_error', err instanceof Error ? err.message : 'Unknown error');
1746
1756
  }
1747
1757
  }
1758
+ /**
1759
+ * PRI-698 Phase 1: governed apply-full dispatch (flag `release_manager_write_
1760
+ * authority` on, readiness ready at registration time). The ReleaseManager
1761
+ * orchestrates the update through the installer + transaction journal; this
1762
+ * layer maps the outcome into the legacy doInlineFullUpdate response contract
1763
+ * ({success, message, reason?, nextAction?, newVersion?, requiresRestart}) —
1764
+ * wire contract unchanged. It performs NO runtime mutation itself.
1765
+ */
1766
+ async function runReleaseManagerApplyFullDispatch(mod, req, res, ctx) {
1767
+ if (req.method !== 'POST') {
1768
+ sendMethodNotAllowed(res);
1769
+ return;
1770
+ }
1771
+ let authority;
1772
+ try {
1773
+ authority = mod.createReleaseManagerAuthority({
1774
+ pdHome: path.join(os.homedir(), '.pd'),
1775
+ metadataBaseUrl: process.env.PD_RELEASE_METADATA_URL,
1776
+ });
1777
+ }
1778
+ catch {
1779
+ res.setHeader('X-PD-Mutation-Authority', `${LEGACY_MUTATION_AUTHORITY} (preferred: ${RELEASE_MANAGER_AUTHORITY} unavailable)`);
1780
+ res.setHeader('X-PD-Mutation-Fallback-Reason', 'authority_module_unavailable');
1781
+ await legacyApplyFullMutation(req, res, ctx);
1782
+ return;
1783
+ }
1784
+ if (authority.installStatus === null || !authority.kinds['apply-full'].ready) {
1785
+ // Readiness flipped between registration sync and dispatch — explicit
1786
+ // fallback, never a half-governed mutation.
1787
+ const reasons = authority.installStatus === null
1788
+ ? 'install_state_corrupt'
1789
+ : authority.kinds['apply-full'].reasons.join(',');
1790
+ res.setHeader('X-PD-Mutation-Authority', `${LEGACY_MUTATION_AUTHORITY} (preferred: ${RELEASE_MANAGER_AUTHORITY} unavailable)`);
1791
+ res.setHeader('X-PD-Mutation-Fallback-Reason', `release_manager_unavailable:${reasons}`);
1792
+ await legacyApplyFullMutation(req, res, ctx);
1793
+ return;
1794
+ }
1795
+ try {
1796
+ const outcome = await authority.manager.apply({ workspaceDir: ctx.workspaceDir });
1797
+ if (outcome.kind === 'applied') {
1798
+ sendSuccess(res, {
1799
+ success: true,
1800
+ message: `Updated to ${outcome.productVersion}. Transaction ${outcome.transactionId} confirmed in the journal.`,
1801
+ newVersion: outcome.productVersion,
1802
+ requiresRestart: true,
1803
+ nextAction: 'Restart PD Console to run the updated build.',
1804
+ });
1805
+ }
1806
+ else {
1807
+ sendSuccess(res, {
1808
+ success: true,
1809
+ message: `No update applied: ${outcome.note}`,
1810
+ requiresRestart: false,
1811
+ });
1812
+ }
1813
+ }
1814
+ catch (error) {
1815
+ const mapped = mod.mapReleaseManagerErrorToFallback(error);
1816
+ // PRI-698 default-on safety net: a refusal thrown BEFORE the update
1817
+ // transaction was opened (layout unsupported, metadata unavailable,
1818
+ // journal unwritable) has ZERO side effects, so — exactly like the
1819
+ // governed check — the explicit fallback serves the request with the
1820
+ // refusal reason annotated. A refusal AFTER the transaction opened
1821
+ // (transactionOpened) may have runtime-side effects (staging writes,
1822
+ // journal tail): it surfaces as the legacy failure body, never as a
1823
+ // fallback.
1824
+ if (mapped.transactionOpened !== true) {
1825
+ res.setHeader('X-PD-Mutation-Authority', `${LEGACY_MUTATION_AUTHORITY} (preferred: ${RELEASE_MANAGER_AUTHORITY} refused pre-transaction: ${mapped.reason})`);
1826
+ res.setHeader('X-PD-Mutation-Fallback-Reason', `release_manager_refused_pre_transaction:${mapped.reason}`);
1827
+ await legacyApplyFullMutation(req, res, ctx);
1828
+ return;
1829
+ }
1830
+ sendSuccess(res, {
1831
+ success: false,
1832
+ message: mapped.message,
1833
+ reason: mapped.reason,
1834
+ nextAction: mapped.nextAction ?? 'The runtime is unchanged. Retry the update after resolving the cause.',
1835
+ requiresRestart: false,
1836
+ });
1837
+ }
1838
+ }
1748
1839
  /**
1749
1840
  * Bring the authority registration in line with current flag + readiness
1750
1841
  * state, then dispatch happens through the controller as usual. Idempotent;
@@ -1780,6 +1871,7 @@ async function syncReleaseManagerAuthority(workspaceDir) {
1780
1871
  fallbackToLegacyForAllKinds('authority_module_unavailable');
1781
1872
  return;
1782
1873
  }
1874
+ const writeAuthorityEnabled = releaseManagerWriteFlagEnabled(workspaceDir);
1783
1875
  for (const rmKind of mod.RELEASE_MANAGER_AUTHORITY_KINDS) {
1784
1876
  const readiness = authority.kinds[rmKind];
1785
1877
  if (readiness.ready && rmKind === 'check') {
@@ -1789,9 +1881,21 @@ async function syncReleaseManagerAuthority(workspaceDir) {
1789
1881
  });
1790
1882
  updateMutationController.setFallbackReason('check', null);
1791
1883
  }
1884
+ else if (readiness.ready && rmKind === 'apply-full' && writeAuthorityEnabled) {
1885
+ updateMutationController.register('apply-full', {
1886
+ name: RELEASE_MANAGER_AUTHORITY,
1887
+ handler: (req, res, ctx) => runReleaseManagerApplyFullDispatch(mod, req, res, ctx),
1888
+ });
1889
+ updateMutationController.setFallbackReason('apply-full', null);
1890
+ }
1792
1891
  else {
1793
1892
  updateMutationController.unregister(rmKind, RELEASE_MANAGER_AUTHORITY);
1794
- updateMutationController.setFallbackReason(rmKind, `release_manager_unavailable:${readiness.reasons.join(',')}`);
1893
+ // PRI-698 Phase 1: a structurally-ready apply-full with the write flag
1894
+ // off is a deliberate gate, not an unavailability — name it distinctly.
1895
+ const reason = readiness.ready && rmKind === 'apply-full'
1896
+ ? 'release_manager_write_disabled'
1897
+ : `release_manager_unavailable:${readiness.reasons.join(',')}`;
1898
+ updateMutationController.setFallbackReason(rmKind, reason);
1795
1899
  }
1796
1900
  }
1797
1901
  }
@@ -357,6 +357,10 @@
357
357
  "chainInternalizationTask": "Internalization Task ID",
358
358
  "chainDreamerStatus": "Dreamer Status",
359
359
  "fieldTrigger": "Trigger",
360
+ "hostKind": {
361
+ "codex": "Codex",
362
+ "openclaw": "OpenClaw"
363
+ },
360
364
  "fieldConclusion": "PD's Conclusion",
361
365
  "fieldApplicability": "Applicability",
362
366
  "fieldConfidence": "Confidence",
@@ -357,6 +357,10 @@
357
357
  "chainInternalizationTask": "内化任务 ID",
358
358
  "chainDreamerStatus": "Dreamer 状态",
359
359
  "fieldTrigger": "触发行为",
360
+ "hostKind": {
361
+ "codex": "Codex",
362
+ "openclaw": "OpenClaw"
363
+ },
360
364
  "fieldConclusion": "PD 的结论",
361
365
  "fieldApplicability": "适用/说明",
362
366
  "fieldConfidence": "置信度",
@@ -135,7 +135,7 @@ function EvidenceChainCard({ record, expanded, onToggle, t }) {
135
135
  const confidenceDisplay = layers.layer2.confidence
136
136
  ? `${enumLabel('confidence', layers.layer2.confidence.label, t)} (${layers.layer2.confidence.raw.toFixed(2)})`
137
137
  : null;
138
- return (_jsxs(Card, { className: "overflow-hidden", children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(Badge, { variant: stateVariant, children: stateLabel }), _jsx(Badge, { variant: "outline", children: sourceLabel }), record.admissionDecision && (_jsx(Badge, { variant: "secondary", children: enumLabel('admission', record.admissionDecision, t) }))] }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [_jsx(Button, { variant: "ghost", size: "sm", "data-testid": `pain-feedback-${record.id}`, onClick: () => {
138
+ return (_jsxs(Card, { className: "overflow-hidden", children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(Badge, { variant: stateVariant, children: stateLabel }), _jsx(Badge, { variant: "outline", children: sourceLabel }), record.hostKind && record.hostKind !== 'unknown' && (_jsx(Badge, { variant: "secondary", children: t(`pages.pain.hostKind.${record.hostKind}`) })), record.admissionDecision && (_jsx(Badge, { variant: "secondary", children: enumLabel('admission', record.admissionDecision, t) }))] }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [_jsx(Button, { variant: "ghost", size: "sm", "data-testid": `pain-feedback-${record.id}`, onClick: () => {
139
139
  const params = new URLSearchParams({ source: "pain_page", painId: record.id });
140
140
  navigate(`/report-problem?${params.toString()}`);
141
141
  }, children: t('pages.reportProblem.entryFeedback') }), _jsx("span", { className: "font-mono text-[11px] text-ink-4 whitespace-nowrap", children: formatDate(record.observedAt) })] })] }) }), _jsxs(CardContent, { children: [_jsxs("div", { className: "space-y-3 mb-4", children: [_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldTrigger') }), layer2Empty ? (_jsx("p", { className: "text-ink-3 text-sm italic leading-relaxed", children: t('pages.pain.noHumanSummary') })) : (_jsx(CardTitle, { className: "text-[15px] leading-relaxed", children: layers.layer2.triggerSummary }))] }), layers.layer2.conclusion && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldConclusion') }), _jsx("p", { className: "text-ink text-sm leading-relaxed font-medium", children: layers.layer2.conclusion })] })), layers.layer2.applicability && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldApplicability') }), _jsx("p", { className: "text-ink-2 text-sm leading-relaxed", children: layers.layer2.applicability })] })), confidenceDisplay && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldConfidence') }), _jsx("p", { className: "text-ink-2 text-sm", children: confidenceDisplay })] })), layers.layer2.failureReason && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldFailureReason') }), _jsx("p", { className: "text-danger text-sm leading-relaxed", children: layers.layer2.failureReason })] })), layers.layer2.degradedReason && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldDegradedReason') }), _jsx("p", { className: "text-amber text-sm leading-relaxed", children: layers.layer2.degradedReason })] })), layers.layer2.nextAction && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldNextAction') }), _jsx("p", { className: "text-ink-2 text-sm leading-relaxed", children: layers.layer2.nextAction })] }))] }), shouldRenderIntentTensionPanel(layers.layer2.intentTension) && (_jsx(IntentTensionPanel, { tension: layers.layer2.intentTension, recordId: record.id, painId: record.id, taskId: record.linkedTaskId ?? undefined, linkedCandidateId: record.linkedCandidateId ?? undefined, t: t })), _jsxs("div", { className: "mt-4 pt-3 border-t border-line", children: [_jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: async () => {
@@ -536,6 +536,8 @@ export interface EvidenceChainRecordData {
536
536
  dreamerTaskStatus?: string;
537
537
  /** PRI-469: optional intent tension from diagnostician artifact (SPEC §16). */
538
538
  intentTension?: IntentTensionData;
539
+ /** PRI-625 Slice D: evidence host attribution — openclaw | codex | unknown. */
540
+ hostKind?: 'openclaw' | 'codex' | 'unknown';
539
541
  }
540
542
  export interface IntentTensionData {
541
543
  source: string;
@@ -1791,6 +1791,13 @@ function validateEvidenceChainRecord(v) {
1791
1791
  summary: v.summary,
1792
1792
  };
1793
1793
  // Optional fields — fail loud when present but wrong type (ERR-009)
1794
+ if (Object.hasOwn(v, 'hostKind')) {
1795
+ if (!isString(v.hostKind))
1796
+ return null;
1797
+ if (v.hostKind !== 'openclaw' && v.hostKind !== 'codex' && v.hostKind !== 'unknown')
1798
+ return null;
1799
+ result.hostKind = v.hostKind;
1800
+ }
1794
1801
  if (Object.hasOwn(v, 'admissionDecision')) {
1795
1802
  if (!isString(v.admissionDecision))
1796
1803
  return null;