@bpmsoftwaresolutions/ai-engine-client 1.1.87 → 1.1.89
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/client.js +192 -4903
- package/src/domains/charters.js +5 -0
- package/src/domains/claims.js +58 -0
- package/src/domains/commit-governance.js +68 -0
- package/src/domains/context-orientation.js +48 -0
- package/src/domains/context-sessions.js +46 -0
- package/src/domains/execution-eligibility.js +44 -0
- package/src/domains/governed-implementation.js +7 -0
- package/src/domains/implementation-artifacts.js +61 -0
- package/src/domains/implementation-checks.js +41 -0
- package/src/domains/implementation-items.js +82 -89
- package/src/domains/implementation-packets.js +173 -0
- package/src/domains/implementation-tasks.js +125 -6
- package/src/domains/portfolio.js +125 -1
- package/src/domains/project-chartering.js +18 -0
- package/src/domains/project-reports.js +14 -0
- package/src/domains/project-resume.js +18 -0
- package/src/domains/projects.js +348 -24
- package/src/domains/roadmap-reports.js +6 -0
- package/src/domains/session-governance.js +64 -0
- package/src/domains/tool-binding-approvals.js +102 -0
- package/src/domains/verified-mutations.js +7 -0
- package/src/domains/work-start.js +192 -0
- package/src/domains/workflow-composition.js +3416 -7
- package/src/domains/workflow-turns.js +6 -0
- package/src/index.js +1 -1
- package/src/utils/task-binding.js +31 -0
- package/src/utils/verified-mutations.js +128 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { cleanText } from '../utils/text.js';
|
|
2
|
+
|
|
3
|
+
export function createClaimsDomain(client) {
|
|
4
|
+
return {
|
|
5
|
+
getClaim: (claimId) => {
|
|
6
|
+
if (!claimId) throw new Error('claimId is required.');
|
|
7
|
+
return client._request(`/api/governance/claims/${encodeURIComponent(claimId)}`);
|
|
8
|
+
},
|
|
9
|
+
claimIsValid: async (claimId) => {
|
|
10
|
+
const claim = await client.getClaim(claimId);
|
|
11
|
+
return cleanText(claim?.status) === 'active';
|
|
12
|
+
},
|
|
13
|
+
signoffClaim: (claimId, body = {}) => {
|
|
14
|
+
if (!claimId) throw new Error('claimId is required.');
|
|
15
|
+
return client._request(`/api/governance/claims/${encodeURIComponent(claimId)}/signoff`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
body,
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
promoteClaimSurface: ({
|
|
21
|
+
claimId,
|
|
22
|
+
workflowId,
|
|
23
|
+
contextSessionId,
|
|
24
|
+
actorId,
|
|
25
|
+
requiredToolKeys,
|
|
26
|
+
intentId,
|
|
27
|
+
bindingScope,
|
|
28
|
+
usageMode,
|
|
29
|
+
operatorScope,
|
|
30
|
+
allowedArgumentPolicy,
|
|
31
|
+
...rest
|
|
32
|
+
} = {}) => {
|
|
33
|
+
if (!claimId) throw new Error('claimId is required.');
|
|
34
|
+
if (!workflowId) throw new Error('workflowId is required.');
|
|
35
|
+
if (!contextSessionId) throw new Error('contextSessionId is required.');
|
|
36
|
+
if (!actorId) throw new Error('actorId is required.');
|
|
37
|
+
if (!Array.isArray(requiredToolKeys) || requiredToolKeys.length === 0) {
|
|
38
|
+
throw new Error('requiredToolKeys must be a non-empty array.');
|
|
39
|
+
}
|
|
40
|
+
return client._request('/api/governance/claims/promote-surface', {
|
|
41
|
+
method: 'POST',
|
|
42
|
+
body: {
|
|
43
|
+
...rest,
|
|
44
|
+
claim_id: claimId,
|
|
45
|
+
workflow_id: workflowId,
|
|
46
|
+
context_session_id: contextSessionId,
|
|
47
|
+
actor_id: actorId,
|
|
48
|
+
required_tool_keys: requiredToolKeys,
|
|
49
|
+
intent_id: intentId,
|
|
50
|
+
binding_scope: bindingScope,
|
|
51
|
+
usage_mode: usageMode,
|
|
52
|
+
operator_scope: operatorScope,
|
|
53
|
+
allowed_argument_policy: allowedArgumentPolicy,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export function createCommitGovernanceDomain(client) {
|
|
2
|
+
return {
|
|
3
|
+
evaluateCommitGovernance: ({
|
|
4
|
+
claimId,
|
|
5
|
+
contextSessionId,
|
|
6
|
+
agentId,
|
|
7
|
+
intentId,
|
|
8
|
+
changedFiles,
|
|
9
|
+
declaredScopeFiles,
|
|
10
|
+
diffSummary,
|
|
11
|
+
branch,
|
|
12
|
+
headSha,
|
|
13
|
+
} = {}) => client._request('/api/commit-governance/evaluate', {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
body: {
|
|
16
|
+
claim_id: claimId,
|
|
17
|
+
context_session_id: contextSessionId,
|
|
18
|
+
agent_id: agentId,
|
|
19
|
+
intent_id: intentId,
|
|
20
|
+
changed_files: changedFiles,
|
|
21
|
+
declared_scope_files: declaredScopeFiles,
|
|
22
|
+
diff_summary: diffSummary,
|
|
23
|
+
branch,
|
|
24
|
+
head_sha: headSha,
|
|
25
|
+
},
|
|
26
|
+
}),
|
|
27
|
+
checkGitShipReadiness: ({
|
|
28
|
+
claimId,
|
|
29
|
+
actorId,
|
|
30
|
+
targetBranch,
|
|
31
|
+
shipCommand,
|
|
32
|
+
packageName,
|
|
33
|
+
declaredScopeFiles,
|
|
34
|
+
stagedFiles,
|
|
35
|
+
dirtyFiles,
|
|
36
|
+
branch,
|
|
37
|
+
headSha,
|
|
38
|
+
packageJsonVersion,
|
|
39
|
+
facadeMinClientVersion,
|
|
40
|
+
packageRelease,
|
|
41
|
+
packageJsonHash,
|
|
42
|
+
sdkVersionHash,
|
|
43
|
+
} = {}) => client._request('/api/commit-governance/ship-readiness', {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
body: {
|
|
46
|
+
claim_id: claimId,
|
|
47
|
+
actor_id: actorId,
|
|
48
|
+
target_branch: targetBranch,
|
|
49
|
+
ship_command: shipCommand,
|
|
50
|
+
package_name: packageName,
|
|
51
|
+
declared_scope_files: declaredScopeFiles,
|
|
52
|
+
staged_files: stagedFiles,
|
|
53
|
+
dirty_files: dirtyFiles,
|
|
54
|
+
branch,
|
|
55
|
+
head_sha: headSha,
|
|
56
|
+
package_json_version: packageJsonVersion,
|
|
57
|
+
facade_min_client_version: facadeMinClientVersion,
|
|
58
|
+
package_release: packageRelease,
|
|
59
|
+
package_json_hash: packageJsonHash,
|
|
60
|
+
sdk_version_hash: sdkVersionHash,
|
|
61
|
+
},
|
|
62
|
+
}),
|
|
63
|
+
getCommitGovernanceEvaluation: (evaluationId) => client._request(`/api/commit-governance/evaluations/${encodeURIComponent(evaluationId)}`),
|
|
64
|
+
listCommitGovernanceEvaluationsByClaim: (claimId, { limit } = {}) => client._request(`/api/commit-governance/claims/${encodeURIComponent(claimId)}/evaluations`, {
|
|
65
|
+
query: { limit },
|
|
66
|
+
}),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export function createContextOrientationDomain(client) {
|
|
2
|
+
return {
|
|
3
|
+
conductOrientation: async ({
|
|
4
|
+
agentId,
|
|
5
|
+
runtimeSessionId,
|
|
6
|
+
intentId,
|
|
7
|
+
executionPurpose,
|
|
8
|
+
agentSignature,
|
|
9
|
+
understandingSummary,
|
|
10
|
+
lockClaim = true,
|
|
11
|
+
} = {}) => {
|
|
12
|
+
const { context_session, reminders } = await client.contextSessions.openContextSession({
|
|
13
|
+
agentId,
|
|
14
|
+
runtimeSessionId,
|
|
15
|
+
intentId,
|
|
16
|
+
executionPurpose,
|
|
17
|
+
});
|
|
18
|
+
const sessionId = context_session.context_session_id;
|
|
19
|
+
|
|
20
|
+
const required = (reminders || []).filter((reminder) => reminder.severity === 'required');
|
|
21
|
+
let acknowledgedCount = 0;
|
|
22
|
+
for (const reminder of required) {
|
|
23
|
+
await client.contextSessions.acknowledgeReminder(sessionId, {
|
|
24
|
+
reminderId: reminder.reminder_id,
|
|
25
|
+
agentSignature,
|
|
26
|
+
understandingSummary,
|
|
27
|
+
});
|
|
28
|
+
acknowledgedCount++;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const completion = await client.contextSessions.completeOrientation(sessionId);
|
|
32
|
+
|
|
33
|
+
let claimLockResult = null;
|
|
34
|
+
if (lockClaim) {
|
|
35
|
+
claimLockResult = await client.contextSessions.lockContextSessionClaim(sessionId);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
context_session_id: sessionId,
|
|
40
|
+
intent_id: intentId,
|
|
41
|
+
context_session: claimLockResult?.context_session || completion.context_session,
|
|
42
|
+
gate_result: claimLockResult?.gate_result || completion.gate_result,
|
|
43
|
+
acknowledged_count: acknowledgedCount,
|
|
44
|
+
claim_locked: lockClaim && !!claimLockResult,
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { cleanText } from '../utils/text.js';
|
|
2
|
+
|
|
3
|
+
export function contextSessionIdFromInput(input) {
|
|
4
|
+
if (input !== null && typeof input === 'object' && !Array.isArray(input)) {
|
|
5
|
+
return cleanText(input.contextSessionId)
|
|
6
|
+
|| cleanText(input.context_session_id)
|
|
7
|
+
|| cleanText(input.context_session?.context_session_id)
|
|
8
|
+
|| cleanText(input.claim?.context_session_id);
|
|
9
|
+
}
|
|
10
|
+
return cleanText(input);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createContextSessionsDomain(client) {
|
|
14
|
+
return {
|
|
15
|
+
openContextSession: ({ agentId, runtimeSessionId, intentId, executionPurpose, notes } = {}) => client._request('/api/context-session/open', {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
body: {
|
|
18
|
+
agent_id: agentId,
|
|
19
|
+
runtime_session_id: runtimeSessionId,
|
|
20
|
+
intent_id: intentId,
|
|
21
|
+
execution_purpose: executionPurpose,
|
|
22
|
+
notes,
|
|
23
|
+
},
|
|
24
|
+
}),
|
|
25
|
+
getOrientationWindow: (contextSessionId) => client._request(`/api/context-session/${encodeURIComponent(contextSessionId)}/window`),
|
|
26
|
+
acknowledgeReminder: (contextSessionId, { reminderId, agentSignature, understandingSummary } = {}) => client._request(`/api/context-session/${encodeURIComponent(contextSessionId)}/acknowledge`, {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
body: {
|
|
29
|
+
reminder_id: reminderId,
|
|
30
|
+
agent_signature: agentSignature,
|
|
31
|
+
understanding_summary: understandingSummary,
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
34
|
+
completeOrientation: (contextSessionId) => client._request(`/api/context-session/${encodeURIComponent(contextSessionId)}/complete`, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
}),
|
|
37
|
+
lockContextSessionClaim: (input) => {
|
|
38
|
+
const contextSessionId = contextSessionIdFromInput(input);
|
|
39
|
+
if (!contextSessionId) throw new Error('contextSessionId is required.');
|
|
40
|
+
return client._request(`/api/context-session/${encodeURIComponent(contextSessionId)}/lock-claim`, {
|
|
41
|
+
method: 'POST',
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
getContextSessionGateStatus: (contextSessionId) => client._request(`/api/context-session/${encodeURIComponent(contextSessionId)}/gate-status`),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { cleanText } from '../utils/text.js';
|
|
2
|
+
import { GOVERNED_MUTATION_REQUIRED_CAPABILITIES } from '../constants/governance.js';
|
|
3
|
+
|
|
4
|
+
export function buildEligibilityError(message, details = {}) {
|
|
5
|
+
const error = new Error(message);
|
|
6
|
+
error.code = 'EXECUTION_ELIGIBILITY_FAILED';
|
|
7
|
+
error.details = details;
|
|
8
|
+
return error;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createExecutionEligibilityDomain(client) {
|
|
12
|
+
return {
|
|
13
|
+
getExecutionEligibility: (body = {}) => client._request('/api/governance/execution-eligibility', {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
body: {
|
|
16
|
+
required_capabilities: GOVERNED_MUTATION_REQUIRED_CAPABILITIES,
|
|
17
|
+
verification_required: true,
|
|
18
|
+
...body,
|
|
19
|
+
},
|
|
20
|
+
}),
|
|
21
|
+
_assertExecutionEligibility: async (body = {}) => {
|
|
22
|
+
const eligibility = await client.getExecutionEligibility(body);
|
|
23
|
+
if (eligibility?.execution_eligible && eligibility?.mutation_allowed) {
|
|
24
|
+
return eligibility;
|
|
25
|
+
}
|
|
26
|
+
const remediation = cleanText(eligibility?.remediation_command);
|
|
27
|
+
const verification = cleanText(eligibility?.verification_command);
|
|
28
|
+
throw buildEligibilityError(
|
|
29
|
+
[
|
|
30
|
+
`Execution eligibility gate blocked mutation${cleanText(body?.requested_mutation_surface) ? ` on ${cleanText(body.requested_mutation_surface)}` : ''}.`,
|
|
31
|
+
remediation ? `Fix: ${remediation}` : null,
|
|
32
|
+
verification ? `Then verify: ${verification}` : null,
|
|
33
|
+
].filter(Boolean).join(' '),
|
|
34
|
+
{
|
|
35
|
+
required_gate: eligibility?.required_gate || 'execution_eligibility.required_gate',
|
|
36
|
+
execution_eligibility: eligibility ?? null,
|
|
37
|
+
requested_mutation_surface: cleanText(body?.requested_mutation_surface) || null,
|
|
38
|
+
remediation_command: remediation || null,
|
|
39
|
+
verification_command: verification || null,
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function createGovernedImplementationDomain(client) {
|
|
2
|
+
return {
|
|
3
|
+
getExecutionEligibility: (body = {}) => client.executionEligibility.getExecutionEligibility(body),
|
|
4
|
+
_assertExecutionEligibility: (body = {}) => client.executionEligibility._assertExecutionEligibility(body),
|
|
5
|
+
executeVerifiedMutation: (request = {}) => client.verifiedMutations.executeVerifiedMutation(request),
|
|
6
|
+
};
|
|
7
|
+
}
|
|
@@ -1,6 +1,67 @@
|
|
|
1
|
+
import { isPlainObject } from '../utils/text.js';
|
|
2
|
+
import { buildVerificationError } from '../utils/verified-mutations.js';
|
|
3
|
+
|
|
1
4
|
export function createImplementationArtifactsDomain(client) {
|
|
2
5
|
return {
|
|
3
6
|
getArtifactManifest: (implementationItemId) => client._request(`/api/governed-implementation/items/${implementationItemId}/artifact-manifest`),
|
|
4
7
|
getDecisionPacket: (implementationItemId) => client._request(`/api/governed-implementation/items/${implementationItemId}/decision-packet`),
|
|
8
|
+
verifyImplementationItemArtifacts: async (implementationItemId, { requiredArtifacts = [] } = {}) => {
|
|
9
|
+
const requiredKinds = Array.isArray(requiredArtifacts) ? requiredArtifacts : [];
|
|
10
|
+
const verifications = [];
|
|
11
|
+
const artifactReaders = {
|
|
12
|
+
artifact_manifest: async () => client.getArtifactManifest(implementationItemId),
|
|
13
|
+
decision_packet: async () => client.getDecisionPacket(implementationItemId),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
for (const kind of requiredKinds) {
|
|
17
|
+
const reader = artifactReaders[kind];
|
|
18
|
+
if (typeof reader !== 'function') {
|
|
19
|
+
throw new Error(`Unsupported required artifact: ${kind}`);
|
|
20
|
+
}
|
|
21
|
+
const payload = await reader();
|
|
22
|
+
if (payload?.source_truth !== 'sql') {
|
|
23
|
+
throw buildVerificationError(`Artifact ${kind} did not declare SQL as source_truth.`, {
|
|
24
|
+
artifact_kind: kind,
|
|
25
|
+
verified_current_state: payload ?? null,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
if (payload?.item_id !== implementationItemId) {
|
|
29
|
+
throw buildVerificationError(`Artifact ${kind} returned item_id ${payload?.item_id ?? 'unknown'} instead of ${implementationItemId}.`, {
|
|
30
|
+
artifact_kind: kind,
|
|
31
|
+
verified_current_state: payload ?? null,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const dataKey = kind === 'artifact_manifest' ? 'artifact_manifest' : 'decision_packet';
|
|
35
|
+
if (!isPlainObject(payload?.[dataKey])) {
|
|
36
|
+
throw buildVerificationError(`Artifact ${kind} did not include required ${dataKey} data.`, {
|
|
37
|
+
artifact_kind: kind,
|
|
38
|
+
verified_current_state: payload ?? null,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
verifications.push({
|
|
42
|
+
artifact_kind: kind,
|
|
43
|
+
http_status: 200,
|
|
44
|
+
source_truth: payload.source_truth,
|
|
45
|
+
item_id: payload.item_id,
|
|
46
|
+
verified_current_state: payload[dataKey],
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
itemId: implementationItemId,
|
|
52
|
+
requiredArtifacts: requiredKinds,
|
|
53
|
+
verified: true,
|
|
54
|
+
mutationVerificationEvidence: {
|
|
55
|
+
mutation_name: 'verifyImplementationItemArtifacts',
|
|
56
|
+
evidence_label: `implementation-item-artifacts:${implementationItemId}`,
|
|
57
|
+
mutation_attempted: false,
|
|
58
|
+
authoritative_read_performed: true,
|
|
59
|
+
post_condition_verified: true,
|
|
60
|
+
expected_state: { required_artifacts: requiredKinds },
|
|
61
|
+
verified_current_state: verifications,
|
|
62
|
+
},
|
|
63
|
+
artifacts: verifications,
|
|
64
|
+
};
|
|
65
|
+
},
|
|
5
66
|
};
|
|
6
67
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { executeVerifiedMutation } from '../utils/verified-mutations.js';
|
|
2
|
+
|
|
3
|
+
export function createImplementationChecksDomain(client) {
|
|
4
|
+
return {
|
|
5
|
+
getImplementationItemAcceptanceChecks: (implementationItemId) => client._request(`/api/governed-implementation/items/${implementationItemId}/acceptance-checks`),
|
|
6
|
+
updateAcceptanceCheckStatus: (implementationItemId, acceptanceCheckId, body) => {
|
|
7
|
+
client._assertExecutionEligibility({
|
|
8
|
+
...(body || {}),
|
|
9
|
+
claimed_item_id: body?.claimed_item_id || implementationItemId,
|
|
10
|
+
requested_mutation_surface: body?.requested_mutation_surface || 'implementation_acceptance_check',
|
|
11
|
+
verification_required: true,
|
|
12
|
+
});
|
|
13
|
+
return client._request(
|
|
14
|
+
`/api/governed-implementation/items/${implementationItemId}/acceptance-checks/${acceptanceCheckId}/status`,
|
|
15
|
+
{ method: 'PATCH', body }
|
|
16
|
+
);
|
|
17
|
+
},
|
|
18
|
+
updateAcceptanceCheckStatusVerified: (implementationItemId, acceptanceCheckId, status, body = {}) => executeVerifiedMutation({
|
|
19
|
+
mutationName: 'updateAcceptanceCheckStatus',
|
|
20
|
+
evidenceLabel: `acceptance-check-status:${implementationItemId}:${acceptanceCheckId}`,
|
|
21
|
+
mutationFn: () => client.updateAcceptanceCheckStatus(implementationItemId, acceptanceCheckId, { ...body, status }),
|
|
22
|
+
verificationFn: async () => client.getImplementationItemAcceptanceChecks(implementationItemId),
|
|
23
|
+
expectedState: (verificationResult) => {
|
|
24
|
+
const checks = Array.isArray(verificationResult?.acceptance_checks) ? verificationResult.acceptance_checks : [];
|
|
25
|
+
const targetCheck = checks.find((check) => check?.acceptance_check_id === acceptanceCheckId) || null;
|
|
26
|
+
if (!targetCheck) {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
message: `Acceptance check ${acceptanceCheckId} was not returned by the authoritative read.`,
|
|
30
|
+
verifiedCurrentState: verificationResult,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
ok: targetCheck.status === status,
|
|
35
|
+
message: `Acceptance check ${acceptanceCheckId} status remained ${targetCheck.status ?? 'unknown'} after mutation attempt.`,
|
|
36
|
+
verifiedCurrentState: targetCheck,
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -1,94 +1,9 @@
|
|
|
1
|
+
import { cleanText, isPlainObject } from '../utils/text.js';
|
|
2
|
+
import { buildVerificationError, executeVerifiedMutation } from '../utils/verified-mutations.js';
|
|
3
|
+
|
|
1
4
|
export function createImplementationItemsDomain(client) {
|
|
2
5
|
return {
|
|
3
|
-
createImplementationTask:
|
|
4
|
-
title,
|
|
5
|
-
implementationPacketId,
|
|
6
|
-
description,
|
|
7
|
-
priority,
|
|
8
|
-
assignedTo,
|
|
9
|
-
assignedBy,
|
|
10
|
-
dueAt,
|
|
11
|
-
sortOrder,
|
|
12
|
-
notes,
|
|
13
|
-
createdBy,
|
|
14
|
-
parentTaskId,
|
|
15
|
-
claimId,
|
|
16
|
-
claimProjectId,
|
|
17
|
-
projectId,
|
|
18
|
-
claimedItemId,
|
|
19
|
-
workflowRunId,
|
|
20
|
-
agentSessionId,
|
|
21
|
-
allowedMutationSurfaces,
|
|
22
|
-
acknowledgedReminders,
|
|
23
|
-
executionIntent,
|
|
24
|
-
executionType,
|
|
25
|
-
executionPurpose,
|
|
26
|
-
} = {}) => {
|
|
27
|
-
const normalizedClaimId = String(claimId || '').trim() || null;
|
|
28
|
-
const normalizedClaimProjectId = String(claimProjectId || projectId || '').trim() || null;
|
|
29
|
-
const normalizedClaimedItemId = String(claimedItemId || implementationItemId || '').trim() || null;
|
|
30
|
-
const normalizedWorkflowRunId = String(workflowRunId || '').trim() || null;
|
|
31
|
-
const normalizedAgentSessionId = String(agentSessionId || '').trim() || null;
|
|
32
|
-
const normalizedAllowedMutationSurfaces = Array.isArray(allowedMutationSurfaces) && allowedMutationSurfaces.length > 0
|
|
33
|
-
? allowedMutationSurfaces
|
|
34
|
-
: ['project_roadmap_task'];
|
|
35
|
-
const normalizedAcknowledgedReminders = Array.isArray(acknowledgedReminders)
|
|
36
|
-
? acknowledgedReminders
|
|
37
|
-
: undefined;
|
|
38
|
-
const normalizedExecutionIntent = (() => {
|
|
39
|
-
if (executionIntent && typeof executionIntent === 'object') {
|
|
40
|
-
const execution_type = String(executionIntent.execution_type || executionIntent.executionType || '').trim();
|
|
41
|
-
const execution_purpose = String(executionIntent.execution_purpose || executionIntent.executionPurpose || '').trim();
|
|
42
|
-
if (execution_type || execution_purpose) {
|
|
43
|
-
return {
|
|
44
|
-
...(execution_type ? { execution_type } : {}),
|
|
45
|
-
...(execution_purpose ? { execution_purpose } : {}),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
const normalizedExecutionType = String(executionType || '').trim() || 'implementation_task';
|
|
50
|
-
const normalizedExecutionPurpose = String(executionPurpose || title || '').trim() || 'implementation task';
|
|
51
|
-
return {
|
|
52
|
-
execution_type: normalizedExecutionType,
|
|
53
|
-
execution_purpose: normalizedExecutionPurpose,
|
|
54
|
-
};
|
|
55
|
-
})();
|
|
56
|
-
await client._assertExecutionEligibility({
|
|
57
|
-
claim_id: normalizedClaimId,
|
|
58
|
-
claim_project_id: normalizedClaimProjectId,
|
|
59
|
-
claimed_item_id: normalizedClaimedItemId,
|
|
60
|
-
workflow_run_id: normalizedWorkflowRunId,
|
|
61
|
-
agent_session_id: normalizedAgentSessionId,
|
|
62
|
-
allowed_mutation_surfaces: normalizedAllowedMutationSurfaces,
|
|
63
|
-
acknowledged_reminders: normalizedAcknowledgedReminders || [],
|
|
64
|
-
requested_mutation_surface: 'project_roadmap_task',
|
|
65
|
-
verification_required: true,
|
|
66
|
-
});
|
|
67
|
-
return client._request(`/api/operator/implementation-items/${implementationItemId}/tasks`, {
|
|
68
|
-
method: 'POST',
|
|
69
|
-
body: {
|
|
70
|
-
title,
|
|
71
|
-
implementation_packet_id: implementationPacketId,
|
|
72
|
-
description,
|
|
73
|
-
priority,
|
|
74
|
-
assigned_to: assignedTo,
|
|
75
|
-
assigned_by: assignedBy,
|
|
76
|
-
due_at: dueAt,
|
|
77
|
-
sort_order: sortOrder,
|
|
78
|
-
notes,
|
|
79
|
-
created_by: createdBy,
|
|
80
|
-
parent_task_id: parentTaskId,
|
|
81
|
-
claim_id: normalizedClaimId,
|
|
82
|
-
claim_project_id: normalizedClaimProjectId,
|
|
83
|
-
claimed_item_id: normalizedClaimedItemId,
|
|
84
|
-
workflow_run_id: normalizedWorkflowRunId,
|
|
85
|
-
agent_session_id: normalizedAgentSessionId,
|
|
86
|
-
allowed_mutation_surfaces: normalizedAllowedMutationSurfaces,
|
|
87
|
-
acknowledged_reminders: normalizedAcknowledgedReminders,
|
|
88
|
-
execution_intent: normalizedExecutionIntent,
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
},
|
|
6
|
+
createImplementationTask: (implementationItemId, request) => client.implementationTasks.createImplementationTask(implementationItemId, request),
|
|
92
7
|
listImplementationTasks: (implementationItemId) => client._request(`/api/operator/implementation-items/${implementationItemId}/tasks`),
|
|
93
8
|
listImplementationSubtasks: (taskId) => client._request(`/api/operator/implementation-item-tasks/${taskId}/subtasks`),
|
|
94
9
|
updateImplementationTask: (taskId, updates) => client._request(`/api/operator/implementation-item-tasks/${taskId}`, {
|
|
@@ -103,5 +18,83 @@ export function createImplementationItemsDomain(client) {
|
|
|
103
18
|
method: 'POST',
|
|
104
19
|
body: { completed_by: request.completedBy },
|
|
105
20
|
}),
|
|
21
|
+
updateImplementationItemStatus: async (implementationItemId, body) => {
|
|
22
|
+
await client._assertExecutionEligibility({
|
|
23
|
+
...(body || {}),
|
|
24
|
+
claimed_item_id: body?.claimed_item_id || implementationItemId,
|
|
25
|
+
requested_mutation_surface: body?.requested_mutation_surface || 'implementation_packet_item',
|
|
26
|
+
verification_required: true,
|
|
27
|
+
});
|
|
28
|
+
const result = await client._request(`/api/governed-implementation/items/${implementationItemId}/status`, {
|
|
29
|
+
method: 'PATCH', body,
|
|
30
|
+
});
|
|
31
|
+
const expectedStatus = cleanText(body?.status);
|
|
32
|
+
const authoritativeItem = isPlainObject(result?.implementation_item) ? result.implementation_item : null;
|
|
33
|
+
const actualStatus = cleanText(authoritativeItem?.status);
|
|
34
|
+
if (expectedStatus && !authoritativeItem) {
|
|
35
|
+
throw buildVerificationError(
|
|
36
|
+
`updateImplementationItemStatus did not return authoritative item state for ${implementationItemId}.`,
|
|
37
|
+
{
|
|
38
|
+
mutation_name: 'updateImplementationItemStatus',
|
|
39
|
+
mutation_attempted: true,
|
|
40
|
+
authoritative_read_performed: false,
|
|
41
|
+
post_condition_verified: false,
|
|
42
|
+
expected_state: { status: expectedStatus },
|
|
43
|
+
mutation_result: result ?? null,
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (expectedStatus && actualStatus !== expectedStatus) {
|
|
48
|
+
throw buildVerificationError(
|
|
49
|
+
`updateImplementationItemStatus returned ${actualStatus ?? 'unknown'} instead of ${expectedStatus}.`,
|
|
50
|
+
{
|
|
51
|
+
mutation_name: 'updateImplementationItemStatus',
|
|
52
|
+
mutation_attempted: true,
|
|
53
|
+
authoritative_read_performed: true,
|
|
54
|
+
post_condition_verified: false,
|
|
55
|
+
expected_state: { status: expectedStatus },
|
|
56
|
+
verified_current_state: authoritativeItem ?? result ?? null,
|
|
57
|
+
mutation_result: result ?? null,
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
},
|
|
63
|
+
updateImplementationItemStatusVerified: (implementationItemId, status, body = {}) => executeVerifiedMutation({
|
|
64
|
+
mutationName: 'updateImplementationItemStatus',
|
|
65
|
+
evidenceLabel: `implementation-item-status:${implementationItemId}`,
|
|
66
|
+
mutationFn: () => client.updateImplementationItemStatus(implementationItemId, { ...body, status }),
|
|
67
|
+
verificationFn: async (mutationResult) => {
|
|
68
|
+
const workflowId = cleanText(body.workflowId)
|
|
69
|
+
|| cleanText(body.workflow_id)
|
|
70
|
+
|| cleanText(mutationResult?.workflow_id);
|
|
71
|
+
if (!workflowId) {
|
|
72
|
+
throw new Error('workflowId is required to verify implementation item status.');
|
|
73
|
+
}
|
|
74
|
+
const roadmap = await client.getWorkflowImplementationRoadmap(workflowId);
|
|
75
|
+
const items = Array.isArray(roadmap?.items) ? roadmap.items : [];
|
|
76
|
+
const matchedItem = items.find((item) => item?.implementation_item_id === implementationItemId) || null;
|
|
77
|
+
return {
|
|
78
|
+
workflow_id: workflowId,
|
|
79
|
+
item: matchedItem,
|
|
80
|
+
roadmap,
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
expectedState: (verificationResult) => {
|
|
84
|
+
const item = verificationResult?.item || null;
|
|
85
|
+
if (!item) {
|
|
86
|
+
return {
|
|
87
|
+
ok: false,
|
|
88
|
+
message: `Implementation item ${implementationItemId} was not present in the authoritative roadmap read.`,
|
|
89
|
+
verifiedCurrentState: verificationResult,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
ok: item.status === status,
|
|
94
|
+
message: `Implementation item ${implementationItemId} status remained ${item.status ?? 'unknown'} after mutation attempt.`,
|
|
95
|
+
verifiedCurrentState: item,
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
}),
|
|
106
99
|
};
|
|
107
100
|
}
|