@company-semantics/contracts 0.88.0 → 0.90.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@company-semantics/contracts",
3
- "version": "0.88.0",
3
+ "version": "0.90.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,7 +8,6 @@ import {
8
8
  } from '../status.js'
9
9
  import { LIFECYCLE_DECISIONS, applyIntent } from '../lifecycle.js'
10
10
  import type { ExecutionErrorCode } from '../errors.js'
11
- import { ExecutionError } from '../errors.js'
12
11
  import { parseExpiresAt, isConfirmationExpired } from '../expiry.js'
13
12
 
14
13
  const ALL_STATES: ExecutionState[] = [
@@ -108,6 +107,20 @@ describe('decision table key consistency', () => {
108
107
  const decisionKeys = Object.keys(LIFECYCLE_DECISIONS.confirm).sort()
109
108
  expect(decisionKeys).toEqual(transitionKeys)
110
109
  })
110
+
111
+ it('LIFECYCLE_DECISIONS.reject keys match VALID_TRANSITIONS keys', () => {
112
+ const transitionKeys = Object.keys(VALID_TRANSITIONS).sort()
113
+ const decisionKeys = Object.keys(LIFECYCLE_DECISIONS.reject).sort()
114
+ expect(decisionKeys).toEqual(transitionKeys)
115
+ })
116
+
117
+ it('all intent rows have the same set of state keys', () => {
118
+ const intents = Object.keys(LIFECYCLE_DECISIONS) as Array<keyof typeof LIFECYCLE_DECISIONS>
119
+ const referenceKeys = Object.keys(LIFECYCLE_DECISIONS[intents[0]]).sort()
120
+ for (const intent of intents) {
121
+ expect(Object.keys(LIFECYCLE_DECISIONS[intent]).sort()).toEqual(referenceKeys)
122
+ }
123
+ })
111
124
  })
112
125
 
113
126
  // ---------------------------------------------------------------------------
@@ -158,48 +171,37 @@ describe('applyIntent', () => {
158
171
  it('undone + confirm = conflict', () => {
159
172
  expect(applyIntent('undone', 'confirm')).toBe('conflict')
160
173
  })
161
- })
162
-
163
- // ---------------------------------------------------------------------------
164
- // 7. EXECUTION_ERROR TESTS
165
- // ---------------------------------------------------------------------------
166
- describe('ExecutionError', () => {
167
- it('has correct name', () => {
168
- const err = new ExecutionError('execution_expired', 'test', 410)
169
- expect(err.name).toBe('ExecutionError')
170
- })
171
174
 
172
- it('has correct code', () => {
173
- const err = new ExecutionError('execution_invalid_transition', 'bad transition', 409)
174
- expect(err.code).toBe('execution_invalid_transition')
175
+ it('pending_confirmation + reject = approve', () => {
176
+ expect(applyIntent('pending_confirmation', 'reject')).toBe('approve')
175
177
  })
176
178
 
177
- it('has correct message', () => {
178
- const err = new ExecutionError('execution_not_found', 'not found', 404)
179
- expect(err.message).toBe('not found')
179
+ it('expired + reject = expired', () => {
180
+ expect(applyIntent('expired', 'reject')).toBe('expired')
180
181
  })
181
182
 
182
- it('has correct httpStatus', () => {
183
- const err = new ExecutionError('execution_forbidden', 'forbidden', 403)
184
- expect(err.httpStatus).toBe(403)
183
+ it('cancelled + reject = conflict', () => {
184
+ expect(applyIntent('cancelled', 'reject')).toBe('conflict')
185
185
  })
186
186
 
187
- it('httpStatus is optional', () => {
188
- const err = new ExecutionError('execution_expired', 'expired')
189
- expect(err.httpStatus).toBeUndefined()
187
+ it('ready + reject = conflict', () => {
188
+ expect(applyIntent('ready', 'reject')).toBe('conflict')
190
189
  })
191
190
 
192
- it('instanceof Error works', () => {
193
- const err = new ExecutionError('execution_expired', 'expired', 410)
194
- expect(err).toBeInstanceOf(Error)
191
+ it('executing + reject = conflict', () => {
192
+ expect(applyIntent('executing', 'reject')).toBe('conflict')
195
193
  })
196
194
 
197
- it('instanceof ExecutionError works', () => {
198
- const err = new ExecutionError('execution_expired', 'expired', 410)
199
- expect(err).toBeInstanceOf(ExecutionError)
195
+ it('completed + reject = conflict', () => {
196
+ expect(applyIntent('completed', 'reject')).toBe('conflict')
200
197
  })
198
+ })
201
199
 
202
- it('supports all error codes', () => {
200
+ // ---------------------------------------------------------------------------
201
+ // 7. EXECUTION_ERROR TYPE TESTS
202
+ // ---------------------------------------------------------------------------
203
+ describe('ExecutionErrorCode', () => {
204
+ it('covers all expected error codes', () => {
203
205
  const codes: ExecutionErrorCode[] = [
204
206
  'execution_expired',
205
207
  'execution_already_confirmed',
@@ -208,11 +210,7 @@ describe('ExecutionError', () => {
208
210
  'execution_forbidden',
209
211
  'execution_invalid_transition',
210
212
  ]
211
- for (const code of codes) {
212
- const err = new ExecutionError(code, `msg-${code}`)
213
- expect(err.code).toBe(code)
214
- expect(err.name).toBe('ExecutionError')
215
- }
213
+ expect(codes).toHaveLength(6)
216
214
  })
217
215
  })
218
216
 
@@ -6,13 +6,8 @@ export type ExecutionErrorCode =
6
6
  | 'execution_forbidden'
7
7
  | 'execution_invalid_transition';
8
8
 
9
- export class ExecutionError extends Error {
10
- constructor(
11
- public readonly code: ExecutionErrorCode,
12
- message: string,
13
- public readonly httpStatus?: number,
14
- ) {
15
- super(message);
16
- this.name = 'ExecutionError';
17
- }
9
+ export interface ExecutionError {
10
+ readonly name: 'ExecutionError';
11
+ readonly code: ExecutionErrorCode;
12
+ readonly message: string;
18
13
  }
@@ -103,8 +103,7 @@ export { parseExpiresAt, isConfirmationExpired } from './expiry'
103
103
  // Error Types
104
104
  // =============================================================================
105
105
 
106
- export type { ExecutionErrorCode } from './errors'
107
- export { ExecutionError } from './errors'
106
+ export type { ExecutionErrorCode, ExecutionError } from './errors'
108
107
 
109
108
  // =============================================================================
110
109
  // Definition Types
@@ -1,6 +1,6 @@
1
1
  import type { ExecutionState } from './status';
2
2
 
3
- export type ExecutionIntent = 'confirm';
3
+ export type ExecutionIntent = 'confirm' | 'reject';
4
4
 
5
5
  export type LifecycleDecision =
6
6
  | 'approve'
@@ -29,6 +29,20 @@ export const LIFECYCLE_DECISIONS: DecisionTable = {
29
29
  failed_with_partial_execution: 'conflict',
30
30
  undone: 'conflict',
31
31
  },
32
+ reject: {
33
+ pending_confirmation: 'approve',
34
+ expired: 'expired',
35
+ cancelled: 'conflict',
36
+ blocked_pending_approval: 'conflict',
37
+ ready: 'conflict',
38
+ executing: 'conflict',
39
+ completed: 'conflict',
40
+ completed_with_rollbacks: 'conflict',
41
+ failed_retryable: 'conflict',
42
+ failed_terminal: 'conflict',
43
+ failed_with_partial_execution: 'conflict',
44
+ undone: 'conflict',
45
+ },
32
46
  };
33
47
 
34
48
  export function applyIntent(
package/src/index.ts CHANGED
@@ -2,11 +2,10 @@
2
2
  * @company-semantics/contracts
3
3
  *
4
4
  * Shared semantic vocabulary across Company Semantics codebases.
5
- * Types only - no runtime code, no business logic.
5
+ * Types and pure deterministic functions — no runtime code, no business logic.
6
6
  *
7
- * This package intentionally contains only minimal shared vocabulary,
8
- * not full domain models. Structural types live in individual codebases
9
- * until they are proven stable.
7
+ * This package contains shared vocabulary and pure derivation functions.
8
+ * Structural types live in individual codebases until they are proven stable.
10
9
  *
11
10
  * @see https://github.com/company-semantics/company-semantics-contracts
12
11
  */
@@ -466,6 +465,14 @@ export type {
466
465
  UsageByFeature,
467
466
  UsageByUser,
468
467
  OrgUsageResponse,
468
+ // Unified usage types (PRD-00276/277)
469
+ UnifiedUsageSummary,
470
+ UnifiedDailyUsage,
471
+ UnifiedProfileUsage,
472
+ UnifiedUserUsage,
473
+ UnifiedModelUsage,
474
+ UnifiedFeatureUsage,
475
+ UnifiedUsageResponse,
469
476
  } from './usage/types'
470
477
 
471
478
  // Runtime execution telemetry types
package/src/mcp/index.ts CHANGED
@@ -215,7 +215,7 @@ export interface MCPToolDescriptor {
215
215
  * Edge in the capability graph connecting two tools via a resource.
216
216
  * A tool that produces a resource connects to tools that consume it.
217
217
  *
218
- * @stub Implementation in PRD-00268 (buildCapabilityGraph)
218
+ * @see capability-graph.ts for buildCapabilityGraph() implementation
219
219
  */
220
220
  export interface CapabilityGraphEdge {
221
221
  /** Tool ID that produces the resource */
@@ -232,7 +232,7 @@ export interface CapabilityGraphEdge {
232
232
  * Named workflow derived from capability graph paths.
233
233
  * Represents a common multi-tool sequence (e.g., "Connect Slack → Ingest → Query").
234
234
  *
235
- * @stub Implementation in PRD-00268 (buildCapabilityGraph)
235
+ * @see capability-graph.ts for buildCapabilityGraph() implementation
236
236
  */
237
237
  export interface ToolWorkflow {
238
238
  /** Workflow name (e.g., "Slack Onboarding") */
@@ -247,7 +247,7 @@ export interface ToolWorkflow {
247
247
  * Capability graph derived from tool resource flow metadata.
248
248
  * Built from produces/consumes fields on MCPToolDescriptor.
249
249
  *
250
- * @stub Type definition only. buildCapabilityGraph() ships in PRD-00268.
250
+ * @see capability-graph.ts for buildCapabilityGraph() implementation
251
251
  */
252
252
  export interface CapabilityGraph {
253
253
  /** Resource flow edges between tools */
@@ -270,7 +270,7 @@ export interface ToolDiscoveryResponse {
270
270
  * Capability graph derived from tool resource flow metadata.
271
271
  * Optional — discovery responses may or may not include the computed graph.
272
272
  *
273
- * @stub Graph computation ships in PRD-00268 (buildCapabilityGraph).
273
+ * @see capability-graph.ts for buildCapabilityGraph() implementation
274
274
  */
275
275
  graph?: CapabilityGraph
276
276
  }
@@ -46,6 +46,9 @@ export interface UsageByUser {
46
46
  requestCount: number;
47
47
  }
48
48
 
49
+ /**
50
+ * @deprecated Use UnifiedUsageResponse instead. Will be removed in v1.0.
51
+ */
49
52
  export interface OrgUsageResponse {
50
53
  summary: UsageSummary;
51
54
  daily: DailyUsage[];
@@ -53,3 +56,64 @@ export interface OrgUsageResponse {
53
56
  byFeature: UsageByFeature[];
54
57
  topUsers: UsageByUser[];
55
58
  }
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // Unified Usage Response (PRD-00276/277)
62
+ // ---------------------------------------------------------------------------
63
+
64
+ export interface UnifiedUsageSummary {
65
+ executions: number;
66
+ totalCostUsd: string;
67
+ totalTokens: number;
68
+ avgDurationMs: number;
69
+ failureRate: number;
70
+ }
71
+
72
+ export interface UnifiedDailyUsage {
73
+ date: string;
74
+ executions: number;
75
+ totalCostUsd: string;
76
+ }
77
+
78
+ export interface UnifiedProfileUsage {
79
+ profile: string;
80
+ executions: number;
81
+ percentOfTotal: number;
82
+ totalCostUsd: string;
83
+ avgDurationMs: number;
84
+ failureRate: number;
85
+ }
86
+
87
+ export interface UnifiedUserUsage {
88
+ userId: string;
89
+ email: string;
90
+ executions: number;
91
+ totalCostUsd: string;
92
+ totalTokens: number;
93
+ favoriteProfile: string;
94
+ }
95
+
96
+ export interface UnifiedModelUsage {
97
+ model: string;
98
+ provider: string;
99
+ totalTokens: number;
100
+ estimatedCostUsd: string;
101
+ requestCount: number;
102
+ }
103
+
104
+ export interface UnifiedFeatureUsage {
105
+ feature: string;
106
+ totalTokens: number;
107
+ estimatedCostUsd: string;
108
+ requestCount: number;
109
+ }
110
+
111
+ export interface UnifiedUsageResponse {
112
+ period: { start: string; end: string };
113
+ summary: UnifiedUsageSummary;
114
+ daily: UnifiedDailyUsage[];
115
+ byProfile: UnifiedProfileUsage[];
116
+ byUser: UnifiedUserUsage[];
117
+ byModel: UnifiedModelUsage[];
118
+ byFeature: UnifiedFeatureUsage[];
119
+ }