create-principles-disciple 1.145.32 → 1.145.33

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 (80) hide show
  1. package/_release/product-identity.json +1 -1
  2. package/codex-adapter/dist/ingestion/ingestion.js +3 -1
  3. package/codex-adapter/package.json +1 -1
  4. package/console/dist/server/models/ActivationsConsoleModel.d.ts +19 -2
  5. package/console/dist/server/models/ActivationsConsoleModel.js +124 -10
  6. package/console/dist/server/models/OwnerDecisionConsoleModel.d.ts +3 -1
  7. package/console/dist/server/models/OwnerDecisionConsoleModel.js +6 -2
  8. package/console/dist/server/routes/activations.js +7 -2
  9. package/console/dist/server/routes/owner-decisions.js +1 -1
  10. package/core/dist/runtime-v2/activation/index.d.ts +6 -0
  11. package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
  12. package/core/dist/runtime-v2/activation/index.js +3 -0
  13. package/core/dist/runtime-v2/activation/index.js.map +1 -1
  14. package/core/dist/runtime-v2/activation/openclaw-promotion-checks.d.ts +75 -0
  15. package/core/dist/runtime-v2/activation/openclaw-promotion-checks.d.ts.map +1 -1
  16. package/core/dist/runtime-v2/activation/openclaw-promotion-checks.js +131 -37
  17. package/core/dist/runtime-v2/activation/openclaw-promotion-checks.js.map +1 -1
  18. package/core/dist/runtime-v2/activation/production-gate-deps.d.ts.map +1 -1
  19. package/core/dist/runtime-v2/activation/production-gate-deps.js +7 -3
  20. package/core/dist/runtime-v2/activation/production-gate-deps.js.map +1 -1
  21. package/core/dist/runtime-v2/activation/recovery-composition.d.ts +54 -0
  22. package/core/dist/runtime-v2/activation/recovery-composition.d.ts.map +1 -0
  23. package/core/dist/runtime-v2/activation/recovery-composition.js +129 -0
  24. package/core/dist/runtime-v2/activation/recovery-composition.js.map +1 -0
  25. package/core/dist/runtime-v2/activation/recovery-control-surfaces.d.ts +62 -0
  26. package/core/dist/runtime-v2/activation/recovery-control-surfaces.d.ts.map +1 -0
  27. package/core/dist/runtime-v2/activation/recovery-control-surfaces.js +84 -0
  28. package/core/dist/runtime-v2/activation/recovery-control-surfaces.js.map +1 -0
  29. package/core/dist/runtime-v2/activation/rulecode-shadow-summary.d.ts +13 -1
  30. package/core/dist/runtime-v2/activation/rulecode-shadow-summary.d.ts.map +1 -1
  31. package/core/dist/runtime-v2/activation/rulecode-shadow-summary.js +24 -1
  32. package/core/dist/runtime-v2/activation/rulecode-shadow-summary.js.map +1 -1
  33. package/core/dist/runtime-v2/index.d.ts +2 -2
  34. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  35. package/core/dist/runtime-v2/index.js +1 -1
  36. package/core/dist/runtime-v2/index.js.map +1 -1
  37. package/core/dist/runtime-v2/trajectory-schema.d.ts.map +1 -1
  38. package/core/dist/runtime-v2/trajectory-schema.js +12 -1
  39. package/core/dist/runtime-v2/trajectory-schema.js.map +1 -1
  40. package/core/dist/runtime-v2/types/event-types.d.ts +10 -0
  41. package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
  42. package/core/dist/runtime-v2/types/event-types.js +1 -0
  43. package/core/dist/runtime-v2/types/event-types.js.map +1 -1
  44. package/core/package.json +1 -1
  45. package/host-runtime/dist/cli-recovery-probe.d.ts +30 -0
  46. package/host-runtime/dist/cli-recovery-probe.js +169 -0
  47. package/host-runtime/dist/governance-signal-admission.js +22 -5
  48. package/host-runtime/dist/host-liveness-contract.d.ts +51 -28
  49. package/host-runtime/dist/host-liveness-contract.js +143 -46
  50. package/host-runtime/dist/index.d.ts +2 -0
  51. package/host-runtime/dist/index.js +2 -0
  52. package/host-runtime/dist/production-pain-evidence.d.ts +2 -0
  53. package/host-runtime/dist/production-pain-evidence.js +46 -8
  54. package/host-runtime/dist/production-rulehost-gate.js +24 -6
  55. package/host-runtime/dist/workbuddy-rule-context-provider.d.ts +33 -0
  56. package/host-runtime/dist/workbuddy-rule-context-provider.js +126 -0
  57. package/host-runtime/dist/workspace-behavior-evidence.d.ts +22 -5
  58. package/host-runtime/dist/workspace-behavior-evidence.js +41 -11
  59. package/host-runtime/package.json +1 -1
  60. package/package.json +2 -2
  61. package/pd-cli/dist/commands/recovery-reachability-probe.d.ts +25 -0
  62. package/pd-cli/dist/commands/recovery-reachability-probe.d.ts.map +1 -0
  63. package/pd-cli/dist/commands/recovery-reachability-probe.js +50 -0
  64. package/pd-cli/dist/commands/recovery-reachability-probe.js.map +1 -0
  65. package/pd-cli/dist/commands/runtime-activation.d.ts +10 -1
  66. package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
  67. package/pd-cli/dist/commands/runtime-activation.js +81 -3
  68. package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
  69. package/pd-cli/package.json +1 -1
  70. package/plugin/dist/bundle.js +385 -385
  71. package/plugin/dist/governance-audit.js +1 -1
  72. package/plugin/dist/openclaw.plugin.json +1 -1
  73. package/plugin/dist/rulehost-evidence.js +1 -1
  74. package/plugin/openclaw.plugin.json +1 -1
  75. package/plugin/package.json +1 -1
  76. package/release-manager/package.json +2 -2
  77. package/workbuddy-adapter/dist/codec/input-decoder.d.ts +14 -11
  78. package/workbuddy-adapter/dist/codec/input-decoder.js +28 -14
  79. package/workbuddy-adapter/dist/pd-hook.js +31 -12
  80. package/workbuddy-adapter/package.json +1 -1
@@ -7,18 +7,35 @@ export declare function createWorkspaceBehaviorEvidencePort(workspaceDir: string
7
7
  * database. The timestamp is the caller's pre-event cutoff; rows at or after
8
8
  * it are excluded so replayed/future calls cannot enter a live RuleContext.
9
9
  * This is read-only and never creates or migrates trajectory state.
10
+ *
11
+ * Review R2 (SPEC-RULECODE-HOST-PROMOTION-001): when `hostKind` is supplied,
12
+ * the reader partitions the window by PROVEN producer attribution
13
+ * (`tool_calls.host_kind`, stamped by each host's writer) instead of handing
14
+ * back every row: `rows` carries only rows stamped with that host,
15
+ * `otherHostRows` counts rows stamped with a different host (a cross-host
16
+ * session-id collision), and `unattributedRows` counts legacy rows with no
17
+ * stamp (written before the column existed — attribution is unprovable, not
18
+ * assumed). A database whose tool_calls predates the column entirely counts
19
+ * every row in the unattributed bucket. The caller decides the failure
20
+ * policy; this reader never guesses an attribution.
10
21
  */
22
+ export interface WorkspaceRuleContextRowsResult {
23
+ rows: readonly RuleHostContextRow[];
24
+ truncated: boolean;
25
+ unscopedPriorRows: boolean;
26
+ /** Present only for attribution-aware reads: rows stamped with ANOTHER host (never zero-checked when hostKind is absent). */
27
+ otherHostRows?: number;
28
+ /** Present only for attribution-aware reads: legacy rows with no host stamp. */
29
+ unattributedRows?: number;
30
+ }
11
31
  export declare function readWorkspaceRuleContextRowsBefore(workspaceDir: string, input: {
12
32
  sessionId: string;
13
33
  projectDir: string;
14
34
  beforeCreatedAt: string;
15
35
  excludeToolUseId: string;
16
36
  limit: number;
17
- }): {
18
- rows: readonly RuleHostContextRow[];
19
- truncated: boolean;
20
- unscopedPriorRows: boolean;
21
- };
37
+ hostKind?: string;
38
+ }): WorkspaceRuleContextRowsResult;
22
39
  /**
23
40
  * List only Codex sessions proven by normalized host evidence and a matching
24
41
  * project-scoped trajectory row. The trajectory schema has no host_kind on
@@ -74,12 +74,6 @@ export function createWorkspaceBehaviorEvidencePort(workspaceDir, toolSemantics)
74
74
  },
75
75
  };
76
76
  }
77
- /**
78
- * Read one bounded, same-session history window from the canonical trajectory
79
- * database. The timestamp is the caller's pre-event cutoff; rows at or after
80
- * it are excluded so replayed/future calls cannot enter a live RuleContext.
81
- * This is read-only and never creates or migrates trajectory state.
82
- */
83
77
  export function readWorkspaceRuleContextRowsBefore(workspaceDir, input) {
84
78
  const { sessionId, projectDir, beforeCreatedAt, excludeToolUseId, limit } = input;
85
79
  if (sessionId.trim().length === 0)
@@ -95,9 +89,21 @@ export function readWorkspaceRuleContextRowsBefore(workspaceDir, input) {
95
89
  const db = new Database(path.join(workspaceDir, '.state', 'trajectory.db'), { readonly: true, fileMustExist: true });
96
90
  try {
97
91
  db.pragma('busy_timeout = 100');
92
+ const attributionAware = input.hostKind !== undefined;
93
+ // Select host_kind ONLY for attribution-aware reads on schemas that carry
94
+ // the column. A plain read (or a legacy schema without the column) keeps
95
+ // the historical column list — never a failing query.
96
+ const includeHostKind = attributionAware && (() => {
97
+ const columns = db.prepare('PRAGMA table_info(tool_calls)').all();
98
+ return Array.isArray(columns)
99
+ && columns.some((column) => record(column) && typeof column.name === 'string' && column.name === 'host_kind');
100
+ })();
98
101
  return db.transaction(() => {
99
- const rows = db.prepare(`
100
- SELECT id, tool_name, outcome, params_json
102
+ // Attribution-aware read: fetch one extra slot beyond the limit so the
103
+ // partition counts stay truthful about a truncated window's tail.
104
+ const selectColumns = includeHostKind ? 'id, tool_name, outcome, params_json, host_kind' : 'id, tool_name, outcome, params_json';
105
+ const fetched = db.prepare(`
106
+ SELECT ${selectColumns}
101
107
  FROM tool_calls
102
108
  WHERE session_id = ? AND project_dir = ? AND created_at < ? AND (tool_use_id IS NULL OR tool_use_id <> ?)
103
109
  ORDER BY created_at DESC, id DESC
@@ -108,12 +114,36 @@ export function readWorkspaceRuleContextRowsBefore(workspaceDir, input) {
108
114
  WHERE session_id = ? AND project_dir IS NULL AND created_at < ?
109
115
  AND (tool_use_id IS NULL OR tool_use_id <> ?) LIMIT 1
110
116
  `).get(sessionId, beforeCreatedAt, excludeToolUseId);
111
- if (!Array.isArray(rows))
117
+ if (!Array.isArray(fetched))
112
118
  throw new Error('history_query_invalid');
119
+ if (!attributionAware) {
120
+ return {
121
+ rows: fetched.slice(0, limit).reverse().map(contextRow),
122
+ truncated: fetched.length > limit,
123
+ unscopedPriorRows: unscoped !== undefined,
124
+ };
125
+ }
126
+ let otherHostRows = 0;
127
+ let unattributedRows = 0;
128
+ const matching = [];
129
+ for (const row of fetched) {
130
+ if (!record(row) || !Object.hasOwn(row, 'host_kind') || row.host_kind === null || row.host_kind === undefined) {
131
+ // No stamp (or no column): unprovable — never guessed into the host.
132
+ unattributedRows += 1;
133
+ continue;
134
+ }
135
+ if (row.host_kind !== input.hostKind) {
136
+ otherHostRows += 1;
137
+ continue;
138
+ }
139
+ matching.push(row);
140
+ }
113
141
  return {
114
- rows: rows.slice(0, limit).reverse().map(contextRow),
115
- truncated: rows.length > limit,
142
+ rows: matching.slice(0, limit).reverse().map(contextRow),
143
+ truncated: fetched.length > limit,
116
144
  unscopedPriorRows: unscoped !== undefined,
145
+ otherHostRows,
146
+ unattributedRows,
117
147
  };
118
148
  })();
119
149
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principles/host-runtime",
3
- "version": "0.14.1",
3
+ "version": "0.14.2",
4
4
  "description": "Shared host-neutral orchestration for Principles Disciple MVP-Core hook paths.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-principles-disciple",
3
- "version": "1.145.32",
3
+ "version": "1.145.33",
4
4
  "description": "Interactive CLI installer for Principles Disciple OpenClaw plugin",
5
5
  "type": "module",
6
6
  "bin": {
@@ -89,6 +89,6 @@
89
89
  "directory": "packages/create-principles-disciple"
90
90
  },
91
91
  "pd": {
92
- "bundledPluginVersion": "2.2.6"
92
+ "bundledPluginVersion": "2.2.7"
93
93
  }
94
94
  }
@@ -0,0 +1,25 @@
1
+ import type { RecoveryCapabilityEvidence } from '@principles/core/runtime-v2';
2
+ /**
3
+ * SPEC-RULECODE-HOST-PROMOTION-001 R3/R4: CLI-channel recovery reachability
4
+ * for the pd-cli readiness path. Thin wrapper — the real subprocess probes
5
+ * live in host-runtime (`probeCliRecoveryCapabilities`) so the Console
6
+ * readiness assembly reuses the SAME implementation. This wrapper only
7
+ * resolves the built pd CLI entry for the CURRENT environment and fails
8
+ * closed (all capabilities not-verified) when it cannot.
9
+ *
10
+ * Evidence semantics (R4/P1): the CLI subprocess channel can prove
11
+ * `pd_status` and `rulecode_deactivate` (real `--dry-run` validation path —
12
+ * no audit write, no mutation); the console-channel capabilities are
13
+ * reported NOT-VERIFIED with the precise reason — never fabricated as ok.
14
+ */
15
+ export { DEACTIVATE_DRY_RUN_PROBE_ACTIVATION_ID } from '@principles/host-runtime';
16
+ /**
17
+ * Probe the CLI-channel recovery capabilities against the target workspace.
18
+ * When `expectedActivationId` is supplied, pd_status additionally requires
19
+ * that activation to appear in the listing — proof the probe targeted the
20
+ * governed workspace, not merely some workspace.
21
+ */
22
+ export declare function probeCliRecoveryReachability(workspaceDir: string, expectedActivationId?: string, options?: {
23
+ timeoutMs?: number;
24
+ }): Promise<RecoveryCapabilityEvidence[]>;
25
+ //# sourceMappingURL=recovery-reachability-probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-reachability-probe.d.ts","sourceRoot":"","sources":["../../src/commands/recovery-reachability-probe.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAE9E;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,sCAAsC,EAAE,MAAM,0BAA0B,CAAC;AAelF;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAAC,YAAY,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,0BAA0B,EAAE,CAAC,CAW/K"}
@@ -0,0 +1,50 @@
1
+ import { existsSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { probeCliRecoveryCapabilities } from '@principles/host-runtime';
5
+ /**
6
+ * SPEC-RULECODE-HOST-PROMOTION-001 R3/R4: CLI-channel recovery reachability
7
+ * for the pd-cli readiness path. Thin wrapper — the real subprocess probes
8
+ * live in host-runtime (`probeCliRecoveryCapabilities`) so the Console
9
+ * readiness assembly reuses the SAME implementation. This wrapper only
10
+ * resolves the built pd CLI entry for the CURRENT environment and fails
11
+ * closed (all capabilities not-verified) when it cannot.
12
+ *
13
+ * Evidence semantics (R4/P1): the CLI subprocess channel can prove
14
+ * `pd_status` and `rulecode_deactivate` (real `--dry-run` validation path —
15
+ * no audit write, no mutation); the console-channel capabilities are
16
+ * reported NOT-VERIFIED with the precise reason — never fabricated as ok.
17
+ */
18
+ export { DEACTIVATE_DRY_RUN_PROBE_ACTIVATION_ID } from '@principles/host-runtime';
19
+ function resolveCliEntry() {
20
+ // Built layout: dist/commands/<this>.js with the entry at dist/index.js.
21
+ const here = path.dirname(fileURLToPath(import.meta.url));
22
+ const candidates = [
23
+ path.resolve(here, '..', 'index.js'),
24
+ path.resolve(process.cwd(), 'dist', 'index.js'),
25
+ ];
26
+ for (const candidate of candidates) {
27
+ if (existsSync(candidate))
28
+ return candidate;
29
+ }
30
+ return null;
31
+ }
32
+ /**
33
+ * Probe the CLI-channel recovery capabilities against the target workspace.
34
+ * When `expectedActivationId` is supplied, pd_status additionally requires
35
+ * that activation to appear in the listing — proof the probe targeted the
36
+ * governed workspace, not merely some workspace.
37
+ */
38
+ export async function probeCliRecoveryReachability(workspaceDir, expectedActivationId, options) {
39
+ const cliEntry = resolveCliEntry();
40
+ if (cliEntry === null) {
41
+ return [
42
+ { capabilityId: 'pd_status', channel: 'cli', ok: false, workspaceMatched: false, detail: 'pd CLI entry not found (built entry missing in this environment)' },
43
+ { capabilityId: 'rulecode_deactivate', channel: 'cli', ok: false, workspaceMatched: false, detail: 'pd CLI entry not found (built entry missing in this environment)' },
44
+ { capabilityId: 'rulecode_global_pause', channel: 'console', ok: false, workspaceMatched: false, detail: 'console-channel control: verifying the HTTP-only recovery entry requires the Owner Console process; a CLI subprocess cannot produce this evidence' },
45
+ { capabilityId: 'owner_review_access', channel: 'console', ok: false, workspaceMatched: false, detail: 'console-channel control: verifying the HTTP-only recovery entry requires the Owner Console process; a CLI subprocess cannot produce this evidence' },
46
+ ];
47
+ }
48
+ return probeCliRecoveryCapabilities({ cliEntry, workspaceDir, ...(expectedActivationId !== undefined ? { expectedActivationId } : {}), ...(options?.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}) });
49
+ }
50
+ //# sourceMappingURL=recovery-reachability-probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery-reachability-probe.js","sourceRoot":"","sources":["../../src/commands/recovery-reachability-probe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAGxE;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,sCAAsC,EAAE,MAAM,0BAA0B,CAAC;AAElF,SAAS,eAAe;IACtB,yEAAyE;IACzE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC;QACpC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC;KAChD,CAAC;IACF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;IAC9C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,YAAoB,EAAE,oBAA6B,EAAE,OAAgC;IACtI,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO;YACL,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,kEAAkE,EAAE;YAC7J,EAAE,YAAY,EAAE,qBAAqB,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,kEAAkE,EAAE;YACvK,EAAE,YAAY,EAAE,uBAAuB,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,mJAAmJ,EAAE;YAC9P,EAAE,YAAY,EAAE,qBAAqB,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,mJAAmJ,EAAE;SAC7P,CAAC;IACJ,CAAC;IACD,OAAO,4BAA4B,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,CAAC,oBAAoB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,OAAO,EAAE,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC1N,CAAC"}
@@ -29,7 +29,7 @@ export interface CollectedRuleCodeEventEntries {
29
29
  */
30
30
  export declare function collectRuleCodeEventEntries(workspaceDir: string): CollectedRuleCodeEventEntries;
31
31
  /** Exported for PRI-577 regression tests and reuse by promote evidence assembly. */
32
- export declare function readShadowSummaryForActivation(workspaceDir: string, activationId: string): PromotionEvidenceSnapshot['shadowSummary'];
32
+ export declare function readShadowSummaryForActivation(workspaceDir: string, activationId: string, targetHostKind?: string): PromotionEvidenceSnapshot['shadowSummary'];
33
33
  interface ActivationDispatchOptions {
34
34
  workspace?: string;
35
35
  artifactId?: string;
@@ -44,6 +44,15 @@ interface ActivationDeactivateOptions {
44
44
  activationId?: string;
45
45
  reasonCode?: string;
46
46
  json?: boolean;
47
+ /**
48
+ * SPEC-RULECODE-HOST-PROMOTION-001 R4/P1: non-destructive validation path
49
+ * for the recovery reachability probe. Runs the REAL entry through real
50
+ * parsing, workspace binding, and target-resolution preconditions, then
51
+ * returns BEFORE the governance audit write and BEFORE any store mutation.
52
+ * Mutually exclusive with an actual deactivation by construction: the
53
+ * dry-run branch never reaches the deactivate call.
54
+ */
55
+ dryRun?: boolean;
47
56
  }
48
57
  export interface DeactivateResult {
49
58
  ok: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-activation.d.ts","sourceRoot":"","sources":["../../src/commands/runtime-activation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime-activation.d.ts","sourceRoot":"","sources":["../../src/commands/runtime-activation.ts"],"names":[],"mappings":"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"}
@@ -35,6 +35,7 @@ function buildLedgerIdentityDeps(workspaceDir, connection, getArtifactById) {
35
35
  }
36
36
  import { resolveOwnerIdentity, defaultOwnerIdentityHomeDir } from '@principles/core/runtime-v2';
37
37
  import { resolvePromotionHostLiveness } from '@principles/host-runtime';
38
+ import { probeCliRecoveryReachability } from './recovery-reachability-probe.js';
38
39
  import { authorizeGovernanceAction, writeGovernanceAction } from 'principles-disciple/governance-audit';
39
40
  import { resolveWorkspaceDir } from '../resolve-workspace.js';
40
41
  import { loadPdConfig, computeFlagsFromLoadResult } from '../services/pd-config-loader.js';
@@ -110,11 +111,14 @@ export function collectRuleCodeEventEntries(workspaceDir) {
110
111
  return { entries, sourceDirsFound };
111
112
  }
112
113
  /** Exported for PRI-577 regression tests and reuse by promote evidence assembly. */
113
- export function readShadowSummaryForActivation(workspaceDir, activationId) {
114
+ export function readShadowSummaryForActivation(workspaceDir, activationId, targetHostKind) {
114
115
  const { entries, sourceDirsFound } = collectRuleCodeEventEntries(workspaceDir);
115
116
  if (sourceDirsFound === 0)
116
117
  return unavailableShadowSummary();
117
- return summarizeRuleCodeShadowEvents(entries, activationId);
118
+ // SPEC-RULECODE-HOST-PROMOTION-001 B3: per-host attribution — with a
119
+ // resolved promotion host, only that host's samples count toward the
120
+ // threshold (legacy unattributed rows count toward none).
121
+ return summarizeRuleCodeShadowEvents(entries, activationId, targetHostKind);
118
122
  }
119
123
  function mapRolloutDecision(reviewDecision) {
120
124
  // P0-E (MVP_CORE_LOOP_CONTRACT INV-04): needs_revision 绝不映射 require_approval。
@@ -356,6 +360,55 @@ export async function handleRuntimeActivationDeactivate(opts) {
356
360
  return;
357
361
  }
358
362
  const workspaceDir = opts.workspace ? path.resolve(opts.workspace) : resolveWorkspaceDir();
363
+ // SPEC R4/P1: the dry-run branch initializes the workspace READ-ONLY and
364
+ // returns before the governance audit write and before any store mutation —
365
+ // a reachability probe must leave zero governance traces.
366
+ if (opts.dryRun === true) {
367
+ const stateManagerDryRun = new RuntimeStateManager({ workspaceDir, readonly: true });
368
+ let dryRunResult;
369
+ try {
370
+ await stateManagerDryRun.initialize();
371
+ const targetExists = stateManagerDryRun.connection.getDb()
372
+ .prepare('SELECT 1 FROM activations WHERE activation_id = ? LIMIT 1')
373
+ .get(opts.activationId) !== undefined;
374
+ dryRunResult = {
375
+ ok: true,
376
+ activationId: opts.activationId,
377
+ reason: 'dry_run_ok',
378
+ nextAction: targetExists
379
+ ? 'Dry run only — nothing was deactivated. Re-run without --dry-run to deactivate.'
380
+ : 'Dry run only — nothing was deactivated. The activation id does not exist in this workspace (expected for a reachability probe).',
381
+ };
382
+ if (opts.json) {
383
+ console.log(JSON.stringify({ ...dryRunResult, dryRun: true, workspaceDir, targetExists }, null, 2));
384
+ }
385
+ else {
386
+ console.log(`Dry run: validation ok — ${opts.activationId}`);
387
+ console.log(` reason: ${dryRunResult.reason}`);
388
+ console.log(` nextAction: ${dryRunResult.nextAction}`);
389
+ }
390
+ }
391
+ catch (err) {
392
+ dryRunResult = {
393
+ ok: false,
394
+ activationId: opts.activationId,
395
+ reason: `dry_run_failed: ${err instanceof Error ? err.message : String(err)}`,
396
+ nextAction: 'Check workspace directory and DB integrity. Try `pd runtime diagnostics`.',
397
+ };
398
+ if (opts.json)
399
+ console.log(JSON.stringify(dryRunResult, null, 2));
400
+ else {
401
+ console.error(`Error: ${dryRunResult.reason}`);
402
+ console.error(`Next action: ${dryRunResult.nextAction}`);
403
+ }
404
+ }
405
+ finally {
406
+ await stateManagerDryRun.close();
407
+ }
408
+ if (!dryRunResult.ok)
409
+ process.exitCode = 1;
410
+ return;
411
+ }
359
412
  const stateManager = new RuntimeStateManager({ workspaceDir });
360
413
  try {
361
414
  await stateManager.initialize();
@@ -542,7 +595,30 @@ export async function handleRuntimeActivationPromote(opts) {
542
595
  && actor.authentication.method === 'cli_owner_credential',
543
596
  safetyControlsEnabled: isFeatureEnabled(flags, 'rulecode_safety_controls'),
544
597
  hostContract: promotionHost.ok ? promotionHost.hostContract : null,
598
+ // SPEC-RULECODE-HOST-PROMOTION-001 B: bind the check to the
599
+ // resolver's contract version — a wrong-host contract fails
600
+ // runtime_compatibility instead of passing as-is.
601
+ ...(promotionHost.ok ? { expectedHostContractVersion: promotionHost.hostRuntimeVersion } : {}),
545
602
  existingLiveArtifacts: liveArtifacts,
603
+ // Review R3/P1 + R4/P1: composition through the production
604
+ // boundary + per-evaluation PER-CAPABILITY reachability. The
605
+ // CLI process proves the two CLI-channel capabilities with real
606
+ // subprocesses (status listing; deactivate --dry-run) and
607
+ // reports the console-channel capabilities as explicitly NOT
608
+ // verified — promoting through the CLI therefore fails
609
+ // emergency_controls (fail closed) until the Owner Console
610
+ // process supplies its own channel evidence.
611
+ projectDir: workspaceDir,
612
+ ...(workspaceToolSemantics ? { toolSemantics: workspaceToolSemantics } : {}),
613
+ recoveryReachability: await (async () => {
614
+ const capabilities = await probeCliRecoveryReachability(workspaceDir, activationId);
615
+ return {
616
+ source: 'cli-status-probe',
617
+ ok: capabilities.every(capability => capability.ok),
618
+ workspaceMatched: capabilities.every(capability => capability.workspaceMatched),
619
+ capabilities,
620
+ };
621
+ })(),
546
622
  validateProductionArtifact: value => writer.canActivate(value),
547
623
  });
548
624
  },
@@ -555,7 +631,7 @@ export async function handleRuntimeActivationPromote(opts) {
555
631
  expectedArtifactDigest: request.expectedArtifactDigest,
556
632
  ownerIdentity: actor,
557
633
  hostRuntimeVersion: promotionHost.ok ? promotionHost.hostRuntimeVersion : promotionHost.reason,
558
- shadowSummary: readShadowSummaryForActivation(workspaceDir, activationId),
634
+ shadowSummary: readShadowSummaryForActivation(workspaceDir, activationId, promotionHost.ok ? promotionHost.hostKind : undefined),
559
635
  });
560
636
  },
561
637
  newEvaluationId: () => `readiness-${randomUUID()}`,
@@ -1536,9 +1612,11 @@ export function registerRuntimeActivationDeactivateCommand(parent) {
1536
1612
  .option('--reason-code <code>', 'Structured governance reason code (default: cli_deactivate_requested)')
1537
1613
  .option('-w, --workspace <path>', 'Workspace directory')
1538
1614
  .option('--json', 'Output raw JSON')
1615
+ .option('--dry-run', 'Validate the deactivation entry without deactivating (recovery reachability probe; no audit write, no mutation)')
1539
1616
  .action(async (opts) => {
1540
1617
  await handleRuntimeActivationDeactivate({
1541
1618
  activationId: opts.activationId,
1619
+ dryRun: opts.dryRun,
1542
1620
  workspace: opts.workspace,
1543
1621
  reasonCode: opts.reasonCode,
1544
1622
  json: opts.json,