skilldrop-cli 0.16.44 → 0.16.46

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 (255) hide show
  1. package/catalogue.json +1 -0
  2. package/model-routing.json +1 -0
  3. package/package.json +1 -1
  4. package/packs/converters/skills/md-to-html/manifest.json +1 -1
  5. package/packs/converters/skills/md-to-html/scripts/md_to_html.py +3 -0
  6. package/packs/design/skills/brand-kit/manifest.json +1 -1
  7. package/packs/design/skills/brand-kit/scripts/check_brand.py +11 -1
  8. package/packs/dev-team/skills/behaviour-equivalence/manifest.json +1 -1
  9. package/packs/dev-team/skills/behaviour-equivalence/scripts/golden_diff.py +11 -1
  10. package/packs/frontend/skills/bundle-size-review/manifest.json +1 -1
  11. package/packs/frontend/skills/bundle-size-review/scripts/bundle_stats.py +13 -1
  12. package/packs/frontend/skills/web-performance-review/manifest.json +1 -1
  13. package/packs/frontend/skills/web-performance-review/scripts/lh_summary.py +12 -2
  14. package/packs/grc/skills/risk-register/manifest.json +1 -1
  15. package/packs/grc/skills/risk-register/scripts/check_register.py +9 -1
  16. package/packs/infra-as-code/skills/terraform-plan-review/manifest.json +1 -1
  17. package/packs/infra-as-code/skills/terraform-plan-review/scripts/plan_summary.py +12 -2
  18. package/packs/product-manager/skills/feedback-synthesis/manifest.json +1 -1
  19. package/packs/product-manager/skills/feedback-synthesis/scripts/theme_counts.py +6 -1
  20. package/packs/research/skills/hypothesis-comparison/manifest.json +1 -1
  21. package/packs/research/skills/hypothesis-comparison/scripts/ach_matrix.py +10 -2
  22. package/packs/solution-architect/skills/context-graph/SKILL.md +119 -0
  23. package/packs/solution-architect/skills/context-graph/evals/eval_queries.json +11 -0
  24. package/packs/solution-architect/skills/context-graph/evals/evals.json +225 -0
  25. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0001-record-architecture-decisions.md +19 -0
  26. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0002-postgres-as-primary-database.md +16 -0
  27. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0003-use-redis-for-session-storage.md +24 -0
  28. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0004-structured-json-logging.md +15 -0
  29. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0005-session-lifetime-eight-hours.md +22 -0
  30. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0006-move-sessions-to-postgres.md +16 -0
  31. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0007-stateless-signed-session-cookies.md +35 -0
  32. package/packs/solution-architect/skills/context-graph/evals/files/1/services/api/__init__.py +0 -0
  33. package/packs/solution-architect/skills/context-graph/evals/files/1/services/api/db.py +0 -0
  34. package/packs/solution-architect/skills/context-graph/evals/files/1/services/api/logging_setup.py +0 -0
  35. package/packs/solution-architect/skills/context-graph/evals/files/1/services/auth/__init__.py +0 -0
  36. package/packs/solution-architect/skills/context-graph/evals/files/1/services/auth/cookie_sessions.py +7 -0
  37. package/packs/solution-architect/skills/context-graph/evals/files/1/services/auth/redis_sessions.py +7 -0
  38. package/packs/solution-architect/skills/context-graph/evals/files/10/README.md +8 -0
  39. package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0001-record-architecture-decisions.md +10 -0
  40. package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0004-service-auth-hmac-shared-keys.md +21 -0
  41. package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0007-secrets-from-vault-agent.md +19 -0
  42. package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0011-service-auth-mtls.md +23 -0
  43. package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/app.py +16 -0
  44. package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/auth/__init__.py +4 -0
  45. package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/auth/hmac_verify.py +31 -0
  46. package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/config/settings.py +14 -0
  47. package/packs/solution-architect/skills/context-graph/evals/files/10/services/ledger-worker/auth/__init__.py +4 -0
  48. package/packs/solution-architect/skills/context-graph/evals/files/10/services/ledger-worker/auth/mtls.py +18 -0
  49. package/packs/solution-architect/skills/context-graph/evals/files/11/README.md +4 -0
  50. package/packs/solution-architect/skills/context-graph/evals/files/11/app/models/base.py +3 -0
  51. package/packs/solution-architect/skills/context-graph/evals/files/11/app/models/line_item.py +14 -0
  52. package/packs/solution-architect/skills/context-graph/evals/files/11/app/models/order.py +24 -0
  53. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-003-money-as-minor-units.md +10 -0
  54. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-005-orders-typed-columns-only.md +10 -0
  55. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-009-line-items-immutable.md +11 -0
  56. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-014-optional-order-attributes-json.md +16 -0
  57. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-016-order-attributes-table.md +11 -0
  58. package/packs/solution-architect/skills/context-graph/evals/files/11/migrations/0007_create_orders.sql +11 -0
  59. package/packs/solution-architect/skills/context-graph/evals/files/11/migrations/0012_add_order_attributes.sql +2 -0
  60. package/packs/solution-architect/skills/context-graph/evals/files/12/README.md +8 -0
  61. package/packs/solution-architect/skills/context-graph/evals/files/12/config/delivery.yaml +4 -0
  62. package/packs/solution-architect/skills/context-graph/evals/files/12/config/export.yaml +2 -0
  63. package/packs/solution-architect/skills/context-graph/evals/files/12/config/partners.yaml +10 -0
  64. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0001-record-architecture-decisions.md +10 -0
  65. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0002-postgres-delivery-log.md +15 -0
  66. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0003-redis-idempotency-keys.md +15 -0
  67. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0004-retry-policy.md +16 -0
  68. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0005-hmac-signed-payloads.md +10 -0
  69. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0006-postgres-idempotency.md +15 -0
  70. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0007-sftp-batch-export.md +12 -0
  71. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0008-partner-config-in-yaml.md +12 -0
  72. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0009-partner-config-admin-api.md +13 -0
  73. package/packs/solution-architect/skills/context-graph/evals/files/12/migrations/003_idempotency_keys.sql +6 -0
  74. package/packs/solution-architect/skills/context-graph/evals/files/12/migrations/004_partners.sql +7 -0
  75. package/packs/solution-architect/skills/context-graph/evals/files/12/src/delivery/dispatcher.py +29 -0
  76. package/packs/solution-architect/skills/context-graph/evals/files/12/src/delivery/retry.py +15 -0
  77. package/packs/solution-architect/skills/context-graph/evals/files/12/src/delivery/signing.py +13 -0
  78. package/packs/solution-architect/skills/context-graph/evals/files/12/src/export/s3_export.py +24 -0
  79. package/packs/solution-architect/skills/context-graph/evals/files/12/src/idempotency/pg_store.py +11 -0
  80. package/packs/solution-architect/skills/context-graph/evals/files/12/src/idempotency/redis_store.py +8 -0
  81. package/packs/solution-architect/skills/context-graph/evals/files/12/src/partners/loader.py +15 -0
  82. package/packs/solution-architect/skills/context-graph/evals/files/12/src/store/delivery_log.py +18 -0
  83. package/packs/solution-architect/skills/context-graph/evals/files/13/README.md +3 -0
  84. package/packs/solution-architect/skills/context-graph/evals/files/13/config/cache.yaml +2 -0
  85. package/packs/solution-architect/skills/context-graph/evals/files/13/config/settings.yaml +2 -0
  86. package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-008-pricing-from-erp.md +10 -0
  87. package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-012-pricing-cache.md +23 -0
  88. package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-015-checkout-price-lock.md +15 -0
  89. package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-019-pricing-service.md +17 -0
  90. package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/catalog/views.py +8 -0
  91. package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/checkout/lock.py +14 -0
  92. package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/pricing/cache.py +22 -0
  93. package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/pricing/client.py +10 -0
  94. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0001-idempotency-keys.md +33 -0
  95. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0002-processor-retry-policy.md +26 -0
  96. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0003-money-in-minor-units.md +31 -0
  97. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0004-webhook-signing.md +27 -0
  98. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0005-retry-with-jitter.md +30 -0
  99. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0006-idempotency-at-gateway.md +28 -0
  100. package/packs/solution-architect/skills/context-graph/evals/files/14/pr-summary.md +27 -0
  101. package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/amount.ts +10 -0
  102. package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/charge.ts +28 -0
  103. package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/idempotency.ts +4 -0
  104. package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/retry.ts +21 -0
  105. package/packs/solution-architect/skills/context-graph/evals/files/14/src/webhooks/send.ts +9 -0
  106. package/packs/solution-architect/skills/context-graph/evals/files/14/src/webhooks/sign.ts +6 -0
  107. package/packs/solution-architect/skills/context-graph/evals/files/15/deploy/services.yaml +14 -0
  108. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0001-record-architecture-decisions.md +20 -0
  109. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0002-use-postgresql-for-shipment-data.md +23 -0
  110. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0003-store-vehicle-telemetry-in-cassandra.md +22 -0
  111. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0004-use-redis-for-session-storage.md +22 -0
  112. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0005-use-react-for-dispatcher-dashboard.md +19 -0
  113. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0006-archive-delivered-shipments-to-object-storage.md +23 -0
  114. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0007-move-shipment-records-to-mongodb.md +23 -0
  115. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0008-store-vehicle-telemetry-in-timescaledb.md +28 -0
  116. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0009-stateless-sessions-with-signed-cookies.md +24 -0
  117. package/packs/solution-architect/skills/context-graph/evals/files/15/services/api/session.py +17 -0
  118. package/packs/solution-architect/skills/context-graph/evals/files/15/services/shipments/db.py +30 -0
  119. package/packs/solution-architect/skills/context-graph/evals/files/15/services/shipments/migrations.sql +3 -0
  120. package/packs/solution-architect/skills/context-graph/evals/files/15/services/telemetry/store.py +23 -0
  121. package/packs/solution-architect/skills/context-graph/evals/files/15/web/dashboard/App.jsx +3 -0
  122. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0001-record-architecture-decisions.md +11 -0
  123. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0002-rabbitmq-for-background-jobs.md +15 -0
  124. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0003-thumbnail-service.md +20 -0
  125. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0004-money-as-integer-minor-units.md +17 -0
  126. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0005-worker-retries.md +12 -0
  127. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0006-fx-amounts-with-four-decimals.md +18 -0
  128. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0007-feature-flags.md +16 -0
  129. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0008-retire-legacy-search.md +14 -0
  130. package/packs/solution-architect/skills/context-graph/evals/files/2/libs/money/__init__.py +0 -0
  131. package/packs/solution-architect/skills/context-graph/evals/files/2/libs/money/amount.py +9 -0
  132. package/packs/solution-architect/skills/context-graph/evals/files/2/services/checkout/flags.py +1 -0
  133. package/packs/solution-architect/skills/context-graph/evals/files/2/services/checkout/publish.py +0 -0
  134. package/packs/solution-architect/skills/context-graph/evals/files/2/services/media/resize.py +5 -0
  135. package/packs/solution-architect/skills/context-graph/evals/files/2/services/worker/consumer.py +0 -0
  136. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0001-how-we-write-rfcs.md +9 -0
  137. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0002-payments-service-boundary.md +16 -0
  138. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0003-webhook-retries-fixed-interval.md +19 -0
  139. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0004-webhook-idempotency-keys.md +16 -0
  140. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0005-notification-retries.md +16 -0
  141. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0006-webhook-retry-backoff.md +26 -0
  142. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0007-webhooks-on-the-job-queue.md +12 -0
  143. package/packs/solution-architect/skills/context-graph/evals/files/3/services/notifications/__init__.py +0 -0
  144. package/packs/solution-architect/skills/context-graph/evals/files/3/services/notifications/retry.py +4 -0
  145. package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/__init__.py +0 -0
  146. package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks/__init__.py +0 -0
  147. package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks/retry.py +15 -0
  148. package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks/send.py +0 -0
  149. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0001-record-architecture-decisions.md +19 -0
  150. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0002-postgres-as-system-of-record.md +18 -0
  151. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0004-redis-locks-for-scheduler.md +19 -0
  152. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0007-remove-redis.md +27 -0
  153. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0009-money-as-integer-minor-units.md +19 -0
  154. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/onboarding.md +12 -0
  155. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/__init__.py +0 -0
  156. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/db/__init__.py +22 -0
  157. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/invoicing.py +9 -0
  158. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/money.py +10 -0
  159. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler/__init__.py +0 -0
  160. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler/lock.py +23 -0
  161. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler/runner.py +17 -0
  162. package/packs/solution-architect/skills/context-graph/evals/files/5/lib/types/index.ts +13 -0
  163. package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0001-service-layout.md +20 -0
  164. package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0003-ingest-retry-policy.md +26 -0
  165. package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0006-shared-retry-library.md +24 -0
  166. package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0008-outbound-http-client.md +22 -0
  167. package/packs/solution-architect/skills/context-graph/evals/files/5/services/export/client.ts +15 -0
  168. package/packs/solution-architect/skills/context-graph/evals/files/5/services/export/retry.ts +12 -0
  169. package/packs/solution-architect/skills/context-graph/evals/files/5/services/ingest/client.ts +14 -0
  170. package/packs/solution-architect/skills/context-graph/evals/files/5/services/ingest/retry.ts +20 -0
  171. package/packs/solution-architect/skills/context-graph/evals/files/6/README.md +4 -0
  172. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0001-monorepo-layout.md +10 -0
  173. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0002-billing-on-postgres.md +13 -0
  174. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0004-ledger-sync-nightly-batch.md +9 -0
  175. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0003-invoice-ids.md +9 -0
  176. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0007-invoice-ids-ulid.md +11 -0
  177. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0009-billing-event-store.md +15 -0
  178. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0010-revenue-service.md +13 -0
  179. package/packs/solution-architect/skills/context-graph/evals/files/6/libs/money/ulid.py +8 -0
  180. package/packs/solution-architect/skills/context-graph/evals/files/6/services/billing/src/events.py +10 -0
  181. package/packs/solution-architect/skills/context-graph/evals/files/6/services/billing/src/store.py +10 -0
  182. package/packs/solution-architect/skills/context-graph/evals/files/6/services/invoicing/ids/generator.py +7 -0
  183. package/packs/solution-architect/skills/context-graph/evals/files/6/services/ledger/README.md +4 -0
  184. package/packs/solution-architect/skills/context-graph/evals/files/6/services/ledger/sync.py +3 -0
  185. package/packs/solution-architect/skills/context-graph/evals/files/7/README.md +4 -0
  186. package/packs/solution-architect/skills/context-graph/evals/files/7/db/queries/orders.sql +2 -0
  187. package/packs/solution-architect/skills/context-graph/evals/files/7/db/sharding/router.py +9 -0
  188. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-001-postgres-primary.md +8 -0
  189. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-002-kafka-event-bus.md +20 -0
  190. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-003-no-orm.md +9 -0
  191. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-006-tenant-sharding.md +9 -0
  192. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-011-orm-for-admin-console.md +11 -0
  193. package/packs/solution-architect/skills/context-graph/evals/files/7/pipelines/fanout/router.py +4 -0
  194. package/packs/solution-architect/skills/context-graph/evals/files/7/pipelines/ingest/consumer.py +5 -0
  195. package/packs/solution-architect/skills/context-graph/evals/files/7/pipelines/ingest/topics.yaml +8 -0
  196. package/packs/solution-architect/skills/context-graph/evals/files/7/rfcs/0004-region-sharding.md +15 -0
  197. package/packs/solution-architect/skills/context-graph/evals/files/7/services/admin-console/models.py +11 -0
  198. package/packs/solution-architect/skills/context-graph/evals/files/7/services/orders/repo.py +9 -0
  199. package/packs/solution-architect/skills/context-graph/evals/files/8/README.md +11 -0
  200. package/packs/solution-architect/skills/context-graph/evals/files/8/api/ledger.proto +30 -0
  201. package/packs/solution-architect/skills/context-graph/evals/files/8/config/http.yaml +10 -0
  202. package/packs/solution-architect/skills/context-graph/evals/files/8/config/messaging.yaml +8 -0
  203. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0001-record-architecture-decisions.md +20 -0
  204. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0002-postgresql-for-ledger.md +22 -0
  205. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0003-rabbitmq-domain-events.md +22 -0
  206. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0004-integer-minor-units.md +32 -0
  207. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0005-provider-http-retries.md +26 -0
  208. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0006-openapi-generated-clients.md +20 -0
  209. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0007-kafka-domain-events.md +25 -0
  210. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0008-structured-logging.md +18 -0
  211. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/rfcs/RFC-012-idempotency-keys.md +19 -0
  212. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/api/idempotency.py +19 -0
  213. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/api/server.py +35 -0
  214. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/clients/provider.py +33 -0
  215. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/db/migrations/0001_init.sql +14 -0
  216. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/db/migrations/0008_idempotency_keys.sql +5 -0
  217. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/db/migrations/0009_fx_entries.sql +4 -0
  218. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/events/publisher.py +28 -0
  219. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/logging.py +25 -0
  220. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/models/entry.py +16 -0
  221. package/packs/solution-architect/skills/context-graph/evals/files/9/.env.example +3 -0
  222. package/packs/solution-architect/skills/context-graph/evals/files/9/README.md +5 -0
  223. package/packs/solution-architect/skills/context-graph/evals/files/9/docker-compose.yml +18 -0
  224. package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/001-session-storage.md +21 -0
  225. package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/002-api-rate-limiting.md +32 -0
  226. package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/003-jwt-sessions.md +29 -0
  227. package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/004-catalog-cache.md +19 -0
  228. package/packs/solution-architect/skills/context-graph/evals/files/9/src/catalog/cache.ts +13 -0
  229. package/packs/solution-architect/skills/context-graph/evals/files/9/src/catalog/repository.ts +13 -0
  230. package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/email.ts +3 -0
  231. package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/export.ts +3 -0
  232. package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/queue.ts +10 -0
  233. package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/worker.ts +8 -0
  234. package/packs/solution-architect/skills/context-graph/evals/files/9/src/lib/db.ts +10 -0
  235. package/packs/solution-architect/skills/context-graph/evals/files/9/src/lib/redis.ts +8 -0
  236. package/packs/solution-architect/skills/context-graph/evals/files/9/src/middleware/rateLimit.ts +26 -0
  237. package/packs/solution-architect/skills/context-graph/evals/files/9/src/server.ts +17 -0
  238. package/packs/solution-architect/skills/context-graph/evals/files/9/src/session/store.ts +10 -0
  239. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/docs/adr/0004-kafka-for-order-events.md +19 -0
  240. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/docs/adr/0006-email-receipts.md +7 -0
  241. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/docs/adr/0009-sqs-for-order-events.md +19 -0
  242. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/services/notifications/receipts.py +0 -0
  243. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/services/orders/publisher.py +0 -0
  244. package/packs/solution-architect/skills/context-graph/examples/order-events.md +63 -0
  245. package/packs/solution-architect/skills/context-graph/manifest.json +33 -0
  246. package/packs/solution-architect/skills/context-graph/reference.md +104 -0
  247. package/packs/solution-architect/skills/context-graph/scripts/context_graph.py +634 -0
  248. package/packs/solution-architect/skills/event-contract-draft/manifest.json +1 -1
  249. package/packs/solution-architect/skills/event-contract-draft/scripts/check_asyncapi.py +14 -2
  250. package/packs/sre-oncall/skills/cloud-cost-review/manifest.json +1 -1
  251. package/packs/sre-oncall/skills/cloud-cost-review/scripts/cost_summary.py +2 -0
  252. package/packs/trackers/skills/backlog-triage/manifest.json +1 -1
  253. package/packs/trackers/skills/backlog-triage/scripts/triage_backlog.py +4 -1
  254. package/packs/trackers/skills/team-status-report/manifest.json +1 -1
  255. package/packs/trackers/skills/team-status-report/scripts/status_counts.py +4 -1
@@ -0,0 +1,20 @@
1
+ // Ingest retry policy — RFC-0003. Do not change to a fixed interval (see INC-114).
2
+ const BASE_MS = 200;
3
+ const CAP_MS = 30_000;
4
+ const MAX_ATTEMPTS = 6;
5
+
6
+ export async function withRetry<T>(fn: () => Promise<T>): Promise<T> {
7
+ let attempt = 0;
8
+ for (;;) {
9
+ try {
10
+ return await fn();
11
+ } catch (err) {
12
+ attempt += 1;
13
+ if (attempt >= MAX_ATTEMPTS) throw err;
14
+ const ceiling = Math.min(CAP_MS, BASE_MS * 2 ** attempt);
15
+ await sleep(Math.random() * ceiling); // full jitter
16
+ }
17
+ }
18
+ }
19
+
20
+ const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
@@ -0,0 +1,4 @@
1
+ # harbourline
2
+
3
+ Freight billing and invoicing platform. Monorepo: `services/` for deployables, `libs/` for shared code.
4
+ Decision records live in `docs/adr/` (architecture decision records) and `docs/rfcs/` (larger proposals).
@@ -0,0 +1,10 @@
1
+ # ADR-0001: Monorepo layout
2
+
3
+ - Status: Accepted
4
+ - Date: 2023-02-10
5
+ - Deciders: Platform team (H. Okafor, L. Brandt)
6
+ - Governs: `services/`, `libs/`
7
+
8
+ ## Decision
9
+ One repository. Each deployable service gets its own folder under `services/<name>/`; shared code goes
10
+ under `libs/`. A service folder is never shared by two deployables.
@@ -0,0 +1,13 @@
1
+ # ADR-0002: Billing data lives in Postgres
2
+
3
+ - Status: Accepted
4
+ - Date: 2023-05-03
5
+ - Deciders: H. Okafor, M. Szabo
6
+ - Governs: `services/billing/`
7
+
8
+ ## Decision
9
+ The billing service stores charges and the invoice ledger in the shared Postgres cluster
10
+ (table `invoices_ledger`). Writes are transactional updates in place.
11
+
12
+ ## Consequences
13
+ Reporting can join billing tables directly. Corrections overwrite the row and keep no history.
@@ -0,0 +1,9 @@
1
+ # ADR-0004: Ledger sync runs as a nightly batch
2
+
3
+ - Status: Accepted
4
+ - Date: 2023-09-12
5
+ - Deciders: L. Brandt
6
+ - Governs: `services/ledger-sync/`
7
+
8
+ ## Decision
9
+ Ledger sync to the finance system runs once a night at 02:00 UTC as a batch job, not as a stream.
@@ -0,0 +1,9 @@
1
+ # RFC-0003: Invoice identifiers
2
+
3
+ - Status: Accepted
4
+ - Date: 2023-06-20
5
+ - Author: M. Szabo
6
+ - Governs: `services/invoicing/ids/`
7
+
8
+ ## Proposal
9
+ Invoice IDs are sequential integers issued by a Postgres sequence, formatted `INV-000123`.
@@ -0,0 +1,11 @@
1
+ # RFC-0007: Switch invoice identifiers to ULIDs
2
+
3
+ - Status: Accepted
4
+ - Date: 2024-03-01
5
+ - Author: R. Achebe
6
+ - Supersedes: RFC-0003
7
+ - Governs: `services/invoicing/ids/`
8
+
9
+ ## Proposal
10
+ Sequential IDs leaked customer invoice volumes and forced a single writer. Invoice IDs become ULIDs,
11
+ generated in-process, formatted `INV-<ulid>`. Existing `INV-000123` IDs stay valid.
@@ -0,0 +1,15 @@
1
+ # RFC-0009: Billing writes go to an append-only event store
2
+
3
+ - Status: Accepted
4
+ - Date: 2024-08-14
5
+ - Author: R. Achebe
6
+ - Governs: `services/billing/`
7
+ - Builds on: RFC-0012 (event schema registry)
8
+
9
+ ## Proposal
10
+ Billing records every charge and correction as an immutable event in the DynamoDB table
11
+ `billing-events`. Current balances are projections of the event stream. This gives auditors a full
12
+ history of corrections.
13
+
14
+ ## Rollout
15
+ Phase 1: write events alongside the existing store. Phase 2: read balances from projections.
@@ -0,0 +1,13 @@
1
+ # RFC-0010: Merge billing and invoicing into a revenue service
2
+
3
+ - Status: Proposed
4
+ - Date: 2026-09-30
5
+ - Author: L. Brandt
6
+ - Governs: `services/revenue/` (new)
7
+
8
+ ## Proposal
9
+ Move `services/billing/` and `services/invoicing/` into a single deployable at `services/revenue/`,
10
+ with `billing/` and `invoicing/` as internal modules. Both old folders are deleted after the move.
11
+
12
+ ## Records affected
13
+ - ADR-0002 (billing storage) — path changes to `services/revenue/billing/`.
@@ -0,0 +1,8 @@
1
+ """Minimal ULID helper (placeholder implementation for the fixture)."""
2
+
3
+ import os
4
+ import time
5
+
6
+
7
+ def new_ulid():
8
+ return f"{int(time.time() * 1000):012x}{os.urandom(10).hex()}"
@@ -0,0 +1,10 @@
1
+ """Phase 1 of the event store rollout: append every charge as an event."""
2
+
3
+ EVENTS_TABLE = "billing-events"
4
+
5
+
6
+ def append_charge_event(client, invoice_id, amount_minor, at):
7
+ client.put_item(
8
+ TableName=EVENTS_TABLE,
9
+ Item={"invoice_id": invoice_id, "type": "charge", "amount_minor": amount_minor, "at": at},
10
+ )
@@ -0,0 +1,10 @@
1
+ """Billing persistence: in-place updates to the Postgres invoice ledger."""
2
+
3
+ LEDGER_TABLE = "invoices_ledger"
4
+
5
+
6
+ def record_charge(conn, invoice_id, amount_minor):
7
+ conn.execute(
8
+ f"UPDATE {LEDGER_TABLE} SET balance_minor = balance_minor + %s WHERE invoice_id = %s",
9
+ (amount_minor, invoice_id),
10
+ )
@@ -0,0 +1,7 @@
1
+ """Invoice ID generation."""
2
+
3
+ from libs.money.ulid import new_ulid
4
+
5
+
6
+ def new_invoice_id():
7
+ return f"INV-{new_ulid()}"
@@ -0,0 +1,4 @@
1
+ # ledger
2
+
3
+ Formerly `services/ledger-sync/` (renamed in 2025 when it gained the reconciliation report).
4
+ Still runs the nightly sync to the finance system at 02:00 UTC.
@@ -0,0 +1,3 @@
1
+ """Nightly ledger sync to the finance system."""
2
+
3
+ SCHEDULE_CRON = "0 2 * * *"
@@ -0,0 +1,4 @@
1
+ # fernwood
2
+
3
+ Multi-tenant data platform: ingest pipelines, an event bus, and the services on top.
4
+ Design decisions: `design/decisions/` (DD-nnn). Bigger proposals: `rfcs/`.
@@ -0,0 +1,2 @@
1
+ -- name: get_order
2
+ SELECT id, tenant_id, total_minor FROM orders WHERE id = %(id)s AND tenant_id = %(tenant_id)s;
@@ -0,0 +1,9 @@
1
+ """Pick the shard for a tenant (DD-006)."""
2
+
3
+ import hashlib
4
+
5
+ SHARD_COUNT = 16
6
+
7
+
8
+ def shard_for(tenant_id: str) -> int:
9
+ return int(hashlib.sha256(tenant_id.encode()).hexdigest(), 16) % SHARD_COUNT
@@ -0,0 +1,8 @@
1
+ # DD-001: Postgres is the primary datastore
2
+
3
+ Status: Accepted
4
+ Date: 2022-04-11
5
+ Deciders: O. Mensah
6
+ Governs: db/, services/
7
+
8
+ All service state lives in Postgres. No second OLTP database without a new decision.
@@ -0,0 +1,20 @@
1
+ # DD-002: Kafka is the event bus
2
+
3
+ Status: Accepted
4
+ Date: 2022-06-02
5
+ Deciders: O. Mensah, T. Lindqvist
6
+ Governs: pipelines/ingest/, pipelines/fanout/
7
+
8
+ ## Context
9
+ Ingest events must reach several independent consumers (fan-out, billing export, the audit sink),
10
+ and a consumer that is down for a deploy must be able to catch up afterwards.
11
+
12
+ ## Options considered
13
+ 1. Postgres LISTEN/NOTIFY — rejected: notifications are lost if no listener is connected at the
14
+ moment they fire, there is no replay, and payloads are capped at 8000 bytes.
15
+ 2. RabbitMQ — rejected: no long replay window without extra plugins.
16
+ 3. Kafka — chosen.
17
+
18
+ ## Decision
19
+ Use Kafka. Every topic keeps 7 days of retention so any consumer can replay a week of events.
20
+ Retention policy details: see DD-007.
@@ -0,0 +1,9 @@
1
+ # DD-003: No ORM in services
2
+
3
+ Status: Accepted
4
+ Date: 2022-07-19
5
+ Deciders: T. Lindqvist
6
+ Governs: services/
7
+
8
+ Services use hand-written SQL kept in db/queries/. No ORM: we want query plans reviewable in code
9
+ review and no lazy-loading surprises on hot paths.
@@ -0,0 +1,9 @@
1
+ # DD-006: Shard by tenant
2
+
3
+ Status: Accepted
4
+ Date: 2023-01-30
5
+ Deciders: Platform guild (O. Mensah, R. Vidal)
6
+ Governs: db/sharding/
7
+
8
+ Each tenant's data lives on exactly one shard, chosen by a hash of tenant_id. Cross-tenant queries
9
+ go through the reporting replica, never the shards.
@@ -0,0 +1,11 @@
1
+ # DD-011: Allow SQLAlchemy in the admin console
2
+
3
+ Status: Accepted
4
+ Date: 2024-05-08
5
+ Deciders: R. Vidal
6
+ Amends: DD-003
7
+ Governs: services/admin-console/
8
+
9
+ The admin console is internal, low-traffic CRUD over ~40 tables. Hand-written SQL there cost more
10
+ than it saved. SQLAlchemy is allowed in services/admin-console/ only. Every other service keeps
11
+ DD-003's no-ORM rule.
@@ -0,0 +1,4 @@
1
+ """Fans ingest.normalised out to downstream consumers."""
2
+
3
+ GROUP_ID = "fanout-router"
4
+ SOURCE_TOPIC = "ingest.normalised"
@@ -0,0 +1,5 @@
1
+ """Reads ingest.raw, normalises records, publishes to ingest.normalised."""
2
+
3
+ GROUP_ID = "ingest-normaliser"
4
+ SOURCE_TOPIC = "ingest.raw"
5
+ SINK_TOPIC = "ingest.normalised"
@@ -0,0 +1,8 @@
1
+ # Kafka topic config for ingest
2
+ topics:
3
+ - name: ingest.raw
4
+ partitions: 12
5
+ retention.ms: 259200000
6
+ - name: ingest.normalised
7
+ partitions: 12
8
+ retention.ms: 259200000
@@ -0,0 +1,15 @@
1
+ # RFC 0004: Shard by region instead of tenant
2
+
3
+ Status: Withdrawn
4
+ Date: 2025-02-14
5
+ Author: P. Tamboli
6
+ Supersedes: DD-006
7
+ Governs: db/sharding/
8
+
9
+ ## Proposal
10
+ Move from tenant sharding to region sharding (eu, us, apac) so data-residency rules map to shards.
11
+
12
+ ## Withdrawal note (2025-03-20)
13
+ Withdrawn after the cost review: re-sharding every tenant was estimated at two quarters of work and
14
+ residency can be met by pinning tenants to regional shards under the existing scheme. Tenant
15
+ sharding (DD-006) stays.
@@ -0,0 +1,11 @@
1
+ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
2
+
3
+
4
+ class Base(DeclarativeBase):
5
+ pass
6
+
7
+
8
+ class Tenant(Base):
9
+ __tablename__ = "tenants"
10
+ id: Mapped[int] = mapped_column(primary_key=True)
11
+ name: Mapped[str]
@@ -0,0 +1,9 @@
1
+ """Orders persistence. SQL lives in db/queries/orders.sql."""
2
+
3
+ from pathlib import Path
4
+
5
+ QUERIES = Path(__file__).resolve().parents[2] / "db" / "queries" / "orders.sql"
6
+
7
+
8
+ def load_queries():
9
+ return QUERIES.read_text()
@@ -0,0 +1,11 @@
1
+ # harbor-ledger
2
+
3
+ Double-entry ledger service for the Harbor payments platform.
4
+
5
+ - `services/ledger/` — the ledger service (Python)
6
+ - `api/` — service interface definitions
7
+ - `config/` — runtime configuration
8
+ - `docs/adr/` — architecture decision records
9
+ - `docs/rfcs/` — proposals under discussion
10
+
11
+ `services/ledger/api/gen/` is generated from `api/ledger.proto` at build time and is not checked in.
@@ -0,0 +1,30 @@
1
+ syntax = "proto3";
2
+
3
+ package harbor.ledger.v1;
4
+
5
+ // Public interface of the ledger service. Client stubs are generated from this file.
6
+ service Ledger {
7
+ rpc PostEntry(PostEntryRequest) returns (PostEntryResponse);
8
+ rpc GetBalance(GetBalanceRequest) returns (Balance);
9
+ }
10
+
11
+ message PostEntryRequest {
12
+ string idempotency_key = 1;
13
+ string account_id = 2;
14
+ int64 amount_minor = 3;
15
+ string currency = 4;
16
+ }
17
+
18
+ message PostEntryResponse {
19
+ string entry_id = 1;
20
+ }
21
+
22
+ message GetBalanceRequest {
23
+ string account_id = 1;
24
+ }
25
+
26
+ message Balance {
27
+ string account_id = 1;
28
+ int64 balance_minor = 2;
29
+ string currency = 3;
30
+ }
@@ -0,0 +1,10 @@
1
+ # Outbound HTTP settings for the payment-provider client
2
+ provider:
3
+ base_url: https://provider.example.invalid/v2
4
+ timeout_seconds: 30
5
+ max_retries: 5
6
+ backoff:
7
+ base_ms: 200
8
+ jitter: full
9
+ retry_methods: [GET, POST]
10
+ api_key: REPLACE_ME
@@ -0,0 +1,8 @@
1
+ # Domain event publishing
2
+ broker: kafka
3
+ bootstrap_servers:
4
+ - kafka-0.harbor.internal:9092
5
+ - kafka-1.harbor.internal:9092
6
+ topic: ledger.entry-events
7
+ key: account_id
8
+ acks: all
@@ -0,0 +1,20 @@
1
+ # 1. Record architecture decisions
2
+
3
+ Date: 2024-01-10
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ We need to record the architectural decisions made on this project.
12
+
13
+ ## Decision
14
+
15
+ We will use Architecture Decision Records, as described by Michael Nygard, kept in `docs/adr/`.
16
+ Larger proposals that need discussion first go in `docs/rfcs/` and become an ADR once accepted.
17
+
18
+ ## Consequences
19
+
20
+ See Michael Nygard's article for a detailed description of the process.
@@ -0,0 +1,22 @@
1
+ # 2. Use PostgreSQL for ledger storage
2
+
3
+ Date: 2024-01-22
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ The ledger needs transactional writes across journal entries and account balances, and the
12
+ team already operates PostgreSQL for two other services.
13
+
14
+ ## Decision
15
+
16
+ Ledger state lives in PostgreSQL. Schema changes are plain SQL migrations under
17
+ `services/ledger/db/migrations/`, numbered sequentially and never edited once merged.
18
+
19
+ ## Consequences
20
+
21
+ - Balances are computed inside a transaction with the entries that change them.
22
+ - No ORM-generated migrations.
@@ -0,0 +1,22 @@
1
+ # 3. Publish domain events over RabbitMQ
2
+
3
+ Date: 2024-02-14
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ Downstream services (notifications, reporting) need to react when entries are posted.
12
+
13
+ ## Decision
14
+
15
+ The ledger publishes `EntryPosted` and `AccountFrozen` events to a RabbitMQ topic exchange
16
+ named `ledger.events`. Publishing code lives in `services/ledger/events/`. Broker settings
17
+ are in `config/messaging.yaml`.
18
+
19
+ ## Consequences
20
+
21
+ - Consumers bind their own queues; the ledger does not know who listens.
22
+ - Events are at-least-once; consumers must be idempotent.
@@ -0,0 +1,32 @@
1
+ ---
2
+ id: ADR-0004
3
+ title: Store money as integer minor units
4
+ status: accepted
5
+ date: 2024-03-05
6
+ deciders: [m.okafor, j.lindqvist]
7
+ ---
8
+
9
+ # Store money as integer minor units
10
+
11
+ ## Context and Problem Statement
12
+
13
+ Floating point and arbitrary-precision decimals have both caused rounding bugs on previous
14
+ projects. How should monetary amounts be represented in the ledger?
15
+
16
+ ## Considered Options
17
+
18
+ * `NUMERIC` columns with Python `Decimal`
19
+ * Integer minor units (cents, pence) with a separate ISO 4217 currency code
20
+
21
+ ## Decision Outcome
22
+
23
+ Chosen option: "Integer minor units", because sums are exact and every currency we support
24
+ has a fixed minor-unit exponent.
25
+
26
+ Every amount column in `services/ledger/db/migrations/` is `BIGINT` named `*_minor`, paired
27
+ with a `currency CHAR(3)` column. `services/ledger/models/entry.py` exposes amounts as `int`.
28
+
29
+ ### Consequences
30
+
31
+ * Good, because addition is exact and fast.
32
+ * Bad, because display code must apply the currency exponent.
@@ -0,0 +1,26 @@
1
+ # ADR 0005: Retry and timeout policy for payment-provider calls
2
+
3
+ * Status: Accepted
4
+ * Date: 2024-04-18
5
+
6
+ ## Context
7
+
8
+ The payment provider occasionally returns 502/503 during their deploys. Unbounded retries
9
+ during an outage amplified load on them last year and held our worker threads.
10
+
11
+ ## Decision
12
+
13
+ Calls from `services/ledger/clients/provider.py` to the provider:
14
+
15
+ | Setting | Value |
16
+ |--------------------|-----------------------------------------|
17
+ | Request timeout | 5 seconds |
18
+ | Max retries | 3 |
19
+ | Backoff | exponential, 200 ms base, full jitter |
20
+ | Retry on | GET and idempotent POST (with key) only |
21
+
22
+ Values are read from `config/http.yaml`; the code must not hard-code them.
23
+
24
+ ## Consequences
25
+
26
+ Worst-case latency of a provider call is bounded at roughly 21 seconds.
@@ -0,0 +1,20 @@
1
+ # 6. Generate service clients from an OpenAPI spec
2
+
3
+ Date: 2024-06-03
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ Three internal teams call the ledger and each hand-wrote a client.
12
+
13
+ ## Decision
14
+
15
+ The ledger's public interface is defined in `api/openapi.yaml`. Clients are generated from it
16
+ into `clients/generated/` on every release; hand-written clients are not accepted.
17
+
18
+ ## Consequences
19
+
20
+ - The spec is the source of truth; the server is checked against it in CI.
@@ -0,0 +1,25 @@
1
+ ---
2
+ id: ADR-0007
3
+ title: Move domain events to Kafka
4
+ status: accepted
5
+ date: 2025-03-11
6
+ supersedes: ADR-0003
7
+ ---
8
+
9
+ # Move domain events to Kafka
10
+
11
+ ## Context and Problem Statement
12
+
13
+ Reporting now needs to replay the full history of posted entries, which RabbitMQ queues
14
+ cannot give us once a message is acknowledged.
15
+
16
+ ## Decision Outcome
17
+
18
+ Domain events are published to the Kafka topic `ledger.entry-events`, keyed by account id,
19
+ with 30-day retention. This supersedes ADR-0003. Publishing stays in
20
+ `services/ledger/events/`; broker settings stay in `config/messaging.yaml`.
21
+
22
+ ### Consequences
23
+
24
+ * Good, because consumers can replay from any offset within retention.
25
+ * Bad, because the team now operates a Kafka cluster.
@@ -0,0 +1,18 @@
1
+ # ADR 0008: Structured JSON logging
2
+
3
+ * Status: Accepted
4
+ * Date: 2025-05-20
5
+
6
+ ## Context
7
+
8
+ Log search across services is painful because each one logs free text differently.
9
+
10
+ ## Decision
11
+
12
+ All ledger logging goes through `services/ledger/logging.py`, which emits one JSON object per
13
+ line with `ts`, `level`, `msg`, `trace_id` and `account_id` fields. The `trace_id` comes from
14
+ the tracing setup described in ADR-0011.
15
+
16
+ ## Consequences
17
+
18
+ Plain `print` and ad-hoc `logging.basicConfig` calls are not allowed in service code.
@@ -0,0 +1,19 @@
1
+ # RFC-012: Idempotency keys for posting entries
2
+
3
+ - **State:** Draft
4
+ - **Author:** j.lindqvist
5
+ - **Opened:** 2025-08-02
6
+
7
+ ## Summary
8
+
9
+ Clients send an `Idempotency-Key` with every `PostEntry` call. The ledger stores the key and
10
+ the response for 24 hours and returns the stored response on a repeat.
11
+
12
+ ## Proposed implementation
13
+
14
+ `services/ledger/api/idempotency.py`, backed by a table `idempotency_keys` in PostgreSQL.
15
+
16
+ ## Open questions
17
+
18
+ - Is 24 hours long enough for the batch importer, which can retry after a day?
19
+ - Should a key reused with a different body be a 409 or a 422?
@@ -0,0 +1,19 @@
1
+ import json
2
+ from datetime import timedelta
3
+
4
+ KEY_TTL = timedelta(hours=24)
5
+
6
+
7
+ def lookup(conn, key: str):
8
+ row = conn.execute(
9
+ "SELECT response FROM idempotency_keys WHERE key = %s AND created_at > now() - %s",
10
+ (key, KEY_TTL),
11
+ ).fetchone()
12
+ return json.loads(row[0]) if row else None
13
+
14
+
15
+ def store(conn, key: str, response: dict) -> None:
16
+ conn.execute(
17
+ "INSERT INTO idempotency_keys (key, response) VALUES (%s, %s) ON CONFLICT DO NOTHING",
18
+ (key, json.dumps(response)),
19
+ )