@aifabrix/builder 2.55.0 → 2.55.2

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 (70) hide show
  1. package/lib/agent-kit/host-approve.js +48 -6
  2. package/lib/agent-kit/init.js +2 -2
  3. package/lib/agent-kit/remote-prompts.js +46 -13
  4. package/lib/agent-kit/run.js +1 -1
  5. package/lib/agent-kit/start.js +310 -0
  6. package/lib/app/deploy.js +7 -4
  7. package/lib/app/offer-create-from-template.js +184 -0
  8. package/lib/cli/setup-app.js +8 -1
  9. package/lib/cli/setup-auth.js +11 -2
  10. package/lib/commands/agent-kit-help.js +74 -4
  11. package/lib/commands/agent-kit.js +83 -12
  12. package/lib/commands/auth-status-user.js +99 -0
  13. package/lib/commands/auth-status.js +14 -4
  14. package/lib/commands/datasource-load-export-cli.js +7 -2
  15. package/lib/commands/datasource-test-trust-cli.js +5 -1
  16. package/lib/commands/governance-command-action.js +5 -4
  17. package/lib/commands/identity-membership-role-cache.js +6 -1
  18. package/lib/commands/lifecycle-command-action.js +16 -15
  19. package/lib/commands/login-credentials.js +8 -3
  20. package/lib/commands/login-device.js +14 -5
  21. package/lib/commands/login.js +14 -1
  22. package/lib/commands/logout.js +50 -15
  23. package/lib/commands/role-assistant.js +24 -12
  24. package/lib/commands/verify-governance-command-action.js +9 -7
  25. package/lib/commands/verify-operations-command-action.js +9 -8
  26. package/lib/commands/verify-trust-command-action.js +6 -5
  27. package/lib/external-system/download.js +1 -2
  28. package/lib/generator/helpers.js +12 -1
  29. package/lib/integration-definition/apply-static-enterprise.js +5 -2
  30. package/lib/role-assistant/knowledge-sync-settings-push.js +172 -0
  31. package/lib/role-assistant/knowledge-sync.js +9 -126
  32. package/lib/role-assistant/test-cases-evaluate.js +12 -1
  33. package/lib/role-assistant/test-cases-evidence.js +44 -5
  34. package/lib/role-assistant/test-cases-lifecycle.js +9 -3
  35. package/lib/role-assistant/test-runner.js +3 -0
  36. package/lib/schema/infra-parameter.schema.json +51 -3
  37. package/lib/schema/infra.parameter.yaml +476 -40
  38. package/lib/schema/type/document-storage.json +1 -1
  39. package/lib/utils/api-required-permissions.js +271 -0
  40. package/lib/utils/api.js +16 -13
  41. package/lib/utils/cli-json-exit.js +41 -0
  42. package/lib/utils/cli-utils.js +23 -5
  43. package/lib/utils/controller-url.js +78 -4
  44. package/lib/utils/deployment-errors.js +15 -0
  45. package/lib/utils/deployment-validation-helpers.js +4 -1
  46. package/lib/utils/device-code.js +31 -10
  47. package/lib/utils/error-formatters/error-parser.js +16 -1
  48. package/lib/utils/error-formatters/permission-errors.js +19 -5
  49. package/lib/utils/keycloak-realm-ready.js +5 -2
  50. package/lib/utils/logger.js +1 -0
  51. package/lib/utils/paths.js +26 -5
  52. package/lib/utils/secrets-helpers.js +2 -2
  53. package/lib/utils/write-stream-and-wait.js +63 -0
  54. package/package.json +20 -6
  55. package/templates/agent-kit/agent-kit.yaml +1 -1
  56. package/templates/agent-kit/instructions/AGENTKIT.md +25 -4
  57. package/templates/agent-kit/instructions/root.AGENTS.md +1 -1
  58. package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +2 -1
  59. package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +1 -1
  60. package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +2 -1
  61. package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +1 -0
  62. package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +1 -0
  63. package/templates/agent-kit/skills/shared/hosts.md +13 -26
  64. package/templates/agent-kit/skills/shared/login.md +16 -0
  65. package/templates/agent-kit/workspace/README.md +1 -1
  66. package/templates/applications/dataplane/application.yaml +1 -2
  67. package/templates/applications/dataplane/env.template +5 -5
  68. package/templates/applications/miso-controller/application.yaml +21 -2
  69. package/templates/applications/miso-controller/env.template +89 -17
  70. package/templates/applications/miso-controller/rbac.yaml +5 -0
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Push role-assistant.yaml knowledge/debug/runtime settings to Assistants.
3
+ *
4
+ * @fileoverview Map local Role Assistant settings onto dataplane Assistants PATCH
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { updateAssistantSettings } = require('../api/assistants.api');
12
+ const {
13
+ readRoleAssistantSettings,
14
+ resolveDocumentStorageKeyFromRoleAssistantSettings,
15
+ resolveRoleAssistantEnvironmentSettings
16
+ } = require('./settings');
17
+
18
+ function resolveRoleAssistantSettingsEnvKey(environment) {
19
+ const token = String(environment || '').trim().toLowerCase();
20
+ return token === 'dev' || token === 'tst' || token === 'pro' ? token : 'dev';
21
+ }
22
+
23
+ /**
24
+ * Map role-assistant.yaml debug.* → Assistants settings PATCH fields.
25
+ * includePromptTrace → fullDebugEnabled (LLM prompt capture gate).
26
+ * enabled → debugEnabled (runtime debug traces).
27
+ * @param {Object|null|undefined} debugSection
28
+ * @returns {{ debugEnabled?: boolean, fullDebugEnabled?: boolean }}
29
+ */
30
+ function mapRoleAssistantDebugToAssistantsSettings(debugSection) {
31
+ if (!debugSection || typeof debugSection !== 'object') {
32
+ return {};
33
+ }
34
+ const body = {};
35
+ if (typeof debugSection.enabled === 'boolean') {
36
+ body.debugEnabled = debugSection.enabled;
37
+ }
38
+ if (typeof debugSection.includePromptTrace === 'boolean') {
39
+ body.fullDebugEnabled = debugSection.includePromptTrace;
40
+ }
41
+ return body;
42
+ }
43
+
44
+ /**
45
+ * Map role-assistant.yaml runtime.* to the governed Assistants settings names.
46
+ * Provider selection remains platform-owned; the assistant may override only
47
+ * its workflow reasoning model and execution profile.
48
+ * @param {Object|null|undefined} runtimeSection
49
+ * @returns {{ workflowReasoningModel?: string, temperature?: number, maxLlmLoops?: number, maxToolLoops?: number }}
50
+ */
51
+ function mapRoleAssistantRuntimeToAssistantsSettings(runtimeSection) {
52
+ if (!runtimeSection || typeof runtimeSection !== 'object') {
53
+ return {};
54
+ }
55
+ const body = {};
56
+ if (typeof runtimeSection.model === 'string' && runtimeSection.model.trim()) {
57
+ body.workflowReasoningModel = runtimeSection.model.trim();
58
+ }
59
+ if (typeof runtimeSection.temperature === 'number') {
60
+ body.temperature = runtimeSection.temperature;
61
+ }
62
+ if (Number.isInteger(runtimeSection.maxLoops)) {
63
+ body.maxLlmLoops = runtimeSection.maxLoops;
64
+ body.maxToolLoops = runtimeSection.maxLoops;
65
+ }
66
+ return body;
67
+ }
68
+
69
+ /**
70
+ * Push role-assistant.yaml knowledge + debug settings to dataplane Assistants.
71
+ * Called on upload/deploy so the operator UI and CLI stay aligned.
72
+ */
73
+ function resolveAssistantSettingsPush(params) {
74
+ const {
75
+ systemKey,
76
+ environment = 'dev',
77
+ pathOptions = {}
78
+ } = params;
79
+ const settingsEnv = resolveRoleAssistantSettingsEnvKey(environment);
80
+ const settings = readRoleAssistantSettings(systemKey, { required: false, pathOptions });
81
+ if (!settings) {
82
+ return { result: { skipped: true, reason: 'missing-role-assistant-settings' } };
83
+ }
84
+ const section = resolveRoleAssistantEnvironmentSettings(settings, settingsEnv, {
85
+ required: false
86
+ });
87
+ if (!section) {
88
+ return { result: { skipped: true, reason: 'missing-env-settings' } };
89
+ }
90
+ const documentStorageKey =
91
+ resolveDocumentStorageKeyFromRoleAssistantSettings(settings, settingsEnv) || '';
92
+ const debugBody = mapRoleAssistantDebugToAssistantsSettings(section.debug);
93
+ const runtimeBody = mapRoleAssistantRuntimeToAssistantsSettings(section.runtime);
94
+ const settingsBody = { ...runtimeBody, ...debugBody };
95
+ if (!documentStorageKey && Object.keys(settingsBody).length === 0) {
96
+ return { result: { skipped: true, reason: 'no-document-storage-key', documentStorageKey: null } };
97
+ }
98
+ const patchBody = { ...settingsBody };
99
+ if (documentStorageKey) {
100
+ patchBody.documentStorageKey = documentStorageKey;
101
+ }
102
+ return { documentStorageKey, debugBody: settingsBody, patchBody };
103
+ }
104
+
105
+ async function applyAssistantSettingsPush(dataplaneUrl, systemKey, authConfig, settingsPush) {
106
+ const { documentStorageKey, debugBody, patchBody } = settingsPush;
107
+ const hasDocumentStorageKey = documentStorageKey !== '';
108
+ const hasDebugSettings = Object.keys(debugBody).length > 0;
109
+ const assistantKey = String(systemKey || '').trim();
110
+ let response = await updateAssistantSettings(
111
+ dataplaneUrl,
112
+ assistantKey,
113
+ authConfig,
114
+ patchBody
115
+ );
116
+ if (response && response.success === false && hasDocumentStorageKey && hasDebugSettings) {
117
+ response = await updateAssistantSettings(
118
+ dataplaneUrl,
119
+ assistantKey,
120
+ authConfig,
121
+ debugBody
122
+ );
123
+ if (response && response.success === false) {
124
+ throw new Error(
125
+ response.formattedError ||
126
+ response.error ||
127
+ 'Failed to update Assistants debug settings'
128
+ );
129
+ }
130
+ return {
131
+ skipped: false,
132
+ documentStorageKey: null,
133
+ documentStoragePushFailed: true,
134
+ ...debugBody
135
+ };
136
+ }
137
+ if (response && response.success === false) {
138
+ throw new Error(
139
+ response.formattedError ||
140
+ response.error ||
141
+ 'Failed to update Knowledge document storage settings'
142
+ );
143
+ }
144
+ return {
145
+ skipped: false,
146
+ documentStorageKey: documentStorageKey || null,
147
+ ...debugBody
148
+ };
149
+ }
150
+
151
+ async function pushRoleAssistantDocumentStorageSettings(params) {
152
+ const { systemKey, dataplaneUrl, authConfig, dryRun = false } = params;
153
+ const settingsPush = resolveAssistantSettingsPush(params);
154
+ if (settingsPush.result) {
155
+ return settingsPush.result;
156
+ }
157
+ const { documentStorageKey, debugBody } = settingsPush;
158
+ if (dryRun) {
159
+ return { skipped: false, dryRun: true, documentStorageKey: documentStorageKey || null, ...debugBody };
160
+ }
161
+ if (!dataplaneUrl || !authConfig) {
162
+ return { skipped: true, reason: 'missing-dataplane-auth' };
163
+ }
164
+ return applyAssistantSettingsPush(dataplaneUrl, systemKey, authConfig, settingsPush);
165
+ }
166
+
167
+ module.exports = {
168
+ resolveRoleAssistantSettingsEnvKey,
169
+ mapRoleAssistantDebugToAssistantsSettings,
170
+ mapRoleAssistantRuntimeToAssistantsSettings,
171
+ pushRoleAssistantDocumentStorageSettings
172
+ };
@@ -15,8 +15,7 @@ const yaml = require('js-yaml');
15
15
  const { listDocuments, validateDocuments, bulkDocuments } = require('../api/datasources-extended.api');
16
16
  const {
17
17
  extractDocumentStorageKeyFromAssistantDetails,
18
- getAssistantDetails,
19
- updateAssistantSettings
18
+ getAssistantDetails
20
19
  } = require('../api/assistants.api');
21
20
  const { resolveExternalSystemPath } = require('../utils/app-path-resolve');
22
21
  const { bareRoleKey } = require('../utils/role-assistant-paths');
@@ -24,9 +23,14 @@ const {
24
23
  SYSTEM_KIND_DIGITAL_WORKER,
25
24
  getRoleAssistantYamlPath,
26
25
  readRoleAssistantSettings,
27
- resolveDocumentStorageKeyFromRoleAssistantSettings,
28
- resolveRoleAssistantEnvironmentSettings
26
+ resolveDocumentStorageKeyFromRoleAssistantSettings
29
27
  } = require('./settings');
28
+ const {
29
+ resolveRoleAssistantSettingsEnvKey,
30
+ mapRoleAssistantDebugToAssistantsSettings,
31
+ mapRoleAssistantRuntimeToAssistantsSettings,
32
+ pushRoleAssistantDocumentStorageSettings
33
+ } = require('./knowledge-sync-settings-push');
30
34
  const {
31
35
  knowledgeSearchMetadataFromFrontmatter,
32
36
  splitMarkdownFrontmatter
@@ -87,123 +91,6 @@ async function resolveDocumentStorageKeyFromDataplane(dataplaneUrl, authConfig,
87
91
  }
88
92
  }
89
93
 
90
- /**
91
- * Map role-assistant.yaml debug.* → Assistants settings PATCH fields.
92
- * includePromptTrace → fullDebugEnabled (LLM prompt capture gate).
93
- * enabled → debugEnabled (runtime debug traces).
94
- * @param {Object|null|undefined} debugSection
95
- * @returns {{ debugEnabled?: boolean, fullDebugEnabled?: boolean }}
96
- */
97
- function mapRoleAssistantDebugToAssistantsSettings(debugSection) {
98
- if (!debugSection || typeof debugSection !== 'object') {
99
- return {};
100
- }
101
- const body = {};
102
- if (typeof debugSection.enabled === 'boolean') {
103
- body.debugEnabled = debugSection.enabled;
104
- }
105
- if (typeof debugSection.includePromptTrace === 'boolean') {
106
- body.fullDebugEnabled = debugSection.includePromptTrace;
107
- }
108
- return body;
109
- }
110
-
111
- /**
112
- * Push role-assistant.yaml knowledge + debug settings to dataplane Assistants.
113
- * Called on upload/deploy so the operator UI and CLI stay aligned.
114
- */
115
- function resolveAssistantSettingsPush(params) {
116
- const {
117
- systemKey,
118
- environment = 'dev',
119
- pathOptions = {}
120
- } = params;
121
- const settingsEnv = resolveRoleAssistantSettingsEnvKey(environment);
122
- const settings = readRoleAssistantSettings(systemKey, { required: false, pathOptions });
123
- if (!settings) {
124
- return { result: { skipped: true, reason: 'missing-role-assistant-settings' } };
125
- }
126
- const section = resolveRoleAssistantEnvironmentSettings(settings, settingsEnv, {
127
- required: false
128
- });
129
- if (!section) {
130
- return { result: { skipped: true, reason: 'missing-env-settings' } };
131
- }
132
- const documentStorageKey =
133
- resolveDocumentStorageKeyFromRoleAssistantSettings(settings, settingsEnv) || '';
134
- const debugBody = mapRoleAssistantDebugToAssistantsSettings(section.debug);
135
- if (!documentStorageKey && Object.keys(debugBody).length === 0) {
136
- return { result: { skipped: true, reason: 'no-document-storage-key', documentStorageKey: null } };
137
- }
138
- const patchBody = { ...debugBody };
139
- if (documentStorageKey) {
140
- patchBody.documentStorageKey = documentStorageKey;
141
- }
142
- return { documentStorageKey, debugBody, patchBody };
143
- }
144
-
145
- async function applyAssistantSettingsPush(dataplaneUrl, systemKey, authConfig, settingsPush) {
146
- const { documentStorageKey, debugBody, patchBody } = settingsPush;
147
- const hasDocumentStorageKey = documentStorageKey !== '';
148
- const hasDebugSettings = Object.keys(debugBody).length > 0;
149
- const assistantKey = String(systemKey || '').trim();
150
- let response = await updateAssistantSettings(
151
- dataplaneUrl,
152
- assistantKey,
153
- authConfig,
154
- patchBody
155
- );
156
- if (response && response.success === false && hasDocumentStorageKey && hasDebugSettings) {
157
- response = await updateAssistantSettings(
158
- dataplaneUrl,
159
- assistantKey,
160
- authConfig,
161
- debugBody
162
- );
163
- if (response && response.success === false) {
164
- throw new Error(
165
- response.formattedError ||
166
- response.error ||
167
- 'Failed to update Assistants debug settings'
168
- );
169
- }
170
- return {
171
- skipped: false,
172
- documentStorageKey: null,
173
- documentStoragePushFailed: true,
174
- ...debugBody
175
- };
176
- }
177
- if (response && response.success === false) {
178
- throw new Error(
179
- response.formattedError ||
180
- response.error ||
181
- 'Failed to update Knowledge document storage settings'
182
- );
183
- }
184
- return {
185
- skipped: false,
186
- documentStorageKey: documentStorageKey || null,
187
- ...debugBody
188
- };
189
- }
190
-
191
- async function pushRoleAssistantDocumentStorageSettings(params) {
192
- const { systemKey, dataplaneUrl, authConfig, dryRun = false } = params;
193
- const settingsPush = resolveAssistantSettingsPush(params);
194
- if (settingsPush.result) {
195
- return settingsPush.result;
196
- }
197
- const { documentStorageKey, debugBody } = settingsPush;
198
- if (dryRun) {
199
- return { skipped: false, dryRun: true, documentStorageKey: documentStorageKey || null, ...debugBody };
200
- }
201
- if (!dataplaneUrl || !authConfig) {
202
- return { skipped: true, reason: 'missing-dataplane-auth' };
203
- }
204
- return applyAssistantSettingsPush(dataplaneUrl, systemKey, authConfig, settingsPush);
205
- }
206
-
207
94
  /**
208
95
  * Resolve Knowledge document storage key.
209
96
  * Order: role-assistant.yaml → dataplane Assistants settings → package dataSources.
@@ -341,11 +228,6 @@ function resolveDocumentFileName(row, index) {
341
228
  return filePath.startsWith('/') ? filePath.slice(1) : filePath;
342
229
  }
343
230
 
344
- function resolveRoleAssistantSettingsEnvKey(environment) {
345
- const token = String(environment || '').trim().toLowerCase();
346
- return token === 'dev' || token === 'tst' || token === 'pro' ? token : 'dev';
347
- }
348
-
349
231
  function writeRoleAssistantSettingsFile(systemKey, docStorageKey, environment = 'dev', pathOptions = {}) {
350
232
  const roleAssistantPath = resolveExternalSystemPath(systemKey, pathOptions);
351
233
  const roleAssistantYamlPath = getRoleAssistantYamlPath(systemKey, { pathOptions });
@@ -477,6 +359,7 @@ module.exports = {
477
359
  resolveRoleAssistantSettingsEnvKey,
478
360
  resolveRoleAssistantDocumentStorageKey,
479
361
  mapRoleAssistantDebugToAssistantsSettings,
362
+ mapRoleAssistantRuntimeToAssistantsSettings,
480
363
  pushRoleAssistantDocumentStorageSettings,
481
364
  importRoleAssistantKnowledge,
482
365
  exportRoleAssistantKnowledge,
@@ -253,10 +253,21 @@ function collectCapabilityAssertions(capabilities, observedCapabilities, soft) {
253
253
  return rows.map((row) => softWrapFailedAssertion(row, soft));
254
254
  }
255
255
 
256
+ function evaluateExecutionIntegrity(observation) {
257
+ if (!observation.workResultError) {
258
+ return null;
259
+ }
260
+ return {
261
+ id: 'execution.integrity',
262
+ passed: false,
263
+ message: `Execution did not produce a readable result: ${observation.workResultError}`
264
+ };
265
+ }
266
+
256
267
  function collectCaseAssertions(expected, observation, preflight = {}) {
257
268
  const soft = expected.soft === true;
258
269
  const observedCapabilities = observation.capabilities?.observed || [];
259
- const assertions = [];
270
+ const assertions = [evaluateExecutionIntegrity(observation)].filter(Boolean);
260
271
  const lifecycleAssertion = softWrapFailedAssertion(
261
272
  evaluateLifecycleStateExpectation(expected.lifecycleState, observation.lifecycleState),
262
273
  soft
@@ -55,6 +55,39 @@ function isActiveStatus(status, requiredStatus) {
55
55
  return status === requiredStatus;
56
56
  }
57
57
 
58
+ /**
59
+ * Dataplane Evidence is append-new versioned, never mutated in place
60
+ * (dataplane 506.2): once a row's content changes, its literal `key` is
61
+ * archived permanently and a new `<key>__vN` row becomes the current
62
+ * identity. A case authored against the original literal key must still
63
+ * resolve against that current versioned successor, not report it missing.
64
+ * `rows` here are already scoped to the case's roleKey+resourceType+status
65
+ * by `loadLiveEvidenceRows`, so any row whose key is exactly `<desired>__vN`
66
+ * is unambiguously that key's current version.
67
+ */
68
+ function findVersionedSuccessor(desiredKey, byKey) {
69
+ const prefix = `${desiredKey}__v`;
70
+ let best = null;
71
+ let bestVersion = -1;
72
+ for (const [key, row] of byKey) {
73
+ if (!key.startsWith(prefix)) {
74
+ continue;
75
+ }
76
+ const suffix = key.slice(prefix.length);
77
+ const version = Number(suffix);
78
+ if (!Number.isInteger(version) || version <= bestVersion) {
79
+ continue;
80
+ }
81
+ best = row;
82
+ bestVersion = version;
83
+ }
84
+ return best;
85
+ }
86
+
87
+ function resolveEvidenceRow(desiredKey, byKey) {
88
+ return byKey.get(desiredKey) || findVersionedSuccessor(desiredKey, byKey);
89
+ }
90
+
58
91
  function findMissingEvidenceKeys(spec, rows) {
59
92
  const byKey = new Map();
60
93
  for (const row of rows) {
@@ -65,7 +98,7 @@ function findMissingEvidenceKeys(spec, rows) {
65
98
  }
66
99
  const missing = [];
67
100
  for (const key of spec.requiredKeys) {
68
- const row = byKey.get(key);
101
+ const row = resolveEvidenceRow(key, byKey);
69
102
  if (!row) {
70
103
  missing.push(`${key} (not in dataplane)`);
71
104
  continue;
@@ -133,11 +166,15 @@ function evaluateEvidenceExpectations(evidenceSpec, observation) {
133
166
  return [];
134
167
  }
135
168
  const preflight = observation?.evidencePreflight || {};
136
- const liveKeys = new Set(
137
- (Array.isArray(preflight.rows) ? preflight.rows : []).map(rowKey).filter(Boolean)
138
- );
169
+ const liveByKey = new Map();
170
+ for (const row of Array.isArray(preflight.rows) ? preflight.rows : []) {
171
+ const key = rowKey(row);
172
+ if (key) {
173
+ liveByKey.set(key, row);
174
+ }
175
+ }
139
176
  return requiredKeys.map((key) => {
140
- const passed = liveKeys.has(key);
177
+ const passed = Boolean(resolveEvidenceRow(key, liveByKey));
141
178
  return {
142
179
  id: `expected.evidence.requiredKeys:${key}`,
143
180
  passed,
@@ -168,6 +205,8 @@ function evaluateForbiddenCapabilities(forbiddenList, observedCapabilities) {
168
205
 
169
206
  module.exports = {
170
207
  evidenceSpecFromCase,
208
+ findVersionedSuccessor,
209
+ resolveEvidenceRow,
171
210
  findMissingEvidenceKeys,
172
211
  assertRoleAssistantEvidencePreflight,
173
212
  evaluateEvidenceExpectations,
@@ -274,13 +274,19 @@ function resolveLifecycleStateFromResult(result) {
274
274
  }
275
275
 
276
276
  function deriveLifecycleState(result, lifecycleVerdict) {
277
- if (lifecycleVerdict === VERDICT.VERIFIED) {
278
- return 'completed';
279
- }
277
+ // lifecycleVerdict is the Role Assistant's own operations/trust/governance
278
+ // certification status, not this case's execution outcome — a VERIFIED
279
+ // (published, trusted) Role Assistant can still run a case that fails,
280
+ // asks a question, or safe-stops. Always prefer a real structured signal
281
+ // from this execution's own result; the verdict is only a fallback default
282
+ // for when no signal exists at all (e.g. an empty/no-op result).
280
283
  const structuredState = resolveLifecycleStateFromResult(result);
281
284
  if (structuredState) {
282
285
  return structuredState;
283
286
  }
287
+ if (lifecycleVerdict === VERDICT.VERIFIED) {
288
+ return 'completed';
289
+ }
284
290
  if (lifecycleVerdict === VERDICT.NOT_VERIFIED) return 'safe-stop';
285
291
  return 'failed';
286
292
  }
@@ -484,6 +484,9 @@ function lifecycleVerdictFromCaseExecution(executionResult, fallbackVerdict) {
484
484
  if (statusToken === 'stopped' || statusToken === 'waiting' || statusToken === 'running') {
485
485
  return VERDICT.NOT_VERIFIED;
486
486
  }
487
+ if (statusToken === 'failed' || statusToken === 'cancelled' || statusToken === 'canceled') {
488
+ return VERDICT.FAILED;
489
+ }
487
490
  return fallbackVerdict || VERDICT.FAILED;
488
491
  }
489
492
 
@@ -37,7 +37,7 @@
37
37
  },
38
38
  "scopeEnum": {
39
39
  "type": "string",
40
- "enum": ["infra", "app", "shared-service"]
40
+ "enum": ["infra", "app", "shared-service", "system"]
41
41
  },
42
42
  "generator": {
43
43
  "type": "object",
@@ -50,6 +50,7 @@
50
50
  "randomBytes32",
51
51
  "randomAlphanumeric",
52
52
  "password",
53
+ "rsaKeyPair",
53
54
  "emptyString",
54
55
  "emptyAllowed",
55
56
  "literal",
@@ -65,8 +66,20 @@
65
66
  "minimum": 1,
66
67
  "maximum": 512,
67
68
  "description": "For randomAlphanumeric: character count (default 32). For password: default 8. Charset [a-zA-Z0-9]."
69
+ },
70
+ "pairId": { "type": "string", "minLength": 1 },
71
+ "part": { "type": "string", "enum": ["private", "public"] }
72
+ },
73
+ "allOf": [
74
+ {
75
+ "if": { "properties": { "type": { "const": "literal" } } },
76
+ "then": { "required": ["value"] }
77
+ },
78
+ {
79
+ "if": { "properties": { "type": { "const": "rsaKeyPair" } } },
80
+ "then": { "required": ["pairId", "part"] }
68
81
  }
69
- }
82
+ ]
70
83
  },
71
84
  "azureBlock": {
72
85
  "type": "object",
@@ -74,6 +87,11 @@
74
87
  "properties": {
75
88
  "vaultSecretName": { "type": "string" },
76
89
  "vaultSecretNamePattern": { "type": "string" },
90
+ "legacyVaultSecretNames": {
91
+ "type": "array",
92
+ "items": { "type": "string", "minLength": 1 },
93
+ "uniqueItems": true
94
+ },
77
95
  "notes": { "type": "string" }
78
96
  }
79
97
  },
@@ -90,6 +108,20 @@
90
108
  "type": "string",
91
109
  "minLength": 1
92
110
  },
111
+ "category": { "type": "string", "minLength": 1 },
112
+ "sensitive": { "type": "boolean" },
113
+ "valueSource": {
114
+ "type": "string",
115
+ "enum": [
116
+ "generated",
117
+ "onboardingInput",
118
+ "providerOutput",
119
+ "legacyMigration",
120
+ "optionalInput"
121
+ ]
122
+ },
123
+ "requiredOnSystemOnboarding": { "type": "boolean" },
124
+ "ownerAppKey": { "type": "string", "minLength": 1 },
93
125
  "scope": { "$ref": "#/definitions/scopeEnum" },
94
126
  "generator": { "$ref": "#/definitions/generator" },
95
127
  "ensureOn": {
@@ -100,7 +132,23 @@
100
132
  "requiredForLocal": { "type": "boolean" },
101
133
  "azure": { "$ref": "#/definitions/azureBlock" },
102
134
  "notes": { "type": "string" }
103
- }
135
+ },
136
+ "allOf": [
137
+ {
138
+ "if": {
139
+ "required": ["scope"],
140
+ "properties": { "scope": { "const": "system" } }
141
+ },
142
+ "then": {
143
+ "required": [
144
+ "category",
145
+ "sensitive",
146
+ "valueSource",
147
+ "requiredOnSystemOnboarding"
148
+ ]
149
+ }
150
+ }
151
+ ]
104
152
  }
105
153
  }
106
154
  }