@skyold/protocol-engine 0.1.0-beta.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/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2026 TokenForge Contributors
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,466 @@
1
+ # TokenForge Protocol Engine
2
+
3
+ [简体中文](./README.zh-CN.md) | English
4
+
5
+ > **New to the Engine?** Start with the practical
6
+ > [Protocol Engine usage guide](../../docs/guides/PROTOCOL_ENGINE.md) (Simplified
7
+ > Chinese). It includes the supported/unsupported matrix, annotated sync,
8
+ > stream, and async examples, architecture diagrams, and the request sequence.
9
+ > This manual remains the complete API and evidence-boundary reference.
10
+
11
+ `@skyold/protocol-engine` is a Host-neutral execution kernel for AI model
12
+ aggregation. Any application, service, or library that implements the V1 port
13
+ contract can embed it. The Engine neither recognizes nor enumerates external
14
+ application types, and does not import a caller's HTTP framework, database,
15
+ identity model, credentials, pricing, usage store, or settlement policy.
16
+
17
+ In this manual, **Host** means only the abstract role that embeds and calls the
18
+ Engine. It does not identify a particular product or deployment shape.
19
+
20
+ ## Module status
21
+
22
+ The Engine is an independent workspace package with one package-root ESM API,
23
+ its own TypeScript build, its own test command, and one runtime dependency:
24
+ `@skyold/model-protocol`. It does not depend on any embedding Host,
25
+ concrete Provider Adapters, storage, HTTP frameworks, credential stores, or
26
+ network clients.
27
+
28
+ The package and its normalized-contract dependency are configured for public
29
+ npm access, but no registry release has been made yet. Therefore:
30
+
31
+ - it is independently embeddable and testable by packages in this repository;
32
+ - its packed runtime surface is independently inspectable;
33
+ - packed tarballs can be installed and exercised by an isolated external
34
+ consumer;
35
+ - public registry availability, a versioned release, and provenance signing are
36
+ not claimed until the release gate completes.
37
+
38
+ The local V1 core implementation is complete against its frozen execution
39
+ boundary. Overall rollout certification is still incomplete: fixture-backed
40
+ conformance is green for all nine built-in protocol families, while current
41
+ real-Provider success evidence covers seven. `openai-embeddings/v1` and
42
+ `openai-images/v1` still require successful real-Provider certification.
43
+ Public release, exact-SHA CI, and deployment are separate delivery gates, not
44
+ reasons to add Host business logic to the Engine.
45
+
46
+ Run its complete package-local gate from the repository root or package
47
+ directory:
48
+
49
+ ```bash
50
+ pnpm --dir packages/protocol-engine check
51
+ ```
52
+
53
+ ## Embed V1
54
+
55
+ ```ts
56
+ import {
57
+ createProtocolEngineTargetBindingV1,
58
+ createProtocolEngineV1,
59
+ isProtocolEngineErrorV1,
60
+ type ProtocolEngineAdapterRegistryPortV1,
61
+ } from '@skyold/protocol-engine';
62
+
63
+ const registry: ProtocolEngineAdapterRegistryPortV1 = createMyRegistry();
64
+ const binding = createProtocolEngineTargetBindingV1({
65
+ target: resolvedTarget,
66
+ bindTransport: (signal) => bindCredentialTransport(resolvedTarget, signal),
67
+ });
68
+ const engine = createProtocolEngineV1({ registry });
69
+ const execution = await engine.execute({ binding, task, signal });
70
+ ```
71
+
72
+ Hosts construct the request-bound execution binding with
73
+ `createProtocolEngineTargetBindingV1({ target, bindTransport })`. The factory
74
+ checks the Engine-requested `connectionRef` against the resolved target before
75
+ delegating credential-bound Transport creation, preventing a target from being
76
+ executed with another connection.
77
+
78
+ Every V1 Registry exposes `listProtocolFamilies()`. The Engine snapshots that
79
+ inventory as the sorted, immutable `engine.protocolFamilies` view, so embedded
80
+ Hosts, conformance tooling, and certification use the same extension contract.
81
+ The snapshot is also the dispatch authority: execute and async-job operations
82
+ reject undeclared families, and a returned Factory must declare exactly the
83
+ requested family before Transport binding.
84
+
85
+ The Host resolves identity, policy, target, and credentials before constructing
86
+ the binding; authenticated Host context never enters the Engine API. Host
87
+ governance runs before the Engine call, while usage, audit, and settlement
88
+ consume its returned normalized facts afterwards.
89
+
90
+ “Unified” means that every embedding consumer uses this same execution lifecycle
91
+ and public contract. It does not merge external application orchestration or move
92
+ identity, routing, credential, governance, usage, or settlement responsibilities
93
+ into the Engine. Consumers may resolve targets differently; after resolution,
94
+ each supplies the same narrow task, target binding, Registry, and Transport ports.
95
+
96
+ The target's `provider` value is opaque compatibility identity data, not Engine
97
+ dispatch authority. Engine core may carry it into protocol capability
98
+ validation, but must never select behavior by Provider name. This distinction
99
+ matters for semantic facts such as embedding compatibility spaces, where two
100
+ otherwise similar models can produce incompatible vectors. Adding another
101
+ Provider for an existing protocol therefore requires no Engine change; adding
102
+ another model usually changes only Host catalog/capability facts; adding a new
103
+ protocol adds its Codec, Adapter, Registry declaration, and conformance cases
104
+ without adding a Provider or Host branch to Engine core.
105
+
106
+ The binding exposes only the dispatch fields the Engine uses: Provider, model,
107
+ connection reference, and protocol/model capability. Host-only `sourceId` and
108
+ `capabilityId` remain beside the call in the Host. Engine execution and job
109
+ results do not echo the target back.
110
+
111
+ ## Public API reference
112
+
113
+ Import every API from the package root. Source and `dist` subpaths are private.
114
+
115
+ ### Runtime exports
116
+
117
+ | Export | Purpose |
118
+ | -------------------------------------------- | ----------------------------------------------------------------------- |
119
+ | `PROTOCOL_ENGINE_API_VERSION` | Exact V1 identifier: `tokenforge-protocol-engine/v1`. |
120
+ | `PROTOCOL_ENGINE_ERROR_CODES_V1` | Frozen inventory of stable V1 Engine failure codes. |
121
+ | `ProtocolEngineErrorV1` | Versioned error class for Engine operation failures. |
122
+ | `isProtocolEngineErrorV1(error)` | Cross-realm-safe guard for the public V1 error shape. |
123
+ | `createProtocolEngineV1({ registry })` | Creates an immutable Engine view over one Adapter Registry inventory. |
124
+ | `createProtocolEngineTargetBindingV1(input)` | Binds one resolved target to one request-scoped Host Transport factory. |
125
+
126
+ ### Exported types
127
+
128
+ | Type group | Exports |
129
+ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
130
+ | Engine | `ProtocolEngineV1`, `ProtocolEngineApiVersion`, `ProtocolEngineAdapterRegistryPortV1` |
131
+ | Execute input | `ProtocolEngineExecuteInputV1`, `ProtocolEngineDispatchTargetV1`, `ProtocolEngineTargetBindingV1`, `CreateProtocolEngineTargetBindingInputV1` |
132
+ | Execute output | `ProtocolEngineExecutionV1`, `ProtocolEngineResponseV1`, `ProtocolEngineStreamV1`, `ProtocolEngineAcceptedJobV1`, `ProtocolEngineRejectedV1` |
133
+ | Async jobs | `ProtocolEngineAsyncJobsV1`, `ProtocolEngineAsyncJobInputV1`, `ProtocolEngineAsyncJobListRequestV1`, `ProtocolEngineAsyncJobObservationV1`, `ProtocolEngineAsyncJobListResultV1`, `ProtocolEngineAsyncJobCancellationV1` |
134
+ | Errors | `ProtocolEngineErrorV1`, `ProtocolEngineErrorCodeV1`, `ProtocolEngineErrorPhaseV1`, `ProtocolEngineErrorOptionsV1` |
135
+
136
+ Normalized task, capability, Adapter, Transport, result, stream-event, usage,
137
+ and job-snapshot types come from `@skyold/model-protocol`; the Engine does
138
+ not duplicate those contracts.
139
+
140
+ ### `createProtocolEngineV1`
141
+
142
+ ```ts
143
+ const engine = createProtocolEngineV1({ registry });
144
+ ```
145
+
146
+ The injected Registry implements:
147
+
148
+ ```ts
149
+ interface ProtocolEngineAdapterRegistryPortV1 {
150
+ listProtocolFamilies(): readonly ProtocolFamily[];
151
+ require(protocolFamily: ProtocolFamily): ProviderAdapterFactory;
152
+ requireAsync?(protocolFamily: ProtocolFamily): ProviderAsyncJobAdapterFactory;
153
+ }
154
+ ```
155
+
156
+ Construction snapshots, sorts, validates, and freezes the protocol inventory.
157
+ Duplicate or malformed families fail immediately. `require()` handles sync and
158
+ stream execution. `requireAsync()` is required only for asynchronous job
159
+ families.
160
+
161
+ TokenForge Hosts normally obtain the Registry from the coherent built-in suite:
162
+
163
+ ```ts
164
+ import { createBuiltinTokenForgeProtocolSuiteV1 } from '@skyold/provider-adapters';
165
+ import { createProtocolEngineV1 } from '@skyold/protocol-engine';
166
+
167
+ const suite = createBuiltinTokenForgeProtocolSuiteV1();
168
+ const engine = createProtocolEngineV1({ registry: suite.registry });
169
+ console.log(engine.apiVersion);
170
+ console.log(engine.protocolFamilies);
171
+ ```
172
+
173
+ `engine.protocolFamilies` is the authoritative runtime inventory; do not copy a
174
+ separate protocol allowlist into a Host.
175
+
176
+ ### Target binding
177
+
178
+ ```ts
179
+ const binding = createProtocolEngineTargetBindingV1({
180
+ target: {
181
+ provider: 'opaque-provider-identity',
182
+ providerModel: 'resolved-provider-model',
183
+ connectionRef: 'host-owned-connection-reference',
184
+ capability: resolvedProtocolCapability,
185
+ },
186
+ bindTransport: (signal) => createCredentialBoundTransport({ resolvedConnection, signal }),
187
+ });
188
+ ```
189
+
190
+ The Host must finish authentication, routing, target selection, credential
191
+ lookup, URL safety policy, and governance before creating this binding. The
192
+ binding rejects connection-reference substitution before credentials or
193
+ network access are possible. Never store a tenant/account-specific Transport
194
+ inside a shared Registry or Engine.
195
+
196
+ ### `engine.execute`
197
+
198
+ ```ts
199
+ const execution = await engine.execute({
200
+ binding,
201
+ task,
202
+ signal,
203
+ // preparedMedia, // optional image-edit media prepared by the Host
204
+ // providerCallbackUrl, // optional async Provider callback selected by the Host
205
+ });
206
+ ```
207
+
208
+ | Input | Meaning |
209
+ | --------------------- | ---------------------------------------------------------------------------------------------------------- |
210
+ | `binding` | Resolved target plus request-bound Transport binder. |
211
+ | `task` | Normalized `TaskEnvelopeV2`; raw HTTP requests do not enter the Engine. |
212
+ | `signal` | Request cancellation signal propagated to Transport and stream/async start. |
213
+ | `preparedMedia` | Optional bounded, validated media streams used by protocols such as image editing. |
214
+ | `providerCallbackUrl` | Optional async-job callback URL; lifecycle persistence and callback handling remain Host responsibilities. |
215
+
216
+ Handle the complete discriminated union rather than assuming every model is a
217
+ synchronous Chat model:
218
+
219
+ ```ts
220
+ switch (execution.kind) {
221
+ case 'response': {
222
+ consumeTerminal(execution.terminal);
223
+ break;
224
+ }
225
+ case 'stream': {
226
+ try {
227
+ for await (const event of execution.events) consumeNormalizedEvent(event);
228
+ consumeTerminal(await execution.terminal);
229
+ } catch (error) {
230
+ execution.abort(error);
231
+ throw error;
232
+ }
233
+ break;
234
+ }
235
+ case 'accepted-job': {
236
+ persistAcceptedJob(execution.providerJobId);
237
+ break;
238
+ }
239
+ case 'rejected': {
240
+ recordRejectedStart(execution.failureCode, execution.acceptance.state);
241
+ break;
242
+ }
243
+ }
244
+ ```
245
+
246
+ `response` and `stream` terminal facts are already normalized and runtime
247
+ validated. `accepted-job` means the Provider durably accepted the job.
248
+ `rejected` includes both known rejection and acceptance-unknown; a Host must not
249
+ blindly retry an acceptance-unknown create because that can duplicate work.
250
+
251
+ ### `engine.jobs`
252
+
253
+ Use the same target binding for the Provider job that was previously accepted:
254
+
255
+ ```ts
256
+ const observation = await engine.jobs.get({ binding, providerJobId, signal });
257
+
258
+ const page = await engine.jobs.list({
259
+ binding,
260
+ pageNum: 1,
261
+ pageSize: 20,
262
+ signal,
263
+ });
264
+
265
+ await engine.jobs.cancel({ binding, providerJobId, signal });
266
+ ```
267
+
268
+ The Engine validates returned snapshots and lists. Job ownership, persistence,
269
+ polling schedules, callback reconciliation, result materialization, usage, and
270
+ settlement remain Host-owned.
271
+
272
+ ### Failure behavior
273
+
274
+ Invalid Registry inventories, target/task mismatches, unsupported capabilities,
275
+ connection substitution, malformed Adapter output, and Transport binding
276
+ failures reject the operation before unsafe facts reach the Host. Every Engine
277
+ operation failure uses `ProtocolEngineErrorV1` with the same
278
+ `tokenforge-protocol-engine/v1` API version, a stable `code`, and one structural
279
+ phase: `configuration`, `input`, `transport`, `adapter`, or `lifecycle`.
280
+
281
+ ```ts
282
+ try {
283
+ await engine.execute({ binding, task, signal });
284
+ } catch (error) {
285
+ if (!isProtocolEngineErrorV1(error)) throw error;
286
+ hostMapEngineFailure(error.code, error.phase);
287
+ }
288
+ ```
289
+
290
+ `cause` is diagnostic-only and can contain Host Transport or Adapter details;
291
+ never serialize it or a raw exception message to clients. The enumerable public
292
+ classification does not include Provider payloads, credentials, retry policy,
293
+ HTTP status, tenant facts, usage, pricing, or settlement decisions. Hosts own
294
+ those mappings. Historical fixed-runtime messages remain temporarily compatible,
295
+ but new integrations must switch on `code`, never `message`.
296
+
297
+ The Engine validates the normalized task against the resolved capability,
298
+ selects the protocol Adapter, and returns one versioned execution start:
299
+
300
+ - `response` for synchronous terminal execution;
301
+ - `stream` for normalized events, a terminal promise, and cancellation;
302
+ - `accepted-job` for durable asynchronous Provider acceptance;
303
+ - `rejected` for not-accepted or acceptance-unknown asynchronous starts.
304
+
305
+ Use `engine.jobs.get`, `engine.jobs.list`, and `engine.jobs.cancel` for later
306
+ async-job operations. Persistence, polling, callbacks, materialization, usage,
307
+ and settlement remain Host responsibilities.
308
+
309
+ An async Adapter factory declares its supported follow-up operations with
310
+ `jobOperations`. The Engine rejects an undeclared operation with
311
+ `PROTOCOL_ENGINE_CAPABILITY_UNSUPPORTED` before binding a Transport. Protocols
312
+ therefore keep their real lifecycle differences: for example, a protocol may
313
+ support `get` without pretending to support `list` or `cancel`.
314
+
315
+ ### Provider response compatibility
316
+
317
+ Provider wire responses are an open-world boundary. An Adapter validates and
318
+ extracts the fields understood by its protocol version, ignores additive fields
319
+ in synchronous bodies and known stream frames, and never retains those unknown
320
+ fields in normalized output. This lets a Provider add response metadata without
321
+ breaking an otherwise compatible protocol implementation.
322
+
323
+ Compatibility does not turn malformed known facts into success. Missing,
324
+ mistyped, conflicting, duplicated, unsafe, or semantically invalid known fields
325
+ still fail. An unknown stream event kind can alter lifecycle semantics, so it is
326
+ not treated as a harmless additive field and fails unless the protocol Adapter
327
+ explicitly supports it. Parser depth, body-size, URL, base64, index, usage, and
328
+ terminal-consistency limits remain enforced.
329
+
330
+ The Engine then validates Adapter outputs before exposing them to a Host. This
331
+ includes sync/stream acceptance, terminal structure and consistency, every
332
+ normalized stream event, plus async start, snapshot, and list result structure.
333
+ Normalized event, metadata, terminal, result, usage, Responses, and async-job
334
+ objects are closed schemas: undeclared fields are rejected. Raw Provider
335
+ extensions therefore cannot leak through an Adapter to Host egress, usage, or
336
+ settlement.
337
+
338
+ Terminal results must match the requested Task kind, and duplicate result,
339
+ terminal, and Responses usage facts must agree when present. A custom Adapter
340
+ therefore cannot rely on TypeScript casts to bypass the V1 runtime contract or
341
+ make Host egress and settlement observe different facts.
342
+
343
+ ## Extension rule
344
+
345
+ A new protocol implements the shared ingress/egress Codec and Adapter factory
346
+ contracts, registers Host Transport metadata, and includes them in one coherent
347
+ Protocol Suite. Engine core must not gain Provider-name, model-name, tenant, or
348
+ Host-framework branches. Embedded consumers may inject a custom Registry;
349
+ The TokenForge repository provides `createBuiltinTokenForgeProtocolSuiteV1()`
350
+ from `@skyold/provider-adapters` as its built-in implementation. Custom suites use
351
+ `createTokenForgeProtocolSuiteV1()`, which validates Adapter/Transport and
352
+ direct Ingress/Egress inventories before an Engine can consume the Registry.
353
+ TokenForge's built-in composition additionally declares direct-HTTP
354
+ participation beside each Adapter/Transport entry and rejects a declaration /
355
+ Codec inventory mismatch. Every embedding integration performs only Registry
356
+ lookup; a new protocol must not add an application-type or Host protocol-family
357
+ branch.
358
+
359
+ Consumers import only the `@skyold/protocol-engine` package root. Internal
360
+ source or build subpaths are not part of V1 and are rejected by the repository
361
+ architecture gate. The packed artifact allowlists only the five production
362
+ modules behind that root plus the English and Simplified Chinese manuals; tests
363
+ and other repository internals are not shipped.
364
+
365
+ The stable contract identifier is `tokenforge-protocol-engine/v1`. Breaking
366
+ contract changes require a new API version rather than changing V1 semantics.
367
+
368
+ ## Testing and proof levels
369
+
370
+ No test suite can mathematically guarantee all future Engine functionality.
371
+ TokenForge uses separate proof layers so a narrow unit test is not mistaken for
372
+ complete proxy evidence.
373
+
374
+ | Layer | Command | What it proves | What it does not prove |
375
+ | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
376
+ | Engine package | `pnpm --dir packages/protocol-engine check` | Independent build plus core Registry, binding, sync, stream, async-job, validation and Host-equivalence tests. | Concrete Adapter wire formats, Host persistence, live network. |
377
+ | Built-in conformance | `pnpm --filter @skyold/provider-adapters test -- src/conformance/runtime-conformance.test.ts` | Every registered built-in family executes through public Engine API with fixture Transports. | Provider credentials or current remote behavior. |
378
+ | Architecture boundary | `pnpm --filter @tokenforge/acceptance test -- src/L1-kernel/import-boundary.test.ts` | Engine dependency isolation, package surface, no raw-forward/direct Adapter bypass, Host neutrality. | Runtime semantic correctness by itself. |
379
+ | Host integration | Targeted suites for each embedding application and repository `pnpm check` | Caller-specific context binding, streams, media persistence, usage and settlement compatibility. | Exact deployed SHA or live Provider availability. |
380
+ | Real Provider certification | `pnpm certify:protocol-engine-real --manifest /protected/path/suite.json --run --env-file .env --ack-real-provider-calls I_AUTHORIZE_REAL_PROVIDER_CALLS` | Current authenticated Provider behavior for every successful evidence shard. | Deployment, billing correctness, or a missing family. |
381
+
382
+ For a local Engine change, the minimum independent gate is the Engine package
383
+ command. A protocol or Adapter change must also pass built-in conformance. A
384
+ Host integration change must additionally pass the affected Host suites. The
385
+ full goal is not complete until the Registry inventory has successful real
386
+ Provider evidence and the exact delivered SHA passes its CI and deployment
387
+ gates.
388
+
389
+ ## Real-Provider certification
390
+
391
+ The repository's opt-in certification Host drives this public Engine API and
392
+ the built-in Adapter Registry directly; it does not enter through any product
393
+ application route. A versioned JSON manifest supplies one or more cases for every
394
+ protocol family returned by `engine.protocolFamilies`, with resolved target and
395
+ capability facts, normalized tasks, secret environment-variable names, exact
396
+ Provider domains, and suite request/time ceilings. Pricing and Provider billing
397
+ are deliberately absent from both the Engine contract and certification facts.
398
+
399
+ Validation is offline and is the default:
400
+
401
+ ```bash
402
+ pnpm certify:protocol-engine-real --manifest /protected/path/suite.json
403
+ ```
404
+
405
+ Real execution additionally requires `--run`, an environment file, and the
406
+ exact CLI authorization
407
+ `--ack-real-provider-calls I_AUTHORIZE_REAL_PROVIDER_CALLS`. The CLI derives the
408
+ runtime domain allowlist from the already validated manifest and loads every
409
+ named key through its environment reference. The runner rejects private or
410
+ metadata network targets, cross-origin redirects, incomplete protocol
411
+ coverage, and request/time ceiling violations. It never prints prompts, keys,
412
+ Provider request IDs, job IDs, Provider names, or model names; durable evidence
413
+ is mode `0600` and contains only protocol facts, terminal state, numeric usage,
414
+ counts, and truncated SHA-256 fingerprints.
415
+ Generated manifests set the request ceiling to the exact worst case derived
416
+ from their cases. CLI summaries report execution starts separately from async
417
+ job list/get observation requests; neither field is a price, rate card, or
418
+ settlement input.
419
+ Cancellation is intentionally absent because it can destroy an externally
420
+ created job; it remains a separately authorized Provider lifecycle check.
421
+
422
+ ```bash
423
+ pnpm certify:protocol-engine-real --manifest /protected/path/suite.json --run \
424
+ --env-file .env \
425
+ --ack-real-provider-calls I_AUTHORIZE_REAL_PROVIDER_CALLS
426
+ ```
427
+
428
+ Passing local validation proves that the suite is structurally ready, not that
429
+ any Provider was called. Only a completed `--run` artifact is real-Provider
430
+ evidence.
431
+
432
+ For a list-capable async target that has already been accepted, the Acceptance
433
+ Host can perform a one-request, read-only diagnostic through `engine.jobs.list`
434
+ without creating another task:
435
+
436
+ ```bash
437
+ pnpm --filter @tokenforge/acceptance diagnose:protocol-engine-real-async \
438
+ --manifest /protected/path/async-shard.json \
439
+ --env-file /protected/path/provider.env \
440
+ --created-after 2026-08-18T03:00:00.000Z \
441
+ --ack-real-provider-calls I_AUTHORIZE_REAL_PROVIDER_CALLS
442
+ ```
443
+
444
+ The diagnostic reports only protocol family, matching count, normalized status
445
+ counts and bounded Provider error codes. It never emits Provider job IDs,
446
+ models, URLs, response messages or bodies and cannot satisfy a certification
447
+ gate.
448
+
449
+ When a list-capable asynchronous shard stopped only because bounded polling was
450
+ exhausted after the Provider had accepted the task, recover that exact submitted
451
+ task without creating another one:
452
+
453
+ ```bash
454
+ pnpm --filter @tokenforge/acceptance recover:protocol-engine-real-shard \
455
+ --manifest /protected/path/async-shard.json \
456
+ --failure-evidence /protected/path/polling-exhausted.json \
457
+ --env-file /protected/path/provider.env \
458
+ --output /protected/path/recovered-success.json \
459
+ --ack-real-provider-calls I_AUTHORIZE_REAL_PROVIDER_CALLS
460
+ ```
461
+
462
+ Recovery accepts only matching polling-exhaustion evidence, performs one
463
+ read-only `engine.jobs.list`, and requires exactly one matching job inside the
464
+ original submission window. It never resubmits the task or emits raw job IDs.
465
+ Only a normalized `succeeded` snapshot produces standard success evidence;
466
+ other states remain non-success evidence.