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.
- package/.gemstack/state.json +8 -7
- package/CHANGELOG.md +43 -0
- package/README.md +23 -0
- package/RELEASE_NOTES.md +37 -0
- package/{gemstack-ai-1.2.0.tgz → gemstack-ai-1.3.0.tgz} +0 -0
- package/handoff.md +14 -12
- package/package.json +2 -2
- package/specs/008-cost-provider-safety-gates/.gemstack.json +5 -0
- package/specs/008-cost-provider-safety-gates/closure.json +59 -0
- package/specs/008-cost-provider-safety-gates/plan.md +456 -0
- package/specs/008-cost-provider-safety-gates/spec.md +633 -0
- package/specs/008-cost-provider-safety-gates/tasks.md +635 -0
- package/specs/009-context-capsule/closure.json +59 -0
- package/specs/009-context-capsule/context-capsule.json +428 -0
- package/specs/009-context-capsule/plan.md +663 -0
- package/specs/009-context-capsule/spec.md +913 -0
- package/specs/009-context-capsule/tasks.md +720 -0
- package/src/cli.js +2 -0
- package/src/commands/context.js +95 -0
- package/src/commands/verify.js +54 -0
- package/src/lib/closure-context.js +9 -0
- package/src/lib/context-capsule.js +594 -0
- package/src/lib/cost-ledger.js +355 -0
- package/src/lib/provider-boundary.js +186 -0
- package/src/lib/provider-registry.js +265 -0
- package/src/lib/safety-gates.js +277 -0
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
# Tareas de Implementación: 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
|
+
**Spec**: [`specs/008-cost-provider-safety-gates/spec.md`](file:///c:/CODES/Gemstack/specs/008-cost-provider-safety-gates/spec.md)
|
|
6
|
+
**Plan**: [`specs/008-cost-provider-safety-gates/plan.md`](file:///c:/CODES/Gemstack/specs/008-cost-provider-safety-gates/plan.md)
|
|
7
|
+
**Lifecycle Status**: `IMPLEMENTATION_COMPLETE`
|
|
8
|
+
**Stop Reason**: `AWAITING_CLOSURE_VERIFICATION`
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Contratos Congelados Heredados (Dogfooding)
|
|
13
|
+
|
|
14
|
+
```gemstack-contracts
|
|
15
|
+
[
|
|
16
|
+
{
|
|
17
|
+
"id": "zero-dependency-core",
|
|
18
|
+
"type": "BOOLEAN_INVARIANT",
|
|
19
|
+
"value": true,
|
|
20
|
+
"description": "Upgrade C implementation must introduce zero external production npm dependencies, using Node.js built-ins exclusively."
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "upgrade-c-cost-states",
|
|
24
|
+
"type": "ENUM_SET",
|
|
25
|
+
"values": [
|
|
26
|
+
"FREE",
|
|
27
|
+
"BILLABLE",
|
|
28
|
+
"POTENTIALLY_BILLABLE",
|
|
29
|
+
"UNKNOWN"
|
|
30
|
+
],
|
|
31
|
+
"description": "Canonical cost-state classifications for provider actions."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "upgrade-c-environment-types",
|
|
35
|
+
"type": "ENUM_SET",
|
|
36
|
+
"values": [
|
|
37
|
+
"test",
|
|
38
|
+
"ci",
|
|
39
|
+
"development",
|
|
40
|
+
"staging",
|
|
41
|
+
"production"
|
|
42
|
+
],
|
|
43
|
+
"description": "Deterministic environment tiers recognized by provider safety gates."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "unknown-cost-never-free",
|
|
47
|
+
"type": "BOOLEAN_INVARIANT",
|
|
48
|
+
"value": true,
|
|
49
|
+
"description": "Cost classification UNKNOWN must never evaluate or degrade silently to FREE."
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": "provider-gate-fail-closed",
|
|
53
|
+
"type": "BOOLEAN_INVARIANT",
|
|
54
|
+
"value": true,
|
|
55
|
+
"description": "Any gate evaluation error, missing declaration, or ambiguous policy must result in DENY."
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "verify-performs-zero-provider-calls",
|
|
59
|
+
"type": "BOOLEAN_INVARIANT",
|
|
60
|
+
"value": true,
|
|
61
|
+
"description": "gemstack verify must never execute network requests or invoke remote providers during verification."
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "fallback-requires-revalidation",
|
|
65
|
+
"type": "BOOLEAN_INVARIANT",
|
|
66
|
+
"value": true,
|
|
67
|
+
"description": "Provider fallback chains must independently evaluate all capability and cost gates for each candidate."
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "secrets-forbidden-in-safety-artifacts",
|
|
71
|
+
"type": "BOOLEAN_INVARIANT",
|
|
72
|
+
"value": true,
|
|
73
|
+
"description": "API keys, tokens, or credential secrets must never be stored, hashed, or checked into safety manifests or ledgers."
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "legacy-provider-compatibility",
|
|
77
|
+
"type": "BOOLEAN_INVARIANT",
|
|
78
|
+
"value": true,
|
|
79
|
+
"description": "Features without declared provider blocks or provider-free repositories operate cleanly in legacy mode."
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Task Execution Rules & Invariants
|
|
87
|
+
|
|
88
|
+
1. **Central Invariant**: `NO PROOF OF AUTHORIZATION = NO COMMERCIAL EXECUTION`.
|
|
89
|
+
2. **Fail-Closed Default**: Any missing configuration, unknown provider, unclassified cost, or policy ambiguity results in `DENY`.
|
|
90
|
+
3. **Ambient Credential Distrust**: The existence of API keys or tokens in developer/CI environments never constitutes spending authorization.
|
|
91
|
+
4. **Offline Purity**: Safety evaluation and verification operate 100% offline without live network queries, balance checks, or provider mutations.
|
|
92
|
+
5. **Re-entrant Fallbacks**: Fallback providers require independent capability and cost gate evaluations; authorization is never inherited.
|
|
93
|
+
6. **Zero Dependencies**: Core implementation relies strictly on Node.js built-ins (`node:fs`, `node:path`, `node:crypto`).
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Dependency Graph (5 Phased Waves)
|
|
98
|
+
|
|
99
|
+
```mermaid
|
|
100
|
+
graph TD
|
|
101
|
+
subgraph "Phase 1: Schemas & Cost Ledger Foundation"
|
|
102
|
+
UC_T001["T001: Cost Ledger Parser & Validator"] --> UC_T002["T002: Secrets Scanner & Forbidden Keys"]
|
|
103
|
+
UC_T002 --> UC_T003["T003: Staleness & Freshness Date Evaluator"]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
subgraph "Phase 2: Provider Registry & Environment Safety"
|
|
107
|
+
UC_T001 --> UC_T004["T004: Provider Registry Loader & Validator"]
|
|
108
|
+
UC_T004 --> UC_T005["T005: Environment Tier Resolver & Default Deny"]
|
|
109
|
+
UC_T005 --> UC_T006["T006: Mock Integrity & Anti-Escape Validator"]
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
subgraph "Phase 3: Safety Gates"
|
|
113
|
+
UC_T004 --> UC_T007["T007: ProviderCapabilityGate Implementation"]
|
|
114
|
+
UC_T003 --> UC_T008["T008: BillableActionGate Implementation"]
|
|
115
|
+
UC_T005 --> UC_T008
|
|
116
|
+
UC_T007 --> UC_T009["T009: Structured Decision & Denial Reason Model"]
|
|
117
|
+
UC_T008 --> UC_T009
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
subgraph "Phase 4: Execution Boundary & Fallbacks"
|
|
121
|
+
UC_T009 --> UC_T010["T010: Execution Boundary Interceptor"]
|
|
122
|
+
UC_T010 --> UC_T011["T011: Re-entrant Fallback Chain Evaluator"]
|
|
123
|
+
UC_T011 --> UC_T012["T012: Architectural Direct-Bypass Protections"]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
subgraph "Phase 5: Verify, Closure & Verification"
|
|
127
|
+
UC_T003 --> UC_T013["T013: Verify Stage 5/6 Cost Safety Extension"]
|
|
128
|
+
UC_T013 --> UC_T014["T014: Mechanical Network Purity Enforcer"]
|
|
129
|
+
UC_T013 --> UC_T015["T015: Closure Context RelevantClosureFiles Integration"]
|
|
130
|
+
UC_T013 --> UC_T016["T016: Findings & Accepted Exceptions Binding"]
|
|
131
|
+
UC_T013 --> UC_T017["T017: Progressive Legacy Mode Compatibility"]
|
|
132
|
+
UC_T014 --> UC_T018["T018: Adversarial & Bypass Test Suite"]
|
|
133
|
+
UC_T015 --> UC_T019["T019: Frozen Contracts & Full Regression Verification"]
|
|
134
|
+
UC_T018 --> UC_T020["T020: Upgrade C Dogfooding & Mechanical Closure Proof"]
|
|
135
|
+
UC_T019 --> UC_T020
|
|
136
|
+
end
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Tasks Inventory
|
|
142
|
+
|
|
143
|
+
### Phase 1 — Schemas & Cost Ledger Foundation
|
|
144
|
+
|
|
145
|
+
- [x] **T001: Implement canonical cost-ledger parser, schema validator, and code-unit serializer**
|
|
146
|
+
<!-- gemstack:validation_required=true -->
|
|
147
|
+
<!-- gemstack:tests=TEST-COST-E01 -->
|
|
148
|
+
<!-- gemstack:files=src/lib/cost-ledger.js,tests/cost-ledger.test.js -->
|
|
149
|
+
<!-- gemstack:depends= -->
|
|
150
|
+
*Objective*: Create `src/lib/cost-ledger.js` to parse, validate, and serialize `cost-ledger.json`.
|
|
151
|
+
*Files*:
|
|
152
|
+
- NEW: `src/lib/cost-ledger.js`
|
|
153
|
+
- NEW: `tests/cost-ledger.test.js`
|
|
154
|
+
*Prerequisites*: NONE
|
|
155
|
+
*Implementation requirements*:
|
|
156
|
+
- Implement `loadCostLedger(filePath)` and `validateLedgerSchema(data)`.
|
|
157
|
+
- Validate schema version 1, code-unit sorted provider and capability keys.
|
|
158
|
+
- Enforce valid cost states: `FREE`, `BILLABLE`, `POTENTIALLY_BILLABLE`, `UNKNOWN`.
|
|
159
|
+
- Reject malformed syntax or schema violations with `COST_LEDGER_INVALID`.
|
|
160
|
+
*Must NOT*: Introduce external npm packages or perform live pricing network lookups.
|
|
161
|
+
*Tests*: `tests/cost-ledger.test.js`
|
|
162
|
+
*Acceptance IDs*: `TEST-COST-E01`
|
|
163
|
+
*Completion criteria*: `TEST-COST-E01` passes with invalid and valid ledger fixtures.
|
|
164
|
+
*Evidence*: Test assertions passing under `node:test`.
|
|
165
|
+
|
|
166
|
+
- [x] **T002: Implement secrets scanner and forbidden credential detector for safety artifacts**
|
|
167
|
+
<!-- gemstack:validation_required=true -->
|
|
168
|
+
<!-- gemstack:tests=TEST-COST-E03 -->
|
|
169
|
+
<!-- gemstack:files=src/lib/cost-ledger.js,tests/cost-ledger.test.js -->
|
|
170
|
+
<!-- gemstack:depends=T001 -->
|
|
171
|
+
*Objective*: Ensure `cost-ledger.json` and safety configurations never store, hash, or leak secrets.
|
|
172
|
+
*Files*:
|
|
173
|
+
- MODIFY: `src/lib/cost-ledger.js`
|
|
174
|
+
- MODIFY: `tests/cost-ledger.test.js`
|
|
175
|
+
*Prerequisites*: `T001`
|
|
176
|
+
*Implementation requirements*:
|
|
177
|
+
- Implement `auditSecretsForbidden(data)` in `src/lib/cost-ledger.js`.
|
|
178
|
+
- Scan for forbidden property names: `api_key`, `token`, `secret`, `authorization`, `private_key`, `passwd`.
|
|
179
|
+
- Scan string values for common credential patterns (`sk-...`, `ghp_...`, `Bearer ...`).
|
|
180
|
+
- Reject secret-bearing ledgers with non-waivable blocker `COST_LEDGER_INVALID`.
|
|
181
|
+
*Must NOT*: Claim general repository secret scanning; restrict specifically to safety artifacts.
|
|
182
|
+
*Tests*: `tests/cost-ledger.test.js`
|
|
183
|
+
*Acceptance IDs*: `TEST-COST-E03`
|
|
184
|
+
*Completion criteria*: `TEST-COST-E03` passes fail-closed on secret-injected ledgers.
|
|
185
|
+
*Evidence*: Test assertion confirming rejection of credential fields.
|
|
186
|
+
|
|
187
|
+
- [x] **T003: Implement staleness evaluator for provider cost assumptions**
|
|
188
|
+
<!-- gemstack:validation_required=true -->
|
|
189
|
+
<!-- gemstack:tests=TEST-COST-E02 -->
|
|
190
|
+
<!-- gemstack:files=src/lib/cost-ledger.js,tests/cost-ledger.test.js -->
|
|
191
|
+
<!-- gemstack:depends=T001 -->
|
|
192
|
+
*Objective*: Detect expired or stale pricing assumptions without halting evaluation.
|
|
193
|
+
*Files*:
|
|
194
|
+
- MODIFY: `src/lib/cost-ledger.js`
|
|
195
|
+
- MODIFY: `tests/cost-ledger.test.js`
|
|
196
|
+
*Prerequisites*: `T001`
|
|
197
|
+
*Implementation requirements*:
|
|
198
|
+
- Implement `checkStaleness(capabilityEntry, maxAgeDays, referenceDate)`.
|
|
199
|
+
- Parse `freshness_date` (ISO 8601 YYYY-MM-DD). If older than threshold (default 90 days), emit warning `STALE_PROVIDER_COST_ASSUMPTION`.
|
|
200
|
+
- Allow evaluation to proceed when flagged as a warning.
|
|
201
|
+
*Must NOT*: Contact remote APIs to verify current pricing.
|
|
202
|
+
*Tests*: `tests/cost-ledger.test.js`
|
|
203
|
+
*Acceptance IDs*: `TEST-COST-E02`
|
|
204
|
+
*Completion criteria*: `TEST-COST-E02` passes, emitting `STALE_PROVIDER_COST_ASSUMPTION` without crashing.
|
|
205
|
+
*Evidence*: Unit test verifying warning emission for dates > 90 days old.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### Phase 2 — Provider Registry & Environment Safety
|
|
210
|
+
|
|
211
|
+
- [x] **T004: Implement provider registry loader and capability declaration validator**
|
|
212
|
+
<!-- gemstack:validation_required=true -->
|
|
213
|
+
<!-- gemstack:tests=TEST-COST-B01,TEST-COST-B03 -->
|
|
214
|
+
<!-- gemstack:files=src/lib/provider-registry.js,tests/provider-capability-gate.test.js -->
|
|
215
|
+
<!-- gemstack:depends=T001 -->
|
|
216
|
+
*Objective*: Create `src/lib/provider-registry.js` to load provider identities and declared capabilities.
|
|
217
|
+
*Files*:
|
|
218
|
+
- NEW: `src/lib/provider-registry.js`
|
|
219
|
+
- NEW: `tests/provider-capability-gate.test.js`
|
|
220
|
+
*Prerequisites*: `T001`
|
|
221
|
+
*Implementation requirements*:
|
|
222
|
+
- Implement `loadProviderRegistry(rootPath, featureDir)`.
|
|
223
|
+
- Validate provider identity format (`provider_id` matching canonical slug).
|
|
224
|
+
- Verify `type` is one of `COMMERCIAL`, `LOCAL`, `MOCK`.
|
|
225
|
+
- Index declared capabilities (e.g. `inference.generate_text`).
|
|
226
|
+
- Emit `UNKNOWN_PROVIDER_IDENTITY` for unregistered providers and `PROVIDER_CAPABILITY_UNDECLARED` for undeclared capabilities.
|
|
227
|
+
*Must NOT*: Conflate provider existence with authorization to spend.
|
|
228
|
+
*Tests*: `tests/provider-capability-gate.test.js`
|
|
229
|
+
*Acceptance IDs*: `TEST-COST-B01`, `TEST-COST-B03`
|
|
230
|
+
*Completion criteria*: Unit tests pass rejecting unregistered providers and undeclared capabilities.
|
|
231
|
+
*Evidence*: Deterministic rejection output with correct finding codes.
|
|
232
|
+
|
|
233
|
+
- [x] **T005: Implement environment tier resolution and commercial execution blocking in test/CI**
|
|
234
|
+
<!-- gemstack:validation_required=true -->
|
|
235
|
+
<!-- gemstack:tests=TEST-COST-C01,TEST-COST-C02 -->
|
|
236
|
+
<!-- gemstack:files=src/lib/provider-registry.js,tests/environment-provider-safety.test.js -->
|
|
237
|
+
<!-- gemstack:depends=T004 -->
|
|
238
|
+
*Objective*: Resolve environment tier and strictly block commercial operations in test and CI environments.
|
|
239
|
+
*Files*:
|
|
240
|
+
- MODIFY: `src/lib/provider-registry.js`
|
|
241
|
+
- NEW: `tests/environment-provider-safety.test.js`
|
|
242
|
+
*Prerequisites*: `T004`
|
|
243
|
+
*Implementation requirements*:
|
|
244
|
+
- Implement `resolveEnvironmentTier(options)` resolving `test`, `ci`, `development`, `staging`, `production`.
|
|
245
|
+
- Detect `test` via test runner runner context; detect `ci` via `process.env.CI`.
|
|
246
|
+
- In `test` or `ci`, commercial provider actions are strictly blocked with `ENV_COMMERCIAL_DENIED` even when ambient API keys exist in `process.env`.
|
|
247
|
+
*Must NOT*: Trust developer credentials in ambient environment variables to authorize commercial actions.
|
|
248
|
+
*Tests*: `tests/environment-provider-safety.test.js`
|
|
249
|
+
*Acceptance IDs*: `TEST-COST-C01`, `TEST-COST-C02`
|
|
250
|
+
*Completion criteria*: `TEST-COST-C01` and `TEST-COST-C02` pass, proving commercial denial in test/CI.
|
|
251
|
+
*Evidence*: Assertions passing with dummy credentials present in environment.
|
|
252
|
+
|
|
253
|
+
- [x] **T006: Implement mock provider verification and anti-escape validation**
|
|
254
|
+
<!-- gemstack:validation_required=true -->
|
|
255
|
+
<!-- gemstack:tests=TEST-COST-C03 -->
|
|
256
|
+
<!-- gemstack:files=src/lib/provider-registry.js,tests/environment-provider-safety.test.js -->
|
|
257
|
+
<!-- gemstack:depends=T005 -->
|
|
258
|
+
*Objective*: Allow verified local mocks in `test` environment while preventing mock escape to real networks.
|
|
259
|
+
*Files*:
|
|
260
|
+
- MODIFY: `src/lib/provider-registry.js`
|
|
261
|
+
- MODIFY: `tests/environment-provider-safety.test.js`
|
|
262
|
+
*Prerequisites*: `T005`
|
|
263
|
+
*Implementation requirements*:
|
|
264
|
+
- Implement `validateMockIntegrity(providerConfig)`.
|
|
265
|
+
- Providers declared with `type: "MOCK"` must prove local-only in-memory execution.
|
|
266
|
+
- Return `authorized: true` for verified mocks in `test` environment.
|
|
267
|
+
- Reject mock configurations with external URLs or remote endpoints with `MOCK_PROVIDER_ESCAPE_VIOLATION`.
|
|
268
|
+
*Must NOT*: Trust a provider as a mock based solely on its string name.
|
|
269
|
+
*Tests*: `tests/environment-provider-safety.test.js`
|
|
270
|
+
*Acceptance IDs*: `TEST-COST-C03`
|
|
271
|
+
*Completion criteria*: `TEST-COST-C03` passes for legitimate in-memory mocks.
|
|
272
|
+
*Evidence*: Test execution confirms mock execution permitted in test mode.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
### Phase 3 — Safety Gates
|
|
277
|
+
|
|
278
|
+
- [x] **T007: Implement canonical ProviderCapabilityGate**
|
|
279
|
+
<!-- gemstack:validation_required=true -->
|
|
280
|
+
<!-- gemstack:tests=TEST-COST-B02,TEST-COST-B04 -->
|
|
281
|
+
<!-- gemstack:files=src/lib/safety-gates.js,tests/provider-capability-gate.test.js -->
|
|
282
|
+
<!-- gemstack:depends=T004 -->
|
|
283
|
+
*Objective*: Create `src/lib/safety-gates.js` with fail-closed `ProviderCapabilityGate`.
|
|
284
|
+
*Files*:
|
|
285
|
+
- NEW: `src/lib/safety-gates.js`
|
|
286
|
+
- MODIFY: `tests/provider-capability-gate.test.js`
|
|
287
|
+
*Prerequisites*: `T004`
|
|
288
|
+
*Implementation requirements*:
|
|
289
|
+
- Implement `evaluateProviderCapability(request, registry)`.
|
|
290
|
+
- Evaluate in strict order: provider existence, environment permission, capability declaration, adapter support.
|
|
291
|
+
- Emit `PROVIDER_CAPABILITY_UNSUPPORTED` if adapter lacks support.
|
|
292
|
+
- Return deterministic decision object: `{ authorized, decision, reasonCode, message, context }`.
|
|
293
|
+
*Must NOT*: Mutate provider state or perform network queries.
|
|
294
|
+
*Tests*: `tests/provider-capability-gate.test.js`
|
|
295
|
+
*Acceptance IDs*: `TEST-COST-B02`, `TEST-COST-B04`
|
|
296
|
+
*Completion criteria*: `TEST-COST-B02` and `TEST-COST-B04` pass.
|
|
297
|
+
*Evidence*: Test assertions validating allowed and unsupported capability outcomes.
|
|
298
|
+
|
|
299
|
+
- [x] **T008: Implement canonical BillableActionGate**
|
|
300
|
+
<!-- gemstack:validation_required=true -->
|
|
301
|
+
<!-- gemstack:tests=TEST-COST-A01,TEST-COST-A02,TEST-COST-A03,TEST-COST-A04,TEST-COST-G01 -->
|
|
302
|
+
<!-- gemstack:files=src/lib/safety-gates.js,tests/billable-action-gate.test.js -->
|
|
303
|
+
<!-- gemstack:depends=T007,T003 -->
|
|
304
|
+
*Objective*: Implement `BillableActionGate` enforcing fail-closed spending authorization and budget limits.
|
|
305
|
+
*Files*:
|
|
306
|
+
- MODIFY: `src/lib/safety-gates.js`
|
|
307
|
+
- NEW: `tests/billable-action-gate.test.js`
|
|
308
|
+
*Prerequisites*: `T007`, `T003`
|
|
309
|
+
*Implementation requirements*:
|
|
310
|
+
- Implement `evaluateBillableAction(request, ledger, environmentTier)`.
|
|
311
|
+
- Order of evaluation:
|
|
312
|
+
1. Environment check (deny commercial in test/ci).
|
|
313
|
+
2. Action declaration check (emit `UNDECLARED_BILLABLE_ACTION` if missing).
|
|
314
|
+
3. Cost state resolution (emit `UNKNOWN_COST_CLASSIFICATION` if `UNKNOWN`; strictly fail closed).
|
|
315
|
+
4. Free check (allow if `FREE` and local/mock).
|
|
316
|
+
5. Authorization check (emit `BILLABLE_ACTION_UNAUTHORIZED` if token missing).
|
|
317
|
+
6. Budget check (emit `BUDGET_THRESHOLD_EXCEEDED` if requested units > granted budget).
|
|
318
|
+
*Must NOT*: Allow `UNKNOWN` to silently degrade to `FREE`.
|
|
319
|
+
*Tests*: `tests/billable-action-gate.test.js`
|
|
320
|
+
*Acceptance IDs*: `TEST-COST-A01`, `TEST-COST-A02`, `TEST-COST-A03`, `TEST-COST-A04`, `TEST-COST-G01`
|
|
321
|
+
*Completion criteria*: All 5 acceptance tests pass.
|
|
322
|
+
*Evidence*: Test assertions passing across all decision branches.
|
|
323
|
+
|
|
324
|
+
- [x] **T009: Implement structured decision and denial reason model**
|
|
325
|
+
<!-- gemstack:validation_required=true -->
|
|
326
|
+
<!-- gemstack:tests=TEST-COST-A02,TEST-COST-B02 -->
|
|
327
|
+
<!-- gemstack:files=src/lib/safety-gates.js,tests/billable-action-gate.test.js -->
|
|
328
|
+
<!-- gemstack:depends=T008 -->
|
|
329
|
+
*Objective*: Standardize structured decision objects across both gates with explainable denial reasons.
|
|
330
|
+
*Files*:
|
|
331
|
+
- MODIFY: `src/lib/safety-gates.js`
|
|
332
|
+
- MODIFY: `tests/billable-action-gate.test.js`
|
|
333
|
+
*Prerequisites*: `T008`
|
|
334
|
+
*Implementation requirements*:
|
|
335
|
+
- Format output:
|
|
336
|
+
```json
|
|
337
|
+
{
|
|
338
|
+
"authorized": false,
|
|
339
|
+
"decision": "DENY",
|
|
340
|
+
"reasonCode": "BILLABLE_ACTION_UNAUTHORIZED",
|
|
341
|
+
"message": "Human readable explanation",
|
|
342
|
+
"context": { "provider_id": "...", "capability_id": "...", "cost_state": "...", "environment": "..." }
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
- Never expose secrets, credentials, or raw API keys in messages or context.
|
|
346
|
+
*Must NOT*: Emit unstructured string errors that require regex parsing.
|
|
347
|
+
*Tests*: `tests/billable-action-gate.test.js`
|
|
348
|
+
*Acceptance IDs*: `TEST-COST-A02`, `TEST-COST-B02`
|
|
349
|
+
*Completion criteria*: Decision objects validate against expected JSON schema.
|
|
350
|
+
*Evidence*: Test assertions verifying structure and field types of gate decisions.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### Phase 4 — Execution Boundary & Fallback Chains
|
|
355
|
+
|
|
356
|
+
- [x] **T010: Implement provider execution boundary interceptor**
|
|
357
|
+
<!-- gemstack:validation_required=true -->
|
|
358
|
+
<!-- gemstack:tests=TEST-COST-A03,TEST-COST-B04 -->
|
|
359
|
+
<!-- gemstack:files=src/lib/provider-boundary.js,tests/provider-fallback.test.js -->
|
|
360
|
+
<!-- gemstack:depends=T009 -->
|
|
361
|
+
*Objective*: Create `src/lib/provider-boundary.js` to intercept adapter invocations behind safety gates.
|
|
362
|
+
*Files*:
|
|
363
|
+
- NEW: `src/lib/provider-boundary.js`
|
|
364
|
+
- NEW: `tests/provider-fallback.test.js`
|
|
365
|
+
*Prerequisites*: `T009`
|
|
366
|
+
*Implementation requirements*:
|
|
367
|
+
- Implement `executeProviderAction(actionRequest, adapter, options)`.
|
|
368
|
+
- Sequentially invoke `ProviderCapabilityGate` and `BillableActionGate`.
|
|
369
|
+
- Halt with structured error if either gate denies.
|
|
370
|
+
- Bind authorization token cryptographically to `provider_id` and `capability_id` before calling `adapter.execute()`.
|
|
371
|
+
*Must NOT*: Allow adapter execution if either gate returns `authorized: false`.
|
|
372
|
+
*Tests*: `tests/provider-fallback.test.js`
|
|
373
|
+
*Acceptance IDs*: `TEST-COST-A03`, `TEST-COST-B04`
|
|
374
|
+
*Completion criteria*: Execution succeeds only when both gates approve.
|
|
375
|
+
*Evidence*: Mock adapter execution count is exactly 1 on ALLOW, 0 on DENY.
|
|
376
|
+
|
|
377
|
+
- [x] **T011: Implement re-entrant fallback chain validation**
|
|
378
|
+
<!-- gemstack:validation_required=true -->
|
|
379
|
+
<!-- gemstack:tests=TEST-COST-D01,TEST-COST-D02 -->
|
|
380
|
+
<!-- gemstack:files=src/lib/provider-boundary.js,tests/provider-fallback.test.js -->
|
|
381
|
+
<!-- gemstack:depends=T010 -->
|
|
382
|
+
*Objective*: Guarantee that switching to fallback providers independently re-enters safety gates.
|
|
383
|
+
*Files*:
|
|
384
|
+
- MODIFY: `src/lib/provider-boundary.js`
|
|
385
|
+
- MODIFY: `tests/provider-fallback.test.js`
|
|
386
|
+
*Prerequisites*: `T010`
|
|
387
|
+
*Implementation requirements*:
|
|
388
|
+
- In `executeProviderAction`, handle primary adapter failure with fallback candidates.
|
|
389
|
+
- For each fallback candidate, independently evaluate `ProviderCapabilityGate` and `BillableActionGate`.
|
|
390
|
+
- If a fallback candidate lacks spending authorization, emit `PROVIDER_FALLBACK_UNAUTHORIZED` and halt.
|
|
391
|
+
- Never transfer authorization from primary provider to secondary provider.
|
|
392
|
+
*Must NOT*: Inherit spending authorization or bypass capability checks during fallback.
|
|
393
|
+
*Tests*: `tests/provider-fallback.test.js`
|
|
394
|
+
*Acceptance IDs*: `TEST-COST-D01`, `TEST-COST-D02`
|
|
395
|
+
*Completion criteria*: `TEST-COST-D01` and `TEST-COST-D02` pass.
|
|
396
|
+
*Evidence*: Test assertions confirming re-entrant gate calls and unauthorized fallback denial.
|
|
397
|
+
|
|
398
|
+
- [x] **T012: Implement architectural direct-bypass protections**
|
|
399
|
+
<!-- gemstack:validation_required=true -->
|
|
400
|
+
<!-- gemstack:tests=TEST-COST-D02 -->
|
|
401
|
+
<!-- gemstack:files=src/lib/provider-boundary.js,tests/provider-fallback.test.js -->
|
|
402
|
+
<!-- gemstack:depends=T011 -->
|
|
403
|
+
*Objective*: Prevent alias bypass, wrapper bypass, and direct adapter execution outside boundary.
|
|
404
|
+
*Files*:
|
|
405
|
+
- MODIFY: `src/lib/provider-boundary.js`
|
|
406
|
+
- MODIFY: `tests/provider-fallback.test.js`
|
|
407
|
+
*Prerequisites*: `T011`
|
|
408
|
+
*Implementation requirements*:
|
|
409
|
+
- Enforce provider ID normalization preventing alias spoofing.
|
|
410
|
+
- Reject execution requests missing explicit boundary invocation context.
|
|
411
|
+
*Must NOT*: Rely on user-modifiable strings for boundary security.
|
|
412
|
+
*Tests*: `tests/provider-fallback.test.js`
|
|
413
|
+
*Acceptance IDs*: `TEST-COST-D02`
|
|
414
|
+
*Completion criteria*: Alias and wrapper bypass attempts fail closed.
|
|
415
|
+
*Evidence*: Unit tests proving denial on spoofed provider IDs.
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
### Phase 5 — Verify, Closure & Verification
|
|
420
|
+
|
|
421
|
+
- [x] **T013: Extend gemstack verify with cost ledger and provider safety audits**
|
|
422
|
+
<!-- gemstack:validation_required=true -->
|
|
423
|
+
<!-- gemstack:tests=TEST-COST-F02 -->
|
|
424
|
+
<!-- gemstack:files=src/commands/verify.js,tests/verification-purity-cost.test.js -->
|
|
425
|
+
<!-- gemstack:depends=T008,T002 -->
|
|
426
|
+
*Objective*: Integrate cost ledger and provider safety verification into `gemstack verify` (Stage 5/6).
|
|
427
|
+
*Files*:
|
|
428
|
+
- MODIFY: `src/commands/verify.js`
|
|
429
|
+
- NEW: `tests/verification-purity-cost.test.js`
|
|
430
|
+
*Prerequisites*: `T008`, `T002`
|
|
431
|
+
*Implementation requirements*:
|
|
432
|
+
- Audit `cost-ledger.json` schema, integrity, and secret-free status in read-only mode.
|
|
433
|
+
- Verify that declared commercial adapters implement safety gates.
|
|
434
|
+
- Maintain 100% zero file mutations (before/after file hash snapshot matches).
|
|
435
|
+
*Must NOT*: Write to disk, update ledger files, or call external APIs during verify.
|
|
436
|
+
*Tests*: `tests/verification-purity-cost.test.js`
|
|
437
|
+
*Acceptance IDs*: `TEST-COST-F02`
|
|
438
|
+
*Completion criteria*: `TEST-COST-F02` passes with 0 file mutations.
|
|
439
|
+
*Evidence*: SHA-256 tree diff comparison confirms zero modified bytes.
|
|
440
|
+
|
|
441
|
+
- [x] **T014: Implement mechanical network purity enforcer for gemstack verify**
|
|
442
|
+
<!-- gemstack:validation_required=true -->
|
|
443
|
+
<!-- gemstack:tests=TEST-COST-F01 -->
|
|
444
|
+
<!-- gemstack:files=tests/verification-purity-cost.test.js -->
|
|
445
|
+
<!-- gemstack:depends=T013 -->
|
|
446
|
+
*Objective*: Mechanically prove that `gemstack verify` generates zero outbound network requests.
|
|
447
|
+
*Files*:
|
|
448
|
+
- MODIFY: `tests/verification-purity-cost.test.js`
|
|
449
|
+
*Prerequisites*: `T013`
|
|
450
|
+
*Implementation requirements*:
|
|
451
|
+
- In `tests/verification-purity-cost.test.js`, wrap `node:net.Socket`, `node:http.request`, and `node:https.request` with throwing hooks.
|
|
452
|
+
- Execute `verifyCommand({ target: tempDir })`.
|
|
453
|
+
- Assert that verify completes with exit code 0 and zero network connection attempts.
|
|
454
|
+
*Must NOT*: Rely on passive inspection; must actively intercept network primitives.
|
|
455
|
+
*Tests*: `tests/verification-purity-cost.test.js`
|
|
456
|
+
*Acceptance IDs*: `TEST-COST-F01`
|
|
457
|
+
*Completion criteria*: `TEST-COST-F01` passes cleanly with network sockets blocked.
|
|
458
|
+
*Evidence*: Test log confirming zero socket invocations during complete verify run.
|
|
459
|
+
|
|
460
|
+
- [x] **T015: Integrate cost ledger into closure context RelevantClosureFiles**
|
|
461
|
+
<!-- gemstack:validation_required=true -->
|
|
462
|
+
<!-- gemstack:tests=TEST-COST-F02 -->
|
|
463
|
+
<!-- gemstack:files=src/lib/closure-context.js,tests/verification-purity-cost.test.js -->
|
|
464
|
+
<!-- gemstack:depends=T013 -->
|
|
465
|
+
*Objective*: Include `cost-ledger.json` in `RelevantClosureFiles` and `closureContextHash` when present.
|
|
466
|
+
*Files*:
|
|
467
|
+
- MODIFY: `src/lib/closure-context.js`
|
|
468
|
+
- MODIFY: `tests/verification-purity-cost.test.js`
|
|
469
|
+
*Prerequisites*: `T013`
|
|
470
|
+
*Implementation requirements*:
|
|
471
|
+
- In `resolveRelevantFiles` (`src/lib/closure-context.js`), check for `cost-ledger.json` in root and active feature directories.
|
|
472
|
+
- If present, include path in aggregate hash computation.
|
|
473
|
+
*Must NOT*: Change Upgrade B reconciliation math or make `closure.json` authoritative.
|
|
474
|
+
*Tests*: `tests/verification-purity-cost.test.js`
|
|
475
|
+
*Acceptance IDs*: `TEST-COST-F02`
|
|
476
|
+
*Completion criteria*: `closureContextHash` includes ledger digest when present.
|
|
477
|
+
*Evidence*: Test assertions confirming context hash sensitivity to ledger modifications.
|
|
478
|
+
|
|
479
|
+
- [x] **T016: Integrate Upgrade C findings with accepted exception bindings**
|
|
480
|
+
<!-- gemstack:validation_required=true -->
|
|
481
|
+
<!-- gemstack:tests=TEST-COST-E02 -->
|
|
482
|
+
<!-- gemstack:files=src/commands/verify.js,tests/cost-ledger.test.js -->
|
|
483
|
+
<!-- gemstack:depends=T013 -->
|
|
484
|
+
*Objective*: Map Upgrade C findings into `src/lib/findings.js` and enforce strict non-waivable rules.
|
|
485
|
+
*Files*:
|
|
486
|
+
- MODIFY: `src/commands/verify.js`
|
|
487
|
+
- MODIFY: `tests/cost-ledger.test.js`
|
|
488
|
+
*Prerequisites*: `T013`
|
|
489
|
+
*Implementation requirements*:
|
|
490
|
+
- Generate canonical 64-char lowercase SHA-256 fingerprints for Upgrade C findings.
|
|
491
|
+
- Enforce that only `STALE_PROVIDER_COST_ASSUMPTION` is waivable via `contextHash`.
|
|
492
|
+
- All other Upgrade C findings remain non-waivable blockers.
|
|
493
|
+
*Must NOT*: Introduce wildcard or global exception bypasses.
|
|
494
|
+
*Tests*: `tests/cost-ledger.test.js`
|
|
495
|
+
*Acceptance IDs*: `TEST-COST-E02`
|
|
496
|
+
*Completion criteria*: Non-waivable findings cannot be suppressed; stale warning waives cleanly.
|
|
497
|
+
*Evidence*: Test assertions validating exception suppression rules.
|
|
498
|
+
|
|
499
|
+
- [x] **T017: Implement progressive legacy mode for provider-free projects**
|
|
500
|
+
<!-- gemstack:validation_required=true -->
|
|
501
|
+
<!-- gemstack:tests=TEST-COST-H01 -->
|
|
502
|
+
<!-- gemstack:files=src/commands/verify.js,tests/verification-purity-cost.test.js -->
|
|
503
|
+
<!-- gemstack:depends=T013 -->
|
|
504
|
+
*Objective*: Ensure existing projects without provider integrations operate without friction or errors.
|
|
505
|
+
*Files*:
|
|
506
|
+
- MODIFY: `src/commands/verify.js`
|
|
507
|
+
- MODIFY: `tests/verification-purity-cost.test.js`
|
|
508
|
+
*Prerequisites*: `T013`
|
|
509
|
+
*Implementation requirements*:
|
|
510
|
+
- If no `cost-ledger.json` or provider declarations are present, log informational notice `LEGACY_NO_PROVIDERS_DECLARED`.
|
|
511
|
+
- Verification returns exit code 0 with 0 errors.
|
|
512
|
+
*Must NOT*: Fail or emit blockers on repositories without providers.
|
|
513
|
+
*Tests*: `tests/verification-purity-cost.test.js`
|
|
514
|
+
*Acceptance IDs*: `TEST-COST-H01`
|
|
515
|
+
*Completion criteria*: `TEST-COST-H01` passes on a freshly initialized Gemstack repository.
|
|
516
|
+
*Evidence*: Verify exit code is 0 on legacy fixtures.
|
|
517
|
+
|
|
518
|
+
- [x] **T018: Implement adversarial attack and security bypass test suite**
|
|
519
|
+
<!-- gemstack:validation_required=true -->
|
|
520
|
+
<!-- gemstack:tests=TEST-COST-A04,TEST-COST-C01,TEST-COST-D02,TEST-COST-E03 -->
|
|
521
|
+
<!-- gemstack:files=tests/environment-provider-safety.test.js,tests/provider-fallback.test.js,tests/cost-ledger.test.js -->
|
|
522
|
+
<!-- gemstack:depends=T014,T011,T002 -->
|
|
523
|
+
*Objective*: Validate resistance against ambient credentials, provider aliases, mock escapes, and secret injection.
|
|
524
|
+
*Files*:
|
|
525
|
+
- MODIFY: `tests/environment-provider-safety.test.js`
|
|
526
|
+
- MODIFY: `tests/provider-fallback.test.js`
|
|
527
|
+
- MODIFY: `tests/cost-ledger.test.js`
|
|
528
|
+
*Prerequisites*: `T014`, `T011`, `T002`
|
|
529
|
+
*Implementation requirements*:
|
|
530
|
+
- Execute adversarial test matrix covering 17 required threat scenarios.
|
|
531
|
+
- Assert that every attack scenario fails closed with specific canonical finding codes.
|
|
532
|
+
*Must NOT*: Allow any bypass scenario to execute a mock or commercial target.
|
|
533
|
+
*Tests*: `tests/environment-provider-safety.test.js`, `tests/provider-fallback.test.js`
|
|
534
|
+
*Acceptance IDs*: `TEST-COST-A04`, `TEST-COST-C01`, `TEST-COST-D02`, `TEST-COST-E03`
|
|
535
|
+
*Completion criteria*: All adversarial test cases execute and pass.
|
|
536
|
+
*Evidence*: 100% pass rate across adversarial test cases.
|
|
537
|
+
|
|
538
|
+
- [x] **T019: Verify frozen contract integrity and execute full repository regression suite**
|
|
539
|
+
<!-- gemstack:validation_required=true -->
|
|
540
|
+
<!-- gemstack:tests=TEST-COST-H01 -->
|
|
541
|
+
<!-- gemstack:files=tests/contracts.test.js,tests/closure-gates.test.js,package.json -->
|
|
542
|
+
<!-- gemstack:depends=T018,T017 -->
|
|
543
|
+
*Objective*: Prove zero regression in Upgrade A and Upgrade B baseline test suites.
|
|
544
|
+
*Files*:
|
|
545
|
+
- MODIFY: `package.json` (test script enumeration)
|
|
546
|
+
*Prerequisites*: `T018`, `T017`
|
|
547
|
+
*Implementation requirements*:
|
|
548
|
+
- Update `package.json` test script to include the 6 new Upgrade C test suites (17 physical test files total, zero shell globs).
|
|
549
|
+
- Run `npm test`: confirm 25/25 Upgrade A tests pass, 20/20 Upgrade B tests pass, and 20/20 Upgrade C tests pass.
|
|
550
|
+
- Confirm 100% of historical physical tests pass without modification.
|
|
551
|
+
*Must NOT*: Modify historical Upgrade A/B test assertions.
|
|
552
|
+
*Tests*: `npm test`
|
|
553
|
+
*Acceptance IDs*: `TEST-COST-H01`
|
|
554
|
+
*Completion criteria*: Full repository test suite passes with exit code 0.
|
|
555
|
+
*Evidence*: Complete TAP runner summary showing 0 failures.
|
|
556
|
+
|
|
557
|
+
- [x] **T020: Execute Upgrade C dogfood collection and verify mechanical closure readiness**
|
|
558
|
+
<!-- gemstack:validation_required=true -->
|
|
559
|
+
<!-- gemstack:tests=TEST-COST-A01,TEST-COST-B01,TEST-COST-C01,TEST-COST-D01,TEST-COST-E01,TEST-COST-F01,TEST-COST-G01,TEST-COST-H01 -->
|
|
560
|
+
<!-- gemstack:files=specs/008-cost-provider-safety-gates/closure.json,.gemstack/state.json -->
|
|
561
|
+
<!-- gemstack:depends=T019 -->
|
|
562
|
+
*Objective*: Collect mechanical evidence on Feature 008 and verify closure readiness without version bump.
|
|
563
|
+
*Files*:
|
|
564
|
+
- NEW: `specs/008-cost-provider-safety-gates/closure.json`
|
|
565
|
+
- MODIFY: `.gemstack/state.json`
|
|
566
|
+
*Prerequisites*: `T019`
|
|
567
|
+
*Implementation requirements*:
|
|
568
|
+
- Run `gemstack collect` on `specs/008-cost-provider-safety-gates/`.
|
|
569
|
+
- Validate that `closure.json` records status `VERIFIED` and reconciles all 20 canonical tests.
|
|
570
|
+
- Run `gemstack verify`: confirm read-only verification passes with 0 blockers.
|
|
571
|
+
*Must NOT*: Perform git tag, commit, push, version bump, or release operations.
|
|
572
|
+
*Tests*: All 20 canonical tests
|
|
573
|
+
*Acceptance IDs*: All 20 canonical acceptance IDs
|
|
574
|
+
*Completion criteria*: Fresh `closure.json` generated with status `VERIFIED` and 0 blockers.
|
|
575
|
+
*Evidence*: Verified `closure.json` in feature directory.
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
## Acceptance Traceability Table (20/20 Canonical Tests)
|
|
580
|
+
|
|
581
|
+
| Canonical Acceptance ID | Implementation Task(s) | Target Physical Test Suite | Planned Mechanical Proof |
|
|
582
|
+
| :--- | :--- | :--- | :--- |
|
|
583
|
+
| **TEST-COST-A01** | T008, T020 | `tests/billable-action-gate.test.js` | Undeclared action throws `UNDECLARED_BILLABLE_ACTION` |
|
|
584
|
+
| **TEST-COST-A02** | T008, T009, T020 | `tests/billable-action-gate.test.js` | Missing token throws `BILLABLE_ACTION_UNAUTHORIZED` |
|
|
585
|
+
| **TEST-COST-A03** | T008, T010, T020 | `tests/billable-action-gate.test.js` | Valid authorization token returns `authorized: true` |
|
|
586
|
+
| **TEST-COST-A04** | T008, T018, T020 | `tests/billable-action-gate.test.js` | `UNKNOWN` cost classification fails closed |
|
|
587
|
+
| **TEST-COST-B01** | T004, T007, T020 | `tests/provider-capability-gate.test.js` | Undeclared capability throws `PROVIDER_CAPABILITY_UNDECLARED` |
|
|
588
|
+
| **TEST-COST-B02** | T007, T009, T020 | `tests/provider-capability-gate.test.js` | Unsupported capability throws `PROVIDER_CAPABILITY_UNSUPPORTED` |
|
|
589
|
+
| **TEST-COST-B03** | T004, T007, T020 | `tests/provider-capability-gate.test.js` | Unregistered provider throws `UNKNOWN_PROVIDER_IDENTITY` |
|
|
590
|
+
| **TEST-COST-B04** | T007, T010, T020 | `tests/provider-capability-gate.test.js` | Declared and supported capability returns `authorized: true` |
|
|
591
|
+
| **TEST-COST-C01** | T005, T018, T020 | `tests/environment-provider-safety.test.js` | Commercial execution blocked in `test` mode with `ENV_COMMERCIAL_DENIED` |
|
|
592
|
+
| **TEST-COST-C02** | T005, T020 | `tests/environment-provider-safety.test.js` | Commercial execution blocked in `ci` environment |
|
|
593
|
+
| **TEST-COST-C03** | T006, T020 | `tests/environment-provider-safety.test.js` | Verified in-memory mock allowed in `test` mode |
|
|
594
|
+
| **TEST-COST-D01** | T011, T020 | `tests/provider-fallback.test.js` | Fallback triggers independent gate re-evaluation |
|
|
595
|
+
| **TEST-COST-D02** | T011, T012, T018, T020 | `tests/provider-fallback.test.js` | Unauthorized secondary provider emits `PROVIDER_FALLBACK_UNAUTHORIZED` |
|
|
596
|
+
| **TEST-COST-E01** | T001, T020 | `tests/cost-ledger.test.js` | Invalid ledger schema emits `COST_LEDGER_INVALID` |
|
|
597
|
+
| **TEST-COST-E02** | T003, T016, T020 | `tests/cost-ledger.test.js` | Stale pricing date emits `STALE_PROVIDER_COST_ASSUMPTION` warning |
|
|
598
|
+
| **TEST-COST-E03** | T002, T018, T020 | `tests/cost-ledger.test.js` | Secret-bearing ledger rejected with `COST_LEDGER_INVALID` |
|
|
599
|
+
| **TEST-COST-F01** | T014, T020 | `tests/verification-purity-cost.test.js` | `gemstack verify` completes with sockets mocked to throw (0 network calls) |
|
|
600
|
+
| **TEST-COST-F02** | T013, T015, T020 | `tests/verification-purity-cost.test.js` | `gemstack verify` completes with 0 file mutations on disk |
|
|
601
|
+
| **TEST-COST-G01** | T008, T020 | `tests/billable-action-gate.test.js` | Exceeded unit budget throws `BUDGET_THRESHOLD_EXCEEDED` |
|
|
602
|
+
| **TEST-COST-H01** | T017, T019, T020 | `tests/verification-purity-cost.test.js` | Provider-free legacy project passes verify with exit code 0 |
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
## Adversarial Coverage Matrix (17 Threat Vectors)
|
|
607
|
+
|
|
608
|
+
| # | Adversarial Threat Vector | Planned Test Suite | Assigned Task | Expected Defense Outcome |
|
|
609
|
+
| :- | :--- | :--- | :--- | :--- |
|
|
610
|
+
| 1 | Ambient credentials in CI environment | `tests/environment-provider-safety.test.js` | T005 | `ENV_COMMERCIAL_DENIED` fail-closed |
|
|
611
|
+
| 2 | Unknown provider string in execution request | `tests/provider-capability-gate.test.js` | T004 | `UNKNOWN_PROVIDER_IDENTITY` |
|
|
612
|
+
| 3 | Unknown capability requested | `tests/provider-capability-gate.test.js` | T007 | `PROVIDER_CAPABILITY_UNDECLARED` |
|
|
613
|
+
| 4 | Unknown cost status in ledger | `tests/billable-action-gate.test.js` | T008 | `UNKNOWN_COST_CLASSIFICATION` |
|
|
614
|
+
| 5 | Unauthorized billable action execution | `tests/billable-action-gate.test.js` | T008 | `BILLABLE_ACTION_UNAUTHORIZED` |
|
|
615
|
+
| 6 | Provider alias bypass attempt | `tests/provider-fallback.test.js` | T012 | Alias canonicalization & rejection |
|
|
616
|
+
| 7 | Fallback provider authorization bypass | `tests/provider-fallback.test.js` | T011 | `PROVIDER_FALLBACK_UNAUTHORIZED` |
|
|
617
|
+
| 8 | Fake "mock" provider with external URL | `tests/environment-provider-safety.test.js` | T006 | `MOCK_PROVIDER_ESCAPE_VIOLATION` |
|
|
618
|
+
| 9 | Mock provider forwarding to real network | `tests/environment-provider-safety.test.js` | T006 | Socket throw assertion |
|
|
619
|
+
| 10 | Direct adapter path missing safety boundary | `tests/provider-fallback.test.js` | T010 | Boundary check throws on ungated call |
|
|
620
|
+
| 11 | Invalid ledger provider reference | `tests/cost-ledger.test.js` | T001 | `COST_LEDGER_INVALID` |
|
|
621
|
+
| 12 | Invalid action reference in request | `tests/billable-action-gate.test.js` | T008 | `UNDECLARED_BILLABLE_ACTION` |
|
|
622
|
+
| 13 | Secret token inserted into ledger | `tests/cost-ledger.test.js` | T002 | `COST_LEDGER_INVALID` |
|
|
623
|
+
| 14 | Conflicting policy declarations | `tests/environment-provider-safety.test.js` | T005 | Strict fail-closed default-deny |
|
|
624
|
+
| 15 | Stale pricing assumption (> 90 days) | `tests/cost-ledger.test.js` | T003 | `STALE_PROVIDER_COST_ASSUMPTION` |
|
|
625
|
+
| 16 | Verify attempting outbound network sockets | `tests/verification-purity-cost.test.js` | T014 | Sockets blocked; 0 network attempts |
|
|
626
|
+
| 17 | Primary failure followed by unvetted fallback | `tests/provider-fallback.test.js` | T011 | Re-entrant gate check blocks fallback |
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
## Explicit Deferred Items
|
|
631
|
+
|
|
632
|
+
- Live real-time provider credit balance queries (out of scope, non-goal).
|
|
633
|
+
- Payment provider webhook integration (out of scope, non-goal).
|
|
634
|
+
- Context compression algorithms (strictly reserved for Upgrade D).
|
|
635
|
+
- Package version bumping, release tagging, and npm publishing (handled strictly post-closure).
|