gemstack-ai 1.2.0 → 1.3.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.
@@ -0,0 +1,633 @@
1
+ # Especificación de Funcionalidad: Cost & Provider Safety Gates (Upgrade C)
2
+
3
+ **Feature Branch**: `008-cost-provider-safety-gates`
4
+ **Feature Directory**: `specs/008-cost-provider-safety-gates/`
5
+ **Lifecycle Status**: `SPEC_COMPLETE`
6
+ **Stop Reason**: `SPEC_COMPLETE_AWAITING_REVIEW`
7
+
8
+ ---
9
+
10
+ ## 1. Problem Statement
11
+
12
+ Gemstack v1.2.0 establishes mathematical and mechanical certainty for architectural consistency (Upgrade A) and implementation test closure (Upgrade B). However, modern agentic software development and automated coding pipelines increasingly interface with external commercial, remote, or paid providers:
13
+ - Large Language Models (LLMs) and inference APIs (e.g., OpenAI, Anthropic, Gemini, local Ollama vs remote cloud endpoints).
14
+ - Vector databases, hosted embeddings, and paid semantic search platforms.
15
+ - Image, audio, multimodal generation and processing APIs.
16
+ - Cloud deployment and ephemeral infrastructure providers (e.g., Cloud Run, AWS, Vercel, Fly.io).
17
+ - External transactional SaaS (e.g., email, SMS, notification dispatchers, third-party payment gateways).
18
+
19
+ Under existing framework capabilities, a local tool execution, test suite run, or AI agent workflow that appears completely harmless on disk can silently trigger:
20
+ 1. **Unintended Financial Charges**: Incurring commercial costs or exhausting paid developer quotas/credits without explicit spending authorization.
21
+ 2. **Test & CI Contamination**: Automated unit test suites, integration passes, or CI runners invoking live remote billable APIs simply because credentials/tokens exist in the ambient shell environment.
22
+ 3. **Provider Fallback Blindspots**: A requested provider failing and silently falling back to a vastly more expensive or unvetted secondary provider without re-evaluating cost policy.
23
+ 4. **Capability Mismatches**: Requesting operations that a provider cannot fulfill or is not configured to provide, causing non-deterministic runtime failures or silent mock deceptions.
24
+ 5. **False Closure via Live Network Couplings**: Verification workflows (`gemstack verify`) accidentally attempting remote queries or mutating external provider states rather than validating local declared evidence.
25
+
26
+ Gemstack requires a fail-closed, deterministic safety gate framework that verifies provider authorization, capability claims, and cost policies **before** any billable or external provider action can execute.
27
+
28
+ ---
29
+
30
+ ## 2. Goals & Non-Goals
31
+
32
+ ### Goals
33
+ - **Fail-Closed Gate Architecture**: Establish two canonical safety gates: `BillableActionGate` and `ProviderCapabilityGate`. If authorization or capability cannot be proven deterministically, execution is strictly blocked.
34
+ - **Provider Cost Validation Ledger**: Establish a machine-readable, deterministic ledger artifact (`cost-ledger.json`) making billing classifications, unit pricing assumptions, and estimation policies auditable without turning Gemstack into an invoice processor.
35
+ - **Strict Separation of Validation and Execution**: Preserve the Upgrade B invariant (`VERIFY = VALIDATE`). Neither `gemstack verify` nor safety gates ever call remote billing endpoints, mutate provider state, or require network access to validate policy.
36
+ - **Ambient Credential Distrust**: Reject commercial execution even when valid API tokens, environment variables, or SDK packages are present, unless an explicit authorization policy permits the action.
37
+ - **Environment Safety Isolation**: Deterministically isolate environments (`test`, `ci`, `development`, `production`), prohibiting commercial actions in automated test/CI contexts by default.
38
+ - **Re-entrant Fallback Validation**: Enforce that any provider switch, fallback chain, or dynamic adapter selection re-evaluates all gates independently.
39
+ - **Backward Compatibility & Legacy Mode**: Ensure projects with zero external providers or existing features continue without friction or errors under progressive Legacy Mode.
40
+ - **Zero External Dependencies**: Implement the entire Upgrade C safety engine using native Node.js standard library built-ins exclusively.
41
+
42
+ ### Non-Goals
43
+ - Gemstack is **NOT** an accounting system, payment processor, or invoice reconciler.
44
+ - Gemstack does **NOT** scrape real-time dynamic pricing from provider websites or APIs.
45
+ - Gemstack does **NOT** manage provider secrets, API keys, or credentials.
46
+ - Gemstack is **NOT** a general-purpose network firewall or operating system sandboxing tool.
47
+ - Gemstack does **NOT** perform autonomous provider purchasing, automated account creation, or dynamic bidding.
48
+ - Gemstack does **NOT** claim to prevent hostile code from directly importing third-party SDKs outside the Gemstack provider abstraction.
49
+
50
+ ---
51
+
52
+ ## 3. Core Safety Principle & Architectural Invariants
53
+
54
+ The fundamental axiom of Upgrade C is:
55
+
56
+ > **NO BILLABLE OR COMMERCIAL PROVIDER ACTION MAY EXECUTE UNLESS GEMSTACK CAN PROVE THAT THE ACTION IS DECLARED, THE PROVIDER IS ALLOWED, THE REQUIRED CAPABILITY IS AVAILABLE, AND THE APPLICABLE COST POLICY AUTHORIZES EXECUTION.**
57
+
58
+ ```text
59
+ ================================================================================
60
+ UPGRADE C CANONICAL SAFETY INVARIANTS
61
+ ================================================================================
62
+ 1. credentials present ≠ authorization
63
+ 2. provider available ≠ provider allowed
64
+ 3. capability implemented ≠ capability authorized
65
+ 4. known price ≠ permission to spend
66
+ 5. unknown cost ≠ free
67
+ 6. fallback provider ≠ inherited authorization
68
+ 7. verification ≠ provider execution
69
+ 8. evidence ≠ authority
70
+ 9. mock label ≠ trusted mock
71
+ 10. commercial action ≠ implicit permission
72
+ ================================================================================
73
+ ```
74
+
75
+ Failure to prove authorization MUST resolve deterministically to: **DO NOT EXECUTE**.
76
+
77
+ ---
78
+
79
+ ## 4. Bootstrap Architecture Contracts
80
+
81
+ This specification declares its frozen architectural contracts under the Upgrade A `FrozenContractRegistry`:
82
+
83
+ ```gemstack-contracts
84
+ [
85
+ {
86
+ "id": "zero-dependency-core",
87
+ "type": "BOOLEAN_INVARIANT",
88
+ "value": true,
89
+ "description": "Upgrade C implementation must introduce zero external production npm dependencies, using Node.js built-ins exclusively."
90
+ },
91
+ {
92
+ "id": "upgrade-c-cost-states",
93
+ "type": "ENUM_SET",
94
+ "values": [
95
+ "FREE",
96
+ "BILLABLE",
97
+ "POTENTIALLY_BILLABLE",
98
+ "UNKNOWN"
99
+ ],
100
+ "description": "Canonical cost-state classifications for provider actions."
101
+ },
102
+ {
103
+ "id": "upgrade-c-environment-types",
104
+ "type": "ENUM_SET",
105
+ "values": [
106
+ "test",
107
+ "ci",
108
+ "development",
109
+ "staging",
110
+ "production"
111
+ ],
112
+ "description": "Deterministic environment tiers recognized by provider safety gates."
113
+ },
114
+ {
115
+ "id": "unknown-cost-never-free",
116
+ "type": "BOOLEAN_INVARIANT",
117
+ "value": true,
118
+ "description": "Cost classification UNKNOWN must never evaluate or degrade silently to FREE."
119
+ },
120
+ {
121
+ "id": "provider-gate-fail-closed",
122
+ "type": "BOOLEAN_INVARIANT",
123
+ "value": true,
124
+ "description": "Any gate evaluation error, missing declaration, or ambiguous policy must result in DENY."
125
+ },
126
+ {
127
+ "id": "verify-performs-zero-provider-calls",
128
+ "type": "BOOLEAN_INVARIANT",
129
+ "value": true,
130
+ "description": "gemstack verify must never execute network requests or invoke remote providers during verification."
131
+ },
132
+ {
133
+ "id": "fallback-requires-revalidation",
134
+ "type": "BOOLEAN_INVARIANT",
135
+ "value": true,
136
+ "description": "Provider fallback chains must independently evaluate all capability and cost gates for each candidate."
137
+ },
138
+ {
139
+ "id": "secrets-forbidden-in-safety-artifacts",
140
+ "type": "BOOLEAN_INVARIANT",
141
+ "value": true,
142
+ "description": "API keys, tokens, or credential secrets must never be stored, hashed, or checked into safety manifests or ledgers."
143
+ },
144
+ {
145
+ "id": "legacy-provider-compatibility",
146
+ "type": "BOOLEAN_INVARIANT",
147
+ "value": true,
148
+ "description": "Features without declared provider blocks or provider-free repositories operate cleanly in legacy mode."
149
+ }
150
+ ]
151
+ ```
152
+
153
+ ---
154
+
155
+ ## 5. Canonical Terminology
156
+
157
+ | Term | Canonical Meaning |
158
+ | :--- | :--- |
159
+ | **`BillableAction`** | An atomic logical operation requested against an external or commercial provider that is capable of incurring financial cost, consuming quota, or debiting developer credits. |
160
+ | **`BillableActionGate`** | A fail-closed authorization filter that intercepts billable action execution requests and evaluates cost policy, environment tiers, and spending allowances. |
161
+ | **`ProviderCapabilityGate`** | A fail-closed compatibility filter that validates whether a designated provider is explicitly permitted, declared, and capable of executing a specific operation. |
162
+ | **`CostValidationLedger`** | A versioned, declarative repository ledger (`cost-ledger.json`) documenting known pricing models, unit estimates, and billing classifications for declared actions. |
163
+ | **`ProviderIdentity`** | An immutable canonical identifier (`provider_id`) distinguishing unique provider endpoints, accounts, and execution adapters (e.g. `gemini-cloud`, `ollama-local`, `mock-test`). |
164
+ | **`CapabilityID`** | A dot-delimited hierarchical token defining an atomic provider capability (e.g. `inference.generate_text`, `storage.upload_artifact`). |
165
+ | **`CommercialAdapter`** | An execution adapter that interacts with a third-party or remote provider involving financial metering, remote service accounts, or live external mutations. |
166
+ | **`MockProvider`** | A local-only, synthetic adapter explicitly declared for test execution that guarantees zero remote network invocations and zero credit consumption. |
167
+ | **`CostState`** | One of the four canonical states: `FREE`, `BILLABLE`, `POTENTIALLY_BILLABLE`, or `UNKNOWN`. |
168
+ | **`SideEffectClassification`** | An orthogonality classification distinguishing reading, local mutating, or remote infrastructure mutating actions independent of billing. |
169
+
170
+ ---
171
+
172
+ ## 6. Architecture & Sources of Truth
173
+
174
+ Upgrade C establishes a single authoritative source for every safety concept to avoid split-brain states:
175
+
176
+ ```text
177
+ +-------------------------------------------------------------------------------+
178
+ | SOURCES OF TRUTH |
179
+ +-------------------------------------------------------------------------------+
180
+ | 1. Provider Registry & Capabilities --> specs/<feature>/plan.md OR |
181
+ | .gemstack/providers.json |
182
+ | 2. Billable Action Declarations --> specs/<feature>/spec.md |
183
+ | 3. Cost Assumptions Ledger --> specs/<feature>/cost-ledger.json OR |
184
+ | .gemstack/cost-ledger.json |
185
+ | 4. Environment Safety Policy --> .gemstack/state.json / environment |
186
+ | 5. Runtime Gate Authorization --> Evaluated in-memory (Side-Effect Free)|
187
+ | 6. Verification Findings --> Derived deterministically |
188
+ +-------------------------------------------------------------------------------+
189
+ ```
190
+
191
+ ### Authority Hierarchy
192
+ 1. **Specification (`spec.md`)**: Defines the canonical business requirements and declares expected `gemstack-billable-actions` and `gemstack-capabilities`.
193
+ 2. **Technical Plan (`plan.md`)**: Binds actions to concrete provider identities and maps capability requirements.
194
+ 3. **Cost Ledger (`cost-ledger.json`)**: Houses declared pricing models, cost units, and approval thresholds.
195
+ 4. **Safety Gates (Runtime Interceptor)**: Evaluates requests against the above authoritative sources. It **never** mutates declarations to force an authorization pass.
196
+
197
+ ---
198
+
199
+ ## 7. Action & Cost Classification Model
200
+
201
+ ### 7.1 Billable Action Categories
202
+ Every provider action requested by an agent, tool, or CLI runner is classified into one of five operational categories:
203
+ 1. **DEFINITELY_BILLABLE**: Incurs explicit metering or invoice charges upon invocation (e.g., commercial LLM tokens, cloud GPU runtime, paid SMS).
204
+ 2. **POTENTIALLY_BILLABLE**: Operations that may be billable depending on account tiers, free quota exhaustion, or request volume (e.g., cloud storage transfers, search API tiers).
205
+ 3. **NON_BILLABLE_LOCAL**: Local synthetic execution, deterministic hash calculation, in-memory mocks, or local Ollama executions on developer hardware.
206
+ 4. **EXTERNALLY_MUTATING**: Operations that modify remote infrastructure or external database states (e.g. creating a cloud deployment or deleting remote records) regardless of financial fee.
207
+ 5. **METERED_READ**: Pure read-only queries that nevertheless incur provider charges (e.g., vector database retrieval queries, paid credit searches).
208
+
209
+ ### 7.2 Cost State Model
210
+ The gate evaluates the action's cost status into one of four states:
211
+ - **`FREE`**: Proven to have zero monetary cost (e.g., approved local mock). Permitted under all valid environment policies.
212
+ - **`BILLABLE`**: Explicitly declared as billable with known pricing classification in the ledger. Permitted **only** when explicit spending authorization exists.
213
+ - **`POTENTIALLY_BILLABLE`**: May incur costs. Treated as `BILLABLE` under strict and standard environments; fail-closed by default.
214
+ - **`UNKNOWN`**: Missing cost metadata or unclassified action. **Strictly forbidden from execution.** Never degrades to `FREE`.
215
+
216
+ ---
217
+
218
+ ## 8. Safety Gates Contract & Lifecycle
219
+
220
+ ### 8.1 BillableActionGate Lifecycle
221
+
222
+ ```text
223
+ [Action Request]
224
+
225
+
226
+ 1. Is Environment Permitted? ────(NO)───► [DENY: ENV_COMMERCIAL_DENIED]
227
+ │ (YES)
228
+
229
+ 2. Is Action Declared in Spec? ──(NO)───► [DENY: UNDECLARED_BILLABLE_ACTION]
230
+ │ (YES)
231
+
232
+ 3. Is Cost Classification Known? ─(UNKNOWN)─► [DENY: UNKNOWN_COST_CLASSIFICATION]
233
+ │ (KNOWN)
234
+
235
+ 4. Is Action Cost Free? ─────────(YES)──► [ALLOW: ACTION_AUTHORIZED_FREE]
236
+ │ (BILLABLE)
237
+
238
+ 5. Is Explicit Spending Authorized? ─(NO)──► [DENY: BILLABLE_ACTION_UNAUTHORIZED]
239
+ │ (YES)
240
+
241
+ 6. Within Budget / Unit Threshold? ──(NO)──► [DENY: BUDGET_THRESHOLD_EXCEEDED]
242
+ │ (YES)
243
+
244
+ [ALLOW: ACTION_AUTHORIZED]
245
+ ```
246
+
247
+ #### Gate Input Schema
248
+ ```json
249
+ {
250
+ "action_id": "generate-summary",
251
+ "provider_id": "anthropic-cloud",
252
+ "capability_id": "inference.generate_text",
253
+ "environment": "development",
254
+ "requested_units": 1,
255
+ "authorization_token": {
256
+ "source": "CLI_FLAG",
257
+ "granted_by": "developer",
258
+ "max_budget_units": 5.00,
259
+ "currency": "USD"
260
+ }
261
+ }
262
+ ```
263
+
264
+ #### Gate Decision Output Schema
265
+ ```json
266
+ {
267
+ "authorized": false,
268
+ "decision": "DENY",
269
+ "reason_code": "BILLABLE_ACTION_UNAUTHORIZED",
270
+ "message": "Action \"generate-summary\" on provider \"anthropic-cloud\" requires explicit spending authorization in development environment.",
271
+ "context": {
272
+ "provider_id": "anthropic-cloud",
273
+ "capability_id": "inference.generate_text",
274
+ "cost_state": "BILLABLE",
275
+ "environment": "development"
276
+ }
277
+ }
278
+ ```
279
+
280
+ ### 8.2 ProviderCapabilityGate Lifecycle
281
+
282
+ ```text
283
+ [Capability Request]
284
+
285
+
286
+ 1. Is Provider Registered? ───────(NO)───► [DENY: UNKNOWN_PROVIDER_IDENTITY]
287
+ │ (YES)
288
+
289
+ 2. Is Provider Allowed in Env? ───(NO)───► [DENY: PROVIDER_DISALLOWED_IN_ENV]
290
+ │ (YES)
291
+
292
+ 3. Is Capability Declared? ───────(NO)───► [DENY: PROVIDER_CAPABILITY_UNDECLARED]
293
+ │ (YES)
294
+
295
+ 4. Does Adapter Support Capability? ─(NO)──► [DENY: PROVIDER_CAPABILITY_UNSUPPORTED]
296
+ │ (YES)
297
+
298
+ [ALLOW: CAPABILITY_VERIFIED]
299
+ ```
300
+
301
+ ---
302
+
303
+ ## 9. Provider Cost Validation Ledger
304
+
305
+ The Provider Cost Validation Ledger (`cost-ledger.json`) is a declarative artifact recording pricing models, unit estimates, and authorization constraints.
306
+
307
+ ### 9.1 Ledger Artifact Schema
308
+ ```json
309
+ {
310
+ "$schema": "https://gemstack.dev/schemas/cost-ledger-v1.json",
311
+ "version": 1,
312
+ "updated_at": "2026-09-11T17:00:00.000Z",
313
+ "currency": "USD",
314
+ "providers": {
315
+ "gemini-cloud": {
316
+ "type": "COMMERCIAL",
317
+ "pricing_model": "PER_1K_TOKENS",
318
+ "capabilities": {
319
+ "inference.generate_text": {
320
+ "cost_state": "BILLABLE",
321
+ "estimated_unit_cost": 0.0005,
322
+ "assumption_source": "google-cloud-pricing-2026-08",
323
+ "freshness_date": "2026-08-31",
324
+ "requires_human_approval": false
325
+ }
326
+ }
327
+ },
328
+ "mock-local": {
329
+ "type": "MOCK",
330
+ "pricing_model": "NONE",
331
+ "capabilities": {
332
+ "inference.generate_text": {
333
+ "cost_state": "FREE",
334
+ "estimated_unit_cost": 0.0,
335
+ "assumption_source": "local-synthetic-inmemory",
336
+ "freshness_date": "2026-09-11",
337
+ "requires_human_approval": false
338
+ }
339
+ }
340
+ }
341
+ }
342
+ }
343
+ ```
344
+
345
+ ### 9.2 Stale Assumptions Policy
346
+ Pricing assumptions in the ledger are informative baselines, not authoritative real-time quotes. The gate enforces:
347
+ - **Price Knowledge ≠ Spending Permission**: Even a fresh, valid entry in the ledger does **not** grant permission to spend unless the active environment policy and authorization token authorize execution.
348
+ - If a ledger entry's `freshness_date` is beyond the configured maximum age (e.g. > 90 days), the gate emits finding `STALE_PROVIDER_COST_ASSUMPTION`.
349
+
350
+ ---
351
+
352
+ ## 10. Provider Identity & Fallback Chain Safety
353
+
354
+ ### 10.1 Multi-Account & Alias Isolation
355
+ Providers must be registered with unambiguous identifiers. Aliasing or wrapping a commercial provider under an innocuous name (e.g., labeling an OpenAI cloud proxy as `local-helper`) is strictly forbidden.
356
+ - `type: "MOCK"` adapters must prove local-only in-memory execution. Any mock adapter opening outbound HTTP sockets to commercial domains is treated as a security violation (`MOCK_PROVIDER_ESCAPE_VIOLATION`).
357
+
358
+ ### 10.2 Re-entrant Fallback Invariant
359
+ If an application or agent configures a fallback chain (e.g., Primary: `local-inference`, Secondary: `cloud-inference`):
360
+ ```text
361
+ Primary (local-inference) FAILS
362
+
363
+
364
+ Switching to Secondary (cloud-inference)
365
+
366
+
367
+ [RE-ENTER GATES] ──► Must pass BillableActionGate & ProviderCapabilityGate
368
+ for cloud-inference INDEPENDENTLY!
369
+ ```
370
+ Fallback from a free or local provider to a paid provider **never** inherits authorization. The secondary provider must independently obtain explicit spending permission.
371
+
372
+ ---
373
+
374
+ ## 11. Environment Safety Tiers & Non-Interactive Semantics
375
+
376
+ | Environment | Default Policy | Commercial Allowed? | Mock Required? |
377
+ | :--- | :--- | :--- | :--- |
378
+ | **`test`** | STRICT_ISOLATION | **DENIED** (Fail-Closed) | **YES** |
379
+ | **`ci`** | HEADLESS_GATE | **DENIED** unless secret-free signed waiver | **YES** |
380
+ | **`development`** | EXPLICIT_AUTHORIZATION | **DENIED** without `--allow-billable` flag | **OPTIONAL** |
381
+ | **`staging`** | BOUNDED_QUOTA | Allowed within declared session budget | **NO** |
382
+ | **`production`** | BOUNDED_QUOTA | Allowed with registered service accounts | **NO** |
383
+
384
+ ### Automated Agent & Headless Semantics
385
+ In non-interactive environments (CI, autonomous subagents, background jobs):
386
+ - Interactive prompts (`Are you sure? [y/N]`) are **strictly disabled**.
387
+ - If explicit authorization is not pre-configured via command flags (`--allow-billable`) or policy artifacts, the gate **fails immediately with exit code 1** and structured JSON denial output.
388
+
389
+ ---
390
+
391
+ ## 12. Read-Only Verification Purity & Offline Verification
392
+
393
+ Preserving the Upgrade B invariant (`VERIFY = VALIDATE`):
394
+ - `gemstack verify` inspects declarations in `spec.md`, mappings in `plan.md`, and ledger entries in `cost-ledger.json`.
395
+ - `gemstack verify` **NEVER**:
396
+ 1. Contacts remote provider APIs or balance endpoints.
397
+ 2. Executes billable actions.
398
+ 3. Mutates or updates ledger pricing.
399
+ 4. Requires network connectivity to validate safety configurations.
400
+ - Offline verification is 100% supported: safety gates evaluate static configuration, hashes, and declarations deterministically without internet access.
401
+
402
+ ---
403
+
404
+ ## 13. Threat Model & Policy Bypass Analysis
405
+
406
+ | Threat / Bypass Vector | Mitigation Architecture |
407
+ | :--- | :--- |
408
+ | **Ambient Credential Leakage** (Dev has `OPENAI_API_KEY` set in shell during `npm test`) | Gates check active environment policy first. In `test` and `ci`, commercial execution is denied regardless of ambient environment variables. |
409
+ | **Stealth Provider Fallback** (Free local model fails, library falls back to paid API) | Re-entrant gate enforcement intercepting adapter calls; each provider candidate evaluated separately. |
410
+ | **Mock Impersonation** (Developer labels commercial adapter as `type: MOCK`) | Mocks audited for external network descriptors; unit tests run in zero-network sandboxes. |
411
+ | **TOCTOU Disconnect** (Gate authorizes Provider A, runtime executes Provider B) | The authorization token is cryptographically bound to `provider_id`, `capability_id`, and execution hash. |
412
+ | **Silent Unknown Cost Degradation** (Unmetered action treated as free) | Invariant: `UNKNOWN` fails closed; requires explicit classification before execution. |
413
+ | **Ledger Tampering to Bypass Verification** | Ledger is hashed in `closureContextHash` (Upgrade B); unauthorized mutations invalidate closure evidence. |
414
+
415
+ ---
416
+
417
+ ## 14. Canonical Finding Taxonomy (Upgrade C)
418
+
419
+ All safety findings use canonical uppercase finding codes and 64-character lowercase SHA-256 fingerprints:
420
+
421
+ | Finding Code | Severity | Description | Waivable via Exception? |
422
+ | :--- | :--- | :--- | :--- |
423
+ | **`UNDECLARED_BILLABLE_ACTION`** | BLOCKER | An executed or planned provider action is not declared in `spec.md`. | **NO** |
424
+ | **`BILLABLE_ACTION_UNAUTHORIZED`** | BLOCKER | Action requires spending authorization that was not granted. | **NO** |
425
+ | **`UNKNOWN_COST_CLASSIFICATION`** | BLOCKER | Cost state is `UNKNOWN` or missing in ledger. | **NO** |
426
+ | **`UNKNOWN_PROVIDER_IDENTITY`** | BLOCKER | Action references an unregistered or ambiguous provider ID. | **NO** |
427
+ | **`PROVIDER_CAPABILITY_UNDECLARED`**| BLOCKER | Capability requested is not declared in specification or plan. | **NO** |
428
+ | **`PROVIDER_CAPABILITY_UNSUPPORTED`**| BLOCKER | Adapter is missing declared implementation support for capability. | **NO** |
429
+ | **`ENV_COMMERCIAL_DENIED`** | BLOCKER | Commercial provider action attempted in `test` or `ci` environment. | **NO** |
430
+ | **`PROVIDER_FALLBACK_UNAUTHORIZED`** | BLOCKER | Fallback provider failed secondary gate authorization. | **NO** |
431
+ | **`STALE_PROVIDER_COST_ASSUMPTION`** | WARNING | Ledger cost estimate is older than maximum freshness threshold. | **YES** |
432
+ | **`BUDGET_THRESHOLD_EXCEEDED`** | BLOCKER | Estimated action cost exceeds configured spending limit. | **NO** |
433
+ | **`MOCK_PROVIDER_ESCAPE_VIOLATION`** | BLOCKER | Provider declared as MOCK attempted remote network socket invocation. | **NO** |
434
+ | **`COST_LEDGER_INVALID`** | BLOCKER | `cost-ledger.json` schema or JSON syntax validation failed. | **NO** |
435
+
436
+ ---
437
+
438
+ ## 15. Canonical Acceptance Matrix (TEST-COST-A01 through TEST-COST-H01)
439
+
440
+ Upgrade C establishes 20 canonical acceptance test requirements:
441
+
442
+ ```gemstack-test-matrix
443
+ [
444
+ {
445
+ "id": "TEST-COST-A01",
446
+ "category": "ACTION_GATE",
447
+ "layer": "UNIT",
448
+ "description": "Rejects execution when billable action is not declared in spec.md.",
449
+ "pass_criteria": "Emits UNDECLARED_BILLABLE_ACTION and halts execution with exit code 1.",
450
+ "gate": "REQUIRED"
451
+ },
452
+ {
453
+ "id": "TEST-COST-A02",
454
+ "category": "ACTION_GATE",
455
+ "layer": "UNIT",
456
+ "description": "Rejects billable action when explicit spending authorization is missing.",
457
+ "pass_criteria": "Emits BILLABLE_ACTION_UNAUTHORIZED when authorization token is absent.",
458
+ "gate": "REQUIRED"
459
+ },
460
+ {
461
+ "id": "TEST-COST-A03",
462
+ "category": "ACTION_GATE",
463
+ "layer": "UNIT",
464
+ "description": "Authorizes billable action when explicit valid spending token is supplied.",
465
+ "pass_criteria": "Gate returns authorized: true with zero blockers.",
466
+ "gate": "REQUIRED"
467
+ },
468
+ {
469
+ "id": "TEST-COST-A04",
470
+ "category": "ACTION_GATE",
471
+ "layer": "UNIT",
472
+ "description": "Rejects action when cost state is UNKNOWN without falling back to FREE.",
473
+ "pass_criteria": "Emits UNKNOWN_COST_CLASSIFICATION and blocks execution fail-closed.",
474
+ "gate": "REQUIRED"
475
+ },
476
+ {
477
+ "id": "TEST-COST-B01",
478
+ "category": "CAPABILITY_GATE",
479
+ "layer": "UNIT",
480
+ "description": "Blocks execution when capability is not declared in plan or provider registry.",
481
+ "pass_criteria": "Emits PROVIDER_CAPABILITY_UNDECLARED with deterministic denial result.",
482
+ "gate": "REQUIRED"
483
+ },
484
+ {
485
+ "id": "TEST-COST-B02",
486
+ "category": "CAPABILITY_GATE",
487
+ "layer": "UNIT",
488
+ "description": "Blocks execution when adapter does not implement requested capability.",
489
+ "pass_criteria": "Emits PROVIDER_CAPABILITY_UNSUPPORTED without attempting network invocation.",
490
+ "gate": "REQUIRED"
491
+ },
492
+ {
493
+ "id": "TEST-COST-B03",
494
+ "category": "CAPABILITY_GATE",
495
+ "layer": "UNIT",
496
+ "description": "Blocks execution when provider identity is unknown or unregistered.",
497
+ "pass_criteria": "Emits UNKNOWN_PROVIDER_IDENTITY for unregistered provider strings.",
498
+ "gate": "REQUIRED"
499
+ },
500
+ {
501
+ "id": "TEST-COST-B04",
502
+ "category": "CAPABILITY_GATE",
503
+ "layer": "UNIT",
504
+ "description": "Allows execution when provider and capability are declared and supported.",
505
+ "pass_criteria": "Returns authorized: true when provider capability contract is fully satisfied.",
506
+ "gate": "REQUIRED"
507
+ },
508
+ {
509
+ "id": "TEST-COST-C01",
510
+ "category": "ENVIRONMENT",
511
+ "layer": "INTEGRATION",
512
+ "description": "Blocks commercial provider invocation in test environment despite ambient credentials.",
513
+ "pass_criteria": "Emits ENV_COMMERCIAL_DENIED during test run when commercial provider is requested.",
514
+ "gate": "REQUIRED"
515
+ },
516
+ {
517
+ "id": "TEST-COST-C02",
518
+ "category": "ENVIRONMENT",
519
+ "layer": "INTEGRATION",
520
+ "description": "Blocks commercial provider invocation in CI environment without explicit signed waiver.",
521
+ "pass_criteria": "Emits ENV_COMMERCIAL_DENIED in CI environment.",
522
+ "gate": "REQUIRED"
523
+ },
524
+ {
525
+ "id": "TEST-COST-C03",
526
+ "category": "ENVIRONMENT",
527
+ "layer": "UNIT",
528
+ "description": "Allows verified MOCK providers to execute cleanly in test environment.",
529
+ "pass_criteria": "Returns authorized: true for declared MOCK provider in test environment.",
530
+ "gate": "REQUIRED"
531
+ },
532
+ {
533
+ "id": "TEST-COST-D01",
534
+ "category": "FALLBACK",
535
+ "layer": "INTEGRATION",
536
+ "description": "Re-evaluates safety gates when switching from primary to fallback provider.",
537
+ "pass_criteria": "Fallback candidate triggers independent gate evaluation before execution.",
538
+ "gate": "REQUIRED"
539
+ },
540
+ {
541
+ "id": "TEST-COST-D02",
542
+ "category": "FALLBACK",
543
+ "layer": "INTEGRATION",
544
+ "description": "Blocks fallback when secondary provider does not satisfy cost authorization policy.",
545
+ "pass_criteria": "Emits PROVIDER_FALLBACK_UNAUTHORIZED when fallback target lacks spending permission.",
546
+ "gate": "REQUIRED"
547
+ },
548
+ {
549
+ "id": "TEST-COST-E01",
550
+ "category": "LEDGER",
551
+ "layer": "UNIT",
552
+ "description": "Validates syntax and schema structure of cost-ledger.json.",
553
+ "pass_criteria": "Rejects malformed ledger with COST_LEDGER_INVALID finding.",
554
+ "gate": "REQUIRED"
555
+ },
556
+ {
557
+ "id": "TEST-COST-E02",
558
+ "category": "LEDGER",
559
+ "layer": "UNIT",
560
+ "description": "Emits warning finding when pricing assumption freshness date exceeds threshold.",
561
+ "pass_criteria": "Emits STALE_PROVIDER_COST_ASSUMPTION without crashing gate evaluation.",
562
+ "gate": "REQUIRED"
563
+ },
564
+ {
565
+ "id": "TEST-COST-E03",
566
+ "category": "LEDGER",
567
+ "layer": "UNIT",
568
+ "description": "Enforces that cost ledger never contains credential secrets or authentication tokens.",
569
+ "pass_criteria": "Rejects ledger containing API keys or private tokens with non-waivable blocker.",
570
+ "gate": "REQUIRED"
571
+ },
572
+ {
573
+ "id": "TEST-COST-F01",
574
+ "category": "VERIFICATION_PURITY",
575
+ "layer": "INTEGRATION",
576
+ "description": "Proves gemstack verify executes zero outbound network or provider requests.",
577
+ "pass_criteria": "Verify command completes with exit 0 with all network sockets mocked to throw.",
578
+ "gate": "REQUIRED"
579
+ },
580
+ {
581
+ "id": "TEST-COST-F02",
582
+ "category": "VERIFICATION_PURITY",
583
+ "layer": "INTEGRATION",
584
+ "description": "Proves gemstack verify does not mutate cost ledger or state files on disk.",
585
+ "pass_criteria": "Before and after SHA-256 file hashes match 100% (0 mutations).",
586
+ "gate": "REQUIRED"
587
+ },
588
+ {
589
+ "id": "TEST-COST-G01",
590
+ "category": "BUDGET",
591
+ "layer": "UNIT",
592
+ "description": "Blocks action execution when estimated unit cost exceeds granted budget limit.",
593
+ "pass_criteria": "Emits BUDGET_THRESHOLD_EXCEEDED when requested cost exceeds token limit.",
594
+ "gate": "REQUIRED"
595
+ },
596
+ {
597
+ "id": "TEST-COST-H01",
598
+ "category": "LEGACY",
599
+ "layer": "UNIT",
600
+ "description": "Preserves backward compatibility for provider-free projects in legacy mode.",
601
+ "pass_criteria": "Legacy project verify passes with zero errors and informational legacy notice.",
602
+ "gate": "REQUIRED"
603
+ }
604
+ ]
605
+ ```
606
+
607
+ ---
608
+
609
+ ## 16. Future Test Strategy (Design Only)
610
+
611
+ Implementation testing will be organized into dedicated physical test suites:
612
+ 1. `tests/billable-action-gate.test.js`: Unit tests for `BillableActionGate` authorization logic, state transitions, and spending token verification (`TEST-COST-A01` to `A04`, `G01`).
613
+ 2. `tests/provider-capability-gate.test.js`: Unit tests for capability discovery, adapter compatibility validation, and unknown provider rejection (`TEST-COST-B01` to `B04`).
614
+ 3. `tests/environment-provider-safety.test.js`: Integration tests proving test/CI isolation against ambient developer credentials (`TEST-COST-C01` to `C03`).
615
+ 4. `tests/provider-fallback.test.js`: Multi-adapter switching tests verifying re-entrant gate validation on fallback chains (`TEST-COST-D01`, `D02`).
616
+ 5. `tests/cost-ledger.test.js`: Schema validation, freshness checks, and secret leakage audits for `cost-ledger.json` (`TEST-COST-E01` to `E03`).
617
+ 6. `tests/verification-purity-cost.test.js`: Network isolation assertions ensuring `gemstack verify` operates strictly offline without disk mutations or provider API calls (`TEST-COST-F01`, `F02`, `H01`).
618
+
619
+ All test suites will run strictly offline using pure Node.js in-memory mocks without commercial charges or real credentials.
620
+
621
+ ---
622
+
623
+ ## 17. Compatibility & Legacy Migration
624
+
625
+ - **Existing Projects**: Projects without `cost-ledger.json` or provider definitions operate under **Legacy Progressive Mode** (`LEGACY_NO_PROVIDERS_DECLARED`). Verification passes with zero errors.
626
+ - **Upgrades A & B Alignment**: No Upgrade A frozen contracts or Upgrade B closure semantics are modified. Upgrade C artifacts (`cost-ledger.json`) will be incorporated into Upgrade B's `RelevantClosureFiles` during plan phase.
627
+ - **Zero Runtime Dependencies**: Fully built on Node.js core modules (`node:fs`, `node:path`, `node:crypto`).
628
+
629
+ ---
630
+
631
+ ## 18. Open Questions
632
+
633
+ **NONE.** The architecture, gate lifecycles, cost classification model, fallback re-entrancy rules, and acceptance criteria are fully resolved and aligned with existing repository primitives.