@aifabrix/builder 2.54.1 → 2.55.0
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/README.md +8 -0
- package/lib/agent-kit/apply-ops.js +82 -0
- package/lib/agent-kit/checksums.js +28 -0
- package/lib/agent-kit/classify.js +113 -0
- package/lib/agent-kit/claude-shim.js +61 -0
- package/lib/agent-kit/constants.js +55 -0
- package/lib/agent-kit/file-list.js +103 -0
- package/lib/agent-kit/host-approve.js +130 -0
- package/lib/agent-kit/hosting/github.js +63 -0
- package/lib/agent-kit/hosts.js +71 -0
- package/lib/agent-kit/init.js +319 -0
- package/lib/agent-kit/kit-root.js +17 -0
- package/lib/agent-kit/managed-section.js +79 -0
- package/lib/agent-kit/package-load.js +45 -0
- package/lib/agent-kit/plan-ops.js +69 -0
- package/lib/agent-kit/remote-prompts.js +239 -0
- package/lib/agent-kit/render-host-markdown.js +40 -0
- package/lib/agent-kit/repo-guard.js +47 -0
- package/lib/agent-kit/report.js +107 -0
- package/lib/agent-kit/run.js +82 -0
- package/lib/agent-kit/scm/git.js +122 -0
- package/lib/agent-kit/state-file.js +83 -0
- package/lib/agent-kit/status.js +50 -0
- package/lib/agent-kit/v1-detect.js +81 -0
- package/lib/agent-kit/validate-kit.js +87 -0
- package/lib/agent-kit/workspace-name.js +40 -0
- package/lib/agent-kit/workspace-skeleton.js +103 -0
- package/lib/api/role-assistant-test-pack.api.js +86 -0
- package/lib/api/work-search.api.js +31 -4
- package/lib/api/work.api.js +19 -12
- package/lib/app/list-external-systems.js +2 -1
- package/lib/app/show-display.js +33 -6
- package/lib/app/show.js +25 -2
- package/lib/channels/add-channel.js +1 -0
- package/lib/channels/approval-guides/claude.js +2 -2
- package/lib/channels/channel-add-failure.js +1 -0
- package/lib/channels/channel-add-remaining.js +15 -9
- package/lib/channels/channel-definition-status.js +115 -0
- package/lib/channels/channel-description.js +2 -1
- package/lib/channels/channel-install-envelope.js +4 -2
- package/lib/channels/channel-integration-generator.js +2 -0
- package/lib/channels/channel-runtime-resolver.js +14 -0
- package/lib/channels/channel-targets.js +31 -5
- package/lib/channels/claude-setup-values.js +4 -1
- package/lib/channels/slack-channel-add.js +59 -6
- package/lib/channels/slack-mcp-callback.js +51 -0
- package/lib/channels/slack-mcp-runtime.js +156 -0
- package/lib/channels/slack-provisioning/install-cli.js +14 -2
- package/lib/channels/slack-provisioning/with-curl-on-path.js +6 -1
- package/lib/cli/index.js +4 -0
- package/lib/cli/setup-certification-commands.js +2 -2
- package/lib/cli/setup-certification.help.js +3 -1
- package/lib/commands/agent-kit-help.js +79 -0
- package/lib/commands/agent-kit.js +346 -0
- package/lib/commands/channel-add-help.js +5 -5
- package/lib/commands/datasource-capability-relate-cli.js +5 -4
- package/lib/commands/repair-auth-apply.js +1 -1
- package/lib/commands/repair-datasource-key-skip.js +39 -0
- package/lib/commands/repair-datasource-keys.js +24 -12
- package/lib/commands/repair-rbac.js +16 -10
- package/lib/commands/role-assistant-copy-output.js +61 -0
- package/lib/commands/role-assistant-copy.js +155 -0
- package/lib/commands/role-assistant-test-output.js +8 -9
- package/lib/commands/role-assistant-test-result-rows.js +42 -0
- package/lib/commands/role-assistant.js +117 -48
- package/lib/commands/search.js +143 -0
- package/lib/commands/test-trust-external.js +7 -5
- package/lib/commands/upload-sidecar-followups.js +4 -1
- package/lib/commands/verify-operations-skip-e2e.js +131 -0
- package/lib/commands/verify-operations-step-plan.js +6 -33
- package/lib/commands/verify-operations-steps.js +3 -1
- package/lib/datasource/capability/relate-operations.js +28 -10
- package/lib/datasource/capability/run-capability-relate.js +48 -25
- package/lib/datasource/datasource-identifier.js +13 -5
- package/lib/deployment/deployer-poll-run.js +117 -35
- package/lib/external-system/deploy-dataplane-published.js +70 -0
- package/lib/external-system/deploy.js +12 -2
- package/lib/external-system/download-role-assistant.js +41 -15
- package/lib/external-system/download.js +7 -1
- package/lib/generator/wizard-datasource-key.js +54 -0
- package/lib/generator/wizard.js +55 -54
- package/lib/integration-definition/apply-datasource-keys.js +75 -0
- package/lib/integration-definition/apply-relationships.js +195 -0
- package/lib/integration-definition/apply-static-enterprise.js +229 -0
- package/lib/integration-definition/apply-system-file.js +71 -0
- package/lib/integration-definition/apply-test-endpoint.js +89 -0
- package/lib/integration-definition/apply-viewpoint-defaults.js +157 -0
- package/lib/integration-definition/apply.js +78 -59
- package/lib/integration-definition/enrich-openapi-operations.js +36 -10
- package/lib/integration-definition/enrich-openapi-pick.js +87 -0
- package/lib/lifecycle/role-assistant-governance.js +56 -21
- package/lib/programmatic/capability-registry.js +1 -0
- package/lib/programmatic/index.js +2 -0
- package/lib/programmatic/openapi-apply-result-schemas.js +8 -0
- package/lib/programmatic/openapi-channel-install-schemas.js +4 -1
- package/lib/programmatic/openapi-component-schemas.js +1 -0
- package/lib/programmatic/openapi-descriptions.js +9 -3
- package/lib/programmatic/openapi-envelope-examples.js +7 -0
- package/lib/programmatic/openapi-operation-bindings.js +5 -0
- package/lib/programmatic/openapi-request-schemas.js +5 -0
- package/lib/programmatic/openapi-schema-descriptions-channel.js +8 -5
- package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
- package/lib/programmatic/openapi-spec.js +1 -0
- package/lib/programmatic/request-timeout.js +3 -0
- package/lib/programmatic/route-handler-map.js +7 -0
- package/lib/programmatic/run-channel-catalog.js +50 -8
- package/lib/programmatic/run-channel-install-options.js +5 -1
- package/lib/programmatic/run-download.js +41 -0
- package/lib/protection/auth-context.js +3 -1
- package/lib/protection/protection-display.js +3 -2
- package/lib/protection/report-exit.js +50 -0
- package/lib/protection/run-commands.js +2 -0
- package/lib/role-assistant/package-validate.js +175 -0
- package/lib/role-assistant/test-case-assertion-row.js +36 -0
- package/lib/role-assistant/test-case-copy-bind.js +77 -0
- package/lib/role-assistant/test-case-copy-expected.js +127 -0
- package/lib/role-assistant/test-case-copy-from-work.js +90 -0
- package/lib/role-assistant/test-case-copy-interactions.js +67 -0
- package/lib/role-assistant/test-case-copy.js +119 -0
- package/lib/role-assistant/test-case-expected-catalog.js +135 -0
- package/lib/role-assistant/test-case-validate.js +88 -0
- package/lib/role-assistant/test-cases-bid.js +117 -4
- package/lib/role-assistant/test-cases-evaluate.js +137 -30
- package/lib/role-assistant/test-cases-honesty.js +155 -6
- package/lib/role-assistant/test-cases-lifecycle.js +291 -0
- package/lib/role-assistant/test-cases-search-graph.js +122 -0
- package/lib/role-assistant/test-cases-search.js +20 -2
- package/lib/role-assistant/test-cases.js +34 -168
- package/lib/role-assistant/test-pack-map.js +180 -0
- package/lib/role-assistant/test-pack-sync.js +187 -0
- package/lib/role-assistant/test-runner-debug.js +54 -0
- package/lib/role-assistant/test-runner-respond-body.js +36 -0
- package/lib/role-assistant/test-runner-search.js +20 -5
- package/lib/role-assistant/test-runner-start-payload.js +63 -10
- package/lib/role-assistant/test-runner-workhub-answers.js +45 -16
- package/lib/role-assistant/test-runner-workhub.js +45 -21
- package/lib/role-assistant/test-runner.js +50 -10
- package/lib/schema/external-datasource.schema.json +36 -5
- package/lib/schema/external-system.schema.json +20 -2
- package/lib/schema/role-assistant-test-case.schema.json +408 -0
- package/lib/search/dataplane-context.js +23 -0
- package/lib/search/search-args.js +211 -0
- package/lib/search/search-display.js +238 -0
- package/lib/search/search-errors.js +50 -0
- package/lib/search/search-prompts.js +119 -0
- package/lib/search/search-roles.js +85 -0
- package/lib/search/search-run.js +241 -0
- package/lib/search/search-skills.js +198 -0
- package/lib/utils/authentication-slot-show.js +153 -0
- package/lib/utils/credential-display.js +43 -1
- package/lib/utils/external-system-readiness-compact-blocks.js +5 -1
- package/lib/utils/external-system-readiness-compact-display.js +30 -1
- package/lib/utils/external-system-validators.js +2 -1
- package/lib/utils/help-builder.js +3 -1
- package/lib/utils/schema-loader.js +37 -0
- package/lib/validation/validate-external-file.js +5 -1
- package/lib/validation/validate.js +3 -2
- package/package.json +1 -1
- package/templates/agent-kit/adapters/claude/nested.CLAUDE.md +1 -0
- package/templates/agent-kit/adapters/claude/root.CLAUDE.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-0-plan.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-1-validate.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-2-build.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-3-push.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-biz-1-validate.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-biz-2-build.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-biz-3-prove.md +5 -0
- package/templates/agent-kit/agent-kit.yaml +45 -0
- package/templates/agent-kit/instructions/AGENTKIT.md +83 -0
- package/templates/agent-kit/instructions/integration.AGENTS.md +25 -0
- package/templates/agent-kit/instructions/role-assistant.AGENTS.md +22 -0
- package/templates/agent-kit/instructions/root.AGENTS.md +37 -0
- package/templates/agent-kit/parity-inventory.yaml +188 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +58 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/references/contract-checklist.md +40 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +54 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/references/production-safety.md +35 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/scripts/reserved-system-key.js +19 -0
- package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +51 -0
- package/templates/agent-kit/skills/aifabrix-plan/references/challenge-checklist.md +108 -0
- package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +34 -0
- package/templates/agent-kit/skills/aifabrix-plan/references/plan-template.md +182 -0
- package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +50 -0
- package/templates/agent-kit/skills/aifabrix-prove/references/demo-template.md +65 -0
- package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +68 -0
- package/templates/agent-kit/skills/aifabrix-prove/references/learning-template.md +66 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +42 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/references/package-boundary.md +21 -0
- package/templates/agent-kit/skills/shared/hosts.md +78 -0
- package/templates/agent-kit/workspace/.cursor/plans/README.md +22 -0
- package/templates/agent-kit/workspace/LICENSE.mit +21 -0
- package/templates/agent-kit/workspace/README.md +89 -0
- package/templates/applications/builder-api/Dockerfile +3 -1
- package/templates/applications/dataplane/application.yaml +2 -2
- package/templates/applications/dataplane/env.template +1 -1
- package/templates/applications/dataplane/rbac.yaml +28 -0
- package/templates/applications/keycloak/env.template +3 -3
- package/templates/applications/miso-controller/application.yaml +1 -1
- package/templates/applications/miso-controller/env.template +8 -9
- package/templates/channels/claude/TROUBLESHOOTING.md +3 -0
- package/templates/channels/claude/channel.json +1 -1
- package/templates/channels/claude/install.template.md.hbs +1 -0
- package/templates/channels/claude/integration/claude-system.json +1 -1
- package/templates/channels/slack/channel.json +11 -0
- package/templates/channels/slack/install.template.md.hbs +9 -0
- package/templates/channels/slack/integration/slack-system.json +11 -0
- package/templates/channels/slack/manifest.template.json.hbs +6 -3
- package/templates/channels/teams-bot/channel.json +1 -0
- package/templates/python/docker-compose.hbs +14 -0
- package/templates/typescript/docker-compose.hbs +14 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map role-assistant test results to expected lifecycleState tokens.
|
|
3
|
+
* @fileoverview Prefer work.result completion over coarse work.status.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const { VERDICT } = require('../lifecycle/product-model');
|
|
9
|
+
|
|
10
|
+
const SUPPORTED_LIFECYCLE_STATES = new Set([
|
|
11
|
+
'completed',
|
|
12
|
+
'question',
|
|
13
|
+
'approval-required',
|
|
14
|
+
'dependency',
|
|
15
|
+
'safe-stop',
|
|
16
|
+
'rejected',
|
|
17
|
+
'failed'
|
|
18
|
+
]);
|
|
19
|
+
const LIFECYCLE_STATE_ALIASES = Object.freeze({
|
|
20
|
+
completed: ['completed', 'complete', 'done', 'success', 'verified'],
|
|
21
|
+
question: ['question', 'question_required', 'awaiting_question', 'pending_question'],
|
|
22
|
+
'approval-required': [
|
|
23
|
+
'approval_required',
|
|
24
|
+
'awaiting_approval',
|
|
25
|
+
'pending_approval',
|
|
26
|
+
'requires_approval'
|
|
27
|
+
],
|
|
28
|
+
dependency: ['dependency', 'dependency_wait', 'dependency_blocked', 'awaiting_dependency'],
|
|
29
|
+
'safe-stop': ['safe_stop', 'safe_stopped', 'policy_blocked', 'halted', 'paused'],
|
|
30
|
+
rejected: ['rejected', 'denied', 'declined', 'policy_rejected'],
|
|
31
|
+
failed: ['failed', 'error', 'errored', 'timeout', 'cancelled', 'canceled']
|
|
32
|
+
});
|
|
33
|
+
const WORK_STATUS_TO_LIFECYCLE = Object.freeze({
|
|
34
|
+
completed: 'completed',
|
|
35
|
+
waiting: 'question',
|
|
36
|
+
running: 'dependency',
|
|
37
|
+
stopped: 'safe-stop'
|
|
38
|
+
});
|
|
39
|
+
const WAIT_REASON_TO_LIFECYCLE = Object.freeze({
|
|
40
|
+
ask: 'question',
|
|
41
|
+
approval: 'approval-required',
|
|
42
|
+
ownerroute: 'dependency',
|
|
43
|
+
realityconfirm: 'question',
|
|
44
|
+
knowledgeconfirm: 'question'
|
|
45
|
+
});
|
|
46
|
+
const WORKER_TASK_STATUS_TO_LIFECYCLE = Object.freeze({
|
|
47
|
+
draft: 'dependency',
|
|
48
|
+
pendingapproval: 'approval-required',
|
|
49
|
+
approved: 'dependency',
|
|
50
|
+
running: 'dependency',
|
|
51
|
+
completed: 'completed',
|
|
52
|
+
failed: 'failed',
|
|
53
|
+
cancelled: 'rejected',
|
|
54
|
+
canceled: 'rejected'
|
|
55
|
+
});
|
|
56
|
+
const WORKER_APPROVAL_STATE_TO_LIFECYCLE = Object.freeze({
|
|
57
|
+
pending: 'approval-required',
|
|
58
|
+
approved: 'dependency',
|
|
59
|
+
rejected: 'rejected'
|
|
60
|
+
});
|
|
61
|
+
const COMPLETION_STATE_TO_LIFECYCLE = Object.freeze({
|
|
62
|
+
safestopped: 'safe-stop',
|
|
63
|
+
safe_stopped: 'safe-stop',
|
|
64
|
+
cancelled: 'rejected',
|
|
65
|
+
canceled: 'rejected',
|
|
66
|
+
completed: 'completed',
|
|
67
|
+
waiting: 'question'
|
|
68
|
+
});
|
|
69
|
+
const STEP_SIGNAL_FIELDS = [
|
|
70
|
+
'lifecycleState',
|
|
71
|
+
'state',
|
|
72
|
+
'status',
|
|
73
|
+
'code',
|
|
74
|
+
'errorCode',
|
|
75
|
+
'reason',
|
|
76
|
+
'kind',
|
|
77
|
+
'type',
|
|
78
|
+
'error',
|
|
79
|
+
'failure',
|
|
80
|
+
'details',
|
|
81
|
+
'result'
|
|
82
|
+
];
|
|
83
|
+
const OBJECT_SIGNAL_FIELDS = [
|
|
84
|
+
'lifecycleState',
|
|
85
|
+
'state',
|
|
86
|
+
'status',
|
|
87
|
+
'code',
|
|
88
|
+
'type',
|
|
89
|
+
'reason',
|
|
90
|
+
'kind',
|
|
91
|
+
'category',
|
|
92
|
+
'errorCode'
|
|
93
|
+
];
|
|
94
|
+
const TOP_LEVEL_SIGNAL_PATHS = [
|
|
95
|
+
'lifecycleState',
|
|
96
|
+
'state',
|
|
97
|
+
'status',
|
|
98
|
+
'lifecycle.state',
|
|
99
|
+
'report.lifecycleState',
|
|
100
|
+
'report.state',
|
|
101
|
+
'report.status',
|
|
102
|
+
'report.lifecycle.state',
|
|
103
|
+
'report.runtime.state',
|
|
104
|
+
'report.work.state'
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
function normalizeLifecycleStateToken(value) {
|
|
108
|
+
if (typeof value !== 'string') {
|
|
109
|
+
return '';
|
|
110
|
+
}
|
|
111
|
+
return value
|
|
112
|
+
.trim()
|
|
113
|
+
.toLowerCase()
|
|
114
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
115
|
+
.replace(/^_+|_+$/g, '');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function lifecycleStateFromToken(token) {
|
|
119
|
+
if (!token) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
for (const [state, aliases] of Object.entries(LIFECYCLE_STATE_ALIASES)) {
|
|
123
|
+
for (const alias of aliases) {
|
|
124
|
+
if (token === alias || token.startsWith(`${alias}_`)) {
|
|
125
|
+
return state;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function lifecycleStateFromSignalValue(value) {
|
|
133
|
+
if (value === null || value === undefined) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
if (typeof value === 'string') {
|
|
137
|
+
return lifecycleStateFromToken(normalizeLifecycleStateToken(value));
|
|
138
|
+
}
|
|
139
|
+
if (Array.isArray(value)) {
|
|
140
|
+
return firstLifecycleFromValues(value);
|
|
141
|
+
}
|
|
142
|
+
if (typeof value === 'object') {
|
|
143
|
+
return firstLifecycleFromValues(OBJECT_SIGNAL_FIELDS.map((field) => value[field]));
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function firstLifecycleFromValues(values) {
|
|
149
|
+
for (const candidate of values) {
|
|
150
|
+
const state = lifecycleStateFromSignalValue(candidate);
|
|
151
|
+
if (state) {
|
|
152
|
+
return state;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function mapWorkStatusFromResult(result) {
|
|
159
|
+
const rawStatus = normalizeLifecycleStateToken(result?.status);
|
|
160
|
+
if (rawStatus && WORK_STATUS_TO_LIFECYCLE[rawStatus]) {
|
|
161
|
+
const waitReason = normalizeLifecycleStateToken(result?.wait?.waitReason || '');
|
|
162
|
+
if (rawStatus === 'waiting' && waitReason && WAIT_REASON_TO_LIFECYCLE[waitReason]) {
|
|
163
|
+
return WAIT_REASON_TO_LIFECYCLE[waitReason];
|
|
164
|
+
}
|
|
165
|
+
return WORK_STATUS_TO_LIFECYCLE[rawStatus];
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function mapWorkerTaskStateFromResult(result) {
|
|
171
|
+
const statusCandidates = [result?.task?.status, result?.status, result?.workerTask?.status];
|
|
172
|
+
for (const row of statusCandidates) {
|
|
173
|
+
const token = normalizeLifecycleStateToken(row);
|
|
174
|
+
if (token && WORKER_TASK_STATUS_TO_LIFECYCLE[token]) {
|
|
175
|
+
return WORKER_TASK_STATUS_TO_LIFECYCLE[token];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const approvalCandidates = [
|
|
179
|
+
result?.task?.approvalState,
|
|
180
|
+
result?.approvalState,
|
|
181
|
+
result?.workerTask?.approvalState
|
|
182
|
+
];
|
|
183
|
+
for (const row of approvalCandidates) {
|
|
184
|
+
const token = normalizeLifecycleStateToken(row);
|
|
185
|
+
if (token && WORKER_APPROVAL_STATE_TO_LIFECYCLE[token]) {
|
|
186
|
+
return WORKER_APPROVAL_STATE_TO_LIFECYCLE[token];
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function workResultCompletionObject(result) {
|
|
193
|
+
const workResult =
|
|
194
|
+
result?.workResult && typeof result.workResult === 'object' ? result.workResult : null;
|
|
195
|
+
const completion =
|
|
196
|
+
workResult?.completion && typeof workResult.completion === 'object'
|
|
197
|
+
? workResult.completion
|
|
198
|
+
: null;
|
|
199
|
+
return { workResult, completion };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function mapWorkResultCompletionToLifecycle(result) {
|
|
203
|
+
const { workResult, completion } = workResultCompletionObject(result);
|
|
204
|
+
const state = normalizeLifecycleStateToken(completion?.state);
|
|
205
|
+
if (!workResult || !completion || !state) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
if (state === 'failed') {
|
|
209
|
+
return workResultSignalsRejected(workResult) ? 'rejected' : 'failed';
|
|
210
|
+
}
|
|
211
|
+
return COMPLETION_STATE_TO_LIFECYCLE[state] || lifecycleStateFromToken(state);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function completionReasonBag(processExecution) {
|
|
215
|
+
const pe = processExecution && typeof processExecution === 'object' ? processExecution : {};
|
|
216
|
+
if (pe.completionReason && typeof pe.completionReason === 'object') {
|
|
217
|
+
return pe.completionReason;
|
|
218
|
+
}
|
|
219
|
+
if (pe.completion_reason && typeof pe.completion_reason === 'object') {
|
|
220
|
+
return pe.completion_reason;
|
|
221
|
+
}
|
|
222
|
+
return {};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function workResultSignalsRejected(workResult) {
|
|
226
|
+
const reasonBag = completionReasonBag(workResult?.processExecution);
|
|
227
|
+
const kind = normalizeLifecycleStateToken(reasonBag.kind || reasonBag.Kind);
|
|
228
|
+
if (kind === 'rejected' || kind === 'denied' || kind === 'unauthorized') {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
const text = [
|
|
232
|
+
reasonBag.summary,
|
|
233
|
+
workResult?.completion?.businessLanguage?.reason,
|
|
234
|
+
workResult?.completion?.businessLanguage?.summary,
|
|
235
|
+
workResult?.completion?.businessLanguage?.outcomeState,
|
|
236
|
+
workResult?.task?.resultSummary
|
|
237
|
+
]
|
|
238
|
+
.filter((row) => typeof row === 'string' && row.trim())
|
|
239
|
+
.join(' ')
|
|
240
|
+
.toLowerCase();
|
|
241
|
+
return /\b(trust|authority|denied|rejected|unauthorized|not authorized)\b/.test(text);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function valueAtDottedPath(source, dottedPath) {
|
|
245
|
+
return dottedPath.split('.').reduce((cursor, key) => {
|
|
246
|
+
if (!cursor || typeof cursor !== 'object') {
|
|
247
|
+
return undefined;
|
|
248
|
+
}
|
|
249
|
+
return cursor[key];
|
|
250
|
+
}, source);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function lifecycleStateFromStepsRun(result) {
|
|
254
|
+
const steps = Array.isArray(result?.stepsRun) ? result.stepsRun : [];
|
|
255
|
+
for (const row of steps) {
|
|
256
|
+
const state = firstLifecycleFromValues(STEP_SIGNAL_FIELDS.map((field) => row?.[field]));
|
|
257
|
+
if (state) {
|
|
258
|
+
return state;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function resolveLifecycleStateFromResult(result) {
|
|
265
|
+
// Prefer governed work.result completion over coarse work.status "stopped"
|
|
266
|
+
// (which collapses failed + safeStopped + cancelled into safe-stop).
|
|
267
|
+
return (
|
|
268
|
+
mapWorkResultCompletionToLifecycle(result) ||
|
|
269
|
+
mapWorkStatusFromResult(result) ||
|
|
270
|
+
mapWorkerTaskStateFromResult(result) ||
|
|
271
|
+
firstLifecycleFromValues(TOP_LEVEL_SIGNAL_PATHS.map((path) => valueAtDottedPath(result, path))) ||
|
|
272
|
+
lifecycleStateFromStepsRun(result)
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function deriveLifecycleState(result, lifecycleVerdict) {
|
|
277
|
+
if (lifecycleVerdict === VERDICT.VERIFIED) {
|
|
278
|
+
return 'completed';
|
|
279
|
+
}
|
|
280
|
+
const structuredState = resolveLifecycleStateFromResult(result);
|
|
281
|
+
if (structuredState) {
|
|
282
|
+
return structuredState;
|
|
283
|
+
}
|
|
284
|
+
if (lifecycleVerdict === VERDICT.NOT_VERIFIED) return 'safe-stop';
|
|
285
|
+
return 'failed';
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
module.exports = {
|
|
289
|
+
SUPPORTED_LIFECYCLE_STATES,
|
|
290
|
+
deriveLifecycleState
|
|
291
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph hop assertions for expected.search (one-level related records).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Evaluate graphDepth, relatedTypes, and related.minRows
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
function asObject(value) {
|
|
12
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function relatedRows(payload, resourceType) {
|
|
16
|
+
const related = asObject(asObject(payload).related);
|
|
17
|
+
if (!Object.prototype.hasOwnProperty.call(related, resourceType)) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const bundle = related[resourceType];
|
|
21
|
+
if (Array.isArray(bundle)) {
|
|
22
|
+
return bundle;
|
|
23
|
+
}
|
|
24
|
+
if (bundle && Array.isArray(bundle.data)) {
|
|
25
|
+
return bundle.data;
|
|
26
|
+
}
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function relatedMeta(payload, resourceType) {
|
|
31
|
+
const bundle = asObject(asObject(payload).related)[resourceType];
|
|
32
|
+
return asObject(asObject(bundle).meta);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function evaluateGraphDepth(expectedSearch, meta) {
|
|
36
|
+
if (!Number.isFinite(Number(expectedSearch.graphDepth))) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const expected = Number(expectedSearch.graphDepth);
|
|
40
|
+
const actual = Number(meta.graphDepth);
|
|
41
|
+
const passed = actual === expected;
|
|
42
|
+
return {
|
|
43
|
+
id: 'expected.search.graphDepth',
|
|
44
|
+
passed,
|
|
45
|
+
message: passed
|
|
46
|
+
? `Search graphDepth matched ${expected}.`
|
|
47
|
+
: `Search graphDepth expected ${expected} but got ${Number.isFinite(actual) ? actual : 'none'}.`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function evaluateRelatedTypes(expectedTypes, meta) {
|
|
52
|
+
if (!Array.isArray(expectedTypes) || expectedTypes.length === 0) {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
const observed = Array.isArray(meta.relatedTypes) ? meta.relatedTypes.map(String) : [];
|
|
56
|
+
return expectedTypes.map((item) => {
|
|
57
|
+
const key = String(item || '').trim();
|
|
58
|
+
const passed = Boolean(key && observed.includes(key));
|
|
59
|
+
return {
|
|
60
|
+
id: `expected.search.relatedTypes:${key}`,
|
|
61
|
+
passed,
|
|
62
|
+
message: passed
|
|
63
|
+
? `Search relatedTypes included "${key}".`
|
|
64
|
+
: `Search relatedTypes did not include "${key}".`
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function evaluateRelatedHop(resourceType, spec, payload) {
|
|
70
|
+
const assertions = [];
|
|
71
|
+
const rows = relatedRows(payload, resourceType);
|
|
72
|
+
if (Number.isFinite(Number(spec.minRows))) {
|
|
73
|
+
const minRows = Number(spec.minRows);
|
|
74
|
+
if (rows === null) {
|
|
75
|
+
assertions.push({
|
|
76
|
+
id: `expected.search.related.${resourceType}.minRows`,
|
|
77
|
+
passed: false,
|
|
78
|
+
message: `Related "${resourceType}" was omitted from the search graph.`
|
|
79
|
+
});
|
|
80
|
+
} else {
|
|
81
|
+
const passed = rows.length >= minRows;
|
|
82
|
+
assertions.push({
|
|
83
|
+
id: `expected.search.related.${resourceType}.minRows`,
|
|
84
|
+
passed,
|
|
85
|
+
message: passed
|
|
86
|
+
? `Related "${resourceType}" returned at least ${minRows} row(s).`
|
|
87
|
+
: `Related "${resourceType}" returned ${rows.length} row(s); expected at least ${minRows}.`
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (spec.resultMode) {
|
|
92
|
+
const actual = String(relatedMeta(payload, resourceType).resultMode || '');
|
|
93
|
+
const passed = rows !== null && actual === String(spec.resultMode);
|
|
94
|
+
assertions.push({
|
|
95
|
+
id: `expected.search.related.${resourceType}.resultMode`,
|
|
96
|
+
passed,
|
|
97
|
+
message: passed
|
|
98
|
+
? `Related "${resourceType}" resultMode matched "${spec.resultMode}".`
|
|
99
|
+
: `Related "${resourceType}" resultMode expected "${spec.resultMode}" but got "${actual || 'omitted'}".`
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return assertions;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function evaluateSearchGraphExpectations(expectedSearch, payload, meta) {
|
|
106
|
+
const assertions = [];
|
|
107
|
+
const depth = evaluateGraphDepth(expectedSearch, meta);
|
|
108
|
+
if (depth) {
|
|
109
|
+
assertions.push(depth);
|
|
110
|
+
}
|
|
111
|
+
assertions.push(...evaluateRelatedTypes(expectedSearch.relatedTypes, meta));
|
|
112
|
+
const related = asObject(expectedSearch.related);
|
|
113
|
+
for (const resourceType of Object.keys(related)) {
|
|
114
|
+
const spec = asObject(related[resourceType]);
|
|
115
|
+
assertions.push(...evaluateRelatedHop(resourceType, spec, payload));
|
|
116
|
+
}
|
|
117
|
+
return assertions;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
module.exports = {
|
|
121
|
+
evaluateSearchGraphExpectations
|
|
122
|
+
};
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
11
|
const { operationKeys } = require('./test-runner-search');
|
|
12
|
+
const { skillsEnvelope } = require('../search/search-skills');
|
|
13
|
+
const { evaluateSearchGraphExpectations } = require('./test-cases-search-graph');
|
|
12
14
|
|
|
13
15
|
function asObject(value) {
|
|
14
16
|
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
@@ -128,11 +130,19 @@ function evaluateSearchExpectations(expectedSearch, observation) {
|
|
|
128
130
|
assertions.push(errorAssertion);
|
|
129
131
|
}
|
|
130
132
|
assertions.push(...evaluateSearchShape(expectedSearch, searchObs));
|
|
133
|
+
assertions.push(
|
|
134
|
+
...evaluateSearchGraphExpectations(
|
|
135
|
+
expectedSearch,
|
|
136
|
+
searchObs.payload,
|
|
137
|
+
searchMeta(searchObs.payload)
|
|
138
|
+
)
|
|
139
|
+
);
|
|
131
140
|
return assertions;
|
|
132
141
|
}
|
|
133
142
|
|
|
134
143
|
function skillsResourceEntry(skillsPayload, resourceType) {
|
|
135
|
-
const
|
|
144
|
+
const root = skillsEnvelope(skillsPayload) || asObject(skillsPayload);
|
|
145
|
+
const rts = asObject(asObject(root).search).resourceTypes;
|
|
136
146
|
return asObject(asObject(rts)[resourceType]);
|
|
137
147
|
}
|
|
138
148
|
|
|
@@ -208,7 +218,15 @@ function evaluateSkillsExpectations(expectedSkills, observation) {
|
|
|
208
218
|
: `work.skills did not publish resourceType "${resourceType}".`
|
|
209
219
|
});
|
|
210
220
|
}
|
|
211
|
-
if (expectedSkills.operationRequired ===
|
|
221
|
+
if (expectedSkills.operationRequired === false) {
|
|
222
|
+
assertions.push({
|
|
223
|
+
id: 'expected.skills.operationRequired',
|
|
224
|
+
passed: true,
|
|
225
|
+
skip: true,
|
|
226
|
+
kind: 'skip',
|
|
227
|
+
message: 'operationRequired is false — check skipped.'
|
|
228
|
+
});
|
|
229
|
+
} else if (expectedSkills.operationRequired === true) {
|
|
212
230
|
const passed = spec.operationRequired === true;
|
|
213
231
|
assertions.push({
|
|
214
232
|
id: 'expected.skills.operationRequired',
|