@synoi/gap 0.1.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.
Files changed (58) hide show
  1. package/LICENSE +195 -0
  2. package/README.md +223 -0
  3. package/dist/canonicalize.d.ts +19 -0
  4. package/dist/canonicalize.d.ts.map +1 -0
  5. package/dist/canonicalize.js +36 -0
  6. package/dist/canonicalize.js.map +1 -0
  7. package/dist/capabilities.d.ts +605 -0
  8. package/dist/capabilities.d.ts.map +1 -0
  9. package/dist/capabilities.js +53 -0
  10. package/dist/capabilities.js.map +1 -0
  11. package/dist/cdro.d.ts +63 -0
  12. package/dist/cdro.d.ts.map +1 -0
  13. package/dist/cdro.js +16 -0
  14. package/dist/cdro.js.map +1 -0
  15. package/dist/channels.d.ts +107 -0
  16. package/dist/channels.d.ts.map +1 -0
  17. package/dist/channels.js +29 -0
  18. package/dist/channels.js.map +1 -0
  19. package/dist/constants.d.ts +32 -0
  20. package/dist/constants.d.ts.map +1 -0
  21. package/dist/constants.js +36 -0
  22. package/dist/constants.js.map +1 -0
  23. package/dist/index.d.ts +28 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +35 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/oid.d.ts +28 -0
  28. package/dist/oid.d.ts.map +1 -0
  29. package/dist/oid.js +68 -0
  30. package/dist/oid.js.map +1 -0
  31. package/dist/receipts.d.ts +128 -0
  32. package/dist/receipts.d.ts.map +1 -0
  33. package/dist/receipts.js +14 -0
  34. package/dist/receipts.js.map +1 -0
  35. package/dist/revocations.d.ts +65 -0
  36. package/dist/revocations.d.ts.map +1 -0
  37. package/dist/revocations.js +22 -0
  38. package/dist/revocations.js.map +1 -0
  39. package/dist/validate.d.ts +59 -0
  40. package/dist/validate.d.ts.map +1 -0
  41. package/dist/validate.js +835 -0
  42. package/dist/validate.js.map +1 -0
  43. package/dist/workflows.d.ts +186 -0
  44. package/dist/workflows.d.ts.map +1 -0
  45. package/dist/workflows.js +14 -0
  46. package/dist/workflows.js.map +1 -0
  47. package/package.json +55 -0
  48. package/src/canonicalize.ts +38 -0
  49. package/src/capabilities.ts +711 -0
  50. package/src/cdro.ts +92 -0
  51. package/src/channels.ts +183 -0
  52. package/src/constants.ts +46 -0
  53. package/src/index.ts +180 -0
  54. package/src/oid.ts +71 -0
  55. package/src/receipts.ts +169 -0
  56. package/src/revocations.ts +90 -0
  57. package/src/validate.ts +1008 -0
  58. package/src/workflows.ts +241 -0
@@ -0,0 +1,169 @@
1
+ /**
2
+ * receipts.ts -- GAP Decision Receipts.
3
+ *
4
+ * Every gate decision (capability invocation, workflow transition, grant
5
+ * issuance/revocation, federation handshake (reserved for GAP 1.1), provisional block) produces
6
+ * an immutable Decision Receipt. These are the audit trail of the agent
7
+ * platform -- what was allowed, what was denied, when, and by whom.
8
+ *
9
+ * Mirrors GAP_SPEC §8.
10
+ */
11
+
12
+ import type { GapCdroEnvelope } from './cdro.js'
13
+ import type { GapActorType } from './capabilities.js'
14
+
15
+ export type DecisionSubjectKind =
16
+ | 'capability_invocation'
17
+ | 'stage_transition'
18
+ | 'grant_issued'
19
+ | 'grant_revoked'
20
+ | 'workflow_started'
21
+ | 'workflow_terminated'
22
+ | 'revocation_initiated'
23
+ | 'revocation_effective'
24
+ | 'federation_handshake' // reserved for GAP 1.1 - not part of the active 1.0 conformance surface
25
+ | 'provisional_block'
26
+
27
+ export type DecisionStatus =
28
+ | 'ok'
29
+ | 'denied'
30
+ | 'failed'
31
+ | 'deferred'
32
+ | 'timed_out'
33
+ | 'pending'
34
+ | 'rate_limited'
35
+
36
+ export interface GapDecisionReceiptBody {
37
+ subject_kind: DecisionSubjectKind
38
+ subject_oid: string
39
+ initiator: {
40
+ actor_oid: string
41
+ actor_type: GapActorType
42
+ }
43
+ status: DecisionStatus
44
+ detail?: string
45
+ capability_grant_oids?: string[]
46
+ workflow_instance_oid?: string
47
+ workflow_stage_id?: string
48
+ inference_receipt_oid?: string
49
+ channel_event_oids?: string[]
50
+ initiated_at_ms: number
51
+ resolved_at_ms: number
52
+ metrics?: {
53
+ latency_ms?: number
54
+ channel_count?: number
55
+ listen_match_count?: number
56
+ }
57
+ compliance_tags?: string[]
58
+ /**
59
+ * True when this receipt was served from the idempotency deduplication cache
60
+ * rather than freshly evaluated. The cached args and grant state at the time
61
+ * of original evaluation apply; this is NOT a fresh gate decision.
62
+ */
63
+ is_idempotency_replay?: boolean
64
+ /**
65
+ * The client-supplied `invoked_at_ms` value from the invocation body,
66
+ * preserved here for debugging only. MUST NOT be used as `initiated_at_ms`.
67
+ * The gateway always server-stamps `initiated_at_ms`.
68
+ */
69
+ client_claimed_at_ms?: number
70
+ /**
71
+ * For receipts covering physical_safety=true capabilities: constrained
72
+ * devices performing offline Ed25519 signature verification MUST NOT accept
73
+ * this receipt after this TTL has elapsed (milliseconds since epoch).
74
+ * Absent means no offline TTL is enforced by the protocol (gateway-level
75
+ * policy may still apply).
76
+ */
77
+ max_offline_ttl_ms?: number
78
+ /**
79
+ * For 21 CFR Part 11 contexts: display name, role, and credential identifier
80
+ * of the authorizing human. The `granted_by` actor OID SHOULD resolve to
81
+ * this identity. Gateway-populated when the deployment asserts 21 CFR Part 11
82
+ * compliance and the receipt covers a medical device / clinical capability.
83
+ */
84
+ signer_identity?: {
85
+ display_name: string
86
+ role?: string
87
+ credential_id?: string
88
+ }
89
+ /**
90
+ * C8: Sub-millisecond sequence numbers (GAP spec section Phase 4).
91
+ *
92
+ * Monotonically increasing integer within the tenant, incremented per receipt,
93
+ * gapless. Gaps in the sequence indicate dropped receipts. Provides
94
+ * determinable ordering within a millisecond for high-frequency deployments
95
+ * (MiFID II RTS 25). A gateway MUST guarantee strict monotonicity within a
96
+ * tenant.
97
+ */
98
+ sequence_number?: number
99
+ /**
100
+ * C8: Optional nanoseconds since Unix epoch for sub-millisecond precision.
101
+ * RECOMMENDED for financial.* capabilities. Complements decided_at_ms
102
+ * (the spec's alias for resolved_at_ms) when nanosecond ordering matters.
103
+ */
104
+ decided_at_ns?: number
105
+ /**
106
+ * Item 3 [DESIGN]: Settled token consumption for this invocation. Populated
107
+ * by the gateway post-invoke when the 'token_budget' precondition is active.
108
+ * input_tokens and output_tokens MUST be non-negative integers.
109
+ */
110
+ token_consumption?: TokenConsumption
111
+ }
112
+
113
+ // -- Item 3: Token Consumption -----------------------------------------------
114
+
115
+ /**
116
+ * [DESIGN] Actual token usage settled onto the receipt by the gateway after
117
+ * execution. Used by the 'token_budget' precondition (post_invoke evaluation).
118
+ * Any cost_usd figures are [MODELED] until a conformance vector exists.
119
+ */
120
+ export interface TokenConsumption {
121
+ /** Input (prompt) tokens consumed. Must be a non-negative integer. */
122
+ input_tokens: number
123
+ /** Output (completion) tokens consumed. Must be a non-negative integer. */
124
+ output_tokens: number
125
+ /** Model identifier that produced the tokens. */
126
+ model: string
127
+ /** Estimated cost in USD. [MODELED] -- not authoritative until conformance vector exists. */
128
+ cost_usd?: number
129
+ /** Unix epoch ms when consumption was settled. */
130
+ settled_at_ms: number
131
+ }
132
+
133
+ export type GapDecisionReceipt = GapCdroEnvelope<GapDecisionReceiptBody>
134
+
135
+ // -- Failure typing (non-CDRO; in-process return shape) ----------------------
136
+
137
+ /**
138
+ * In-process failure classification returned by gate helpers and SDK utilities.
139
+ * This is an internal enum and does NOT appear on the wire.
140
+ *
141
+ * The wire `detail` field in `GapDecisionReceipt.body.detail` uses the
142
+ * namespaced error codes from ERROR_CODES.md, for example:
143
+ * capability_denied:no_grant
144
+ * capability_denied:grant_expired
145
+ * capability_denied:grant_revoked
146
+ * capability_denied:rate_limited
147
+ * Do NOT expose GapFailureReason values in serialized receipts or HTTP responses.
148
+ */
149
+ export type GapFailureReason =
150
+ | 'capability_not_found'
151
+ | 'capability_denied'
152
+ | 'capability_revoked'
153
+ | 'precondition_failed'
154
+ | 'rate_limited'
155
+ | 'grant_expired'
156
+ | 'workflow_not_found'
157
+ | 'workflow_revoked'
158
+ | 'missing_required_channels'
159
+ | 'execution_failed'
160
+
161
+ export interface GapFailure {
162
+ reason: GapFailureReason
163
+ detail?: string
164
+ receipt_oid: string
165
+ }
166
+
167
+ export function isGapFailure<T>(r: T | GapFailure): r is GapFailure {
168
+ return typeof r === 'object' && r !== null && 'reason' in (r as Record<string, unknown>)
169
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * revocations.ts -- RevocationEvent CDRO.
3
+ *
4
+ * Revocation in GAP is leveled (L1 / L2 / L3) per GAP_SPEC §7. V1 gateway
5
+ * scope is L1 only; L2/L3 fields are tracked here for forward compatibility.
6
+ *
7
+ * Targets include declarations, grants, workflow definitions, workflow
8
+ * instances, and whole skills. A revocation can be provisional (immediately
9
+ * blocks but pending finalization) or final.
10
+ */
11
+
12
+ import type { GapCdroEnvelope } from './cdro.js'
13
+
14
+ export type RevocationTargetKind =
15
+ | 'capability_declaration'
16
+ | 'capability_grant'
17
+ | 'workflow_definition'
18
+ | 'workflow_instance'
19
+ | 'skill'
20
+
21
+ export interface RevocationEventBody {
22
+ target_kind: RevocationTargetKind
23
+ target_oid: string
24
+ reason: string
25
+ evidence_oids?: string[]
26
+ required_level: 1 | 2 | 3
27
+ provisional: boolean
28
+ approvers: Array<{
29
+ actor_oid: string
30
+ approved_at_ms: number
31
+ cooling_off_satisfied: boolean
32
+ attestation_oid?: string
33
+ }>
34
+ public_notice_started_at_ms?: number
35
+ public_notice_window_ms?: number
36
+ effective_at_ms: number | null
37
+ lifted_at_ms?: number | null
38
+ /**
39
+ * Controls what happens when a provisional block's TTL expires without the
40
+ * required L3 quorum completing:
41
+ * 'renew' -- the block auto-renews (fail-closed). Default, and MUST be
42
+ * the behavior when any targeted grant covers a capability
43
+ * with physical_safety=true or safety_class='C'.
44
+ * 'revert' -- the block expires and the target is re-enabled. Only
45
+ * permissible for safety_class A/B capabilities with explicit
46
+ * operator override.
47
+ *
48
+ * Absent defaults to 'renew' for physical safety targets, 'revert' for
49
+ * others (legacy behavior). Gateways MUST treat absent-for-physical-safety
50
+ * as 'renew'.
51
+ */
52
+ provisional_block_policy?: {
53
+ on_expiry_without_quorum: 'renew' | 'revert'
54
+ /**
55
+ * M-5: Operator override for the provisional block TTL. Defaults to 72
56
+ * hours (259_200_000 ms). Minimum: 1 hour (3_600_000 ms). For
57
+ * safety_class C capabilities with on_expiry_without_quorum='renew', the
58
+ * renewal cycle period equals this value.
59
+ */
60
+ provisional_block_ttl_ms?: number
61
+ }
62
+ /**
63
+ * Minimum number of distinct approvers required to make `effective_at_ms`
64
+ * non-null. Default: 1 for L2, gateway-configured for L3 (recommended >= 2).
65
+ * The gateway MUST reject a duplicate approval from the same actor_oid.
66
+ * Self-approval (approver actor_oid === revocation event created_by) MUST
67
+ * be rejected.
68
+ */
69
+ min_approvers?: number
70
+ }
71
+
72
+ export type RevocationEvent = GapCdroEnvelope<RevocationEventBody>
73
+
74
+ export function revokeGapObject(
75
+ target_kind: RevocationTargetKind,
76
+ target_oid: string,
77
+ reason: string,
78
+ required_level: 1 | 2 | 3,
79
+ provisional: boolean,
80
+ ): RevocationEventBody {
81
+ return {
82
+ target_kind,
83
+ target_oid,
84
+ reason,
85
+ required_level,
86
+ provisional,
87
+ approvers: [],
88
+ effective_at_ms: null,
89
+ }
90
+ }