@plasius/economy 0.3.1 → 0.4.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/README.md CHANGED
@@ -4,10 +4,11 @@ Provider-neutral TypeScript contracts and deterministic invariants for the
4
4
  Plasius sitewide Token economy.
5
5
 
6
6
  This package models exact TokenSubunit amounts, immutable double-entry journal
7
- transactions, source lots, family gameplay reservations, early-backer basis,
8
- future spend requests, acquisition contracts, projections, and persistence
9
- ports. It intentionally contains no HTTP, authentication, provider SDK,
10
- database driver, secret, or Azure implementation.
7
+ transactions, source lots, family gameplay reservations, purpose-bound learning
8
+ module allowances, early-backer basis, future spend requests, acquisition
9
+ contracts, projections, and persistence ports. It intentionally contains no
10
+ HTTP, authentication, provider SDK, database driver, secret, or Azure
11
+ implementation.
11
12
 
12
13
  ## Product boundary
13
14
 
@@ -160,6 +161,44 @@ settlements after `evaluatedAt`. The caller must derive both window timestamps
160
161
  from the entire public cohort and exclude non-production/test lots: staff,
161
162
  closed-beta, and test availability must never open or close the public window.
162
163
 
164
+ ## Junior Coder Module Allowances
165
+
166
+ `ModuleAllowanceV1` is a Guardian-funded reservation for one linked child and
167
+ one purpose: purchasing independently sellable Junior Coder module
168
+ entitlements. It is deliberately separate from `GameplayAllocationV1`; callers
169
+ cannot spend gameplay value as a learning allowance or silently move learning
170
+ value into gameplay.
171
+
172
+ The purchase contracts implement the deterministic parts of:
173
+
174
+ ```text
175
+ immutable quote -> allowance hold -> pending entitlement
176
+ -> settle spend -> activate entitlement -> durable receipt
177
+ ```
178
+
179
+ An immutable quote binds the exact module version, Token price, child,
180
+ Guardian acknowledgement, catalog version, and requirements-manifest version
181
+ plus canonical SHA-256 reference. This makes software-only declarations and
182
+ robotics bills of materials durable pre-purchase evidence even after a live
183
+ manifest changes.
184
+
185
+ `createModuleSpendHold()` moves whole Tokens from available to held value.
186
+ `settleModuleSpendHold()` requires a pending entitlement ID before it can move
187
+ held value to spent value. `releaseModuleSpendHold()` returns failed or expired
188
+ holds to the same Module Allowance. `createModulePurchaseReceipt()` accepts only
189
+ matching quote and settled-hold evidence. `reconcileModulePurchase()` returns
190
+ one forward-safe repair instruction and fails closed to manual review for a
191
+ settled debit without an entitlement or an active paid entitlement without a
192
+ settled debit.
193
+
194
+ These functions produce immutable next-state projections; they do not perform
195
+ authorization or persistence. The consuming service must evaluate
196
+ `learning.junior-coder.purchase.enabled`, enforce Guardian/child capabilities,
197
+ store actor/subject/operation-scoped idempotency evidence, and compare-and-swap
198
+ allowance and hold versions alongside the balanced journal, entitlement,
199
+ receipt, and outbox in a serializable transaction. A disabled feature may still
200
+ release and reconcile existing holds, but must reject new quotes and purchases.
201
+
163
202
  ## Acquisition and future contracts
164
203
 
165
204
  Purchase intents bind payer, receiving household/wallet, pack, catalog,
@@ -172,6 +211,45 @@ versions, exact payout values, and beneficiary/wallet IDs. ayeT and BitLabs lots
172
211
  are structurally restricted to `same-user-only`; changing a provider-earned lot
173
212
  to household-allocatable is rejected.
174
213
 
214
+ ### Deterministic paid-acquisition lifecycle
215
+
216
+ `PurchaseIntentLifecycleV1` adds receipts and optimistic versions around the
217
+ unchanged `PurchaseIntentV1`. `reducePurchaseIntentTransitions()` canonicalizes
218
+ out-of-order checkout, payment, credit, expiry, cancellation, and dispute
219
+ evidence. Exact retries collapse, conflicting ID reuse fails, and one intent
220
+ can emit at most one stable intent-ID-scoped credit instruction. The transition
221
+ name is `checkout-bound`; the published compatible intent status remains
222
+ `checkout-created`.
223
+
224
+ `reserveRollingPurchaseCaps()` mirrors one exact GBP-minor-unit reservation
225
+ into payer and household aggregates. Both expected versions must match and both
226
+ returned versions must be committed in one serializable transaction.
227
+ Settlement keeps the amount in the rolling window; release and expiry free it.
228
+ Exact command replays are no-ops, including after finalization. GBP minor units
229
+ use canonical non-negative signed-64-bit strings through
230
+ `parseGbpMinorUnits()` and `serializeGbpMinorUnits()`.
231
+
232
+ `PaidLotLifecycleV1` separately preserves early-backer retained basis:
233
+
234
+ - a dispute hold leaves retained basis unchanged;
235
+ - a dispute win releases only the hold;
236
+ - refunds, lost disputes, direct chargebacks, and the one permitted reversal
237
+ reduce retained basis exactly;
238
+ - partial outcomes retain their unreversed remainder;
239
+ - `createEarlyBackerRetentionFromPaidLot()` supplies a current
240
+ `PaidLotRetentionV1` for recalculation.
241
+
242
+ Retained basis is not a spendable-balance claim. Before a compensation commits,
243
+ the authoritative service must atomically reclaim allocated-but-unused value,
244
+ reject value already spent or otherwise unavailable, append balanced journal
245
+ postings, update source-lot/lifecycle projections, save idempotency evidence,
246
+ and append the outbox. This package contains none of those provider or
247
+ persistence adapters.
248
+
249
+ These contracts do not enable checkout. The site must still enforce
250
+ `economy.tokens.shopify.enabled`, payer/household authorization, legal gates,
251
+ provider-signature verification, and server-derived purchase facts.
252
+
175
253
  `BASELINE_MONTHLY_SUBSCRIPTION_PLAN` preserves the provider-neutral future £10
176
254
  monthly/100 Token shape with `enabled: false`. Spend-request contracts likewise
177
255
  exist for future use but this package does not enable their creation.
@@ -243,7 +321,14 @@ Coverage must remain at least 80%, and every changed source file must appear in
243
321
  LCOV. Generated property tests cover exact arithmetic, double-entry balance,
244
322
  projection rebuilds, idempotency, reversals, lot isolation, and allocation
245
323
  non-negativity. npm publication is performed only by the approved GitHub CD
246
- workflow.
324
+ workflow on configurable trusted self-hosted runners. Release LCOV and the
325
+ CycloneDX SBOM remain retained even when an external coverage or npm provenance
326
+ service is unavailable. Release tags and GitHub Releases use a current-repository
327
+ GitHub App token with explicit Contents and Workflows write permissions; npm
328
+ publication continues to use only the protected `NPM_TOKEN`. Both release jobs
329
+ install a checksum-pinned GitHub CLI under `RUNNER_TEMP`. A requested version
330
+ bump reuses the current version only when neither npm nor GitHub records it as a
331
+ completed release; use `bump=none` for deliberate recovery of prepared metadata.
247
332
 
248
333
  ## Security
249
334