@company-semantics/contracts 0.41.1 → 0.43.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.41.1",
3
+ "version": "0.43.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -32,6 +32,10 @@
32
32
  "types": "./src/execution/index.ts",
33
33
  "default": "./src/execution/index.ts"
34
34
  },
35
+ "./email": {
36
+ "types": "./src/email/index.ts",
37
+ "default": "./src/email/index.ts"
38
+ },
35
39
  "./schemas/guard-result.schema.json": "./schemas/guard-result.schema.json"
36
40
  },
37
41
  "types": "./src/index.ts",
@@ -0,0 +1,38 @@
1
+ /**
2
+ * CI Envelope Types Barrel
3
+ *
4
+ * Re-exports all CI execution envelope vocabulary types.
5
+ * Import from '@company-semantics/contracts/ci-envelope' or '@company-semantics/contracts'.
6
+ *
7
+ * Note: This module exports types only (no runtime code per contracts policy).
8
+ * Builder, validation, and policy logic live in company-semantics-ci/envelope/.
9
+ *
10
+ * @see ADR-CONT-033 for contracts boundary rationale
11
+ */
12
+
13
+ // Types
14
+ export type {
15
+ // Actor & Session
16
+ CIActorInfo,
17
+ CISessionInfo,
18
+ // Intent
19
+ ExecutionIntent,
20
+ CIIntentDeclaration,
21
+ // Scope
22
+ CIChangeKind,
23
+ CIExecutionScope,
24
+ // Authority
25
+ CIAuthorityGrant,
26
+ // Guard Plan
27
+ CIGuardPlan,
28
+ // Status
29
+ CIEnvelopeStatus,
30
+ // Outcome
31
+ CIGuardViolation,
32
+ CIExecutionOutcome,
33
+ // Core Envelope
34
+ CIExecutionEnvelope,
35
+ } from './types';
36
+
37
+ // Constants (documentation/type-level, not runtime)
38
+ export { ENVELOPE_TRANSITIONS } from './types';
@@ -0,0 +1,216 @@
1
+ /**
2
+ * CI Execution Envelope Type Vocabulary (v1.0.0)
3
+ *
4
+ * Canonical types for CI execution envelopes — first-class, append-only records
5
+ * that capture AI intent, scope, and authority before mutations occur.
6
+ *
7
+ * Design invariants:
8
+ * - Types only — no validation logic, no policy mappings (those live in CI repo)
9
+ * - Envelope is append-only (status transitions, no field deletions)
10
+ * - Schema version enables future migration
11
+ *
12
+ * @see ADR-CONT-033 for design rationale
13
+ * @see company-semantics-ci/envelope/ for builder and validation logic
14
+ */
15
+
16
+ // =============================================================================
17
+ // Actor & Session Types
18
+ // =============================================================================
19
+
20
+ /**
21
+ * Actor information for audit trail.
22
+ * Currently Claude-only, extensible for future actor types.
23
+ */
24
+ export type CIActorInfo = {
25
+ kind: 'claude';
26
+ model: string;
27
+ };
28
+
29
+ /**
30
+ * Session context for correlating envelope to conversation.
31
+ */
32
+ export type CISessionInfo = {
33
+ conversationId: string;
34
+ turnId: string;
35
+ };
36
+
37
+ // =============================================================================
38
+ // Intent Types
39
+ // =============================================================================
40
+
41
+ /**
42
+ * Execution intent categories.
43
+ * Defines the semantic "why" of an execution.
44
+ *
45
+ * Note: Policy mappings (intent → required guards) live in CI repo,
46
+ * not here. This type defines vocabulary only.
47
+ */
48
+ export type ExecutionIntent =
49
+ | 'feature_extension'
50
+ | 'bug_fix'
51
+ | 'refactor_structural'
52
+ | 'guard_update'
53
+ | 'policy_update'
54
+ | 'schema_change'
55
+ | 'doc_update'
56
+ | 'cleanup'
57
+ | 'experimental';
58
+
59
+ /**
60
+ * Intent declaration with optional ADR references.
61
+ */
62
+ export type CIIntentDeclaration = {
63
+ primary: ExecutionIntent;
64
+ secondary?: ExecutionIntent[];
65
+ description: string;
66
+ adrRefs?: string[];
67
+ };
68
+
69
+ // =============================================================================
70
+ // Scope Types
71
+ // =============================================================================
72
+
73
+ /**
74
+ * Change kind for scope declarations.
75
+ */
76
+ export type CIChangeKind = 'add' | 'modify' | 'delete';
77
+
78
+ /**
79
+ * Execution scope defining affected repos and paths.
80
+ */
81
+ export type CIExecutionScope = {
82
+ repos: string[];
83
+ /** Glob patterns for affected paths */
84
+ paths: string[];
85
+ changeKinds: CIChangeKind[];
86
+ };
87
+
88
+ // =============================================================================
89
+ // Authority Types
90
+ // =============================================================================
91
+
92
+ /**
93
+ * Authority grant documenting permission basis.
94
+ */
95
+ export type CIAuthorityGrant = {
96
+ /** References to CLAUDE.md / AI_AUTONOMY.md sections */
97
+ allowedBy: string[];
98
+ requiresConfirmation: boolean;
99
+ };
100
+
101
+ // =============================================================================
102
+ // Guard Plan Types
103
+ // =============================================================================
104
+
105
+ /**
106
+ * Guard execution plan resolved from intent + scope.
107
+ * Populated by guard plan resolver in CI repo.
108
+ */
109
+ export type CIGuardPlan = {
110
+ /** Guard IDs that MUST pass */
111
+ required: string[];
112
+ /** Guard IDs allowed to warn (advisory) */
113
+ advisory: string[];
114
+ };
115
+
116
+ // =============================================================================
117
+ // Status Types
118
+ // =============================================================================
119
+
120
+ /**
121
+ * Envelope lifecycle status.
122
+ *
123
+ * State machine:
124
+ * - proposed → validated | blocked
125
+ * - validated → executing | blocked
126
+ * - executing → finalized | blocked
127
+ * - blocked → (terminal)
128
+ * - finalized → (terminal)
129
+ *
130
+ * Note: Transition validation logic lives in CI repo, not here.
131
+ */
132
+ export type CIEnvelopeStatus =
133
+ | 'proposed'
134
+ | 'validated'
135
+ | 'blocked'
136
+ | 'executing'
137
+ | 'finalized';
138
+
139
+ // =============================================================================
140
+ // Outcome Types
141
+ // =============================================================================
142
+
143
+ /**
144
+ * A single guard violation for post-execution audit.
145
+ */
146
+ export type CIGuardViolation = {
147
+ guardId: string;
148
+ severity: 'error' | 'warning';
149
+ message: string;
150
+ file?: string;
151
+ line?: number;
152
+ };
153
+
154
+ /**
155
+ * Execution outcome populated on finalization.
156
+ */
157
+ export type CIExecutionOutcome = {
158
+ filesChanged: number;
159
+ commits: string[];
160
+ violations?: CIGuardViolation[];
161
+ };
162
+
163
+ // =============================================================================
164
+ // Core Envelope Type
165
+ // =============================================================================
166
+
167
+ /**
168
+ * CI Execution Envelope — the atomic unit of governed execution.
169
+ *
170
+ * Created before mutations, finalized after. Enables:
171
+ * - Pre-execution gating (intent/scope/authority check)
172
+ * - Post-hoc audit (what was planned vs what happened)
173
+ * - Deterministic explanation (no LLM guesswork)
174
+ */
175
+ export type CIExecutionEnvelope = {
176
+ /** Schema version for migration (bump on breaking changes) */
177
+ envelopeVersion: 1;
178
+ /** Unique identifier (UUID v7 recommended) */
179
+ executionId: string;
180
+ /** ISO 8601 timestamp */
181
+ createdAt: string;
182
+ actor: CIActorInfo;
183
+ session: CISessionInfo;
184
+ intent: CIIntentDeclaration;
185
+ scope: CIExecutionScope;
186
+ authority: CIAuthorityGrant;
187
+ guardPlan: CIGuardPlan;
188
+ status: CIEnvelopeStatus;
189
+ /** Structured reason when status='blocked' */
190
+ blockedReason?: string;
191
+ /** Populated on finalization */
192
+ outcome?: CIExecutionOutcome;
193
+ };
194
+
195
+ // =============================================================================
196
+ // Transition Graph (Documentation Only)
197
+ // =============================================================================
198
+
199
+ /**
200
+ * Valid status transitions (documentation only).
201
+ *
202
+ * This const documents the state machine for reference.
203
+ * Actual transition validation logic lives in CI repo.
204
+ *
205
+ * Terminal states: blocked, finalized (empty transition arrays)
206
+ */
207
+ export const ENVELOPE_TRANSITIONS: Record<
208
+ CIEnvelopeStatus,
209
+ readonly CIEnvelopeStatus[]
210
+ > = {
211
+ proposed: ['validated', 'blocked'],
212
+ validated: ['executing', 'blocked'],
213
+ blocked: [],
214
+ executing: ['finalized', 'blocked'],
215
+ finalized: [],
216
+ } as const;
@@ -0,0 +1,35 @@
1
+ # email/
2
+
3
+ ## Purpose
4
+
5
+ TypeScript types and registry for transactional email kinds and their metadata.
6
+
7
+ ## Invariants
8
+
9
+ - Types only; minimal runtime code (pure functions for registry lookup)
10
+ - No external dependencies (contracts policy)
11
+ - `EmailKind` union MUST match keys in `EMAIL_KINDS` registry
12
+ - `EMAIL_KINDS` is the single source of truth for subjects and rendering rules
13
+ - OTP values MUST NEVER appear in contracts (security: logged if leaked)
14
+ - Subjects are owned by the registry, never duplicated in templates
15
+ - Unknown email kinds MUST be rejected at API boundaries via `isValidEmailKind()`
16
+
17
+ ## Public API
18
+
19
+ ### Types
20
+
21
+ - `EmailKind` — Union of valid email kind identifiers
22
+ - `EmailPayloads` — Type-safe payload mapping for each kind
23
+ - `SendEmailInput<K>` — Type-safe input for sending emails
24
+ - `EmailKindDefinition` — Full definition schema for a kind
25
+
26
+ ### Registry & Functions
27
+
28
+ - `EMAIL_KINDS` — Registry of all email kinds
29
+ - `getEmailKindDefinition(kind)` — Type-safe registry lookup
30
+ - `isValidEmailKind(kind)` — Validate string is EmailKind
31
+
32
+ ## Dependencies
33
+
34
+ **Imports from:** (none — leaf module)
35
+ **Imported by:** company-semantics-backend (email service, templates)
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Email Domain Barrel
3
+ *
4
+ * Re-exports email kind vocabulary types and registry.
5
+ * Import from '@company-semantics/contracts/email'.
6
+ *
7
+ * @see ADR-CONT-034 for design rationale
8
+ */
9
+
10
+ // =============================================================================
11
+ // Kind Types
12
+ // =============================================================================
13
+
14
+ export type { EmailKind, EmailPayloads, SendEmailInput } from './types'
15
+
16
+ // =============================================================================
17
+ // Definition Types
18
+ // =============================================================================
19
+
20
+ export type { EmailKindDefinition } from './registry'
21
+
22
+ // =============================================================================
23
+ // Registry
24
+ // =============================================================================
25
+
26
+ export {
27
+ EMAIL_KINDS,
28
+ getEmailKindDefinition,
29
+ isValidEmailKind,
30
+ } from './registry'
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Email Kind Registry
3
+ *
4
+ * Central registry of all email kinds and their definitions.
5
+ * This is the single source of truth for email metadata.
6
+ *
7
+ * Invariants:
8
+ * - Every EmailKind MUST have an entry in EMAIL_KINDS
9
+ * - Registry keys MUST match definition.kind
10
+ * - Registry is exhaustive (satisfies Record<EmailKind, ...>)
11
+ * - Subjects are owned here, not duplicated in templates
12
+ *
13
+ * @see ADR-CONT-034 for design rationale
14
+ */
15
+
16
+ import type { EmailKind } from './types'
17
+
18
+ // =============================================================================
19
+ // Email Kind Definition
20
+ // =============================================================================
21
+
22
+ /**
23
+ * Complete definition for an email kind.
24
+ *
25
+ * This interface is the schema for entries in EMAIL_KINDS registry.
26
+ * It captures subject, rendering requirements, and domain metadata.
27
+ *
28
+ * Invariants:
29
+ * - kind field MUST match the registry key
30
+ * - subject is the authoritative source (templates import from here)
31
+ */
32
+ export interface EmailKindDefinition {
33
+ /** The email kind this definition describes */
34
+ kind: EmailKind
35
+ /** Email subject line (single source of truth) */
36
+ subject: string
37
+ /** Whether plain text body is required */
38
+ plainTextRequired: boolean
39
+ /** Whether HTML body is supported */
40
+ htmlSupported: boolean
41
+ }
42
+
43
+ // =============================================================================
44
+ // Registry
45
+ // =============================================================================
46
+
47
+ /**
48
+ * EMAIL_KINDS is the authoritative registry.
49
+ *
50
+ * All subjects, rendering rules, and domain metadata are derived from here.
51
+ * Backend email templates MUST use this registry for subjects
52
+ * rather than hardcoding values.
53
+ *
54
+ * To add a new kind:
55
+ * 1. Add to EmailKind union in types.ts
56
+ * 2. Add entry to this registry
57
+ * 3. Add payload to EmailPayloads if needed
58
+ * 4. Implement template in backend
59
+ */
60
+ export const EMAIL_KINDS = {
61
+ 'auth.otp': {
62
+ kind: 'auth.otp',
63
+ subject: 'Your login code',
64
+ plainTextRequired: true,
65
+ htmlSupported: false,
66
+ },
67
+ 'auth.magic_link': {
68
+ kind: 'auth.magic_link',
69
+ subject: 'Your login link',
70
+ plainTextRequired: true,
71
+ htmlSupported: false,
72
+ },
73
+ 'org.invite': {
74
+ kind: 'org.invite',
75
+ subject: 'You have been invited to join a workspace',
76
+ plainTextRequired: true,
77
+ htmlSupported: true,
78
+ },
79
+ 'security.alert': {
80
+ kind: 'security.alert',
81
+ subject: 'Security alert for your account',
82
+ plainTextRequired: true,
83
+ htmlSupported: false,
84
+ },
85
+ } as const satisfies Record<EmailKind, EmailKindDefinition>
86
+
87
+ // =============================================================================
88
+ // Registry Helpers
89
+ // =============================================================================
90
+
91
+ /**
92
+ * Type-safe registry lookup.
93
+ * Returns the definition for a given email kind.
94
+ */
95
+ export function getEmailKindDefinition(kind: EmailKind): EmailKindDefinition {
96
+ return EMAIL_KINDS[kind]
97
+ }
98
+
99
+ /**
100
+ * Check if a string is a valid EmailKind.
101
+ * Use at API boundaries to reject unknown kinds.
102
+ */
103
+ export function isValidEmailKind(kind: string): kind is EmailKind {
104
+ return kind in EMAIL_KINDS
105
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Email Domain Types
3
+ *
4
+ * Shared types for transactional email across Company Semantics codebases.
5
+ * Types only - no runtime code, no business logic.
6
+ *
7
+ * @see ADR-CONT-034 for design rationale
8
+ */
9
+
10
+ // =============================================================================
11
+ // EmailKind Union
12
+ // =============================================================================
13
+
14
+ /**
15
+ * EmailKind identifies the type of transactional email.
16
+ *
17
+ * Naming convention: `{domain}.{type}`
18
+ * - domain: auth, org, security
19
+ * - type: specific email variant
20
+ *
21
+ * New kinds MUST be added to:
22
+ * 1. This union type
23
+ * 2. EMAIL_KINDS registry in registry.ts
24
+ * 3. EmailPayloads interface (if kind has payload)
25
+ */
26
+ export type EmailKind =
27
+ | 'auth.otp'
28
+ | 'auth.magic_link' // future
29
+ | 'org.invite' // future
30
+ | 'security.alert' // future
31
+
32
+ // =============================================================================
33
+ // Email Payloads
34
+ // =============================================================================
35
+
36
+ /**
37
+ * Type-safe payload mapping for each email kind.
38
+ *
39
+ * Each key is an EmailKind, and the value is the required payload shape.
40
+ * Kinds without entries here have empty payloads.
41
+ */
42
+ export interface EmailPayloads {
43
+ 'auth.otp': {
44
+ /** The 6-digit OTP code */
45
+ otp: string
46
+ /** How long until the code expires */
47
+ expiresInMinutes: number
48
+ /** IP address of the request (for security context) */
49
+ requestIp?: string
50
+ /** User agent of the request (for security context) */
51
+ userAgent?: string
52
+ }
53
+ }
54
+
55
+ // =============================================================================
56
+ // Send Email Input
57
+ // =============================================================================
58
+
59
+ /**
60
+ * Type-safe input for sending emails.
61
+ *
62
+ * The payload type is inferred from the kind.
63
+ * If the kind is in EmailPayloads, that payload is required.
64
+ */
65
+ export interface SendEmailInput<K extends EmailKind> {
66
+ /** The type of email to send */
67
+ kind: K
68
+ /** Recipient email address (will be normalized) */
69
+ to: string
70
+ /** Type-safe payload for this email kind */
71
+ payload: K extends keyof EmailPayloads ? EmailPayloads[K] : never
72
+ /** Idempotency key to prevent duplicate sends */
73
+ idempotencyKey: string
74
+ }
package/src/index.ts CHANGED
@@ -112,6 +112,21 @@ export { extractFirstWord, resolveDisplayName, deriveFullName } from './identity
112
112
  // Auth domain types
113
113
  export { OTPErrorCode } from './auth/index'
114
114
 
115
+ // Email domain types
116
+ // @see ADR-CONT-034 for design rationale
117
+ export type {
118
+ EmailKind,
119
+ EmailPayloads,
120
+ SendEmailInput,
121
+ EmailKindDefinition,
122
+ } from './email/index'
123
+
124
+ export {
125
+ EMAIL_KINDS,
126
+ getEmailKindDefinition,
127
+ isValidEmailKind,
128
+ } from './email/index'
129
+
115
130
  // Organization domain types
116
131
  // @see ADR-BE-XXX for design rationale (Personal vs Shared Organization Model)
117
132
  export type {
@@ -260,3 +275,30 @@ export {
260
275
  getExecutionKindDefinition,
261
276
  isValidExecutionKind,
262
277
  } from './execution/index'
278
+
279
+ // CI Execution Envelope types
280
+ // @see ADR-CONT-033 for contracts boundary rationale
281
+ export type {
282
+ // Actor & Session
283
+ CIActorInfo,
284
+ CISessionInfo,
285
+ // Intent
286
+ ExecutionIntent,
287
+ CIIntentDeclaration,
288
+ // Scope
289
+ CIChangeKind,
290
+ CIExecutionScope,
291
+ // Authority
292
+ CIAuthorityGrant,
293
+ // Guard Plan
294
+ CIGuardPlan,
295
+ // Status
296
+ CIEnvelopeStatus,
297
+ // Outcome
298
+ CIGuardViolation,
299
+ CIExecutionOutcome,
300
+ // Core Envelope
301
+ CIExecutionEnvelope,
302
+ } from './ci-envelope/index'
303
+
304
+ export { ENVELOPE_TRANSITIONS } from './ci-envelope/index'