@pome-sh/cli 0.1.1 → 0.2.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.
Files changed (277) hide show
  1. package/README.md +5 -6
  2. package/dist/build-info.json +3 -3
  3. package/dist/src/cli/eval.js +26 -8
  4. package/dist/src/cli/init-sdk.d.ts +0 -3
  5. package/dist/src/cli/init-sdk.js +117 -24
  6. package/dist/src/cli/main.js +23 -69
  7. package/dist/src/cli/register.d.ts +9 -0
  8. package/dist/src/cli/register.js +51 -5
  9. package/dist/src/cli/session.d.ts +7 -1
  10. package/dist/src/cli/session.js +87 -27
  11. package/dist/src/demo/runDemo.js +3 -2
  12. package/dist/src/hosted/client.d.ts +41 -5
  13. package/dist/src/hosted/client.js +333 -19
  14. package/dist/src/hosted/errors.d.ts +11 -1
  15. package/dist/src/hosted/errors.js +8 -1
  16. package/dist/src/hosted/evalResultView.d.ts +2 -0
  17. package/dist/src/hosted/evalResultView.js +22 -0
  18. package/dist/src/hosted/uploadAndFinalize.d.ts +18 -1
  19. package/dist/src/hosted/uploadAndFinalize.js +51 -3
  20. package/dist/src/recorder/inspect.js +20 -2
  21. package/dist/src/runner/mergeAdapterSignals.js +2 -2
  22. package/dist/src/runner/ports.js +3 -0
  23. package/dist/src/runner/runScenario.d.ts +79 -2
  24. package/dist/src/runner/runScenario.js +94 -36
  25. package/dist/src/runner/runScenarioHosted.d.ts +37 -0
  26. package/dist/src/runner/runScenarioHosted.js +257 -58
  27. package/dist/src/runner/runTrialGroup.d.ts +1 -3
  28. package/dist/src/runner/runTrialGroup.js +1 -3
  29. package/dist/src/scenario/parseScenario.d.ts +5 -0
  30. package/dist/src/scenario/parseScenario.js +135 -8
  31. package/dist/src/scenario/scenarioSchema.d.ts +200 -3
  32. package/dist/src/scenario/scenarioSchema.js +12 -1
  33. package/dist/src/twin/twinHarness.d.ts +10 -0
  34. package/dist/src/twin/twinHarness.js +6 -2
  35. package/dist/src/twin/twinStart.d.ts +19 -0
  36. package/dist/src/twin/twinStart.js +156 -0
  37. package/node_modules/@pome-sh/sdk/dist/fidelity-inventory.d.ts +121 -0
  38. package/node_modules/@pome-sh/sdk/dist/fidelity-inventory.js +204 -0
  39. package/node_modules/@pome-sh/sdk/dist/fidelity-inventory.js.map +1 -0
  40. package/node_modules/@pome-sh/sdk/dist/parity.d.ts +55 -0
  41. package/node_modules/@pome-sh/sdk/dist/parity.js +112 -0
  42. package/node_modules/@pome-sh/sdk/dist/parity.js.map +1 -0
  43. package/node_modules/@pome-sh/sdk/dist/server-helpers.d.ts +15 -0
  44. package/node_modules/@pome-sh/sdk/dist/server-helpers.js +96 -0
  45. package/node_modules/@pome-sh/sdk/dist/server-helpers.js.map +1 -1
  46. package/node_modules/@pome-sh/sdk/dist/server.d.ts +1 -1
  47. package/node_modules/@pome-sh/sdk/dist/server.js +9 -7
  48. package/node_modules/@pome-sh/sdk/dist/server.js.map +1 -1
  49. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/errors.d.ts +39 -0
  50. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/errors.js +33 -0
  51. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/errors.js.map +1 -0
  52. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/evaluator-hooks.d.ts +13 -0
  53. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/evaluator-hooks.js +6 -0
  54. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/evaluator-hooks.js.map +1 -0
  55. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/finalize-shapes.d.ts +215 -0
  56. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/finalize-shapes.js +83 -0
  57. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/finalize-shapes.js.map +1 -0
  58. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/github-access-control.d.ts +175 -0
  59. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/github-access-control.js +182 -0
  60. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/github-access-control.js.map +1 -0
  61. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/identity.d.ts +90 -0
  62. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/identity.js +72 -0
  63. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/identity.js.map +1 -0
  64. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/index.d.ts +27 -0
  65. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/index.js +34 -0
  66. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/index.js.map +1 -0
  67. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/event-schema.d.ts +286 -0
  68. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/event-schema.js +33 -0
  69. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/event-schema.js.map +1 -0
  70. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/fixtures/data.d.ts +65 -0
  71. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/fixtures/data.js +455 -0
  72. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/fixtures/data.js.map +1 -0
  73. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/fixtures/index.d.ts +39 -0
  74. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/fixtures/index.js +47 -0
  75. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/fixtures/index.js.map +1 -0
  76. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/index.d.ts +25 -0
  77. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/index.js +27 -0
  78. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/index.js.map +1 -0
  79. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/legacy-shim.d.ts +100 -0
  80. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/legacy-shim.js +185 -0
  81. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/legacy-shim.js.map +1 -0
  82. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/map-span.d.ts +64 -0
  83. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/map-span.js +112 -0
  84. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/map-span.js.map +1 -0
  85. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/nano.d.ts +26 -0
  86. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/nano.js +61 -0
  87. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/nano.js.map +1 -0
  88. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/project.d.ts +42 -0
  89. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/project.js +96 -0
  90. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/project.js.map +1 -0
  91. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/semconv.d.ts +51 -0
  92. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/semconv.js +74 -0
  93. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/semconv.js.map +1 -0
  94. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/span-event.d.ts +134 -0
  95. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/span-event.js +152 -0
  96. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/otel/span-event.js.map +1 -0
  97. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/recorder-events.d.ts +418 -0
  98. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/recorder-events.js +234 -0
  99. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/recorder-events.js.map +1 -0
  100. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/redaction.d.ts +2 -0
  101. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/redaction.js +152 -0
  102. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/redaction.js.map +1 -0
  103. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/rest.d.ts +198 -0
  104. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/rest.js +225 -0
  105. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/rest.js.map +1 -0
  106. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/run.d.ts +201 -0
  107. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/run.js +166 -0
  108. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/run.js.map +1 -0
  109. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/seed-state.d.ts +446 -0
  110. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/seed-state.js +167 -0
  111. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/seed-state.js.map +1 -0
  112. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/sessions.d.ts +53 -0
  113. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/sessions.js +51 -0
  114. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/sessions.js.map +1 -0
  115. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/task-vocab.d.ts +66 -0
  116. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/task-vocab.js +84 -0
  117. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/task-vocab.js.map +1 -0
  118. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/task.d.ts +483 -0
  119. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/task.js +60 -0
  120. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/dist/task.js.map +1 -0
  121. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/package.json +54 -0
  122. package/node_modules/@pome-sh/sdk/node_modules/@pome-sh/shared-types/trace-contract.json +41 -0
  123. package/node_modules/@pome-sh/sdk/package.json +6 -2
  124. package/node_modules/@pome-sh/shared-types/dist/errors.d.ts +39 -0
  125. package/node_modules/@pome-sh/shared-types/dist/errors.js +33 -0
  126. package/node_modules/@pome-sh/shared-types/dist/errors.js.map +1 -0
  127. package/node_modules/@pome-sh/shared-types/dist/finalize-shapes.d.ts +252 -0
  128. package/node_modules/@pome-sh/shared-types/dist/finalize-shapes.js +122 -0
  129. package/node_modules/@pome-sh/shared-types/dist/finalize-shapes.js.map +1 -0
  130. package/node_modules/@pome-sh/shared-types/dist/identity.d.ts +90 -0
  131. package/node_modules/@pome-sh/shared-types/dist/identity.js +72 -0
  132. package/node_modules/@pome-sh/shared-types/dist/identity.js.map +1 -0
  133. package/node_modules/@pome-sh/shared-types/dist/index.d.ts +13 -1353
  134. package/node_modules/@pome-sh/shared-types/dist/index.js +14 -568
  135. package/node_modules/@pome-sh/shared-types/dist/index.js.map +1 -1
  136. package/node_modules/@pome-sh/shared-types/dist/otel/event-schema.d.ts +45 -0
  137. package/node_modules/@pome-sh/shared-types/dist/otel/legacy-shim.js +8 -0
  138. package/node_modules/@pome-sh/shared-types/dist/otel/legacy-shim.js.map +1 -1
  139. package/node_modules/@pome-sh/shared-types/dist/otel/semconv.js +7 -0
  140. package/node_modules/@pome-sh/shared-types/dist/otel/semconv.js.map +1 -1
  141. package/node_modules/@pome-sh/shared-types/dist/recorder-events.d.ts +62 -0
  142. package/node_modules/@pome-sh/shared-types/dist/recorder-events.js +36 -0
  143. package/node_modules/@pome-sh/shared-types/dist/recorder-events.js.map +1 -1
  144. package/node_modules/@pome-sh/shared-types/dist/rest.d.ts +245 -0
  145. package/node_modules/@pome-sh/shared-types/dist/rest.js +303 -0
  146. package/node_modules/@pome-sh/shared-types/dist/rest.js.map +1 -0
  147. package/node_modules/@pome-sh/shared-types/dist/run.d.ts +7 -0
  148. package/node_modules/@pome-sh/shared-types/dist/run.js +4 -0
  149. package/node_modules/@pome-sh/shared-types/dist/run.js.map +1 -1
  150. package/node_modules/@pome-sh/shared-types/dist/seed-envelope.d.ts +14 -0
  151. package/node_modules/@pome-sh/shared-types/dist/seed-envelope.js +46 -0
  152. package/node_modules/@pome-sh/shared-types/dist/seed-envelope.js.map +1 -0
  153. package/node_modules/@pome-sh/shared-types/dist/seed-state.d.ts +446 -0
  154. package/node_modules/@pome-sh/shared-types/dist/seed-state.js +167 -0
  155. package/node_modules/@pome-sh/shared-types/dist/seed-state.js.map +1 -0
  156. package/node_modules/@pome-sh/shared-types/dist/sessions.d.ts +53 -0
  157. package/node_modules/@pome-sh/shared-types/dist/sessions.js +51 -0
  158. package/node_modules/@pome-sh/shared-types/dist/sessions.js.map +1 -0
  159. package/node_modules/@pome-sh/shared-types/dist/task.d.ts +485 -0
  160. package/node_modules/@pome-sh/shared-types/dist/task.js +60 -0
  161. package/node_modules/@pome-sh/shared-types/dist/task.js.map +1 -0
  162. package/node_modules/@pome-sh/shared-types/package.json +2 -1
  163. package/node_modules/@pome-sh/shared-types/trace-contract.json +1 -1
  164. package/node_modules/@pome-sh/twin-github/FIDELITY.md +127 -67
  165. package/node_modules/@pome-sh/twin-github/README.md +3 -7
  166. package/node_modules/@pome-sh/twin-github/dist/examples/claude-github-agent.js +4 -20
  167. package/node_modules/@pome-sh/twin-github/dist/examples/claude-github-agent.js.map +1 -1
  168. package/node_modules/@pome-sh/twin-github/dist/src/access-control.d.ts +3 -3
  169. package/node_modules/@pome-sh/twin-github/dist/src/domain.d.ts +141 -3
  170. package/node_modules/@pome-sh/twin-github/dist/src/domain.js +0 -0
  171. package/node_modules/@pome-sh/twin-github/dist/src/domain.js.map +1 -1
  172. package/node_modules/@pome-sh/twin-github/dist/src/routes.js +2 -0
  173. package/node_modules/@pome-sh/twin-github/dist/src/routes.js.map +1 -1
  174. package/node_modules/@pome-sh/twin-github/dist/src/seed.d.ts +1 -1
  175. package/node_modules/@pome-sh/twin-github/dist/src/serializers.d.ts +2 -2
  176. package/node_modules/@pome-sh/twin-github/dist/src/server.js +7 -6
  177. package/node_modules/@pome-sh/twin-github/dist/src/server.js.map +1 -1
  178. package/node_modules/@pome-sh/twin-github/dist/src/tools.d.ts +168 -18
  179. package/node_modules/@pome-sh/twin-github/dist/src/tools.js +23 -0
  180. package/node_modules/@pome-sh/twin-github/dist/src/tools.js.map +1 -1
  181. package/node_modules/@pome-sh/twin-github/fidelity.inventory.json +773 -0
  182. package/node_modules/@pome-sh/twin-github/package.json +5 -4
  183. package/node_modules/@pome-sh/twin-slack/FIDELITY.md +121 -35
  184. package/node_modules/@pome-sh/twin-slack/README.md +2 -6
  185. package/node_modules/@pome-sh/twin-slack/dist/scripts/fidelity-parity.d.ts +1 -0
  186. package/node_modules/@pome-sh/twin-slack/dist/scripts/fidelity-parity.js +92 -0
  187. package/node_modules/@pome-sh/twin-slack/dist/scripts/fidelity-parity.js.map +1 -0
  188. package/node_modules/@pome-sh/twin-slack/dist/scripts/smoke.js +3 -3
  189. package/node_modules/@pome-sh/twin-slack/dist/scripts/smoke.js.map +1 -1
  190. package/node_modules/@pome-sh/twin-slack/dist/scripts/validate-mcp.js +1 -1
  191. package/node_modules/@pome-sh/twin-slack/dist/scripts/validate-mcp.js.map +1 -1
  192. package/node_modules/@pome-sh/twin-slack/dist/src/server.js +7 -6
  193. package/node_modules/@pome-sh/twin-slack/dist/src/server.js.map +1 -1
  194. package/node_modules/@pome-sh/twin-slack/dist/src/tools.d.ts +30 -4
  195. package/node_modules/@pome-sh/twin-slack/dist/src/tools.js +48 -1
  196. package/node_modules/@pome-sh/twin-slack/dist/src/tools.js.map +1 -1
  197. package/node_modules/@pome-sh/twin-slack/fidelity.inventory.json +377 -0
  198. package/node_modules/@pome-sh/twin-slack/package.json +5 -4
  199. package/node_modules/@pome-sh/twin-stripe/FIDELITY.md +151 -50
  200. package/node_modules/@pome-sh/twin-stripe/README.md +42 -45
  201. package/node_modules/@pome-sh/twin-stripe/dist/scripts/fidelity-parity.d.ts +1 -0
  202. package/node_modules/@pome-sh/twin-stripe/dist/scripts/fidelity-parity.js +186 -0
  203. package/node_modules/@pome-sh/twin-stripe/dist/scripts/fidelity-parity.js.map +1 -0
  204. package/node_modules/@pome-sh/twin-stripe/dist/scripts/smoke.js +8 -4
  205. package/node_modules/@pome-sh/twin-stripe/dist/scripts/smoke.js.map +1 -1
  206. package/node_modules/@pome-sh/twin-stripe/dist/src/db.js +26 -2
  207. package/node_modules/@pome-sh/twin-stripe/dist/src/db.js.map +1 -1
  208. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/billing.d.ts +101 -0
  209. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/billing.js +195 -0
  210. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/billing.js.map +1 -0
  211. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/charges.d.ts +15 -1
  212. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/charges.js +17 -5
  213. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/charges.js.map +1 -1
  214. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/customers.d.ts +47 -0
  215. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/customers.js +103 -0
  216. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/customers.js.map +1 -0
  217. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/events.d.ts +1 -1
  218. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/events.js.map +1 -1
  219. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/index.d.ts +6 -0
  220. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/index.js +3 -0
  221. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/index.js.map +1 -1
  222. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/payment-intents.d.ts +61 -2
  223. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/payment-intents.js +214 -52
  224. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/payment-intents.js.map +1 -1
  225. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/payment-methods.d.ts +45 -0
  226. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/payment-methods.js +159 -0
  227. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/payment-methods.js.map +1 -0
  228. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/refunds.d.ts +6 -0
  229. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/refunds.js +16 -0
  230. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/refunds.js.map +1 -1
  231. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/schema.d.ts +1 -0
  232. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/schema.js +144 -1
  233. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/schema.js.map +1 -1
  234. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/stripe-domain.d.ts +420 -43
  235. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/stripe-domain.js +442 -13
  236. package/node_modules/@pome-sh/twin-stripe/dist/src/domain/stripe-domain.js.map +1 -1
  237. package/node_modules/@pome-sh/twin-stripe/dist/src/errors.d.ts +19 -0
  238. package/node_modules/@pome-sh/twin-stripe/dist/src/errors.js +15 -1
  239. package/node_modules/@pome-sh/twin-stripe/dist/src/errors.js.map +1 -1
  240. package/node_modules/@pome-sh/twin-stripe/dist/src/ids.d.ts +2 -0
  241. package/node_modules/@pome-sh/twin-stripe/dist/src/ids.js +2 -0
  242. package/node_modules/@pome-sh/twin-stripe/dist/src/ids.js.map +1 -1
  243. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/_helpers.d.ts +8 -0
  244. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/_helpers.js +105 -1
  245. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/_helpers.js.map +1 -1
  246. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/billing.d.ts +4 -0
  247. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/billing.js +117 -0
  248. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/billing.js.map +1 -0
  249. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/customers.d.ts +4 -0
  250. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/customers.js +47 -0
  251. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/customers.js.map +1 -0
  252. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/index.js +6 -0
  253. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/index.js.map +1 -1
  254. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/payment-intents.js +28 -102
  255. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/payment-intents.js.map +1 -1
  256. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/payment-methods.d.ts +4 -0
  257. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/payment-methods.js +33 -0
  258. package/node_modules/@pome-sh/twin-stripe/dist/src/routes/payment-methods.js.map +1 -0
  259. package/node_modules/@pome-sh/twin-stripe/dist/src/seed.d.ts +10 -8
  260. package/node_modules/@pome-sh/twin-stripe/dist/src/seed.js +3 -2
  261. package/node_modules/@pome-sh/twin-stripe/dist/src/seed.js.map +1 -1
  262. package/node_modules/@pome-sh/twin-stripe/dist/src/serializers.d.ts +181 -21
  263. package/node_modules/@pome-sh/twin-stripe/dist/src/serializers.js +257 -34
  264. package/node_modules/@pome-sh/twin-stripe/dist/src/serializers.js.map +1 -1
  265. package/node_modules/@pome-sh/twin-stripe/dist/src/server.js +7 -6
  266. package/node_modules/@pome-sh/twin-stripe/dist/src/server.js.map +1 -1
  267. package/node_modules/@pome-sh/twin-stripe/dist/src/tools.d.ts +107 -5
  268. package/node_modules/@pome-sh/twin-stripe/dist/src/tools.js +139 -6
  269. package/node_modules/@pome-sh/twin-stripe/dist/src/tools.js.map +1 -1
  270. package/node_modules/@pome-sh/twin-stripe/dist/src/types.d.ts +73 -0
  271. package/node_modules/@pome-sh/twin-stripe/dist/src/upstream-types.d.ts +8 -0
  272. package/node_modules/@pome-sh/twin-stripe/dist/src/x402.js +6 -1
  273. package/node_modules/@pome-sh/twin-stripe/dist/src/x402.js.map +1 -1
  274. package/node_modules/@pome-sh/twin-stripe/fidelity.inventory.json +425 -0
  275. package/node_modules/@pome-sh/twin-stripe/package.json +5 -4
  276. package/package.json +8 -8
  277. package/skills/pome-setup/SKILL.md +1 -1
@@ -5,7 +5,7 @@
5
5
  page documents exactly which surfaces are faithful to real Stripe today,
6
6
  at what tier, and how fidelity is verified.
7
7
 
8
- Last verified: 2026-05-09.
8
+ Last verified: 2026-07-12.
9
9
  Stripe API version pinned: `2026-03-04.preview`.
10
10
 
11
11
  ## What "fidelity" means here
@@ -16,13 +16,23 @@ Each REST route and MCP tool is classified into one of three tiers:
16
16
  covered by tests. PaymentIntent state-machine transitions, balance
17
17
  arithmetic, idempotency-key dedupe, and the rest behave the way agents
18
18
  expect when they call real Stripe.
19
- - **`shape`** — the response shape is checked against captured real
20
- Stripe fixtures, but the underlying behavior is not fully semantic.
21
- v1 has no shape-tier routes.
19
+ - **`shape`** — the response shape is faithful (compile-anchored against
20
+ the official `stripe` types, FDRS-478) but the underlying behavior is
21
+ deliberately not semantic. The billing surfaces (products, prices,
22
+ subscriptions, invoice reads — F-734, ruled warm by F-729) sit here:
23
+ stored rows served back in Stripe shape, with referential 404s, but no
24
+ events emitted, no invoices minted, no billing-cycle arithmetic.
22
25
  - **`unsupported`** — not implemented. The clone returns a loud 501
23
26
  envelope (see below) so an agent never silently succeeds against a
24
27
  missing route.
25
28
 
29
+ Fidelity ("how deep a surface *is*") is one of two orthogonal dimensions;
30
+ the other is **heat** ("how deep it *should* be", `hot`/`warm`/`cold`,
31
+ ruled per milestone). The engine-level rubric — tier criteria, target
32
+ mapping, gap and tier-mismatch semantics — lives at
33
+ [`packages/sdk/ENDPOINT-TIERS.md`](../sdk/ENDPOINT-TIERS.md). The `Tier`
34
+ column below means fidelity.
35
+
26
36
  The bar Pome aims for: **agents written against real Stripe x402 run
27
37
  unchanged against this twin**, and trip a loud failure for anything
28
38
  outside the documented surface.
@@ -34,27 +44,68 @@ build depends on (port `:3333`, `/healthz`, `STRIPE_CLONE_HOST`,
34
44
  in the package README. Changing any of those is a breaking change for
35
45
  `pome-cloud` and requires a matching cloud consumer PR.
36
46
 
37
- ## REST routes (v1 = 12 semantic + everything else loud 501)
38
-
39
- | Route | Tier | Tests | Notes |
40
- | --- | --- | --- | --- |
41
- | `POST /s/:sid/v1/payment_intents` | semantic | `pi.test.ts`, `tools.test.ts` | Crypto deposit mode only. Generates deterministic Base USDC deposit address. PI status starts at `requires_action`. |
42
- | `GET /s/:sid/v1/payment_intents/:id` | semantic | `pi.test.ts` | |
43
- | `GET /s/:sid/v1/payment_intents` | semantic | `pi.test.ts` | Cursor pagination on `(created, id)` via `starting_after` / `ending_before` (matches Stripe's cursor model). |
44
- | `POST /s/:sid/v1/payment_intents/:id/confirm` | semantic | `pi.test.ts` | For crypto-only PIs, confirm is mostly a no-op (state already `requires_action` after create). Idempotent return. |
45
- | `POST /s/:sid/v1/payment_intents/:id/cancel` | semantic | `pi.test.ts` | CAS-on-status; refused once `succeeded`. |
46
- | `POST /s/:sid/v1/test_helpers/payment_intents/:id/simulate_crypto_deposit` | semantic | `pi.test.ts`, `pi-concurrency.test.ts`, `events.test.ts` | The x402 settlement entry point. CAS `requires_action → processing → succeeded`; mints charge + balance txn + 5 events synchronously. |
47
- | `GET /s/:sid/v1/charges/:id` | semantic | `charges.test.ts` | Latest charge of a settled PI. |
48
- | `GET /s/:sid/v1/charges` | semantic | `charges.test.ts` | Filter by `payment_intent`, `customer`. |
49
- | `GET /s/:sid/v1/balance` | semantic | `balance.test.ts` | Available + pending; updated as PIs settle. |
50
- | `GET /s/:sid/v1/balance_transactions` | semantic | `balance.test.ts` | Ledger entries. |
51
- | `GET /s/:sid/v1/events/:id` | semantic | `events.test.ts` | |
52
- | `GET /s/:sid/v1/events` | semantic | `events.test.ts` | Filter by `type`, `created`. **No webhook delivery in v1** agents poll this. |
53
-
54
- Anything else under `/v1/*` (`/v1/customers`,
55
- `/v1/setup_intents`, `/v1/checkout/*`, `/v1/products`, `/v1/prices`,
56
- `/v1/webhook_endpoints`, `/v1/payment_methods`, `/v1/shared_payment/*`,
57
- `/v1/profiles`, etc.) returns:
47
+ ## REST routes (v1 = 26 semantic + 13 shape + everything else loud 501)
48
+
49
+ | Route | Heat | Tier | Tests | Notes |
50
+ | --- | --- | --- | --- | --- |
51
+ | `POST /s/:sid/v1/payment_intents` | hot | semantic | `pi.test.ts`, `pi-card.test.ts`, `tools.test.ts` | Two rails (F-731): crypto deposit mode (deterministic Base USDC deposit address, starts at `requires_action`) and card (starts at `requires_payment_method`, or `requires_confirmation` with a `payment_method`; `confirm: true` runs the one-shot attempt). |
52
+ | `GET /s/:sid/v1/payment_intents/:id` | hot | semantic | `pi.test.ts`, `pi-card.test.ts` | Card PIs surface `last_payment_error` after a declined attempt. |
53
+ | `GET /s/:sid/v1/payment_intents` | hot | semantic | `pi.test.ts` | Cursor pagination on `(created, id)` via `starting_after` / `ending_before` (matches Stripe's cursor model). |
54
+ | `POST /s/:sid/v1/payment_intents/:id/confirm` | hot | semantic | `pi.test.ts`, `pi-card.test.ts` | Card PIs (F-731): synchronous attempt success mints charge + balance txn + events; magic test PMs decline with a 402 `card_error` embedding the post-attempt PI. Crypto PIs: idempotent no-op. CAS picks exactly one winner among parallel confirms. |
55
+ | `POST /s/:sid/v1/payment_intents/:id` | hot | semantic | `pi-card.test.ts` | Update (F-731, ruled in scope by F-729 point 1) — the retry-with-new-PM step. Metadata merges per-key; attaching a PM moves `requires_payment_method → requires_confirmation`. Refused once terminal. |
56
+ | `POST /s/:sid/v1/payment_intents/:id/cancel` | hot | semantic | `pi.test.ts`, `pi-card.test.ts` | CAS-on-status; refused once `succeeded`. |
57
+ | `POST /s/:sid/v1/test_helpers/payment_intents/:id/simulate_crypto_deposit` | hot | semantic | `pi.test.ts`, `pi-concurrency.test.ts`, `events.test.ts` | The x402 settlement entry point. CAS `requires_action → processing → succeeded`; mints charge + balance txn + 5 events synchronously. |
58
+ | `GET /s/:sid/v1/charges/:id` | hot | semantic | `charges.test.ts` | Latest charge of a settled PI. |
59
+ | `GET /s/:sid/v1/charges` | hot | semantic | `charges.test.ts` | Filter by `payment_intent`, `customer`. |
60
+ | `POST /s/:sid/v1/refunds` | hot | semantic | `refunds.test.ts`, `refund-abuse-trap.test.ts` | F-733 (heat: hot, ruled F-729). Full or partial; `amount` defaults to the remaining refundable. Refuses over-refunds (`charge_already_refunded`) and failed charges (`charge_not_refundable`). Mints a negative `refund`-type balance transaction and emits `charge.refunded` + `refund.created` in the same transaction. |
61
+ | `GET /s/:sid/v1/refunds/:id` | hot | semantic | `refunds.test.ts` | |
62
+ | `GET /s/:sid/v1/refunds` | hot | semantic | `refunds.test.ts` | Filter by `charge`, `payment_intent`. Omits the legacy `count` field (divergence #9). |
63
+ | `GET /s/:sid/v1/balance` | hot | semantic | `balance.test.ts` | Available + pending; updated as PIs settle. |
64
+ | `GET /s/:sid/v1/balance_transactions` | hot | semantic | `balance.test.ts` | Ledger entries. |
65
+ | `GET /s/:sid/v1/events/:id` | hot | semantic | `events.test.ts` | |
66
+ | `GET /s/:sid/v1/events` | hot | semantic | `events.test.ts` | Filter by `type`, `created`. **No webhook delivery in v1** — agents poll this. |
67
+ | `POST /s/:sid/v1/customers` | hot | semantic | `customers.test.ts` | F-732 (heat: hot, ruled F-729). Every field optional, like real Stripe. Emits `customer.created`. |
68
+ | `GET /s/:sid/v1/customers/:id` | hot | semantic | `customers.test.ts` | Deleted customers serve the `{deleted: true}` stub, like real Stripe. |
69
+ | `GET /s/:sid/v1/customers` | hot | semantic | `customers.test.ts` | Cursor pagination on `(created, id)`; `email` filter; deleted rows excluded. |
70
+ | `POST /s/:sid/v1/customers/:id` | hot | semantic | `customers.test.ts` | Update. Metadata merges per-key; an empty value unsets the key (Stripe's metadata contract). |
71
+ | `DELETE /s/:sid/v1/customers/:id` | hot | semantic | `customers.test.ts` | Soft delete; detaches the customer's payment methods in the same transaction. Idempotent. |
72
+ | `GET /s/:sid/v1/customers/:id/payment_methods` | hot | semantic | `payment-methods.test.ts` | The hot card-on-file read. `type` filter. 404 for deleted customers. |
73
+ | `POST /s/:sid/v1/payment_methods` | hot | semantic | `payment-methods.test.ts` | Card only (F-731 adds card PIs). Test card numbers → brand/last4; Luhn + expiry `card_error`s; PAN never stored. |
74
+ | `GET /s/:sid/v1/payment_methods/:id` | hot | semantic | `payment-methods.test.ts` | Top-level `GET /v1/payment_methods` (list) stays loud 501 per the F-729 ruling. |
75
+ | `POST /s/:sid/v1/payment_methods/:id/attach` | hot | semantic | `payment-methods.test.ts` | One customer per PM; a previously-detached PM can never be reattached. Emits `payment_method.attached`. |
76
+ | `POST /s/:sid/v1/payment_methods/:id/detach` | hot | semantic | `payment-methods.test.ts` | Emits `payment_method.detached`. |
77
+ | `POST /s/:sid/v1/products` | warm | shape | `billing-shape.test.ts` | F-734 (heat: warm, ruled F-729). `name` required; unknown params accepted-and-ignored per the twin's v1 policy. Product/price updates stay unlisted-cold (501). |
78
+ | `GET /s/:sid/v1/products/:id` | warm | shape | `billing-shape.test.ts` | 404 `resource_missing` for unknown ids. |
79
+ | `GET /s/:sid/v1/products` | warm | shape | `billing-shape.test.ts` | Cursor pagination on `(created, id)`; `active` filter. |
80
+ | `POST /s/:sid/v1/prices` | warm | shape | `billing-shape.test.ts` | `currency` + `product` required; the product must exist (referential 404). `recurring.interval` makes it a `recurring` price, otherwise `one_time`. |
81
+ | `GET /s/:sid/v1/prices/:id` | warm | shape | `billing-shape.test.ts` | |
82
+ | `GET /s/:sid/v1/prices` | warm | shape | `billing-shape.test.ts` | Cursor pagination; `product` + `active` filters. |
83
+ | `POST /s/:sid/v1/subscriptions` | warm | shape | `billing-shape.test.ts` | `customer` (live) + `items[][price]` required, both referentially checked. Created `active` immediately — no invoice minted, no event emitted (shape tier). |
84
+ | `GET /s/:sid/v1/subscriptions/:id` | warm | shape | `billing-shape.test.ts` | `items.data[].price` is the expanded Price object, like real Stripe. |
85
+ | `GET /s/:sid/v1/subscriptions` | warm | shape | `billing-shape.test.ts` | Excludes canceled by default; `status=canceled` selects them, `status=all` lifts the filter; `customer` filter. |
86
+ | `POST /s/:sid/v1/subscriptions/:id` | warm | shape | `billing-shape.test.ts` | Update: metadata merges per-key (empty value unsets), `cancel_at_period_end` flips. Canceled subscriptions accept metadata-only updates and refuse everything else, like real Stripe. |
87
+ | `DELETE /s/:sid/v1/subscriptions/:id` | warm | shape | `billing-shape.test.ts` | Immediate cancel: `status → canceled`, `canceled_at`/`ended_at` stamped. Idempotent; no proration, no final invoice (shape tier). |
88
+ | `GET /s/:sid/v1/invoices/:id` | warm | shape | `billing-shape.test.ts` | Always 404 `resource_missing`: invoices are reads-only (F-729 ruling point 2) and nothing in the twin mints one. |
89
+ | `GET /s/:sid/v1/invoices` | warm | shape | `billing-shape.test.ts` | Always the empty Stripe list envelope — see the invoice note under Known divergences. |
90
+
91
+ ### Named cold surfaces (loud 501, test-backed)
92
+
93
+ Per the F-729 ruling these families are cold — outside the twin's
94
+ machine-payments product scope — but agents plausibly probe them, so the
95
+ 501 is documented here and pinned by `unsupported.test.ts` (and the
96
+ `fidelity:parity` 501 probe for checkout sessions):
97
+
98
+ | Route | Heat | Tier | Tests | Notes |
99
+ | --- | --- | --- | --- | --- |
100
+ | `ALL /s/:sid/v1/checkout/sessions*` | cold | unsupported | `unsupported.test.ts` | PS: human-redirect flow. |
101
+ | `ALL /s/:sid/v1/payment_links*` | cold | unsupported | `unsupported.test.ts` | PS: human-redirect flow. |
102
+ | `ALL /s/:sid/v1/setup_intents*` | cold | unsupported | `unsupported.test.ts` | PS: card-on-file is modeled via direct PM attach (F-732). |
103
+ | `ALL /s/:sid/v1/webhook_endpoints*` | cold | unsupported | `unsupported.test.ts` | PS: no webhook delivery loop in v1 (divergence #5); agents poll `GET /v1/events`. |
104
+
105
+ Anything else under `/v1/*` (`/v1/shared_payment/*`, `/v1/profiles`,
106
+ invoice writes like `POST /v1/invoices` or `.../finalize`/`.../pay`,
107
+ product/price updates, the top-level `GET /v1/payment_methods` list,
108
+ etc.) is the unlisted cold tail and returns:
58
109
 
59
110
  ```json
60
111
  {
@@ -75,27 +126,50 @@ Anything else under `/v1/*` (`/v1/customers`,
75
126
 
76
127
  HTTP status: 501.
77
128
 
78
- ## MCP tools (12 — names match `stripe-node` method names)
79
-
80
- | Tool | Backing route | Tier |
81
- | --- | --- | --- |
82
- | `create_payment_intent` | POST /v1/payment_intents | semantic |
83
- | `retrieve_payment_intent` | GET /v1/payment_intents/:id | semantic |
84
- | `list_payment_intents` | GET /v1/payment_intents | semantic |
85
- | `confirm_payment_intent` | POST /v1/payment_intents/:id/confirm | semantic |
86
- | `cancel_payment_intent` | POST /v1/payment_intents/:id/cancel | semantic |
87
- | `simulate_crypto_deposit` | POST /v1/test_helpers/.../simulate_crypto_deposit | semantic |
88
- | `retrieve_charge` | GET /v1/charges/:id | semantic |
89
- | `list_charges` | GET /v1/charges | semantic |
90
- | `retrieve_balance` | GET /v1/balance | semantic |
91
- | `list_balance_transactions` | GET /v1/balance_transactions | semantic |
92
- | `retrieve_event` | GET /v1/events/:id | semantic |
93
- | `list_events` | GET /v1/events | semantic |
129
+ ## MCP tools (26, 1:1 with the live tool list — names match `stripe-node` method names)
130
+
131
+ | Tool | Backing route | Heat | Tier |
132
+ | --- | --- | --- | --- |
133
+ | `create_payment_intent` | POST /v1/payment_intents | hot | semantic |
134
+ | `retrieve_payment_intent` | GET /v1/payment_intents/:id | hot | semantic |
135
+ | `list_payment_intents` | GET /v1/payment_intents | hot | semantic |
136
+ | `confirm_payment_intent` | POST /v1/payment_intents/:id/confirm | hot | semantic |
137
+ | `update_payment_intent` | POST /v1/payment_intents/:id | hot | semantic |
138
+ | `cancel_payment_intent` | POST /v1/payment_intents/:id/cancel | hot | semantic |
139
+ | `simulate_crypto_deposit` | POST /v1/test_helpers/.../simulate_crypto_deposit | hot | semantic |
140
+ | `retrieve_charge` | GET /v1/charges/:id | hot | semantic |
141
+ | `list_charges` | GET /v1/charges | hot | semantic |
142
+ | `create_refund` | POST /v1/refunds | hot | semantic |
143
+ | `retrieve_refund` | GET /v1/refunds/:id | hot | semantic |
144
+ | `list_refunds` | GET /v1/refunds | hot | semantic |
145
+ | `retrieve_balance` | GET /v1/balance | hot | semantic |
146
+ | `list_balance_transactions` | GET /v1/balance_transactions | hot | semantic |
147
+ | `retrieve_event` | GET /v1/events/:id | hot | semantic |
148
+ | `list_events` | GET /v1/events | hot | semantic |
149
+ | `create_customer` | POST /v1/customers | hot | semantic |
150
+ | `retrieve_customer` | GET /v1/customers/:id | hot | semantic |
151
+ | `update_customer` | POST /v1/customers/:id | hot | semantic |
152
+ | `delete_customer` | DELETE /v1/customers/:id | hot | semantic |
153
+ | `list_customers` | GET /v1/customers | hot | semantic |
154
+ | `list_customer_payment_methods` | GET /v1/customers/:id/payment_methods | hot | semantic |
155
+ | `create_payment_method` | POST /v1/payment_methods | hot | semantic |
156
+ | `retrieve_payment_method` | GET /v1/payment_methods/:id | hot | semantic |
157
+ | `attach_payment_method` | POST /v1/payment_methods/:id/attach | hot | semantic |
158
+ | `detach_payment_method` | POST /v1/payment_methods/:id/detach | hot | semantic |
94
159
 
95
160
  Every MCP tool is callable via both `POST /s/:sid/mcp/call` (with
96
161
  `{tool, arguments}` body) and `POST /s/:sid/mcp/tools/:name` (with the
97
162
  arguments as the body). Coverage in `tools.test.ts`.
98
163
 
164
+ The tables above are 1:1-linted against the structured inventory
165
+ [`fidelity.inventory.json`](fidelity.inventory.json) (which also carries the
166
+ hot/warm/cold heat tier per F-729) by `test/fidelity-contract.test.ts`, and
167
+ `npm run fidelity:parity` (shared runner in `@pome-sh/sdk/parity`, F-730)
168
+ exercises every inventoried tool end-to-end. Known gaps between code and
169
+ these tables must be declared in the inventory's `doc_drift` with their
170
+ owning ticket, and the lint fails the moment the docs catch up. None are
171
+ declared today — F-733 reconciled the refunds chain, the last such gap.
172
+
99
173
  ## x402 middleware (`src/x402.ts`)
100
174
 
101
175
  `paymentMiddleware(routeMap, twinOptions)` is a Hono helper that:
@@ -126,7 +200,9 @@ plus the `examples/buyer-agent/` end-to-end demo against a running twin.
126
200
  exactly one 200 (winner of the `requires_action → processing` CAS)
127
201
  and seven 400s with `payment_intent_unexpected_state`. Single
128
202
  `charges` row, single `balance_transactions` row, balance reflects
129
- the PI amount once.
203
+ the PI amount once. The card rail carries the same guarantee
204
+ (`pi-card.test.ts`): 8 parallel confirms → one winner of the
205
+ `requires_confirmation → processing` CAS, single charge.
130
206
  - **Idempotency-Key** (`idempotency.test.ts`): same key + same body →
131
207
  cached response. Same key + different body → 400
132
208
  `idempotency_key_in_use`. Caches 2xx/3xx; skips 4xx and 5xx so a
@@ -195,12 +271,23 @@ not exposed at the root mount — those remain at `/s/:sid/_pome/*` and
195
271
 
196
272
  ## Known divergences from real Stripe (v1)
197
273
 
198
- 1. **PI currency restricted to `usd`**. Non-USD returns
274
+ 1. **PI currency restricted to `usd`** on both rails. Non-USD returns
199
275
  `currency_not_supported`. (Real Stripe accepts many currencies but
200
- x402's USD-priced/USDC-paid model is the v1 wedge.)
201
- 2. **`payment_method_types` restricted to crypto**. The value must be
202
- `["crypto"]`; `["card"]` and others return
203
- `payment_method_type_not_supported`.
276
+ x402's USD-priced/USDC-paid model is the v1 wedge; card PIs keep the
277
+ same restriction.)
278
+ 2. **`payment_method_types` restricted to exactly `["crypto"]` or `["card"]`**
279
+ (F-731 added the card rail). Multi-type lists and other types return a
280
+ loud 400. Card attempts settle synchronously with no 3DS /
281
+ `requires_action` step; declines are driven by Stripe's magic test PMs
282
+ (`4000000000000002` generic_decline, `4000000000009995`
283
+ insufficient_funds, `4000000000000069` expired_card, `4000000000000127`
284
+ incorrect_cvc — the decline is keyed off the stored card fingerprint,
285
+ the PAN is never persisted). A declined confirm answers 402 with a
286
+ `card_error` envelope that embeds `decline_code` and the post-attempt
287
+ `payment_intent`, mints a `failed` charge, and records
288
+ `last_payment_error` — the ruled retry step is
289
+ `POST /v1/payment_intents/:id` with a new `payment_method`, then
290
+ confirm again.
204
291
  3. **Single deposit network and token**. One network (`base`), one token
205
292
  (`usdc`). Tempo and Solana from Stripe's published matrix are deferred.
206
293
  4. **`available_on` equals `created`** for balance transactions (no
@@ -210,8 +297,11 @@ not exposed at the root mount — those remain at `/s/:sid/_pome/*` and
210
297
  6. **EIP-3009 signature verification not enforced** (x402 deviation).
211
298
  7. **`simulate_crypto_deposit` settles synchronously**; no chain-delay
212
299
  simulation.
213
- 8. **`confirm_payment_intent` is a no-op for crypto-only PIs** (the
214
- state machine doesn't need a separate confirm step in deposit mode).
300
+ 8. **`confirm_payment_intent` is a no-op for crypto PIs only** (the
301
+ deposit-mode state machine doesn't need a separate confirm step).
302
+ Card confirms are real synchronous attempts (F-731) — and unlike the
303
+ crypto no-op, re-confirming a settled card PI is refused with
304
+ `payment_intent_unexpected_state`.
215
305
  9. **`/v1/refunds` omits the legacy `count` field**. Real Stripe's
216
306
  refunds list envelope still carries a top-level `count`; the twin (like
217
307
  its other list surfaces, which match real Stripe exactly) omits this
@@ -258,6 +348,16 @@ not exposed at the root mount — those remain at `/s/:sid/_pome/*` and
258
348
  anchor). Bumping `stripe` re-runs the anchor — the FDRS-476 bump → tsc →
259
349
  cover-or-register loop — surfacing every upstream shape change by name.
260
350
 
351
+ 16. **Billing surfaces are shape tier — no billing machine behind them**
352
+ (F-734, ruled warm by F-729). Creating a product / price / subscription
353
+ emits **no events** and mints **no invoices**; real Stripe emits
354
+ `product.created` etc. and invoices a new subscription immediately.
355
+ `GET /v1/invoices` is therefore always the empty list and
356
+ `GET /v1/invoices/:id` always 404s (invoice writes are unlisted-cold per
357
+ ruling point 2). Subscription items omit `current_period_start/end` —
358
+ the shape tier carries no billing-cycle arithmetic, so no period is
359
+ fabricated. Cancellation is an immediate status flip with no proration.
360
+
261
361
  > Pagination is **not** a divergence: `GET /v1/payment_intents` (and the
262
362
  > other list surfaces) use real cursor pagination keyed on `(created, id)`
263
363
  > via `starting_after` / `ending_before`, matching Stripe's cursor model.
@@ -265,7 +365,8 @@ not exposed at the root mount — those remain at `/s/:sid/_pome/*` and
265
365
  ## Verification commands
266
366
 
267
367
  ```bash
268
- npm run test # 14 files / 70 tests, all green
368
+ npm run test # 32 files / 237 tests, all green
269
369
  npm run smoke # full x402 flow against built server
370
+ npm run fidelity:parity # every inventoried MCP tool end-to-end
270
371
  npm run typecheck
271
372
  ```
@@ -7,9 +7,11 @@ x402 machine payments**. Real Stripe sandbox doesn't auto-settle crypto
7
7
  deposits, the CDP facilitator settles on real Base, and `stripe-mock`
8
8
  has no x402 support — so without this twin there is nowhere to run agent
9
9
  tests against the x402 protocol that aren't either flaky, slow, or
10
- expensive. v1 ships **12 REST endpoints + 12 MCP tools + the
11
- `paymentMiddleware()` Hono helper**, all stateful, all tested, all loud
12
- about what they don't do.
10
+ expensive. Today it ships **26 semantic REST routes + 26 MCP tools + the
11
+ `paymentMiddleware()` Hono helper** (card and crypto PaymentIntents,
12
+ customers, payment methods, refunds, charges, balance, events), plus 13
13
+ shape-tier billing routes — all stateful, all tested, all loud about what
14
+ they don't do.
13
15
 
14
16
  ## Quickstart
15
17
 
@@ -20,17 +22,16 @@ twin URL. Skip ahead to [Auth](#auth--works-with-real-stripe-sdks) for
20
22
  how to wire your existing Stripe SDK.
21
23
 
22
24
  To run the twin yourself locally (e.g., in CI or against an offline
23
- agent), clone this repo and run:
25
+ agent), the zero-install path needs only Node ≥ 24:
24
26
 
25
27
  ```bash
26
- git clone https://github.com/pome-sh/pome-twins.git
27
- cd pome-twins && npm install
28
- npm run -w @pome-sh/twin-stripe dev & # starts on :3333
29
- sleep 2
28
+ npx @pome-sh/cli twin start stripe # starts on :3333
29
+ curl http://127.0.0.1:3333/healthz
30
30
 
31
- # Or via Docker (host port 3334 when using root docker-compose --profile twins):
32
- # docker compose --profile twins up -d twin-stripe
33
- # curl http://127.0.0.1:3334/healthz
31
+ # Or, to develop the twin from source:
32
+ # git clone https://github.com/pome-sh/pome-twins.git
33
+ # cd pome-twins && npm install
34
+ # npm run -w @pome-sh/twin-stripe dev
34
35
 
35
36
  # Real Stripe SDKs work via host override — they hit /v1/* directly
36
37
  # (no /s/:sid prefix) and the bearer alone resolves the session:
@@ -58,22 +59,17 @@ deployments (e.g., the pome-cloud per-session proxy, where the `:sid`
58
59
  in the URL must match the bearer). Pick whichever shape your client
59
60
  prefers — they share handlers and produce identical responses.
60
61
 
61
- > **npm publish status**: this package is currently `private: true` in
62
- > `package.json` pending OSS Stage 1 + legal review (see plan §22). After
63
- > Stage 1, `npx @pome-sh/twin-stripe` will be the one-line install path;
64
- > until then, the monorepo clone above or the hosted twin on
65
- > pome.sh is the supported route.
66
-
67
- ## What ships in v1
62
+ ## What ships today
68
63
 
69
64
  | Surface | Count | Tier |
70
65
  | --- | --- | --- |
71
- | REST endpoints under `/s/:sid/v1/*` | 12 | semantic |
72
- | MCP tools (1:1 with stripe-node) | 12 | semantic |
66
+ | REST routes under `/s/:sid/v1/*` (payments, customers, payment methods, refunds, charges, balance, events) | 26 | semantic |
67
+ | Billing reads/writes (products, prices, subscriptions, invoice reads) | 13 | shape |
68
+ | MCP tools (1:1 with stripe-node) | 26 | semantic |
73
69
  | `paymentMiddleware()` Hono helper | 1 | semantic |
74
70
  | Pome introspection (`_pome/{health,state,events}`) | 3 | n/a |
75
71
  | Admin (`/admin/{reset,seed}`, localhost-only) | 2 | n/a |
76
- | Anything else under `/v1/*` | many | **loud 501 with `fidelity:"unsupported"`** |
72
+ | Named cold surfaces (checkout, payment links, setup intents, webhook endpoints) + anything else under `/v1/*` | many | **loud 501 with `fidelity:"unsupported"`** |
77
73
 
78
74
  See [FIDELITY.md](./FIDELITY.md) for the full route table and known
79
75
  deviations from real Stripe.
@@ -137,19 +133,20 @@ Either way, the resolved session id must match the `:sid` in the URL.
137
133
 
138
134
  ## MCP
139
135
 
140
- 15 tools available at `GET /s/:sid/mcp/tools`. Tool names match
136
+ 26 tools available at `GET /s/:sid/mcp/tools`. Tool names match
141
137
  `stripe-node` method names so an agent's mental model translates 1:1:
142
138
 
143
139
  ```
144
- create_payment_intent
145
- retrieve_payment_intent
146
- list_payment_intents
147
- confirm_payment_intent
148
- cancel_payment_intent
149
- simulate_crypto_deposit
150
- retrieve_charge
151
- list_charges
152
- retrieve_balance
140
+ create_payment_intent create_customer
141
+ retrieve_payment_intent retrieve_customer
142
+ list_payment_intents update_customer
143
+ update_payment_intent delete_customer
144
+ confirm_payment_intent list_customers
145
+ cancel_payment_intent list_customer_payment_methods
146
+ simulate_crypto_deposit create_payment_method
147
+ retrieve_charge retrieve_payment_method
148
+ list_charges attach_payment_method
149
+ retrieve_balance detach_payment_method
153
150
  list_balance_transactions
154
151
  retrieve_event
155
152
  list_events
@@ -205,14 +202,19 @@ that pins and verifies the new signed digest.
205
202
  - The snapshot manifest at `pome-cloud/infra/twin-stripe-snapshot.json`
206
203
  records the OSS git sha and signed OCI digest each snapshot was built from.
207
204
 
208
- ## What v1 does NOT do
205
+ ## What it does NOT do
206
+
207
+ Shape tier (faithful response shape, deliberately no billing semantics —
208
+ no events emitted, no invoices minted, no billing-cycle arithmetic):
209
+
210
+ - Products, prices, subscriptions, invoice reads (F-734).
209
211
 
210
212
  Loud 501 with `fidelity: "unsupported"`:
211
213
 
212
- - All `/v1/shared_payment/*` (SPT) deferred to v2.
213
- - Customer / payment-method CRUD — not on the x402 path.
214
- - Setup intents, refunds, products, prices, checkout sessions v2.
215
- - Webhook delivery loop — agents poll `GET /v1/events` in v1.
214
+ - Checkout sessions, payment links, setup intents, webhook endpoints —
215
+ named cold surfaces, test-backed.
216
+ - All `/v1/shared_payment/*` (SPT)deferred.
217
+ - Webhook delivery loop — agents poll `GET /v1/events`.
216
218
  - Profiles, Connect, Issuing, Treasury, Tax, Climate, Identity — out forever
217
219
  for this twin.
218
220
 
@@ -235,26 +237,21 @@ Other deviations from real Stripe:
235
237
  npm install
236
238
  npm run dev # boot on :3333 with default seed
237
239
  npm run typecheck # tsc --noEmit
238
- npm run test # vitest, 17 files / 87 tests
240
+ npm run test # vitest, 32 files / 237 tests
239
241
  npm run build # tsc → dist/src/server.js
240
242
  node dist/src/server.js # production-shape boot
241
243
  ```
242
244
 
243
245
  ## Use it as a Stripe test double in your tests
244
246
 
245
- Until the package is on npm (post-Stage-1), the cleanest way is to clone
246
- this monorepo and shell out to `npm run dev` from your test setup:
247
+ The cleanest way is to boot the published twin from your test setup; all
248
+ it needs is Node 24:
247
249
 
248
250
  ```ts
249
251
  // In your test setup
250
252
  import { spawn } from "node:child_process";
251
- import { join } from "node:path";
252
-
253
- // Path to where you cloned pome-sh/pome-twins on disk
254
- const POME_REPO = process.env.POME_REPO ?? "/path/to/pome-twins";
255
253
 
256
- const twin = spawn("npm", ["run", "dev"], {
257
- cwd: join(POME_REPO, "packages/twin-stripe"),
254
+ const twin = spawn("npx", ["@pome-sh/cli", "twin", "start", "stripe"], {
258
255
  env: { ...process.env, PORT: "3333", STRIPE_CLONE_DB: ":memory:" },
259
256
  });
260
257
  // wait for /healthz before running your suite
@@ -0,0 +1,186 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ //
3
+ // fidelity:parity — declarative parity scenario for twin-stripe (F-730).
4
+ // The runner lives in @pome-sh/sdk/parity; this file is scenario data only:
5
+ // the crypto-deposit money chain (create PI → confirm → settle → charge →
6
+ // refund → ledger → events), a second PI for the cancel path, the
7
+ // customer-management chain (F-732: customer CRUD + card-on-file
8
+ // attach/detach), and the card collect-payment chain (F-731: card PI →
9
+ // update-with-PM → confirm → succeeded), covering every MCP tool in
10
+ // fidelity.inventory.json. The refund steps assert the F-733 semantics:
11
+ // the ledger link on the refund body and the post-refund available
12
+ // balance. The loud-501 probe pins the
13
+ // Stripe-shaped unsupported envelope on /v1/checkout/sessions (it moved
14
+ // off /v1/customers when F-732 made customers a supported surface).
15
+ import { join } from "node:path";
16
+ import { loadFidelityInventory, runParityCli } from "@pome-sh/sdk/parity";
17
+ import { createTwinStripeApp } from "../src/twin.js";
18
+ import { listTools } from "../src/tools.js";
19
+ const createPi = {
20
+ amount: 20000,
21
+ currency: "usd",
22
+ payment_method_types: ["crypto"],
23
+ payment_method_options: { crypto: { mode: "deposit", deposit_options: { networks: ["base"] } } },
24
+ };
25
+ const steps = [
26
+ {
27
+ tool: "create_payment_intent",
28
+ arguments: createPi,
29
+ capture: (body, state) => {
30
+ state.pi = body.id;
31
+ },
32
+ },
33
+ { tool: "retrieve_payment_intent", arguments: (state) => ({ id: state.pi }) },
34
+ { tool: "confirm_payment_intent", arguments: (state) => ({ id: state.pi }) },
35
+ {
36
+ tool: "simulate_crypto_deposit",
37
+ arguments: (state) => ({ id: state.pi }),
38
+ capture: (body, state) => {
39
+ state.charge = body.latest_charge;
40
+ },
41
+ },
42
+ { tool: "list_payment_intents", arguments: { limit: 10 } },
43
+ { tool: "retrieve_charge", arguments: (state) => ({ id: state.charge }) },
44
+ { tool: "list_charges", arguments: (state) => ({ payment_intent: state.pi }) },
45
+ {
46
+ tool: "create_refund",
47
+ arguments: (state) => ({ charge: state.charge, amount: 7500 }),
48
+ capture: (body, state) => {
49
+ state.refund = body.id;
50
+ },
51
+ verify: (body) => typeof body.balance_transaction === "string"
52
+ ? undefined
53
+ : "a refund should link its negative refund-type balance transaction (F-733)",
54
+ },
55
+ { tool: "retrieve_refund", arguments: (state) => ({ id: state.refund }) },
56
+ { tool: "list_refunds", arguments: (state) => ({ charge: state.charge }) },
57
+ {
58
+ tool: "retrieve_balance",
59
+ verify: (body) => {
60
+ const usd = body.available?.find((b) => b.currency === "usd");
61
+ // 20000 settled minus the 7500 refund above.
62
+ return usd?.amount === 12500
63
+ ? undefined
64
+ : `available balance should reflect the refund (expected 12500, got ${usd?.amount})`;
65
+ },
66
+ },
67
+ {
68
+ tool: "list_balance_transactions",
69
+ arguments: { limit: 10 },
70
+ verify: (body) => {
71
+ const data = body.data ?? [];
72
+ return data.some((t) => t.type === "refund" && t.amount === -7500)
73
+ ? undefined
74
+ : "the ledger should carry the negative refund-type entry (F-733)";
75
+ },
76
+ },
77
+ {
78
+ tool: "list_events",
79
+ arguments: { limit: 10 },
80
+ capture: (body, state) => {
81
+ state.event = body.data?.[0]?.id;
82
+ },
83
+ },
84
+ { tool: "retrieve_event", arguments: (state) => ({ id: state.event }) },
85
+ // Second PI: the cancel path (a settled PI refuses cancellation)
86
+ {
87
+ tool: "create_payment_intent",
88
+ arguments: createPi,
89
+ capture: (body, state) => {
90
+ state.pi2 = body.id;
91
+ },
92
+ },
93
+ { tool: "cancel_payment_intent", arguments: (state) => ({ id: state.pi2 }) },
94
+ // Customer-management chain (F-732): CRUD + card-on-file attach/detach.
95
+ {
96
+ tool: "create_customer",
97
+ arguments: { name: "Parity Customer", email: "parity@example.com", metadata: { a: "1" } },
98
+ capture: (body, state) => {
99
+ state.customer = body.id;
100
+ },
101
+ },
102
+ { tool: "retrieve_customer", arguments: (state) => ({ id: state.customer }) },
103
+ {
104
+ tool: "update_customer",
105
+ arguments: (state) => ({ id: state.customer, name: "Parity Customer II", metadata: { a: "", b: "2" } }),
106
+ verify: (body) => {
107
+ const metadata = body.metadata ?? {};
108
+ if (metadata.a !== undefined)
109
+ return "metadata key 'a' should have been unset by the empty value";
110
+ if (metadata.b !== "2")
111
+ return "metadata key 'b' should have been merged in";
112
+ return undefined;
113
+ },
114
+ },
115
+ { tool: "list_customers", arguments: { limit: 10 } },
116
+ {
117
+ tool: "create_payment_method",
118
+ arguments: { type: "card", card: { number: "4242424242424242", exp_month: 12, exp_year: 2032 } },
119
+ capture: (body, state) => {
120
+ state.pm = body.id;
121
+ },
122
+ },
123
+ { tool: "retrieve_payment_method", arguments: (state) => ({ id: state.pm }) },
124
+ {
125
+ tool: "attach_payment_method",
126
+ arguments: (state) => ({ id: state.pm, customer: state.customer }),
127
+ verify: (body) => body.customer ? undefined : "attach should set customer",
128
+ },
129
+ {
130
+ tool: "list_customer_payment_methods",
131
+ arguments: (state) => ({ customer: state.customer }),
132
+ verify: (body) => (body.data?.length ?? 0) === 1
133
+ ? undefined
134
+ : "customer should list exactly the attached PM",
135
+ },
136
+ {
137
+ tool: "detach_payment_method",
138
+ arguments: (state) => ({ id: state.pm }),
139
+ verify: (body) => body.customer === null ? undefined : "detach should clear customer",
140
+ },
141
+ { tool: "delete_customer", arguments: (state) => ({ id: state.customer }) },
142
+ // Card collect-payment chain (F-731): create bare card PI → attach a PM
143
+ // via update (the ruled retry step) → confirm → synchronous settle.
144
+ {
145
+ tool: "create_payment_intent",
146
+ arguments: { amount: 12000, currency: "usd", payment_method_types: ["card"] },
147
+ capture: (body, state) => {
148
+ state.cardPi = body.id;
149
+ },
150
+ verify: (body) => body.status === "requires_payment_method"
151
+ ? undefined
152
+ : "a card PI without a PM should start in requires_payment_method",
153
+ },
154
+ {
155
+ tool: "create_payment_method",
156
+ arguments: { type: "card", card: { number: "4242424242424242", exp_month: 12, exp_year: 2033 } },
157
+ capture: (body, state) => {
158
+ state.cardPm = body.id;
159
+ },
160
+ },
161
+ {
162
+ tool: "update_payment_intent",
163
+ arguments: (state) => ({ id: state.cardPi, payment_method: state.cardPm }),
164
+ verify: (body) => body.status === "requires_confirmation"
165
+ ? undefined
166
+ : "attaching a PM should move the card PI to requires_confirmation",
167
+ },
168
+ {
169
+ tool: "confirm_payment_intent",
170
+ arguments: (state) => ({ id: state.cardPi }),
171
+ verify: (body) => body.status === "succeeded"
172
+ ? undefined
173
+ : "confirming a good card should settle synchronously",
174
+ },
175
+ ];
176
+ await runParityCli({
177
+ app: createTwinStripeApp(),
178
+ twin: "stripe",
179
+ inventory: loadFidelityInventory(join(import.meta.dirname, "..", "fidelity.inventory.json")),
180
+ liveToolNames: listTools().map((tool) => tool.name),
181
+ steps,
182
+ restProbes: [
183
+ { surface: "unsupported-rest", path: "/v1/checkout/sessions", status: 501, expectUnsupportedEnvelope: true },
184
+ ],
185
+ });
186
+ //# sourceMappingURL=fidelity-parity.js.map