@agenticprimitives/fabric 0.0.0-alpha.4 → 0.0.0-alpha.41
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/CLAUDE.md +28 -35
- package/README.md +18 -16
- package/dist/adoption.d.ts +79 -0
- package/dist/adoption.d.ts.map +1 -0
- package/dist/adoption.js +95 -0
- package/dist/adoption.js.map +1 -0
- package/dist/case-emissions.d.ts +95 -0
- package/dist/case-emissions.d.ts.map +1 -0
- package/dist/case-emissions.js +208 -0
- package/dist/case-emissions.js.map +1 -0
- package/dist/case-machine.d.ts +28 -2
- package/dist/case-machine.d.ts.map +1 -1
- package/dist/case-machine.js +34 -7
- package/dist/case-machine.js.map +1 -1
- package/dist/cloudflare/authority-verdict-cache.d.ts +28 -1
- package/dist/cloudflare/authority-verdict-cache.d.ts.map +1 -1
- package/dist/cloudflare/authority-verdict-cache.js +32 -1
- package/dist/cloudflare/authority-verdict-cache.js.map +1 -1
- package/dist/cloudflare/exchange-store.d.ts +20 -1
- package/dist/cloudflare/exchange-store.d.ts.map +1 -1
- package/dist/cloudflare/exchange-store.js +26 -4
- package/dist/cloudflare/exchange-store.js.map +1 -1
- package/dist/cloudflare/index.d.ts +7 -4
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +8 -2
- package/dist/cloudflare/index.js.map +1 -1
- package/dist/cloudflare/interaction-store.d.ts +81 -0
- package/dist/cloudflare/interaction-store.d.ts.map +1 -0
- package/dist/cloudflare/interaction-store.js +281 -0
- package/dist/cloudflare/interaction-store.js.map +1 -0
- package/dist/cloudflare/orchestration-runtime.d.ts +19 -5
- package/dist/cloudflare/orchestration-runtime.d.ts.map +1 -1
- package/dist/cloudflare/orchestration-runtime.js +11 -6
- package/dist/cloudflare/orchestration-runtime.js.map +1 -1
- package/dist/cloudflare/principal-gateway-do.d.ts +360 -30
- package/dist/cloudflare/principal-gateway-do.d.ts.map +1 -1
- package/dist/cloudflare/principal-gateway-do.js +580 -58
- package/dist/cloudflare/principal-gateway-do.js.map +1 -1
- package/dist/cloudflare/receipt-signer.d.ts.map +1 -1
- package/dist/cloudflare/receipt-signer.js +6 -3
- package/dist/cloudflare/receipt-signer.js.map +1 -1
- package/dist/cloudflare/sql-vault.d.ts.map +1 -1
- package/dist/cloudflare/sql-vault.js +56 -0
- package/dist/cloudflare/sql-vault.js.map +1 -1
- package/dist/cloudflare/vault-exchange-store.d.ts +47 -0
- package/dist/cloudflare/vault-exchange-store.d.ts.map +1 -0
- package/dist/cloudflare/vault-exchange-store.js +135 -0
- package/dist/cloudflare/vault-exchange-store.js.map +1 -0
- package/dist/cloudflare/vault-interaction-store.d.ts +44 -0
- package/dist/cloudflare/vault-interaction-store.d.ts.map +1 -0
- package/dist/cloudflare/vault-interaction-store.js +259 -0
- package/dist/cloudflare/vault-interaction-store.js.map +1 -0
- package/dist/communicative-act.d.ts +24 -1
- package/dist/communicative-act.d.ts.map +1 -1
- package/dist/communicative-act.js +28 -0
- package/dist/communicative-act.js.map +1 -1
- package/dist/delivery-envelope.d.ts.map +1 -1
- package/dist/delivery-envelope.js +0 -1
- package/dist/delivery-envelope.js.map +1 -1
- package/dist/email/index.d.ts +79 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +91 -0
- package/dist/email/index.js.map +1 -0
- package/dist/enum-retirement.d.ts +43 -0
- package/dist/enum-retirement.d.ts.map +1 -0
- package/dist/enum-retirement.js +93 -0
- package/dist/enum-retirement.js.map +1 -0
- package/dist/exchange-record.d.ts +35 -4
- package/dist/exchange-record.d.ts.map +1 -1
- package/dist/exchange-record.js.map +1 -1
- package/dist/exchange-reducer.d.ts +32 -4
- package/dist/exchange-reducer.d.ts.map +1 -1
- package/dist/exchange-reducer.js +75 -1
- package/dist/exchange-reducer.js.map +1 -1
- package/dist/exchange-state.d.ts +30 -8
- package/dist/exchange-state.d.ts.map +1 -1
- package/dist/exchange-state.js +12 -10
- package/dist/exchange-state.js.map +1 -1
- package/dist/inbox-doc.d.ts +2 -2
- package/dist/inbox-doc.d.ts.map +1 -1
- package/dist/inbox-doc.js.map +1 -1
- package/dist/inbox-projection.d.ts +2 -2
- package/dist/inbox-projection.d.ts.map +1 -1
- package/dist/inbox-projection.js.map +1 -1
- package/dist/inbox-revision.d.ts +42 -0
- package/dist/inbox-revision.d.ts.map +1 -0
- package/dist/inbox-revision.js +57 -0
- package/dist/inbox-revision.js.map +1 -0
- package/dist/index.d.ts +26 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -2
- package/dist/index.js.map +1 -1
- package/dist/interaction-machines.d.ts +136 -0
- package/dist/interaction-machines.d.ts.map +1 -0
- package/dist/interaction-machines.js +174 -0
- package/dist/interaction-machines.js.map +1 -0
- package/dist/interaction-profile.d.ts +136 -0
- package/dist/interaction-profile.d.ts.map +1 -0
- package/dist/interaction-profile.js +212 -0
- package/dist/interaction-profile.js.map +1 -0
- package/dist/interaction-record.d.ts +168 -0
- package/dist/interaction-record.d.ts.map +1 -0
- package/dist/interaction-record.js +108 -0
- package/dist/interaction-record.js.map +1 -0
- package/dist/interactions/grant-scopes.d.ts +21 -0
- package/dist/interactions/grant-scopes.d.ts.map +1 -0
- package/dist/interactions/grant-scopes.js +88 -0
- package/dist/interactions/grant-scopes.js.map +1 -0
- package/dist/interactions/index.d.ts +1 -0
- package/dist/interactions/index.d.ts.map +1 -1
- package/dist/interactions/index.js +3 -0
- package/dist/interactions/index.js.map +1 -1
- package/dist/interactions/machine.d.ts +2 -2
- package/dist/interactions/machine.d.ts.map +1 -1
- package/dist/interactions/machine.js +2 -2
- package/dist/interactions/machine.js.map +1 -1
- package/dist/interactions/open-case.d.ts +60 -0
- package/dist/interactions/open-case.d.ts.map +1 -0
- package/dist/interactions/open-case.js +83 -0
- package/dist/interactions/open-case.js.map +1 -0
- package/dist/interactions/store.d.ts +9 -0
- package/dist/interactions/store.d.ts.map +1 -1
- package/dist/interactions/store.js +57 -2
- package/dist/interactions/store.js.map +1 -1
- package/dist/messaging/board.d.ts +4 -4
- package/dist/messaging/board.d.ts.map +1 -1
- package/dist/messaging/board.js +2 -2
- package/dist/messaging/board.js.map +1 -1
- package/dist/messaging/consult-routing.d.ts +103 -23
- package/dist/messaging/consult-routing.d.ts.map +1 -1
- package/dist/messaging/consult-routing.js +157 -47
- package/dist/messaging/consult-routing.js.map +1 -1
- package/dist/messaging/consult.d.ts +4 -0
- package/dist/messaging/consult.d.ts.map +1 -1
- package/dist/messaging/consult.js +3 -1
- package/dist/messaging/consult.js.map +1 -1
- package/dist/messaging/conversation-interaction.d.ts +66 -0
- package/dist/messaging/conversation-interaction.d.ts.map +1 -0
- package/dist/messaging/conversation-interaction.js +139 -0
- package/dist/messaging/conversation-interaction.js.map +1 -0
- package/dist/messaging/conversation.d.ts +69 -1
- package/dist/messaging/conversation.d.ts.map +1 -1
- package/dist/messaging/conversation.js +131 -0
- package/dist/messaging/conversation.js.map +1 -1
- package/dist/messaging/delivery.d.ts +2 -2
- package/dist/messaging/delivery.d.ts.map +1 -1
- package/dist/messaging/delivery.js +8 -1
- package/dist/messaging/delivery.js.map +1 -1
- package/dist/messaging/envelope.d.ts +7 -3
- package/dist/messaging/envelope.d.ts.map +1 -1
- package/dist/messaging/envelope.js +18 -1
- package/dist/messaging/envelope.js.map +1 -1
- package/dist/messaging/hash.d.ts +8 -2
- package/dist/messaging/hash.d.ts.map +1 -1
- package/dist/messaging/hash.js +6 -0
- package/dist/messaging/hash.js.map +1 -1
- package/dist/messaging/inbox-assistant.d.ts +16 -4
- package/dist/messaging/inbox-assistant.d.ts.map +1 -1
- package/dist/messaging/inbox-assistant.js +27 -4
- package/dist/messaging/inbox-assistant.js.map +1 -1
- package/dist/messaging/index.d.ts +7 -3
- package/dist/messaging/index.d.ts.map +1 -1
- package/dist/messaging/index.js +11 -2
- package/dist/messaging/index.js.map +1 -1
- package/dist/messaging/outbound-message.d.ts +42 -0
- package/dist/messaging/outbound-message.d.ts.map +1 -0
- package/dist/messaging/outbound-message.js +64 -0
- package/dist/messaging/outbound-message.js.map +1 -0
- package/dist/messaging/projector.d.ts +3 -3
- package/dist/messaging/projector.d.ts.map +1 -1
- package/dist/messaging/projector.js.map +1 -1
- package/dist/messaging/receipts.d.ts +3 -3
- package/dist/messaging/receipts.d.ts.map +1 -1
- package/dist/messaging/receipts.js.map +1 -1
- package/dist/messaging/rules.d.ts +10 -3
- package/dist/messaging/rules.d.ts.map +1 -1
- package/dist/messaging/rules.js +8 -1
- package/dist/messaging/rules.js.map +1 -1
- package/dist/messaging/store.d.ts +4 -4
- package/dist/messaging/store.d.ts.map +1 -1
- package/dist/messaging/store.js +5 -3
- package/dist/messaging/store.js.map +1 -1
- package/dist/messaging/types.d.ts +30 -0
- package/dist/messaging/types.d.ts.map +1 -1
- package/dist/messaging/types.js +3 -0
- package/dist/messaging/types.js.map +1 -1
- package/dist/messaging/vault-store.d.ts +2 -2
- package/dist/messaging/vault-store.d.ts.map +1 -1
- package/dist/messaging/vault-store.js +8 -0
- package/dist/messaging/vault-store.js.map +1 -1
- package/dist/protocol-binding.d.ts +71 -0
- package/dist/protocol-binding.d.ts.map +1 -0
- package/dist/protocol-binding.js +0 -0
- package/dist/protocol-binding.js.map +1 -0
- package/dist/record-catalog.d.ts.map +1 -1
- package/dist/record-catalog.js +12 -0
- package/dist/record-catalog.js.map +1 -1
- package/package.json +28 -15
package/CLAUDE.md
CHANGED
|
@@ -6,22 +6,9 @@ exec/case FSM. Decentralized (per-principal gateway + vault), tiered (T0/T1/T2),
|
|
|
6
6
|
re-verified against the principal SA. Transport-agnostic core; the Cloudflare `PrincipalGatewayDO`
|
|
7
7
|
adapter ships from `./cloudflare`.
|
|
8
8
|
|
|
9
|
-
## Status
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- **W2 DONE (`./cloudflare` adapter):** `PrincipalGatewayDO`, co-resident on one `state.storage.sql`
|
|
13
|
-
trust domain — `createDurableObjectSqlVault` (per-owner DEK, L2 envelope crypto); durable
|
|
14
|
-
single-writer `createDurableObjectExchangeStore` (fail-closed `applyExchangeEvent`); T0
|
|
15
|
-
`deliver`/`applyEvent`/`inbox`; T1 `AuthorityVerdictCache` + `RequestIdLedger` (§3a: cached verdict
|
|
16
|
-
A + single-use requestId); **co-resident MCP** (`invokeFast` runs the tool IN-PROCESS over the DO
|
|
17
|
-
vault after the A→B→requestId gate; heavy verify + KEK wrapper INJECTED via `GatewayDeps`); **T2
|
|
18
|
-
orchestration loop** (co-resident tools AS the `orchestration` ToolInvoker; only the LLM planner
|
|
19
|
-
injected); **signed `DeliveryReceiptV1`** (DO-local secp256k1). The ONLY subtree importing
|
|
20
|
-
`@cloudflare/workers-types`.
|
|
21
|
-
- **W4 DONE:** `GatewaySurfaceCommitmentV1` (gatewayRoot preimage) + peer `DeliveryEnvelopeV1` +
|
|
22
|
-
`receiveDelivery` + `OutboxStore` store-and-forward.
|
|
23
|
-
- **Next:** on-chain `atl:gatewayRoot` record (contracts, separate); `A2aTaskDO`/`SessionStoreDO`
|
|
24
|
-
absorption + `alarm()` drain; `fetch`/`alarm` e2e via vitest-pool-workers.
|
|
9
|
+
## Status
|
|
10
|
+
**W1–W10b DONE** — history: [`docs/architecture.md` §7a](docs/architecture.md). Next: `MessageEnvelopeV1.kind`
|
|
11
|
+
(a re-signing cutover, spec 340 §R.1/§R.3); on-chain `atl:gatewayRoot`; `A2aTaskDO`/`SessionStoreDO` absorption.
|
|
25
12
|
|
|
26
13
|
## What this package owns
|
|
27
14
|
- `ExchangeRecordV1` — the ONE canonical object (spine id `xch_`); two-level FSM: `ExecState`
|
|
@@ -33,12 +20,29 @@ adapter ships from `./cloudflare`.
|
|
|
33
20
|
case reducer + typed payloads + runs (from `interactions`), delivery/admission/discovery.
|
|
34
21
|
|
|
35
22
|
## Hard rules
|
|
23
|
+
- **DO-local is the serving plane; the vault is the RECORD** ([ADR-0055](../../docs/architecture/decisions/0055-vaults-are-the-canonical-system-of-record-for-content.md)
|
|
24
|
+
+ amendment). `state.storage.sql` holds ordering, cursors, receipts, request-id ledgers, projections,
|
|
25
|
+
caches. Test for any new table: *if this DO were wiped, is the loss a rebuild or a bereavement?* A
|
|
26
|
+
projection must be rebuildable AND the rebuild tested (vault-first write · `rebuild()` in code · a test
|
|
27
|
+
that wipes and rebuilds) — `createVaultExchangeStore` / `createVaultInteractionStore` satisfy all three;
|
|
28
|
+
residency (**each party holds their own copy**) is [spec 316 §0b](../../specs/316-agentic-interaction-fabric.md).
|
|
29
|
+
`PrincipalGatewayDO` builds a DO-SQL vault INTERNALLY, so an adopting app MUST inject.
|
|
30
|
+
- **Two serving planes; the transition is a LADDER** ([ADR-0060](../../docs/architecture/decisions/0060-incremental-gateway-adoption.md)).
|
|
31
|
+
`InteractionsDO` serves; this is the target. Ops climb `off → shadow → serving` one at a time. A clean
|
|
32
|
+
shadow proves the planes AGREE, never that either is right.
|
|
33
|
+
- **The gateway authenticates its own ingress** (spec 445 §3.4): `principal`/`tier`/`actor` come only from the
|
|
34
|
+
injected `GatewayDeps.authenticate` via `admitCaller` → `AuthenticatedCaller`; no authenticator ⇒ refused.
|
|
35
|
+
`orchestrate` = verdict + per-step caveat pass + request id. Only an `active` interaction takes exchanges;
|
|
36
|
+
`openInteraction` never overwrites. Consult eligibility = current member ∩ live grant (two inputs).
|
|
36
37
|
- **Authority is never satisfied by the exchange.** A request carries an `authorityRef`; approving a
|
|
37
38
|
case advances the lifecycle, it NEVER unlocks a resource (spec 316 §2, ADR-0041).
|
|
38
39
|
- **`ExecState` is `fulfillment`'s `TaskState`, unmodified** — `fulfillment` stays a pure leaf.
|
|
39
40
|
- **Fail-closed coupling.** An `(exec, case)` pair with no mapping is a typed rejection.
|
|
40
41
|
- **Transport-agnostic core.** No Cloudflare/MCP/A2A-SDK imports in `src/` — `./cloudflare` is the
|
|
41
42
|
only adapter and the only `@cloudflare/workers-types` consumer.
|
|
43
|
+
- **The adoption ladder's mechanics are here** (`src/adoption.ts`, spec 399 §4): `adoptionStage(ledger, op, env)`
|
|
44
|
+
(`GATEWAY_SHADOW` gates a shadow; `""` is unset), `compareServed` / `classifyDivergence`, `shouldShadow`,
|
|
45
|
+
`recordDivergence`. The ledger VALUES — which op is on which rung, and why — stay with the product.
|
|
42
46
|
|
|
43
47
|
## Boundary
|
|
44
48
|
`types`, `fulfillment`, `vault`, `audit`, `delegation`, `chain-state`, `tool-policy`, `agent-naming`
|
|
@@ -46,22 +50,11 @@ adapter ships from `./cloudflare`.
|
|
|
46
50
|
provenance` (the PROV-O projector). No back-edges; nothing imports `fabric` except `./cloudflare` + apps.
|
|
47
51
|
|
|
48
52
|
## Validate
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
(spec 316 W1); demo guide: [`apps/demo-sso-next/docs/messaging-interactions/guide.md`](../../apps/demo-sso-next/docs/messaging-interactions/guide.md).
|
|
58
|
-
- **Home / agentic control plane + inbox** ([`specs/310`](../../specs/310-agentic-trust-home-control-plane-and-inbox.md)) —
|
|
59
|
-
the vault-resident inbox + control-plane projections read fabric wire types; demo guide:
|
|
60
|
-
[`apps/demo-sso-next/docs/home-inbox/guide.md`](../../apps/demo-sso-next/docs/home-inbox/guide.md).
|
|
61
|
-
- Index: [`docs/architecture/cross-cutting-capabilities.md`](../../docs/architecture/cross-cutting-capabilities.md).
|
|
62
|
-
|
|
63
|
-
## Spec + demo guides
|
|
64
|
-
`../../specs/316-agentic-interaction-fabric.md` (architect-of-record) +
|
|
65
|
-
`../../docs/architecture/agentic-interaction-fabric-target.md` + ADR-0047. Demo guides: spec 309
|
|
66
|
-
`../../apps/demo-sso-next/docs/messaging-interactions/guide.md` · spec 310
|
|
67
|
-
`../../apps/demo-sso-next/docs/home-inbox/guide.md`.
|
|
53
|
+
`pnpm --filter @agenticprimitives/fabric typecheck && pnpm --filter @agenticprimitives/fabric test`
|
|
54
|
+
|
|
55
|
+
## Capabilities, spec + guides
|
|
56
|
+
Messaging + Interactions ([spec 309](../../specs/309-messaging-and-interactions.md)) · Home control plane +
|
|
57
|
+
inbox ([spec 310](../../specs/310-agentic-trust-home-control-plane-and-inbox.md)) ·
|
|
58
|
+
[index](../../docs/architecture/cross-cutting-capabilities.md) · [spec 316](../../specs/316-agentic-interaction-fabric.md) (architect-of-record) ·
|
|
59
|
+
[target](../../docs/architecture/agentic-interaction-fabric-target.md) · ADR-0047 ·
|
|
60
|
+
[fabric architecture](docs/architecture.md) (live wiring + build history).
|
package/README.md
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
# @agenticprimitives/fabric
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
(envelope/inbox) and `interactions` (case/run) into ONE canonical exchange object over a two-level
|
|
5
|
-
exec/case state machine. Transport-agnostic core; the Cloudflare gateway ships as a `./cloudflare` adapter.
|
|
3
|
+
> Part of **[Agentic Primitives](https://agenticprimitives.dev)** — the open-source trust substrate for agentic applications: identity that can sign, authority checked at act time, evidence the owner carries. [Developer kit](https://github.com/agentictrustlabs/agentic-primitives) · [All packages](https://agenticprimitives.dev/developers)
|
|
6
4
|
|
|
7
|
-
- **
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- **Subpaths:** `@agenticprimitives/fabric/messaging` + `/interactions` re-export the absorbed surfaces.
|
|
5
|
+
Ring-0 **operational** realization of Agentic Interaction. Semantics live under `apix:`
|
|
6
|
+
([ADR-0058](../../docs/architecture/decisions/0058-agentic-interaction-canonical-bounded-context.md) ·
|
|
7
|
+
[spec 340](../../specs/340-agentic-interaction.md)); this package owns wire types, reducers, and the
|
|
8
|
+
Cloudflare gateway adapter — not the ontology namespace (`apfab:` retired).
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
Runtime doctrine still [spec 316](../../specs/316-agentic-interaction-fabric.md) /
|
|
11
|
+
[ADR-0047](../../docs/architecture/decisions/0047-agent-exchange-fabric-a2a-native.md): A2A-native
|
|
12
|
+
substrate absorbing messaging + interactions into one exchange object over a two-level exec/case FSM.
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
- **Exchange:** `ExchangeRecordV1` — `ExecState` + optional `CaseState`, fail-closed coupling.
|
|
15
|
+
- **Interaction (spec 340):** `InteractionRecordV1` + profiles + context snapshots on
|
|
16
|
+
`PrincipalGatewayDO` — **in package; apps still use demo-a2a `InteractionsDO` + vault board**.
|
|
17
|
+
- **Subpaths:** `@agenticprimitives/fabric/messaging` + `/interactions`.
|
|
18
|
+
|
|
19
|
+
Authority is never satisfied by the exchange (ADR-0041).
|
|
20
|
+
|
|
21
|
+
**Start here for app wiring + adoption matrix:** [`docs/architecture.md`](docs/architecture.md).
|
|
22
|
+
Also: `CLAUDE.md` · [target architecture](../../docs/architecture/agentic-interaction-fabric-target.md) ·
|
|
23
|
+
[commercial comparison](docs/fabric-capabilities-vs-commercial.md) · [gaps](docs/fabric-capability-gaps.md).
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/** Which of the five candidate causes an op's move actually exercises. Naming it per op is the point of
|
|
2
|
+
* moving one at a time: if an op diverges, its concerns say where to look, and where not to. */
|
|
3
|
+
export type AdoptionConcern = 'auth' | 'projection' | 'ordering' | 'data-shape' | 'assistant';
|
|
4
|
+
export type AdoptionStage = 'off' | 'shadow' | 'serving';
|
|
5
|
+
export interface AdoptionEntry {
|
|
6
|
+
stage: AdoptionStage;
|
|
7
|
+
/** What moving this op puts at risk — read this first when its shadow diverges. */
|
|
8
|
+
concerns: readonly AdoptionConcern[];
|
|
9
|
+
/** Why this op is at this rung. Prose, because "it's next" and "it's blocked" look identical in a stage
|
|
10
|
+
* field, and the difference is the whole state of the migration. */
|
|
11
|
+
note: string;
|
|
12
|
+
/**
|
|
13
|
+
* Fields that legitimately differ between the two planes because each computes them at its own instant.
|
|
14
|
+
* Declared PER OP and BEFORE evidence arrives — classifying noise after seeing a report is how a real
|
|
15
|
+
* divergence gets explained away as expected. An EMPTY list is a claim, not an omission: it asserts this
|
|
16
|
+
* op has no per-read computation, so any difference is either a race or a defect. Say why in `note`.
|
|
17
|
+
*/
|
|
18
|
+
volatileFields: readonly string[];
|
|
19
|
+
}
|
|
20
|
+
/** The ledger: one place that says which plane serves what, so adoption is data rather than conditionals
|
|
21
|
+
* spread across a serving object. An op absent from it is `off`: adoption is opt-in, because the failure
|
|
22
|
+
* mode of opt-out is an op that moved because nobody remembered to stop it. */
|
|
23
|
+
export type AdoptionLedger = Readonly<Record<string, AdoptionEntry>>;
|
|
24
|
+
/**
|
|
25
|
+
* The stage an op runs at IN THIS DEPLOYMENT. The ledger says how far an op has climbed in the code; the
|
|
26
|
+
* deployment's `GATEWAY_SHADOW` says whether it is running the comparison at all. Both are required, and the
|
|
27
|
+
* env one defaults to OFF — constructing the gateway creates its tables, and an ungated shadow on a hot op
|
|
28
|
+
* would make that storage decision for every principal at once. Empty string is unset, not enabled
|
|
29
|
+
* (`wrangler`'s `VAR = ""` binds an empty string that `??` sails straight past).
|
|
30
|
+
*/
|
|
31
|
+
export declare function adoptionStage(ledger: AdoptionLedger, op: string, env?: {
|
|
32
|
+
GATEWAY_SHADOW?: string;
|
|
33
|
+
}): AdoptionStage;
|
|
34
|
+
export interface Divergence {
|
|
35
|
+
op: string;
|
|
36
|
+
at: string;
|
|
37
|
+
/** `equal` is recorded too. A shadow that only reports differences cannot distinguish "the planes agree"
|
|
38
|
+
* from "the shadow never ran", and those justify opposite decisions about promoting. */
|
|
39
|
+
kind: 'equal' | 'value' | 'raced' | 'gateway-error' | 'shadow-skipped';
|
|
40
|
+
detail?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Compare the two planes' answers. Canonical JSON with sorted keys: key ORDER is not a difference worth
|
|
44
|
+
* blocking a promotion on. Everything else counts, including `undefined` vs absent — a field that vanished
|
|
45
|
+
* is exactly the data-shape drift being watched for.
|
|
46
|
+
*/
|
|
47
|
+
export declare function compareServed(op: string, served: unknown, shadow: unknown, at: string): Divergence;
|
|
48
|
+
/**
|
|
49
|
+
* Was an apparent divergence just the document moving between the two reads? After the shadow read, take
|
|
50
|
+
* the serving read AGAIN: `servedAgain` matches the shadow ⇒ the document moved — RACED, benign, evidence of
|
|
51
|
+
* nothing; `servedAgain` still matches the original and differs from the shadow ⇒ the planes really
|
|
52
|
+
* disagree. DELIBERATELY CONSERVATIVE: anything not provably a race stays `value`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function classifyDivergence(input: {
|
|
55
|
+
op: string;
|
|
56
|
+
served: unknown;
|
|
57
|
+
shadow: unknown;
|
|
58
|
+
servedAgain: unknown;
|
|
59
|
+
at: string;
|
|
60
|
+
}): Divergence;
|
|
61
|
+
/**
|
|
62
|
+
* Should this call run its shadow? Shadowing doubles the delegated reads on the path being shadowed, so it
|
|
63
|
+
* is SAMPLED: at most one shadow per principal per `intervalMs`. Time-based rather than 1-in-N because it
|
|
64
|
+
* bounds the ADDED LOAD directly; a ratio bounds a proportion of a rate that varies with how many clients a
|
|
65
|
+
* principal has open. The first call always samples — a low-traffic principal must still contribute.
|
|
66
|
+
*/
|
|
67
|
+
export declare function shouldShadow(input: {
|
|
68
|
+
lastShadowAt: number | undefined;
|
|
69
|
+
now: number;
|
|
70
|
+
intervalMs: number;
|
|
71
|
+
}): boolean;
|
|
72
|
+
/** One shadow per principal per minute: enough to catch a systematic difference within a session, far below
|
|
73
|
+
* a per-principal read limiter's budget even with several clients open. */
|
|
74
|
+
export declare const SHADOW_INTERVAL_MS = 60000;
|
|
75
|
+
/** How many divergences to keep — in MEMORY, not durable storage: diagnostics with a shelf life of one
|
|
76
|
+
* investigation. Losing them on isolate recycle is the correct trade. */
|
|
77
|
+
export declare const DIVERGENCE_BUFFER = 20;
|
|
78
|
+
export declare function recordDivergence(buf: Divergence[], d: Divergence): Divergence[];
|
|
79
|
+
//# sourceMappingURL=adoption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adoption.d.ts","sourceRoot":"","sources":["../src/adoption.ts"],"names":[],"mappings":"AAiBA;iGACiG;AACjG,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,YAAY,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,CAAC;AAE9F,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,aAAa,CAAC;IACrB,mFAAmF;IACnF,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IACrC;yEACqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED;;gFAEgF;AAChF,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;AAErE;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CAIlH;AAID,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX;6FACyF;IACzF,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,eAAe,GAAG,gBAAgB,CAAC;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,CAKlG;AAoBD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,UAAU,CAQxI;AAID;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAAE,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAGlH;AAED;4EAC4E;AAC5E,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAEzC;0EAC0E;AAC1E,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,UAAU,GAAG,UAAU,EAAE,CAG/E"}
|
package/dist/adoption.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// INCREMENTAL SERVING-PLANE ADOPTION — the LADDER (ADR-0060; ADR-0055 amendment). Promoted from the runtime
|
|
2
|
+
// app in spec 399 W0 (§4): the ledger TYPES, the rung rule and the divergence/sampling mechanics are the
|
|
3
|
+
// contract every product adopting `PrincipalGatewayDO` needs; the ledger VALUES (which op sits on which rung,
|
|
4
|
+
// and why) stay with the product that owns those ops.
|
|
5
|
+
//
|
|
6
|
+
// THE LADDER. Every op climbs the same three rungs, and never skips one:
|
|
7
|
+
// `off` — the incumbent plane serves. The gateway is not consulted.
|
|
8
|
+
// `shadow` — the incumbent serves AND ITS ANSWER IS THE RESPONSE. The gateway runs alongside and the
|
|
9
|
+
// two are compared. Divergence is recorded; it never reaches the caller and never fails the
|
|
10
|
+
// request. This is the rung that converts "we think it matches" into evidence.
|
|
11
|
+
// `serving` — the gateway serves. Promotion is earned by a shadow run with no unexplained divergence,
|
|
12
|
+
// not by the code being finished.
|
|
13
|
+
//
|
|
14
|
+
// WHAT A RUNG DOES NOT DO. Shadowing proves the two planes AGREE; it does not prove either is right. An op
|
|
15
|
+
// whose incumbent implementation is wrong will shadow perfectly clean while the gateway faithfully
|
|
16
|
+
// reproduces the bug. Promotion is evidence of equivalence, not of correctness.
|
|
17
|
+
/**
|
|
18
|
+
* The stage an op runs at IN THIS DEPLOYMENT. The ledger says how far an op has climbed in the code; the
|
|
19
|
+
* deployment's `GATEWAY_SHADOW` says whether it is running the comparison at all. Both are required, and the
|
|
20
|
+
* env one defaults to OFF — constructing the gateway creates its tables, and an ungated shadow on a hot op
|
|
21
|
+
* would make that storage decision for every principal at once. Empty string is unset, not enabled
|
|
22
|
+
* (`wrangler`'s `VAR = ""` binds an empty string that `??` sails straight past).
|
|
23
|
+
*/
|
|
24
|
+
export function adoptionStage(ledger, op, env) {
|
|
25
|
+
const stage = ledger[op]?.stage ?? 'off';
|
|
26
|
+
if (stage === 'shadow' && (env?.GATEWAY_SHADOW ?? '').trim().toLowerCase() !== 'on')
|
|
27
|
+
return 'off';
|
|
28
|
+
return stage;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Compare the two planes' answers. Canonical JSON with sorted keys: key ORDER is not a difference worth
|
|
32
|
+
* blocking a promotion on. Everything else counts, including `undefined` vs absent — a field that vanished
|
|
33
|
+
* is exactly the data-shape drift being watched for.
|
|
34
|
+
*/
|
|
35
|
+
export function compareServed(op, served, shadow, at) {
|
|
36
|
+
const a = canonical(served);
|
|
37
|
+
const b = canonical(shadow);
|
|
38
|
+
if (a === b)
|
|
39
|
+
return { op, at, kind: 'equal' };
|
|
40
|
+
return { op, at, kind: 'value', detail: firstDifference(a, b) };
|
|
41
|
+
}
|
|
42
|
+
function canonical(v) {
|
|
43
|
+
return JSON.stringify(v, (_k, val) => val && typeof val === 'object' && !Array.isArray(val)
|
|
44
|
+
? Object.fromEntries(Object.entries(val).sort(([x], [y]) => x.localeCompare(y)))
|
|
45
|
+
: val) ?? 'undefined';
|
|
46
|
+
}
|
|
47
|
+
/** A bounded excerpt around the first difference. Bounded because a divergence report that embeds two whole
|
|
48
|
+
* documents is a copy of the person's records in a diagnostic buffer — the thing the vault doctrine exists
|
|
49
|
+
* to prevent, arrived at through the back door. */
|
|
50
|
+
function firstDifference(a, b) {
|
|
51
|
+
let i = 0;
|
|
52
|
+
while (i < a.length && i < b.length && a[i] === b[i])
|
|
53
|
+
i++;
|
|
54
|
+
const w = 40;
|
|
55
|
+
return `@${i}: served=${JSON.stringify(a.slice(Math.max(0, i - 8), i + w))} shadow=${JSON.stringify(b.slice(Math.max(0, i - 8), i + w))}`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Was an apparent divergence just the document moving between the two reads? After the shadow read, take
|
|
59
|
+
* the serving read AGAIN: `servedAgain` matches the shadow ⇒ the document moved — RACED, benign, evidence of
|
|
60
|
+
* nothing; `servedAgain` still matches the original and differs from the shadow ⇒ the planes really
|
|
61
|
+
* disagree. DELIBERATELY CONSERVATIVE: anything not provably a race stays `value`.
|
|
62
|
+
*/
|
|
63
|
+
export function classifyDivergence(input) {
|
|
64
|
+
const first = compareServed(input.op, input.served, input.shadow, input.at);
|
|
65
|
+
if (first.kind === 'equal')
|
|
66
|
+
return first;
|
|
67
|
+
const settled = compareServed(input.op, input.servedAgain, input.shadow, input.at);
|
|
68
|
+
if (settled.kind === 'equal') {
|
|
69
|
+
return { op: input.op, at: input.at, kind: 'raced', detail: 'document changed between the serving read and the shadow read' };
|
|
70
|
+
}
|
|
71
|
+
return first;
|
|
72
|
+
}
|
|
73
|
+
// ── Sampling ──────────────────────────────────────────────────────────────────────────────────────────
|
|
74
|
+
/**
|
|
75
|
+
* Should this call run its shadow? Shadowing doubles the delegated reads on the path being shadowed, so it
|
|
76
|
+
* is SAMPLED: at most one shadow per principal per `intervalMs`. Time-based rather than 1-in-N because it
|
|
77
|
+
* bounds the ADDED LOAD directly; a ratio bounds a proportion of a rate that varies with how many clients a
|
|
78
|
+
* principal has open. The first call always samples — a low-traffic principal must still contribute.
|
|
79
|
+
*/
|
|
80
|
+
export function shouldShadow(input) {
|
|
81
|
+
if (input.lastShadowAt === undefined)
|
|
82
|
+
return true;
|
|
83
|
+
return input.now - input.lastShadowAt >= input.intervalMs;
|
|
84
|
+
}
|
|
85
|
+
/** One shadow per principal per minute: enough to catch a systematic difference within a session, far below
|
|
86
|
+
* a per-principal read limiter's budget even with several clients open. */
|
|
87
|
+
export const SHADOW_INTERVAL_MS = 60_000;
|
|
88
|
+
/** How many divergences to keep — in MEMORY, not durable storage: diagnostics with a shelf life of one
|
|
89
|
+
* investigation. Losing them on isolate recycle is the correct trade. */
|
|
90
|
+
export const DIVERGENCE_BUFFER = 20;
|
|
91
|
+
export function recordDivergence(buf, d) {
|
|
92
|
+
buf.push(d);
|
|
93
|
+
return buf.length > DIVERGENCE_BUFFER ? buf.slice(-DIVERGENCE_BUFFER) : buf;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=adoption.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adoption.js","sourceRoot":"","sources":["../src/adoption.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { CanonicalAgentId } from '@agenticprimitives/types';
|
|
2
|
+
import type { CommitmentRecordV1, CommitmentTransition, DecisionRecordV1, DecisionTransition, MachineRejection } from './interaction-machines.js';
|
|
3
|
+
import type { CaseFsmFields, CaseTransition, CaseTransitionEventV1 } from './case-machine.js';
|
|
4
|
+
/**
|
|
5
|
+
* A record this emission needs to exist before its transition can land, given in its INITIAL state.
|
|
6
|
+
*
|
|
7
|
+
* Both machines refuse a transition out of a state the record is not in — `grant` is `pending →
|
|
8
|
+
* granted`, `void` is `proposed|active → void`. So an emission that only carried a transition would be
|
|
9
|
+
* unapplicable on the first move of a case that never had a decision record. The applier creates the
|
|
10
|
+
* record if absent, in exactly this state, and then applies the transition through the machine. It
|
|
11
|
+
* does NOT create it in the resulting state; that would be the state-assignment bypass this module
|
|
12
|
+
* exists to avoid.
|
|
13
|
+
*/
|
|
14
|
+
export interface DecisionSeedV1 {
|
|
15
|
+
decisionId: string;
|
|
16
|
+
decider: CanonicalAgentId;
|
|
17
|
+
subject: string;
|
|
18
|
+
expiresAt?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface CommitmentSeedV1 {
|
|
21
|
+
commitmentId: string;
|
|
22
|
+
debtor: CanonicalAgentId;
|
|
23
|
+
creditor: CanonicalAgentId;
|
|
24
|
+
}
|
|
25
|
+
export interface CaseEmissionsV1 {
|
|
26
|
+
decision?: {
|
|
27
|
+
seed: DecisionSeedV1;
|
|
28
|
+
transition: DecisionTransition;
|
|
29
|
+
createIfAbsent: boolean;
|
|
30
|
+
};
|
|
31
|
+
commitment?: {
|
|
32
|
+
seed: CommitmentSeedV1;
|
|
33
|
+
transition: CommitmentTransition;
|
|
34
|
+
createIfAbsent: boolean;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Deterministic ids, derived from the case id.
|
|
39
|
+
*
|
|
40
|
+
* Deliberately not random and not clock-derived: a case transition may be replayed (the interaction
|
|
41
|
+
* store is idempotent on `idempotencyKey`, and `processDue` re-runs sweeps), and a fresh id per replay
|
|
42
|
+
* would fork one determination into several. Same case ⇒ same decision ⇒ the second application is a
|
|
43
|
+
* no-op against a terminal state rather than a duplicate record.
|
|
44
|
+
*/
|
|
45
|
+
export declare function decisionIdForCase(caseId: string): string;
|
|
46
|
+
export declare function commitmentIdForCase(caseId: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* Derive what a case transition emits. Pure, and total over `CaseTransition` — a transition with no
|
|
49
|
+
* emission returns `{}` rather than throwing, because most transitions genuinely emit nothing.
|
|
50
|
+
*
|
|
51
|
+
* Call this only for a transition the case machine ACCEPTED. It does not re-check legality: duplicating
|
|
52
|
+
* the case machine's role and ordering rules here would create a second, quietly diverging copy of them.
|
|
53
|
+
*/
|
|
54
|
+
export declare function caseTransitionEmissions(current: CaseFsmFields, event: CaseTransitionEventV1): CaseEmissionsV1;
|
|
55
|
+
/** The case transitions that emit something. Exported so a test can assert the set rather than
|
|
56
|
+
* restate it, and so a newly-added emitting transition shows up in a diff of this constant. */
|
|
57
|
+
export declare const EMITTING_CASE_TRANSITIONS: readonly CaseTransition[];
|
|
58
|
+
/** Seed a decision record in its INITIAL state. Never the resulting state — see `DecisionSeedV1`. */
|
|
59
|
+
export declare function seedDecision(seed: DecisionSeedV1, at: string): DecisionRecordV1;
|
|
60
|
+
/** Seed a commitment record in its INITIAL state. */
|
|
61
|
+
export declare function seedCommitment(seed: CommitmentSeedV1, at: string): CommitmentRecordV1;
|
|
62
|
+
/** Why an emission produced no record. `absent` is the deliberate `void`-without-a-commitment case;
|
|
63
|
+
* the others are the owning machine's own typed rejection, surfaced rather than swallowed. */
|
|
64
|
+
export type EmissionOutcome<T> = {
|
|
65
|
+
applied: true;
|
|
66
|
+
record: T;
|
|
67
|
+
} | {
|
|
68
|
+
applied: false;
|
|
69
|
+
reason: MachineRejection | 'absent';
|
|
70
|
+
};
|
|
71
|
+
export interface CaseEmissionApplyResult {
|
|
72
|
+
decision?: EmissionOutcome<DecisionRecordV1>;
|
|
73
|
+
commitment?: EmissionOutcome<CommitmentRecordV1>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Apply emissions through the OWNING machines.
|
|
77
|
+
*
|
|
78
|
+
* The point of this function is what it does not do: it never assigns a state. A record is created
|
|
79
|
+
* only in its initial state and every move goes through `applyDecisionTransition` /
|
|
80
|
+
* `applyCommitmentTransition`, so their role and ordering checks still hold — the creditor still
|
|
81
|
+
* voids, the decider still decides.
|
|
82
|
+
*
|
|
83
|
+
* Rejections are RETURNED, not thrown and not swallowed. A caller that persists these must treat a
|
|
84
|
+
* rejected emission as a fact about the record it failed to write, because a silent no-op here is
|
|
85
|
+
* indistinguishable from success and would leave a case whose determination was never recorded
|
|
86
|
+
* looking exactly like one whose determination was.
|
|
87
|
+
*/
|
|
88
|
+
export declare function applyCaseEmissions(emissions: CaseEmissionsV1, existing: {
|
|
89
|
+
decision: DecisionRecordV1 | null;
|
|
90
|
+
commitment: CommitmentRecordV1 | null;
|
|
91
|
+
}, event: {
|
|
92
|
+
actor: CanonicalAgentId;
|
|
93
|
+
at: string;
|
|
94
|
+
}): CaseEmissionApplyResult;
|
|
95
|
+
//# sourceMappingURL=case-emissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"case-emissions.d.ts","sourceRoot":"","sources":["../src/case-emissions.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAEjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE9F;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,cAAc,CAAC;QAAC,UAAU,EAAE,kBAAkB,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,CAAC;IAC7F,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,gBAAgB,CAAC;QAAC,UAAU,EAAE,oBAAoB,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,CAAC;CACpG;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAqGD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,qBAAqB,GAC3B,eAAe,CAmBjB;AAED;gGACgG;AAChG,eAAO,MAAM,yBAAyB,EAAE,SAAS,cAAc,EAE1C,CAAC;AAEtB,qGAAqG;AACrG,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,gBAAgB,CAS/E;AAED,qDAAqD;AACrD,wBAAgB,cAAc,CAAC,IAAI,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,GAAG,kBAAkB,CAQrF;AAED;+FAC+F;AAC/F,MAAM,MAAM,eAAe,CAAC,CAAC,IACzB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,CAAC,CAAA;CAAE,GAC5B;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,gBAAgB,GAAG,QAAQ,CAAA;CAAE,CAAC;AAE5D,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,eAAe,CAAC,gBAAgB,CAAC,CAAC;IAC7C,UAAU,CAAC,EAAE,eAAe,CAAC,kBAAkB,CAAC,CAAC;CAClD;AAeD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE;IAAE,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAAA;CAAE,EACtF,KAAK,EAAE;IAAE,KAAK,EAAE,gBAAgB,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC7C,uBAAuB,CAsBzB"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// spec 340 W10 — what a case transition EMITS into the decision and commitment machines.
|
|
2
|
+
//
|
|
3
|
+
// §R.2 established that the eleven `CaseState`s were never one machine: `approved`/`denied`/`expired`
|
|
4
|
+
// are **decisions**, `revoked` is what happens to a **commitment**, and the rest are **execution**. One
|
|
5
|
+
// field was answering three questions with three different signers, which is why a case could be
|
|
6
|
+
// `denied` while a commitment stayed outstanding with nowhere to record it.
|
|
7
|
+
//
|
|
8
|
+
// §R.3 names the order this has to happen in: the case flow EMITS decision and commitment records
|
|
9
|
+
// FIRST, and only then can `CaseState` shrink to execution. Deleting the enum before this module
|
|
10
|
+
// existed would have replaced working behaviour with machines nothing writes to — a regression wearing
|
|
11
|
+
// the costume of a cleanup.
|
|
12
|
+
//
|
|
13
|
+
// WHAT THIS MODULE IS NOT. It derives records; it does not move state. Every emission is expressed as a
|
|
14
|
+
// TRANSITION to be applied by the owning machine, never as a state assignment, so the machines keep
|
|
15
|
+
// their role checks — the creditor still discharges, the decider still decides, and persistence does
|
|
16
|
+
// not become a bypass (ADR-0058 §15, and the same rule `createDurableObjectInteractionStore` follows).
|
|
17
|
+
//
|
|
18
|
+
// NONE OF THIS IS AUTHORITY. A `grant` here records that a determination was made. It permits nothing:
|
|
19
|
+
// the authority re-check happens at the moment of acting regardless of what any of these records say
|
|
20
|
+
// (ADR-0041, ADR-0043).
|
|
21
|
+
import { applyCommitmentTransition, applyDecisionTransition } from './interaction-machines.js';
|
|
22
|
+
/**
|
|
23
|
+
* Deterministic ids, derived from the case id.
|
|
24
|
+
*
|
|
25
|
+
* Deliberately not random and not clock-derived: a case transition may be replayed (the interaction
|
|
26
|
+
* store is idempotent on `idempotencyKey`, and `processDue` re-runs sweeps), and a fresh id per replay
|
|
27
|
+
* would fork one determination into several. Same case ⇒ same decision ⇒ the second application is a
|
|
28
|
+
* no-op against a terminal state rather than a duplicate record.
|
|
29
|
+
*/
|
|
30
|
+
export function decisionIdForCase(caseId) {
|
|
31
|
+
return `dec_${caseId}`;
|
|
32
|
+
}
|
|
33
|
+
export function commitmentIdForCase(caseId) {
|
|
34
|
+
return `cmt_${caseId}`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* WHO IS THE CREDITOR. The approving side — `responder` / `resource-owner`.
|
|
38
|
+
*
|
|
39
|
+
* This is a derivation, not a preference. Case `revoke` is signed by `responder`/`resource-owner`, and
|
|
40
|
+
* the only creditor-only commitment transition is `void`. Under the opposite assignment (debtor =
|
|
41
|
+
* responder, creditor = requester) an issuer revoking what it granted has no legal transition at all,
|
|
42
|
+
* which contradicts a case machine that plainly permits it. One reading is self-consistent; the other
|
|
43
|
+
* is not. `issue-credential` corroborates it: its signers are `resource-owner`/`responder` and
|
|
44
|
+
* `activate` is likewise creditor-only.
|
|
45
|
+
*/
|
|
46
|
+
function creditorOf(c) {
|
|
47
|
+
return c.resourceOwner ?? c.responder;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* WHO IS THE DECIDER — and why it is not one rule.
|
|
51
|
+
*
|
|
52
|
+
* For `approve`/`deny` it is `event.actor`: the party that actually made the determination. It cannot
|
|
53
|
+
* be the deciding ROLE, because the case machine accepts EITHER `responder` or `resource-owner` for
|
|
54
|
+
* those moves while the decision machine requires exactly `decision.decider`. Pinning the decider to
|
|
55
|
+
* the role would make a responder-signed approval on a case that also has a resource-owner emit a
|
|
56
|
+
* decision the decision machine then rejects as `unauthorized-actor` — a case that succeeded and an
|
|
57
|
+
* emission that silently could not land.
|
|
58
|
+
*
|
|
59
|
+
* For `expire` it is the creditor. `expire` is signed by role `any` (time is not an actor, so a
|
|
60
|
+
* deterministic sweep may record it), and attributing an expiry to whichever party happened to run the
|
|
61
|
+
* sweep would put a determination in someone's name they never made. The decision machine skips the
|
|
62
|
+
* actor check for `expire` precisely so this is possible.
|
|
63
|
+
*/
|
|
64
|
+
function decisionSeed(c, event, transition) {
|
|
65
|
+
return {
|
|
66
|
+
decisionId: decisionIdForCase(c.id),
|
|
67
|
+
decider: transition === 'expire' ? creditorOf(c) : event.actor,
|
|
68
|
+
subject: c.id,
|
|
69
|
+
expiresAt: c.expiresAt,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function commitmentSeed(c) {
|
|
73
|
+
return {
|
|
74
|
+
commitmentId: commitmentIdForCase(c.id),
|
|
75
|
+
debtor: c.requester,
|
|
76
|
+
creditor: creditorOf(c),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The mapping, stated once.
|
|
81
|
+
*
|
|
82
|
+
* `deliver-credential` is deliberately ABSENT. It completes the case, and completing the work does not
|
|
83
|
+
* discharge the obligation — that is exactly the collapse ADR-0058 §15 forbids, and `fabric` already
|
|
84
|
+
* refuses to draw that edge implicitly (`mayDischargeOnExecution` exists so a profile has to choose it
|
|
85
|
+
* in a diff). A creditor who wants to discharge does so as its own act, against the commitment
|
|
86
|
+
* machine, with its own signature.
|
|
87
|
+
*
|
|
88
|
+
* `fail` is absent for the same reason in the other direction: a failed execution is not a refusal by
|
|
89
|
+
* anyone, and recording it as one would attribute a determination nobody made.
|
|
90
|
+
*/
|
|
91
|
+
const EMITTING_TRANSITIONS = {
|
|
92
|
+
approve: { decision: 'grant' },
|
|
93
|
+
deny: { decision: 'refuse' },
|
|
94
|
+
expire: { decision: 'expire' },
|
|
95
|
+
// Issuing is what creates the obligation, so this emission may bring the commitment into being.
|
|
96
|
+
'issue-credential': { commitment: 'activate' },
|
|
97
|
+
revoke: { commitment: 'void' },
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Whether an emission may bring its record into existence.
|
|
101
|
+
*
|
|
102
|
+
* Deciding CREATES a determination — there was no prior record and the act of approving or denying is
|
|
103
|
+
* what makes one. Issuing likewise creates the obligation.
|
|
104
|
+
*
|
|
105
|
+
* `void` must not. `revoke` is legal from any non-terminal case, including `submitted`, where nothing
|
|
106
|
+
* was ever approved and no obligation ever arose. Seeding a commitment there so it could immediately
|
|
107
|
+
* be voided would write a record asserting an obligation existed and was released, when neither
|
|
108
|
+
* happened — inventing history to satisfy a type. Absent a commitment, this emission is a no-op, and
|
|
109
|
+
* the case's own `revoked` state remains the honest record of what occurred.
|
|
110
|
+
*/
|
|
111
|
+
const CREATES_ITS_RECORD = {
|
|
112
|
+
grant: true,
|
|
113
|
+
refuse: true,
|
|
114
|
+
expire: true,
|
|
115
|
+
activate: true,
|
|
116
|
+
withdraw: false,
|
|
117
|
+
supersede: false,
|
|
118
|
+
'claim-fulfilment': false,
|
|
119
|
+
'dispute-claim': false,
|
|
120
|
+
discharge: false,
|
|
121
|
+
'assert-breach': false,
|
|
122
|
+
void: false,
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Derive what a case transition emits. Pure, and total over `CaseTransition` — a transition with no
|
|
126
|
+
* emission returns `{}` rather than throwing, because most transitions genuinely emit nothing.
|
|
127
|
+
*
|
|
128
|
+
* Call this only for a transition the case machine ACCEPTED. It does not re-check legality: duplicating
|
|
129
|
+
* the case machine's role and ordering rules here would create a second, quietly diverging copy of them.
|
|
130
|
+
*/
|
|
131
|
+
export function caseTransitionEmissions(current, event) {
|
|
132
|
+
const spec = EMITTING_TRANSITIONS[event.transition];
|
|
133
|
+
if (!spec)
|
|
134
|
+
return {};
|
|
135
|
+
const out = {};
|
|
136
|
+
if (spec.decision) {
|
|
137
|
+
out.decision = {
|
|
138
|
+
seed: decisionSeed(current, event, spec.decision),
|
|
139
|
+
transition: spec.decision,
|
|
140
|
+
createIfAbsent: CREATES_ITS_RECORD[spec.decision],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (spec.commitment) {
|
|
144
|
+
out.commitment = {
|
|
145
|
+
seed: commitmentSeed(current),
|
|
146
|
+
transition: spec.commitment,
|
|
147
|
+
createIfAbsent: CREATES_ITS_RECORD[spec.commitment],
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
/** The case transitions that emit something. Exported so a test can assert the set rather than
|
|
153
|
+
* restate it, and so a newly-added emitting transition shows up in a diff of this constant. */
|
|
154
|
+
export const EMITTING_CASE_TRANSITIONS = Object.keys(EMITTING_TRANSITIONS);
|
|
155
|
+
/** Seed a decision record in its INITIAL state. Never the resulting state — see `DecisionSeedV1`. */
|
|
156
|
+
export function seedDecision(seed, at) {
|
|
157
|
+
return {
|
|
158
|
+
decisionId: seed.decisionId,
|
|
159
|
+
state: 'pending',
|
|
160
|
+
decider: seed.decider,
|
|
161
|
+
subject: seed.subject,
|
|
162
|
+
expiresAt: seed.expiresAt,
|
|
163
|
+
updatedAt: at,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/** Seed a commitment record in its INITIAL state. */
|
|
167
|
+
export function seedCommitment(seed, at) {
|
|
168
|
+
return {
|
|
169
|
+
commitmentId: seed.commitmentId,
|
|
170
|
+
state: 'proposed',
|
|
171
|
+
debtor: seed.debtor,
|
|
172
|
+
creditor: seed.creditor,
|
|
173
|
+
updatedAt: at,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function applyOne(emission, existing, create, apply) {
|
|
177
|
+
if (!emission)
|
|
178
|
+
return undefined;
|
|
179
|
+
const record = existing ?? (emission.createIfAbsent ? create() : null);
|
|
180
|
+
if (record === null)
|
|
181
|
+
return { applied: false, reason: 'absent' };
|
|
182
|
+
const res = apply(record, emission.transition);
|
|
183
|
+
return res.ok ? { applied: true, record: res.next } : { applied: false, reason: res.reason };
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Apply emissions through the OWNING machines.
|
|
187
|
+
*
|
|
188
|
+
* The point of this function is what it does not do: it never assigns a state. A record is created
|
|
189
|
+
* only in its initial state and every move goes through `applyDecisionTransition` /
|
|
190
|
+
* `applyCommitmentTransition`, so their role and ordering checks still hold — the creditor still
|
|
191
|
+
* voids, the decider still decides.
|
|
192
|
+
*
|
|
193
|
+
* Rejections are RETURNED, not thrown and not swallowed. A caller that persists these must treat a
|
|
194
|
+
* rejected emission as a fact about the record it failed to write, because a silent no-op here is
|
|
195
|
+
* indistinguishable from success and would leave a case whose determination was never recorded
|
|
196
|
+
* looking exactly like one whose determination was.
|
|
197
|
+
*/
|
|
198
|
+
export function applyCaseEmissions(emissions, existing, event) {
|
|
199
|
+
const out = {};
|
|
200
|
+
const decision = applyOne(emissions.decision, existing.decision, () => seedDecision(emissions.decision.seed, event.at), (record, transition) => applyDecisionTransition(record, { transition, actor: event.actor, at: event.at }));
|
|
201
|
+
if (decision)
|
|
202
|
+
out.decision = decision;
|
|
203
|
+
const commitment = applyOne(emissions.commitment, existing.commitment, () => seedCommitment(emissions.commitment.seed, event.at), (record, transition) => applyCommitmentTransition(record, { transition, actor: event.actor, at: event.at }));
|
|
204
|
+
if (commitment)
|
|
205
|
+
out.commitment = commitment;
|
|
206
|
+
return out;
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=case-emissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"case-emissions.js","sourceRoot":"","sources":["../src/case-emissions.ts"],"names":[],"mappings":"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"}
|