skilldrop-cli 0.16.45 → 1.0.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 (230) hide show
  1. package/README.md +1 -1
  2. package/catalogue.json +1 -0
  3. package/model-routing.json +1 -0
  4. package/package.json +1 -1
  5. package/packs/solution-architect/skills/context-graph/SKILL.md +119 -0
  6. package/packs/solution-architect/skills/context-graph/evals/eval_queries.json +11 -0
  7. package/packs/solution-architect/skills/context-graph/evals/evals.json +225 -0
  8. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0001-record-architecture-decisions.md +19 -0
  9. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0002-postgres-as-primary-database.md +16 -0
  10. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0003-use-redis-for-session-storage.md +24 -0
  11. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0004-structured-json-logging.md +15 -0
  12. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0005-session-lifetime-eight-hours.md +22 -0
  13. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0006-move-sessions-to-postgres.md +16 -0
  14. package/packs/solution-architect/skills/context-graph/evals/files/1/docs/adr/0007-stateless-signed-session-cookies.md +35 -0
  15. package/packs/solution-architect/skills/context-graph/evals/files/1/services/api/__init__.py +0 -0
  16. package/packs/solution-architect/skills/context-graph/evals/files/1/services/api/db.py +0 -0
  17. package/packs/solution-architect/skills/context-graph/evals/files/1/services/api/logging_setup.py +0 -0
  18. package/packs/solution-architect/skills/context-graph/evals/files/1/services/auth/__init__.py +0 -0
  19. package/packs/solution-architect/skills/context-graph/evals/files/1/services/auth/cookie_sessions.py +7 -0
  20. package/packs/solution-architect/skills/context-graph/evals/files/1/services/auth/redis_sessions.py +7 -0
  21. package/packs/solution-architect/skills/context-graph/evals/files/10/README.md +8 -0
  22. package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0001-record-architecture-decisions.md +10 -0
  23. package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0004-service-auth-hmac-shared-keys.md +21 -0
  24. package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0007-secrets-from-vault-agent.md +19 -0
  25. package/packs/solution-architect/skills/context-graph/evals/files/10/docs/adr/0011-service-auth-mtls.md +23 -0
  26. package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/app.py +16 -0
  27. package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/auth/__init__.py +4 -0
  28. package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/auth/hmac_verify.py +31 -0
  29. package/packs/solution-architect/skills/context-graph/evals/files/10/services/billing-api/config/settings.py +14 -0
  30. package/packs/solution-architect/skills/context-graph/evals/files/10/services/ledger-worker/auth/__init__.py +4 -0
  31. package/packs/solution-architect/skills/context-graph/evals/files/10/services/ledger-worker/auth/mtls.py +18 -0
  32. package/packs/solution-architect/skills/context-graph/evals/files/11/README.md +4 -0
  33. package/packs/solution-architect/skills/context-graph/evals/files/11/app/models/base.py +3 -0
  34. package/packs/solution-architect/skills/context-graph/evals/files/11/app/models/line_item.py +14 -0
  35. package/packs/solution-architect/skills/context-graph/evals/files/11/app/models/order.py +24 -0
  36. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-003-money-as-minor-units.md +10 -0
  37. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-005-orders-typed-columns-only.md +10 -0
  38. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-009-line-items-immutable.md +11 -0
  39. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-014-optional-order-attributes-json.md +16 -0
  40. package/packs/solution-architect/skills/context-graph/evals/files/11/eng/decisions/DR-016-order-attributes-table.md +11 -0
  41. package/packs/solution-architect/skills/context-graph/evals/files/11/migrations/0007_create_orders.sql +11 -0
  42. package/packs/solution-architect/skills/context-graph/evals/files/11/migrations/0012_add_order_attributes.sql +2 -0
  43. package/packs/solution-architect/skills/context-graph/evals/files/12/README.md +8 -0
  44. package/packs/solution-architect/skills/context-graph/evals/files/12/config/delivery.yaml +4 -0
  45. package/packs/solution-architect/skills/context-graph/evals/files/12/config/export.yaml +2 -0
  46. package/packs/solution-architect/skills/context-graph/evals/files/12/config/partners.yaml +10 -0
  47. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0001-record-architecture-decisions.md +10 -0
  48. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0002-postgres-delivery-log.md +15 -0
  49. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0003-redis-idempotency-keys.md +15 -0
  50. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0004-retry-policy.md +16 -0
  51. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0005-hmac-signed-payloads.md +10 -0
  52. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0006-postgres-idempotency.md +15 -0
  53. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0007-sftp-batch-export.md +12 -0
  54. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0008-partner-config-in-yaml.md +12 -0
  55. package/packs/solution-architect/skills/context-graph/evals/files/12/docs/adr/0009-partner-config-admin-api.md +13 -0
  56. package/packs/solution-architect/skills/context-graph/evals/files/12/migrations/003_idempotency_keys.sql +6 -0
  57. package/packs/solution-architect/skills/context-graph/evals/files/12/migrations/004_partners.sql +7 -0
  58. package/packs/solution-architect/skills/context-graph/evals/files/12/src/delivery/dispatcher.py +29 -0
  59. package/packs/solution-architect/skills/context-graph/evals/files/12/src/delivery/retry.py +15 -0
  60. package/packs/solution-architect/skills/context-graph/evals/files/12/src/delivery/signing.py +13 -0
  61. package/packs/solution-architect/skills/context-graph/evals/files/12/src/export/s3_export.py +24 -0
  62. package/packs/solution-architect/skills/context-graph/evals/files/12/src/idempotency/pg_store.py +11 -0
  63. package/packs/solution-architect/skills/context-graph/evals/files/12/src/idempotency/redis_store.py +8 -0
  64. package/packs/solution-architect/skills/context-graph/evals/files/12/src/partners/loader.py +15 -0
  65. package/packs/solution-architect/skills/context-graph/evals/files/12/src/store/delivery_log.py +18 -0
  66. package/packs/solution-architect/skills/context-graph/evals/files/13/README.md +3 -0
  67. package/packs/solution-architect/skills/context-graph/evals/files/13/config/cache.yaml +2 -0
  68. package/packs/solution-architect/skills/context-graph/evals/files/13/config/settings.yaml +2 -0
  69. package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-008-pricing-from-erp.md +10 -0
  70. package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-012-pricing-cache.md +23 -0
  71. package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-015-checkout-price-lock.md +15 -0
  72. package/packs/solution-architect/skills/context-graph/evals/files/13/docs/decisions/RFC-019-pricing-service.md +17 -0
  73. package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/catalog/views.py +8 -0
  74. package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/checkout/lock.py +14 -0
  75. package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/pricing/cache.py +22 -0
  76. package/packs/solution-architect/skills/context-graph/evals/files/13/shopfront/pricing/client.py +10 -0
  77. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0001-idempotency-keys.md +33 -0
  78. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0002-processor-retry-policy.md +26 -0
  79. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0003-money-in-minor-units.md +31 -0
  80. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0004-webhook-signing.md +27 -0
  81. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0005-retry-with-jitter.md +30 -0
  82. package/packs/solution-architect/skills/context-graph/evals/files/14/docs/rfcs/0006-idempotency-at-gateway.md +28 -0
  83. package/packs/solution-architect/skills/context-graph/evals/files/14/pr-summary.md +27 -0
  84. package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/amount.ts +10 -0
  85. package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/charge.ts +28 -0
  86. package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/idempotency.ts +4 -0
  87. package/packs/solution-architect/skills/context-graph/evals/files/14/src/payments/retry.ts +21 -0
  88. package/packs/solution-architect/skills/context-graph/evals/files/14/src/webhooks/send.ts +9 -0
  89. package/packs/solution-architect/skills/context-graph/evals/files/14/src/webhooks/sign.ts +6 -0
  90. package/packs/solution-architect/skills/context-graph/evals/files/15/deploy/services.yaml +14 -0
  91. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0001-record-architecture-decisions.md +20 -0
  92. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0002-use-postgresql-for-shipment-data.md +23 -0
  93. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0003-store-vehicle-telemetry-in-cassandra.md +22 -0
  94. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0004-use-redis-for-session-storage.md +22 -0
  95. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0005-use-react-for-dispatcher-dashboard.md +19 -0
  96. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0006-archive-delivered-shipments-to-object-storage.md +23 -0
  97. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0007-move-shipment-records-to-mongodb.md +23 -0
  98. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0008-store-vehicle-telemetry-in-timescaledb.md +28 -0
  99. package/packs/solution-architect/skills/context-graph/evals/files/15/doc/adr/0009-stateless-sessions-with-signed-cookies.md +24 -0
  100. package/packs/solution-architect/skills/context-graph/evals/files/15/services/api/session.py +17 -0
  101. package/packs/solution-architect/skills/context-graph/evals/files/15/services/shipments/db.py +30 -0
  102. package/packs/solution-architect/skills/context-graph/evals/files/15/services/shipments/migrations.sql +3 -0
  103. package/packs/solution-architect/skills/context-graph/evals/files/15/services/telemetry/store.py +23 -0
  104. package/packs/solution-architect/skills/context-graph/evals/files/15/web/dashboard/App.jsx +3 -0
  105. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0001-record-architecture-decisions.md +11 -0
  106. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0002-rabbitmq-for-background-jobs.md +15 -0
  107. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0003-thumbnail-service.md +20 -0
  108. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0004-money-as-integer-minor-units.md +17 -0
  109. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0005-worker-retries.md +12 -0
  110. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0006-fx-amounts-with-four-decimals.md +18 -0
  111. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0007-feature-flags.md +16 -0
  112. package/packs/solution-architect/skills/context-graph/evals/files/2/docs/adr/0008-retire-legacy-search.md +14 -0
  113. package/packs/solution-architect/skills/context-graph/evals/files/2/libs/money/__init__.py +0 -0
  114. package/packs/solution-architect/skills/context-graph/evals/files/2/libs/money/amount.py +9 -0
  115. package/packs/solution-architect/skills/context-graph/evals/files/2/services/checkout/flags.py +1 -0
  116. package/packs/solution-architect/skills/context-graph/evals/files/2/services/checkout/publish.py +0 -0
  117. package/packs/solution-architect/skills/context-graph/evals/files/2/services/media/resize.py +5 -0
  118. package/packs/solution-architect/skills/context-graph/evals/files/2/services/worker/consumer.py +0 -0
  119. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0001-how-we-write-rfcs.md +9 -0
  120. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0002-payments-service-boundary.md +16 -0
  121. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0003-webhook-retries-fixed-interval.md +19 -0
  122. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0004-webhook-idempotency-keys.md +16 -0
  123. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0005-notification-retries.md +16 -0
  124. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0006-webhook-retry-backoff.md +26 -0
  125. package/packs/solution-architect/skills/context-graph/evals/files/3/docs/rfcs/0007-webhooks-on-the-job-queue.md +12 -0
  126. package/packs/solution-architect/skills/context-graph/evals/files/3/services/notifications/__init__.py +0 -0
  127. package/packs/solution-architect/skills/context-graph/evals/files/3/services/notifications/retry.py +4 -0
  128. package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/__init__.py +0 -0
  129. package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks/__init__.py +0 -0
  130. package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks/retry.py +15 -0
  131. package/packs/solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks/send.py +0 -0
  132. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0001-record-architecture-decisions.md +19 -0
  133. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0002-postgres-as-system-of-record.md +18 -0
  134. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0004-redis-locks-for-scheduler.md +19 -0
  135. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0007-remove-redis.md +27 -0
  136. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/adr/0009-money-as-integer-minor-units.md +19 -0
  137. package/packs/solution-architect/skills/context-graph/evals/files/4/docs/onboarding.md +12 -0
  138. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/__init__.py +0 -0
  139. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/db/__init__.py +22 -0
  140. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/invoicing.py +9 -0
  141. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/money.py +10 -0
  142. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler/__init__.py +0 -0
  143. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler/lock.py +23 -0
  144. package/packs/solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler/runner.py +17 -0
  145. package/packs/solution-architect/skills/context-graph/evals/files/5/lib/types/index.ts +13 -0
  146. package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0001-service-layout.md +20 -0
  147. package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0003-ingest-retry-policy.md +26 -0
  148. package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0006-shared-retry-library.md +24 -0
  149. package/packs/solution-architect/skills/context-graph/evals/files/5/rfcs/0008-outbound-http-client.md +22 -0
  150. package/packs/solution-architect/skills/context-graph/evals/files/5/services/export/client.ts +15 -0
  151. package/packs/solution-architect/skills/context-graph/evals/files/5/services/export/retry.ts +12 -0
  152. package/packs/solution-architect/skills/context-graph/evals/files/5/services/ingest/client.ts +14 -0
  153. package/packs/solution-architect/skills/context-graph/evals/files/5/services/ingest/retry.ts +20 -0
  154. package/packs/solution-architect/skills/context-graph/evals/files/6/README.md +4 -0
  155. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0001-monorepo-layout.md +10 -0
  156. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0002-billing-on-postgres.md +13 -0
  157. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/adr/0004-ledger-sync-nightly-batch.md +9 -0
  158. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0003-invoice-ids.md +9 -0
  159. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0007-invoice-ids-ulid.md +11 -0
  160. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0009-billing-event-store.md +15 -0
  161. package/packs/solution-architect/skills/context-graph/evals/files/6/docs/rfcs/RFC-0010-revenue-service.md +13 -0
  162. package/packs/solution-architect/skills/context-graph/evals/files/6/libs/money/ulid.py +8 -0
  163. package/packs/solution-architect/skills/context-graph/evals/files/6/services/billing/src/events.py +10 -0
  164. package/packs/solution-architect/skills/context-graph/evals/files/6/services/billing/src/store.py +10 -0
  165. package/packs/solution-architect/skills/context-graph/evals/files/6/services/invoicing/ids/generator.py +7 -0
  166. package/packs/solution-architect/skills/context-graph/evals/files/6/services/ledger/README.md +4 -0
  167. package/packs/solution-architect/skills/context-graph/evals/files/6/services/ledger/sync.py +3 -0
  168. package/packs/solution-architect/skills/context-graph/evals/files/7/README.md +4 -0
  169. package/packs/solution-architect/skills/context-graph/evals/files/7/db/queries/orders.sql +2 -0
  170. package/packs/solution-architect/skills/context-graph/evals/files/7/db/sharding/router.py +9 -0
  171. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-001-postgres-primary.md +8 -0
  172. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-002-kafka-event-bus.md +20 -0
  173. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-003-no-orm.md +9 -0
  174. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-006-tenant-sharding.md +9 -0
  175. package/packs/solution-architect/skills/context-graph/evals/files/7/design/decisions/DD-011-orm-for-admin-console.md +11 -0
  176. package/packs/solution-architect/skills/context-graph/evals/files/7/pipelines/fanout/router.py +4 -0
  177. package/packs/solution-architect/skills/context-graph/evals/files/7/pipelines/ingest/consumer.py +5 -0
  178. package/packs/solution-architect/skills/context-graph/evals/files/7/pipelines/ingest/topics.yaml +8 -0
  179. package/packs/solution-architect/skills/context-graph/evals/files/7/rfcs/0004-region-sharding.md +15 -0
  180. package/packs/solution-architect/skills/context-graph/evals/files/7/services/admin-console/models.py +11 -0
  181. package/packs/solution-architect/skills/context-graph/evals/files/7/services/orders/repo.py +9 -0
  182. package/packs/solution-architect/skills/context-graph/evals/files/8/README.md +11 -0
  183. package/packs/solution-architect/skills/context-graph/evals/files/8/api/ledger.proto +30 -0
  184. package/packs/solution-architect/skills/context-graph/evals/files/8/config/http.yaml +10 -0
  185. package/packs/solution-architect/skills/context-graph/evals/files/8/config/messaging.yaml +8 -0
  186. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0001-record-architecture-decisions.md +20 -0
  187. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0002-postgresql-for-ledger.md +22 -0
  188. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0003-rabbitmq-domain-events.md +22 -0
  189. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0004-integer-minor-units.md +32 -0
  190. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0005-provider-http-retries.md +26 -0
  191. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0006-openapi-generated-clients.md +20 -0
  192. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0007-kafka-domain-events.md +25 -0
  193. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/adr/0008-structured-logging.md +18 -0
  194. package/packs/solution-architect/skills/context-graph/evals/files/8/docs/rfcs/RFC-012-idempotency-keys.md +19 -0
  195. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/api/idempotency.py +19 -0
  196. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/api/server.py +35 -0
  197. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/clients/provider.py +33 -0
  198. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/db/migrations/0001_init.sql +14 -0
  199. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/db/migrations/0008_idempotency_keys.sql +5 -0
  200. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/db/migrations/0009_fx_entries.sql +4 -0
  201. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/events/publisher.py +28 -0
  202. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/logging.py +25 -0
  203. package/packs/solution-architect/skills/context-graph/evals/files/8/services/ledger/models/entry.py +16 -0
  204. package/packs/solution-architect/skills/context-graph/evals/files/9/.env.example +3 -0
  205. package/packs/solution-architect/skills/context-graph/evals/files/9/README.md +5 -0
  206. package/packs/solution-architect/skills/context-graph/evals/files/9/docker-compose.yml +18 -0
  207. package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/001-session-storage.md +21 -0
  208. package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/002-api-rate-limiting.md +32 -0
  209. package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/003-jwt-sessions.md +29 -0
  210. package/packs/solution-architect/skills/context-graph/evals/files/9/docs/decisions/004-catalog-cache.md +19 -0
  211. package/packs/solution-architect/skills/context-graph/evals/files/9/src/catalog/cache.ts +13 -0
  212. package/packs/solution-architect/skills/context-graph/evals/files/9/src/catalog/repository.ts +13 -0
  213. package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/email.ts +3 -0
  214. package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/export.ts +3 -0
  215. package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/queue.ts +10 -0
  216. package/packs/solution-architect/skills/context-graph/evals/files/9/src/jobs/worker.ts +8 -0
  217. package/packs/solution-architect/skills/context-graph/evals/files/9/src/lib/db.ts +10 -0
  218. package/packs/solution-architect/skills/context-graph/evals/files/9/src/lib/redis.ts +8 -0
  219. package/packs/solution-architect/skills/context-graph/evals/files/9/src/middleware/rateLimit.ts +26 -0
  220. package/packs/solution-architect/skills/context-graph/evals/files/9/src/server.ts +17 -0
  221. package/packs/solution-architect/skills/context-graph/evals/files/9/src/session/store.ts +10 -0
  222. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/docs/adr/0004-kafka-for-order-events.md +19 -0
  223. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/docs/adr/0006-email-receipts.md +7 -0
  224. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/docs/adr/0009-sqs-for-order-events.md +19 -0
  225. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/services/notifications/receipts.py +0 -0
  226. package/packs/solution-architect/skills/context-graph/examples/inputs/order-events/services/orders/publisher.py +0 -0
  227. package/packs/solution-architect/skills/context-graph/examples/order-events.md +63 -0
  228. package/packs/solution-architect/skills/context-graph/manifest.json +33 -0
  229. package/packs/solution-architect/skills/context-graph/reference.md +104 -0
  230. package/packs/solution-architect/skills/context-graph/scripts/context_graph.py +634 -0
package/README.md CHANGED
@@ -31,7 +31,7 @@ Every skill runs as a real agent session twice: once with the skill, once withou
31
31
  - **Two blind judges preferred the skill's answer in 61% of pairs** (95% interval 55–68%). Each judge saw only the request and both answers, in shuffled order.
32
32
  - **4 skills that didn't beat the plain agent were [retired](https://sananthanarayan.github.io/skilldrop/evals/#retired)**, and they're listed. Each new skill has to win on held-out evals before it ships.
33
33
 
34
- [Get started](https://sananthanarayan.github.io/skilldrop/start/) · [Browse the packs](https://sananthanarayan.github.io/skilldrop/packs/) · [Search all skills](https://sananthanarayan.github.io/skilldrop/catalogue/) · [Docs](https://sananthanarayan.github.io/skilldrop/docs/) · [Contribute](CONTRIBUTING.md)
34
+ [Get started](https://sananthanarayan.github.io/skilldrop/start/) · [Browse the packs](https://sananthanarayan.github.io/skilldrop/packs/) · [Search all skills](https://sananthanarayan.github.io/skilldrop/catalogue/) · [Docs](https://sananthanarayan.github.io/skilldrop/docs/) · [What stays stable in 1.x](guides/reference/versioning-and-stability.md) · [Contribute](CONTRIBUTING.md)
35
35
 
36
36
  ## Start in one command
37
37
 
package/catalogue.json CHANGED
@@ -42,6 +42,7 @@
42
42
  "agent-budget",
43
43
  "terraform-module",
44
44
  "mcp-pairing",
45
+ "context-graph",
45
46
  "event-contract-draft"
46
47
  ]
47
48
  },
@@ -270,6 +270,7 @@
270
270
  "tier": "standard",
271
271
  "rationale": "Reads a SKILL.md and synthesizes eval cases — requires understanding of skill intent but not heavy reasoning."
272
272
  },
273
+ "context-graph": {"tier": "standard", "rationale": "The decision graph and its consistency checks are computed by its script; the model quotes the governing record and writes the fixes."},
273
274
  "event-contract-draft": {
274
275
  "tier": "standard",
275
276
  "rationale": "Contract drafting against the AsyncAPI shape with fixed rules on ordering, delivery and versioning; mid tier is enough."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skilldrop-cli",
3
- "version": "0.16.45",
3
+ "version": "1.0.0",
4
4
  "description": "Portable AI-agent skills, measured against the agent without them. ADRs, PRDs, runbooks, decks and reviews, installable into Claude Code, Cursor, Kiro, and any IDE that takes custom instructions. One command per skill or per role-based pack.",
5
5
  "author": {
6
6
  "name": "Sanjay Ananthanarayan",
@@ -0,0 +1,119 @@
1
+ ---
2
+ name: context-graph
3
+ description: Map the decisions behind a codebase from its ADRs, RFCs and design records — each record's status and date, what supersedes or amends what, which records cite which, the files and folders each decision governs, and with git the commits that implemented it — then answer "why is it like this?" from the record and check the record is still true. Finds supersessions only one side records, current decisions pointing at code that is gone, two current decisions governing the same path, and references to records that don't exist. Use when the user asks "why do we use X", "which decisions govern this file or service", "is this ADR still current", "are our ADRs out of date", "what was decided before I change this", wants a map of the architecture decisions, or is onboarding onto a codebase's history.
4
+ ---
5
+
6
+ # context-graph
7
+
8
+ Answers "why is it like this?" from what the team actually decided and wrote down, and says
9
+ plainly when nothing was written down. It reads every decision record (ADRs, RFCs, design
10
+ decisions), builds the graph between them and the code they govern, and checks that graph against
11
+ the repository as it is today. Writing a new or corrected record is `adr-generator`. Explaining how
12
+ the code works now, with no decision history, is `codebase-tour`. Recovering the architecture from
13
+ the code itself is `reverse-architecture`.
14
+
15
+ ## How to respond
16
+
17
+ **Four rules come before the steps and outrank them:**
18
+
19
+ - **Answer what was asked, first.** Open with the answer, the decision or the artifact, in plain words. Scores, matrices, frameworks and tags come after it, and anything that doesn't change the answer is cut.
20
+ - **Use only what you were given.** Don't add facts, names, numbers, incidents, history, steps or sections the input doesn't contain. What you need and don't have is left out of the artifact and listed once at the end under "To confirm".
21
+ - **Deliver from what you have.** When the request gives you something to work on, state your assumptions in a line and produce the result. When it gives you nothing to work on, ask for it in one or two plain sentences and say what you will do once you have it.
22
+ - **Write for someone who has never heard of this skill.** No skill names, no paths or scripts from this folder, no internal terms, and nothing about how the run was set up. A next step is one plain sentence at the end that describes the work.
23
+ - **For this skill:** A rationale comes only from a record, quoted or cited by its id, and a record is only as true as the code: check the one that answers the question against the files it governs. When no record covers it, say "no recorded decision" and, at most, what the code shows, labelled as inferred. Never mention the script, the graph or any tool in the reply; say what the records and the code show.
24
+
25
+ 1. **Find the records and build the graph with the script.** Read numbers, statuses and links from its output, not by eye. It finds records in the usual folders (`docs/adr`, `docs/decisions`, `docs/rfcs`, `architecture/decisions`, …) or the ones you name, and exits 2 when there are none.
26
+ ```bash
27
+ # Claude Code
28
+ python3 "${CLAUDE_SKILL_DIR}/scripts/context_graph.py" --root .
29
+ python3 "${CLAUDE_SKILL_DIR}/scripts/context_graph.py" --root . --why services/orders/consumer.py
30
+ python3 "${CLAUDE_SKILL_DIR}/scripts/context_graph.py" --root . --record ADR-0004 --git
31
+ # Other IDEs (from the skill folder)
32
+ python3 scripts/context_graph.py --root <repo> --docs architecture/decisions --json -o graph.json --mermaid graph.mmd
33
+ ```
34
+ `--git` adds the commits whose messages mention each record. A path counts as governed when a record names it in backticks or links to it, and it exists. Without the script, do the same by hand and say the links were found by reading, not computed.
35
+
36
+ **The script's findings are leads, not answers.** Confirm each one by reading the records and the code before you report it, and drop the ones that don't hold. Two records "governing the same path" often don't clash at all: say so only when their decisions actually conflict, and quote both.
37
+
38
+ 2. **Answer "why" from the current record, and show the chain.** Say which decision governs the thing now, with its id, title, status and date, and the reason as the record states it. Then name what it replaced, if anything.
39
+ - ✅ *"Order events moved from Kafka to SQS in ADR-0009 (accepted 2026-02-10): 'one fewer system to run, and the volume fits SQS'. ADR-0004 chose Kafka in 2025 and is still marked Accepted, so anyone reading it alone gets the wrong answer."*
40
+ - ❌ *"You use Kafka for order events (ADR-0004), which gives you durability and ordering."* That reads the superseded record and adds a rationale that isn't in it.
41
+
42
+ 3. **Trust the newest record only when the chain agrees.** A record superseded by another is history, even when its own Status line still says Accepted. The script lists each such one-sided supersession as a problem. Say which record a reader should rely on and why.
43
+
44
+ 4. **Check the deciding record against the code.** Open the files it governs and check each thing the record requires (every "must", every named field, check, limit or setting), not only its headline. Confirm or contradict each with the code, quoting the line: ✅ *"`scheduler/jobs.py` line 18 still opens a database transaction per job, as ADR-0012 says."* Report drift as a finding with both sides: ✅ *"ADR-0015 promises 30 days of audit-log retention; `ops/logging.yaml` sets `retention_days: 14`."* When the record describes a phased change (a migration, a dual-write, a rollout), say which phase the code is in. While it's mid-rollout, the old decision still holds for the parts not yet moved: that is a missing cross-reference, not a contradiction.
45
+
46
+ 5. **For "can I remove or change X?", search the code for every use of X,** not only the records: imports, client constructors, config keys, environment variables and container definitions. A use that no record covers is still a dependency: list it as "in use, no recorded decision", with its file. The records tell you why; only the code tells you everything that would break.
47
+
48
+ 6. **Find the decisions that bear on it, not only the ones that name its path.** Read any record that amends, extends or narrows the governing one, and any that sets a rule for the same concern across the codebase (error handling, data access, logging, authentication), even when it names a different folder. A shared-library rule governs a change that creates a shared library. Before you call a related record unrelated, read it.
49
+
50
+ 7. **Report what is no longer true, worst first.** Problems before warnings:
51
+ - **Supersession recorded on one side only:** "ADR-0004 still says Accepted". Fix it by marking it "Superseded by ADR-0009".
52
+ - **A current decision pointing at code that is gone:** the record names a folder or file that no longer exists. When the script suggests where it moved (a renamed sibling), or a README says so, report it as moved, not gone, and give the path to update. Only a path with no successor is gone; then the decision is dead, so deprecate it.
53
+ - **A guide that still teaches a superseded decision:** an onboarding doc or a README that cites the old record, or describes its choice. Name the file and the line to change.
54
+ - **Two current decisions governing the same path, neither superseding nor amending the other:** a possible conflict. Read both, quote the clash if there is one, and recommend which one supersedes or amends the other.
55
+ - **A reference to a record that doesn't exist, a status that's missing or unrecognised, or a duplicate id.**
56
+
57
+ 8. **Give each fix as the exact edit.** The line to change in which record, such as changing `## Status` to `Superseded by ADR-0009`, linked to that record's file, or the new record that's needed and what it must decide. Don't rewrite records nobody asked about.
58
+
59
+ 9. **Say what the record can't tell.** Decisions made in chat or tickets and never written down, code that no record governs, and, without `--git`, whether anything was actually implemented. When a question has no record, say so, and suggest writing one only if the decision is still live.
60
+
61
+ 10. **Write the reply in this order, at the size asked for:**
62
+ - the answer, in two or three sentences, with the governing record's id;
63
+ - the chain or the problems, as a short list, each with its record id and the fix;
64
+ - what the records don't cover;
65
+ - "To confirm", only for inputs that are missing.
66
+
67
+ Answer each question someone asked, in their order. A length they set is a limit: "two lines" is two lines, with the decision and the one thing they must not miss. When they say "keep it short" or "don't need an essay", give a few lines per question, and at most one line on record hygiene that doesn't change the answer. Give a table when they ask for a map, a list or something to paste; otherwise none. No closing offer or summary line.
68
+
69
+ **Non-interactive runs** (subagent, CI, headless): with no records found, emit `BLOCKED: no decision records found; name the folder that holds the ADRs or RFCs`. Exit 1 from the full check means problems were found. Report them; never edit the records yourself.
70
+
71
+ ## Useful references in this skill
72
+
73
+ - [`reference.md`](reference.md): the record formats read (MADR, Nygard, RFC frontmatter), how status, supersession, amendment and governed paths are detected, every check and its fix, and the JSON shape
74
+ - [`scripts/context_graph.py`](scripts/context_graph.py): stdlib; builds the graph, checks it, answers `--why PATH` and `--record ID`; `--json`, `--mermaid`, `--git`; exits 1 on problems and 2 on bad input
75
+ - [`examples/order-events.md`](examples/order-events.md): worked example, a repo whose Kafka ADR was superseded on one side only and whose newer ADR names a folder that was deleted
76
+
77
+ ## Quality bar
78
+
79
+ - **The answer names the governing record by id, status and date**, and the rationale is quoted or closely paraphrased from that record. No reason is supplied that the record doesn't give.
80
+ - **A superseded record is never presented as current**, including one whose own Status line wasn't updated.
81
+ - **"No recorded decision" is said when it's true**, and any reading of the code is labelled as inferred.
82
+ - **Every problem names its record id and the exact fix.** Problems come before warnings.
83
+ - **Two current records on the same path are raised as a possible conflict**, not silently resolved by date.
84
+ - **The deciding record is checked against the code it governs, claim by claim,** with the line quoted, and drift is reported with both sides. A line number is given only when read from the file.
85
+ - **Every script finding in the reply has been confirmed by reading;** one that doesn't hold is dropped.
86
+ - **A removal or change question lists every use of the thing in the code,** recorded or not.
87
+ - **Related records are read before they're called unrelated:** amendments, and rules for the same concern elsewhere in the codebase.
88
+ - **A moved path is reported as moved, with its new location; only a path with no successor is "gone".**
89
+ - **A mid-rollout pair of records is a missing cross-reference, not a contradiction.**
90
+ - **The reply fits the size asked for (a stated limit is obeyed exactly), and never mentions a script, a graph or a tool.**
91
+ - **Statuses, links and governed paths come from the script's output**, or are marked as read by hand when it couldn't run.
92
+ - **No invented records, ids, dates, paths or commits.**
93
+
94
+ ## When to use this skill
95
+
96
+ - ✅ "Why do we use X?" or "Why is this service built this way?" in a repo with ADRs or RFCs
97
+ - ✅ "Which decisions govern this file, folder or service before I change it?"
98
+ - ✅ "Are our ADRs still current?" or "Find the stale or contradictory decisions"
99
+ - ✅ A map of a codebase's architecture decisions for onboarding or a review
100
+
101
+ ## When NOT to use this skill
102
+
103
+ - ❌ Writing a new ADR or fixing one: use `adr-generator`
104
+ - ❌ How the code works now, with no decision history: use `codebase-tour`
105
+ - ❌ Recovering the architecture from code with no records: use `reverse-architecture`
106
+ - ❌ A record of business or product decisions for stakeholders: use `decision-log`
107
+
108
+ ## Anti-patterns to avoid
109
+
110
+ - ❌ **Reading one ADR and stopping.** The record that answers the question may have been superseded by a later one that never touched the first file.
111
+ - ❌ **Trusting a Status line over the chain.** "Accepted" on a record another record supersedes means someone forgot to update it, not that it is still in force.
112
+ - ❌ **Supplying the reason.** "Kafka gives you ordering" is general knowledge, not the team's decision. If the record doesn't say why, say it doesn't.
113
+ - ❌ **Resolving a conflict by date alone.** Two current records on the same path need a person to decide which wins; the newer one isn't automatically right.
114
+ - ❌ **Listing every record.** Answer the question; the full table is for a map that was asked for.
115
+ - ❌ **Passing on a script warning unread.** "Both govern the same path" is a prompt to read both, not a conflict.
116
+ - ❌ **Answering "can I remove it?" from the records alone.** The uses nobody recorded are the ones that break.
117
+ - ❌ **Taking the record's word for it.** A decision the code no longer follows is the most useful thing to find; read the files.
118
+ - ❌ **"Gone" for a folder that was renamed.** Look for where it went before telling someone the decision is dead.
119
+ - ❌ **Telling the reader how you found it.** "The script shows" or "the graph says" means nothing to them; say what the records and the code say.
@@ -0,0 +1,11 @@
1
+ [
2
+ {"query": "Why do we use Kafka for order events? Is the ADR that chose it still the current decision?", "should_trigger": true},
3
+ {"query": "I'm about to refactor services/billing/invoice.py. Which architecture decisions govern it that I should read first?", "should_trigger": true},
4
+ {"query": "Our docs/adr folder has 40 records going back five years. Find the ones that are stale, superseded without being marked, or contradict each other", "should_trigger": true},
5
+ {"query": "Give me a map of our RFCs and ADRs: what supersedes what, and which folders each one covers, for onboarding the new hires", "should_trigger": true},
6
+ {"query": "Is ADR-0012 still true? I think the code it talks about was deleted last year", "should_trigger": true},
7
+ {"query": "We just decided to move our search from Postgres full-text to a hosted search engine. Write the ADR for it in MADR format", "should_trigger": false},
8
+ {"query": "I start on the checkout repo on Monday. How do I run it locally, run the tests, and where's the code for applying discount codes?", "should_trigger": false},
9
+ {"query": "There are no design docs for this monolith. Work out its architecture from the code and the docker-compose file and draw me a C4 diagram", "should_trigger": false},
10
+ {"query": "Here are the notes from this morning's pricing steering meeting. Pull out what was decided, who owns each action and when it's due", "should_trigger": false}
11
+ ]
@@ -0,0 +1,225 @@
1
+ {
2
+ "skill_name": "context-graph",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "I'm new on the platform team and someone told me we keep user sessions in Redis. Before I touch login I'd like to understand why. Our ADRs are in docs/adr and the auth code is in services/auth/. Why do we use Redis for sessions, and is that still the current decision?",
7
+ "assertions": [
8
+ "Answers the question first, in plain words: keeping sessions in Redis is no longer the current decision. ADR-0007 'Stateless signed session cookies' (accepted, 2025-11-04) supersedes ADR-0003 and moves sessions to signed, stateless cookies.",
9
+ "Does not present ADR-0003 as current even though its own Status line still says Accepted, and points out that the supersession is recorded only in ADR-0007.",
10
+ "Gives the original reason as history, from ADR-0003 (2024-05-14): Redis was already run for the page cache, and a shared store removed sticky sessions (nodes logging users out on scale-out or restart) without adding a new system.",
11
+ "Gives ADR-0007's different reason from the record: the 2025-08-19 Redis failover took 40 minutes and logged everyone out, and 'login should depend on nothing but the auth service and its signing key'. It also says a replica was considered and not chosen because it keeps the dependency.",
12
+ "Gives the exact fix: change ADR-0003's '## Status' from 'Accepted' to 'Superseded by ADR-0007' (a link to 0007-stateless-signed-session-cookies.md is fine).",
13
+ "Does not take ADR-0006 ('Sessions stay as described in ADR-0003 for now') as evidence that Redis is current: ADR-0006 is Rejected and predates ADR-0007. ADR-0005's 8-hour lifetime is described as amending ADR-0003 and carried over into ADR-0007 as the cookie expiry, not as a separate live Redis decision.",
14
+ "Notes that services/auth/redis_sessions.py still exists although ADR-0007 says it is removed once every client is on cookie sessions, so the records can't say whether the migration is finished. That is labelled as inferred from the code, or listed under 'To confirm', not stated as fact either way. It also says Redis stays in use for the page cache.",
15
+ "Invents nothing that is not in the files: no rationale such as 'Redis is fast' or 'JWTs scale better', and no record ids, dates, incidents, paths or commits beyond those in docs/adr and services/auth/."
16
+ ]
17
+ },
18
+ {
19
+ "id": 2,
20
+ "prompt": "Can you check whether our architecture decision records are still true? They're in docs/adr, 8 of them going back to 2023, and the code is in services/ and libs/. We have the quarterly architecture review on Thursday and I want to walk in knowing which ones are out of date or contradict each other, and what to change in each.",
21
+ "assertions": [
22
+ "Opens with the direct answer: which records are no longer true. ADR-0003 points at code that is gone, and ADR-0004 and ADR-0006 contradict each other on libs/money/. The answer comes before any table or full list of records.",
23
+ "Reports ADR-0003 'A separate thumbnail service' (accepted, 2023-09-11) as naming services/thumbnailer/, which doesn't exist. The fix is to update the path if the code moved or to mark the record Deprecated. Any suggestion that it moved to services/media/resize.py is labelled as inferred from the code, not stated as fact.",
24
+ "Raises ADR-0004 (accepted, 2024-01-15) and ADR-0006 (accepted, 2025-02-27) as a possible conflict on libs/money/ and quotes or closely paraphrases the clash: integer minor units with 'no floats and no Decimal anywhere in money code' against Decimal with four decimal places. Notes that ADR-0006 only says it 'builds on' ADR-0004 and neither supersedes nor amends it.",
25
+ "Does not settle the money conflict by date or by what libs/money/amount.py does. It says a person has to decide, and that the fix is a 'Supersedes ADR-0004' or 'Amends ADR-0004' line in ADR-0006 (or a new record), with the status of ADR-0004 updated to match. Noting that the code uses Decimal is fine only if it is labelled as inferred.",
26
+ "Reports that ADR-0005 refers to ADR-0011, which doesn't exist, and that the fix is to correct the reference or write the missing backoff record. Also reports that ADR-0007 has no status, and that the fix is to add a '## Status' section whose value the owner confirms (it is not assumed to be Accepted).",
27
+ "Does not present ADR-0002 and ADR-0005, which both govern services/worker/, as a contradiction: ADR-0005 adds a retry policy that ADR-0002 does not contradict. If it mentions the overlap, it says that reading both shows no clash.",
28
+ "Does not flag ADR-0008 for naming services/legacy-search/, which no longer exists, because ADR-0008 is Deprecated and that is expected. Problems (the gone code in ADR-0003) come before warnings, and every item names its record id and the exact edit.",
29
+ "Invents nothing that is not in the files: no record ids other than ADR-0001 to ADR-0008 and the missing ADR-0011, and no dates, owners, paths, incidents or reasons that the records don't contain."
30
+ ]
31
+ },
32
+ {
33
+ "id": 3,
34
+ "prompt": "need to change the payment webhook retry stuff (services/payments/webhooks/retry.py), a merchant complained we give up too early. what decisions should i read before i touch it?? rfcs are somewhere under docs/rfcs. dont want to undo something someone decided on purpose",
35
+ "assertions": [
36
+ "Opens with the short reading list, most relevant first: RFC-0006 'Exponential backoff for webhook retries' (accepted, 2025-04-22), which names retry.py directly; RFC-0004 (accepted, 2024-11-19), which governs services/payments/webhooks/; and RFC-0002 (accepted, 2024-06-10), which governs services/payments/.",
37
+ "States RFC-0006's limits from the record: first retry after 2 seconds, doubling, capped at 10 minutes between attempts, at most 8 attempts, and no retry on a 4xx except 429. Gives its reason: during the 2025-03-06 incident fixed 30-second retries 'hammered their endpoint as it came back and knocked it over again'.",
38
+ "Catches that giving up early is a recorded, accepted consequence of RFC-0006 ('an event can now be given up on within about four minutes'). Changing the attempt count or the timing therefore changes a decision on purpose and needs a new RFC that amends or supersedes RFC-0006, not just a code edit.",
39
+ "Presents RFC-0003 (2024-08-01, every 30 seconds up to 100 times) only as history, superseded by RFC-0006, and never as an allowed setting to return to.",
40
+ "Does not list RFC-0005 as governing this file: it covers services/notifications/retry.py (email and SMS every 5 minutes for 24 hours), a different file with a similar name. If it mentions RFC-0005, it says so.",
41
+ "Includes RFC-0004's constraint: every retry of an event must resend the same Idempotency-Key. It also includes RFC-0002's: a change under services/payments/ needs a review from a payments engineer.",
42
+ "Mentions RFC-0007, if at all, as Proposed and not decided. It does not report RFC-0002, RFC-0004 and RFC-0006 as conflicting with each other: they cover nested scopes and don't clash.",
43
+ "Invents nothing that is not in the files: no retry numbers, incidents, owners, merchants, record ids or dates beyond those in docs/rfcs and services/."
44
+ ]
45
+ },
46
+ {
47
+ "id": 4,
48
+ "held_out": "2026-10-21",
49
+ "prompt": "hey, first week on ledgerline. the onboarding doc says the nightly invoice run takes a redis lock so two workers don't double bill, and ADR-0004 says the same thing and it's marked accepted. but I can't find redis anywhere in the code?? why is it like this, what am I missing. also if there's a quick way to get the lay of the land on the ADRs that would help, I'm meant to read them all this week",
50
+ "assertions": [
51
+ "Answers the actual question up front: Redis is no longer used for the invoice-run lock because ADR-0007 (2024-02-20) superseded ADR-0004 and replaced it with a session-level Postgres advisory lock (pg_try_advisory_lock(727001)) in src/ledgerline/scheduler/lock.py.",
52
+ "Explains the why from the records themselves: ADR-0004 was a reaction to the 2023-04-27 double run that billed 41 customers twice; ADR-0007 removed Redis because it served only this one lock (a managed instance plus an on-call runbook), a January 2024 failover dropped the lock mid-run, and it restores the single-datastore intent of ADR-0002.",
53
+ "Points out that the supersession is recorded on one side only: ADR-0007 says 'Supersedes: ADR-0004' but ADR-0004 still reads 'Status: Accepted', which breaks ADR-0001's own rule; recommends changing ADR-0004's status to 'Superseded by ADR-0007'.",
54
+ "Flags that docs/onboarding.md is stale (last reviewed 2023-09-14, before ADR-0007) and still sends readers to ADR-0004, and that ADR-0004 names src/ledgerline/scheduler/redis_lock.py, which does not exist in the repo.",
55
+ "Checks the current decision against the code and confirms it holds: runner.py takes the lock on direct_connection() (DATABASE_DIRECT_URL, not PgBouncer), as ADR-0007 requires, and calls this out as the trap to avoid (a pooled connection would release the lock early).",
56
+ "Gives a short map of the five records present (0001, 0002, 0004, 0007, 0009) with status, date and what each governs, marks 0004 as superseded, and notes that ADR-0009 cites ADR-0005, which is not in docs/adr/.",
57
+ "Invents nothing that isn't in the files: no extra ADRs, commits, authors, dates, incidents or files. With no git history provided, it claims none, and gives any history check as a command to run (e.g. git log on docs/adr/ or a git log -S search for redis).",
58
+ "Is sized for a newcomer's casual question: the why takes a few sentences and the ADR map is a compact table or list, not a long audit report."
59
+ ]
60
+ },
61
+ {
62
+ "id": 5,
63
+ "held_out": "2026-10-21",
64
+ "prompt": "I'm going to pull services/ingest/retry.ts and services/export/retry.ts into one shared lib/retry/ package and standardise everyone on fixed 1s backoff, 3 attempts. Export already does exactly that so it's the obvious common denominator, and ingest's jitter thing is overkill. Planning to open the PR this afternoon. Quick sanity check: is there anything in rfcs/ I'd be stepping on before I do this?",
65
+ "assertions": [
66
+ "Answers the question directly and first: yes, as planned the change contradicts recorded decisions, so it should not go in as a plain refactor PR without a new or updated RFC.",
67
+ "Identifies that RFC-0006 (status rejected, 2025-06-19) proposed essentially this same lib/retry/ extraction with a single default policy, and gives its reasons: export's billing API is not idempotent, and RFC-0001 keeps runtime code per service ('revisit only if RFC-0001 is superseded').",
68
+ "Identifies that RFC-0003 (accepted, governs services/ingest/retry.ts) requires exponential backoff with full jitter (base 200 ms, cap 30 s, 6 attempts) and bans fixed-interval retries in ingest, and that the proposed fixed 1 s retry is exactly what caused INC-114 (2025-02-27).",
69
+ "Corrects the premise that export 'already does exactly that': services/export/retry.ts retries only 503 responses that carry an Idempotency-Key header, so a uniform fixed 1 s / 3 attempt policy would either retry unsafe non-idempotent calls or drop that check.",
70
+ "Flags RFC-0008 (accepted, 2025-09-30): it governs lib/http/, which does not exist in the repo (its Q4 2025 rollout appears not to have happened), and its fixed 500 ms / 3 attempt policy contradicts RFC-0003, so two accepted records govern ingest's retry behaviour and that clash needs settling first.",
71
+ "Notes at least one record-integrity problem: RFC-0008 cites RFC-0007, which is not in rfcs/, and/or RFC-0008 says it amends RFC-0001 while RFC-0001 records no amendment and still names lib/types/ as the only shared package.",
72
+ "Gives a concrete way forward sized for a pre-PR check, e.g. write an RFC that explicitly revisits RFC-0006 and supersedes or amends RFC-0003 and RFC-0001 (and resolves RFC-0008), or keep per-service policies and share only plumbing. It stays a focused briefing, not a dump of every record.",
73
+ "Invents nothing that isn't in the files: no RFC contents, incidents, authors, commits or files beyond the fixture, and no claim of git history (none is provided). Any history or blame check is given as a command to run."
74
+ ]
75
+ },
76
+ {
77
+ "id": 6,
78
+ "held_out": "2026-10-21",
79
+ "prompt": "We're about to reorganise harbourline — RFC-0010 merges services/billing and services/invoicing into services/revenue. I'm taking it to architecture review on Thursday and need an audit of our decision records first (docs/adr and docs/rfcs): which decisions govern the code that's moving, which of those are actually still current, and anything broken or contradictory in the records that we should fix as part of the move. Give me a table I can paste into the review doc, plus a short list of fixes.",
80
+ "assertions": [
81
+ "Identifies the records governing the code that moves: ADR-0002 and RFC-0009 (services/billing/), RFC-0003 and RFC-0007 (services/invoicing/ids/), and notes ADR-0001's rule about service folders under services/ is touched by the merge; says RFC-0010 itself is only Proposed (2026-09-30), not yet a current decision.",
82
+ "Flags the one-sided supersession: RFC-0007 (2024-03-01) says it supersedes RFC-0003, but RFC-0003 still reads Status: Accepted with no superseded-by note; so RFC-0007 is the current invoice-ID decision (ULIDs, which services/invoicing/ids/generator.py matches), and the fix is to mark RFC-0003 Superseded.",
83
+ "Flags that ADR-0002 (billing in Postgres, in-place updates) and RFC-0009 (append-only DynamoDB event store billing-events) are both Accepted, both govern services/billing/, and neither supersedes or amends the other; notes the code does both (store.py updates invoices_ledger, events.py writes billing-events), so which one holds after the merge has to be settled at the review.",
84
+ "Flags that RFC-0009 'builds on RFC-0012', and no RFC-0012 exists in docs/rfcs.",
85
+ "Flags that ADR-0004 governs services/ledger-sync/, which no longer exists, and uses services/ledger/README.md (renamed from ledger-sync, still nightly at 02:00 UTC) to recommend updating the path rather than calling the decision obsolete; may note ledger is outside the move.",
86
+ "Points out that RFC-0010's 'Records affected' lists only ADR-0002, leaving out RFC-0009, RFC-0007 (and RFC-0003), whose governed paths will point at deleted folders after the move unless RFC-0010 amends them or their paths are updated.",
87
+ "Gives what was asked in the right size: one pasteable table (record, status, date, governs, still current?) and a short, actionable fix list. It is not a long essay, and it does not pad the review with every ADR in the repo.",
88
+ "Invents nothing not in the files: no commit hashes, authors, dates, record IDs or services beyond those present. Since there is no git history in the folder, any claim about implementing commits is stated as a command to run (e.g. git log --follow -- services/billing) rather than asserted."
89
+ ]
90
+ },
91
+ {
92
+ "id": 7,
93
+ "held_out": "2026-10-21",
94
+ "prompt": "hey — started on the fernwood team monday, trying to get my head round why things are the way they are. couple of qs: 1) why kafka and not just postgres listen/notify? feels like overkill 2) is the 'no ORMs' thing still a rule? i saw sqlalchemy in admin-console 3) someone in standup said we're moving off tenant sharding to region sharding — true? where was that decided? i think the design docs are in design/ and rfcs/. don't need an essay",
95
+ "assertions": [
96
+ "Answers question 1 from DD-002: Kafka was chosen because LISTEN/NOTIFY loses notifications when no listener is connected, has no replay, and caps payloads at 8000 bytes, while several independent consumers need to catch up after downtime; cites DD-002 (2022-06-02) rather than generic Kafka-vs-Postgres opinions.",
97
+ "Checks the record against the code and flags that DD-002 promises 7 days of retention, but pipelines/ingest/topics.yaml sets retention.ms 259200000 (3 days) on both ingest topics, so either the record or the config is out of date.",
98
+ "Answers question 2: the no-ORM rule (DD-003) still applies to services in general, but DD-011 (2024-05-08) amends it to allow SQLAlchemy in services/admin-console/ only, which explains what the newcomer saw; notes DD-003 itself does not mention the amendment.",
99
+ "Answers question 3: the rumour is not supported by the records. RFC 0004 (region sharding, P. Tamboli, 2025-02-14) was Withdrawn on 2025-03-20, and DD-006 (tenant sharding, Platform guild: O. Mensah, R. Vidal) is still current. The RFC's 'Supersedes: DD-006' header is not treated as having taken effect.",
100
+ "Mentions, briefly, that DD-002 refers to DD-007 for retention details and no DD-007 exists.",
101
+ "Answers the three questions directly and in order, matching 'don't need an essay': a few short answers, each with the record it comes from. It is not a full decision-graph dump or an audit of every record.",
102
+ "Invents nothing not in the files: no message volumes, commit hashes, people, dates or record numbers beyond those present. Anything that would need git history (e.g. when the retention changed) is offered as a command to run, not stated as fact."
103
+ ]
104
+ },
105
+ {
106
+ "id": 8,
107
+ "held_out": "2026-10-21",
108
+ "prompt": "Quarterly architecture review is Thursday. Our ADRs are in docs/adr and there's an RFC folder too. Before the meeting I need a list of the decisions the code no longer follows, so for each one we can decide whether to fix the code or write a superseding ADR. Code and config are all in this repo.",
109
+ "assertions": [
110
+ "Answers the question directly with a list of the decisions the code no longer follows. The list includes ADR-0004 (migration 0009_fx_entries.sql adds fx_amount NUMERIC(18,4) and fx_rate, and models/entry.py types fx_amount as Decimal, against the integer *_minor BIGINT rule), ADR-0005 (config/http.yaml sets timeout_seconds 30 and max_retries 5 where the ADR says 5 seconds and 3 retries, and retry_methods retries every POST, not only idempotent ones), and ADR-0006 (api/openapi.yaml and clients/generated/ do not exist; the interface is api/ledger.proto served over gRPC).",
111
+ "Does not report the Kafka config as code breaking ADR-0003. It sees that ADR-0007 supersedes ADR-0003 but ADR-0003 still says Accepted with no back-link, and says the fix is to mark ADR-0003 Superseded by ADR-0007, not to change the code.",
112
+ "Points out that the move from OpenAPI to gRPC (api/ledger.proto, services/ledger/api/server.py, generated stubs in services/ledger/api/gen/) was never recorded in any ADR, and recommends a new ADR that supersedes ADR-0006.",
113
+ "Points out that ADR-0008 cites ADR-0011 for tracing, and no ADR-0011 exists in docs/adr.",
114
+ "Does not count RFC-012 as a decision the code breaks, because its State is Draft. It may note that the code already implements it (services/ledger/api/idempotency.py, migration 0008_idempotency_keys.sql, a 24-hour TTL), so the RFC should be accepted as an ADR or its status brought up to date.",
115
+ "Says which decisions still hold, or at least does not list them as drift: ADR-0002 (PostgreSQL with numbered SQL migrations), ADR-0007 (config/messaging.yaml uses Kafka topic ledger.entry-events keyed by account_id), and ADR-0008 (services/ledger/logging.py emits the fields it names).",
116
+ "Is shaped for a review meeting: a compact table or list with one row per finding, giving the record, the evidence (file and value), and whether the fix is a code change or a record change (supersede, amend, mark superseded, write a new record). No long essay.",
117
+ "Invents nothing that is not in the files: no ADR numbers, file paths, config values, dates, authors or commit hashes beyond those in the repo. There is no git history in the folder, so it does not claim which commits implemented or broke a decision. If it suggests a git check, it gives that as a command for the user to run."
118
+ ]
119
+ },
120
+ {
121
+ "id": 9,
122
+ "held_out": "2026-10-21",
123
+ "prompt": "hey can i just rip out redis? pretty sure we only use it for the session cache and we're moving sessions to jwt anyway (theres an rfc for it somewhere in docs). is there anything we decided that depends on it? dont want to get blocked in review",
124
+ "assertions": [
125
+ "Answers the question up front: no, Redis cannot be removed now, because more than sessions depends on it. It gives the reasons straight after.",
126
+ "Identifies decision 002 (accepted, 2023-11-20) as a current decision that needs Redis: the public API rate limiter in src/middleware/rateLimit.ts is a token bucket shared across containers, 600 requests per minute per API key.",
127
+ "Points out that 001 says 'Superseded by 003' but 003 is still only Proposed and not yet reviewed, so the supersession has not taken effect. Sessions on Redis (src/session/store.ts, connect-redis) is still what the code does and still the decision in force.",
128
+ "Points out that the JWT proposal itself (003, open question 1) plans to keep the revocation denylist in Redis, so moving to JWT as written would not remove the need for Redis.",
129
+ "Catches that decision 004 says the catalogue cache is in-process LRU and explicitly not in Redis, but src/catalog/cache.ts reads and writes the catalogue in Redis. The code has drifted from the record. Removing Redis would break the catalogue cache, and the record needs updating or the code needs reverting.",
130
+ "Identifies the BullMQ job queues in src/jobs/queue.ts and src/jobs/worker.ts (email and order-export, and the worker service in docker-compose.yml) as a Redis dependency with no decision record, and suggests recording it.",
131
+ "Notes that decision 002 refers to DR-007 for Redis availability and failover, and that no DR-007 exists in docs/decisions.",
132
+ "Stays proportionate to a casual question and invents nothing: it leads with the answer, gives a short list of what would break and the next steps (for example, get 003 reviewed and decide revocation storage, decide what replaces the limiter and the queue), and names no files, decisions, numbers or libraries that are not in the repo."
133
+ ]
134
+ },
135
+ {
136
+ "id": 10,
137
+ "held_out": "2026-10-21",
138
+ "prompt": "I'm doing the security review of billing-api ahead of our PCI audit. Two things I need to understand from the decision records in this repo: (1) why billing-api authenticates internal callers the way it does, and (2) where its secrets come from. Is what the code does today still the agreed approach, or has the decision moved on? Please cite the specific ADRs and the files so I can put them in my findings.",
139
+ "assertions": [
140
+ "Identifies that billing-api currently authenticates internal callers with HMAC-SHA256 shared-key signatures (services/billing-api/auth/__init__.py wires require_internal_caller to hmac_verify.require_hmac_signature), which is the approach of ADR-0004.",
141
+ "States that ADR-0011 (Accepted, 2025-06-20, mutual TLS via the Ironbark CA) supersedes ADR-0004, so HMAC is no longer the agreed approach and billing-api has not been migrated, while ledger-worker has (services/ledger-worker/auth/mtls.py).",
142
+ "Points out that ADR-0004 still says 'Status: Accepted' even though ADR-0011 supersedes it, which breaks the update rule in ADR-0001 and leaves two Accepted records governing services/billing-api/auth/; recommends marking ADR-0004 'Superseded by ADR-0011'.",
143
+ "Flags that hmac_verify.py reads the shared key from the environment variable BILLING_LEDGER_HMAC_KEY, which violates ADR-0007 (secrets come only from Vault agent files under /vault/secrets/, never from environment variables), even though config/settings.py follows ADR-0007 for the database and processor secrets.",
144
+ "Notes that ADR-0011 defers certificate rotation to ADR-0013, which does not exist in docs/adr/, so rotation is an unrecorded decision worth raising in the review.",
145
+ "Says the git history was not available or not checked (no commits are present to show when or whether the mTLS migration was started) and, where useful, gives the git command to run instead of inventing commit details.",
146
+ "Answers the reviewer's two questions directly near the top (how auth works and why, where secrets come from, and whether each is still agreed) before any wider map of the records, citing ADR numbers and file paths for each finding.",
147
+ "Invents nothing not in the files: no ADR numbers, dates, commits, environment variables, CA names or file paths beyond those present (ADR-0001, 0004, 0007, 0011; the reference to ADR-0013 is reported as missing, not described)."
148
+ ]
149
+ },
150
+ {
151
+ "id": 11,
152
+ "held_out": "2026-10-21",
153
+ "prompt": "adding gift_message to orders - anything already decided about the order model I should know first? 2 lines max pls",
154
+ "assertions": [
155
+ "Gives an answer of at most two lines (or two short sentences), with no extra map of all the decision records, headings or long caveats.",
156
+ "Says gift_message should go as a key in the orders.attributes JSON column (added to ORDER_ATTRIBUTE_KEYS in app/models/order.py) under DR-014, not as a new typed column with a migration.",
157
+ "Gives DR-014's exception: if gift_message will be filtered, joined, indexed or reported on, it must be a typed column instead, per DR-005.",
158
+ "Does not tell the engineer to follow DR-005's 'typed columns only, no JSON' rule as if it were the whole current position; treats DR-014 (Accepted, 2024-02-08) as having amended it.",
159
+ "If DR-016 is mentioned, describes it as only Proposed (moving attributes to an order_attributes table, not agreed) and does not present it as the current decision.",
160
+ "Answers the actual question (what was decided that affects adding this field) directly in the first line, without asking a clarifying question first.",
161
+ "Invents nothing not in the files: no decision IDs, column names, attribute keys, dates or migration numbers beyond those present (for example, no claimed existing gift_message key or a made-up migration 0013)."
162
+ ]
163
+ },
164
+ {
165
+ "id": 12,
166
+ "held_out": "2026-10-21",
167
+ "prompt": "we're handing parcelhook over to the Partner Eng team on 1 Nov. can you write me a short handover note for them: what we decided about it, what still holds, and what they should fix first. the ADRs are in docs/adr I think. keep it short, they'll read the code themselves",
168
+ "assertions": [
169
+ "Flags that ADR-0006 supersedes ADR-0003 but ADR-0003 still says 'Status: Accepted', and, from reading the code, that src/delivery/dispatcher.py still imports and calls redis_store.claim rather than pg_store.claim, so idempotency still runs on Redis (the INC-1874 duplicate risk ADR-0006 was written to remove) and pg_store.py is unused.",
170
+ "Flags that the retry behaviour no longer matches ADR-0004: config/delivery.yaml has max_attempts: 20 and base_delay_seconds: 10, retry.py uses a fixed delay (backoff turned off under the TODO for INC-2291), and after the last attempt the code calls mark_failed instead of publishing to parcelhook.dlq. It notes the risk ADR-0004 itself records, partners rate-limiting or blocking us.",
171
+ "Flags that ADR-0007 (SFTP export, src/export/sftp_export.py) is still Accepted but that file doesn't exist. The export now goes to S3 (src/export/s3_export.py, bucket corvane-parcelhook-exports in config/export.yaml) and no record covers that change.",
172
+ "Flags that ADR-0008 and ADR-0009 are both Accepted and both govern src/partners/, with neither superseding the other, and that the code (src/partners/loader.py reads the partners table every 60 seconds) follows ADR-0009. config/partners.yaml, with 2 partners, is a stale second source of truth.",
173
+ "Flags that ADR-0009 points to ADR-0011 for the admin API's auth model, and that no ADR-0011 exists in docs/adr.",
174
+ "Says which decisions still hold as written, at least ADR-0002 (delivery_attempts log) and ADR-0005 (HMAC-SHA256 over '{timestamp}.{body}' with the X-Parcelhook-Signature and X-Parcelhook-Timestamp headers), so the note covers what still holds and not only what's broken.",
175
+ "Gives a short, ordered 'fix first' list that puts the runtime risks (Redis idempotency in the dispatcher, the retry/DLQ drift) ahead of record cleanup (marking ADR-0003, ADR-0007 and ADR-0008 superseded, writing the missing S3 and ADR-0011 records). The note stays short as asked, roughly a page and not a per-file audit dump.",
176
+ "Invents nothing that isn't in the files: no commit hashes, authors, dates of implementation, incident details or partner counts beyond what the ADRs and code state. Anything that would need git history (e.g. when the dispatcher went back to Redis) is given as a command to run, such as git log on src/delivery/dispatcher.py, and not stated as fact."
177
+ ]
178
+ },
179
+ {
180
+ "id": 13,
181
+ "held_out": "2026-10-21",
182
+ "prompt": "Why is there a Redis cache in front of pricing in shopfront? Support keeps getting tickets about stale prices on the product page and I'd like to just rip it out. Is that safe, or did someone decide this for a reason?",
183
+ "assertions": [
184
+ "Answers the question directly near the top: the cache came from RFC-012 (2023-06-14) to protect the Halvorsen ERP, with its 40 requests/second limit and ~900 ms p95, and ripping it out as-is is not safe because checkout depends on it.",
185
+ "Notices from the code that RFC-012's reason no longer holds: shopfront/pricing/client.py calls pricing-svc (PRICING_SVC_URL) and there is no erp_client.py. RFC-012's own 'Revisit when' condition (the ERP rate limit no longer applying) appears to be met.",
186
+ "Points out that RFC-019 is still marked 'Proposed' although the code already does what it proposes, and that RFC-008 still says Accepted although RFC-019 supersedes it and the file it governs (shopfront/pricing/erp_client.py) is gone.",
187
+ "Identifies RFC-015 (checkout price lock, which amends RFC-012) as the dependency: shopfront/checkout/lock.py relies on the pricing cache, and price_for_charge reads from it. Removing the cache would break the 15-minute price lock unless a per-cart price snapshot replaces it first.",
188
+ "Catches the likely cause of the stale-price tickets from reading the code: lock.py calls cache.touch on the shared price:{sku} key with 900 seconds (15 * 60), so every cart entering checkout extends the cached price for every shopper on the product page. Popular SKUs can stay stale well past the 60-second TTL in config/cache.yaml.",
189
+ "Recommends a concrete path: fix or replace the checkout lock with a per-cart snapshot, then remove or shorten the cache (pricing-svc's quoted 35 ms p95 and lack of a rate limit come from a Proposed record and should be confirmed with the pricing team), and record the change in a new record that supersedes RFC-012 and updates RFC-015, RFC-019 and RFC-008.",
190
+ "Is sized for a short chat question: a few short paragraphs or a brief list, not a full decision-map report of every record.",
191
+ "Invents nothing that isn't in the files: no load-test numbers, owners, incidents, commit history or pricing-svc capacity beyond what RFC-012, RFC-015 and RFC-019 state. Anything that would need git history or the network (e.g. checking when client.py switched to pricing-svc) is given as a command to run."
192
+ ]
193
+ },
194
+ {
195
+ "id": 14,
196
+ "held_out": "2026-10-21",
197
+ "prompt": "reviewing tomas's PR #412, summary of the diff is in pr-summary.md. he says it's all in line with our RFCs (docs/rfcs/) and specifically cites RFC-0002 for the retry change. can you check which recorded decisions this actually touches or breaks? need to leave a review comment before standup so keep it tight",
198
+ "assertions": [
199
+ "Flags that the retry.ts change cites RFC-0002, which is marked superseded by RFC-0005, and that the fixed 2-second delay with 3 attempts contradicts RFC-0005's current policy (up to 4 attempts, exponential backoff with full jitter); it does not accept RFC-0002 as a valid justification.",
200
+ "Flags that removing the Idempotency-Key check and idempotencyStore calls from src/payments/charge.ts breaks RFC-0001 (accepted), noting that RFC-0001 itself says the retry layer only sees outbound processor retries and so cannot dedupe inbound client retries.",
201
+ "Notes that RFC-0006 (moving idempotency to the gateway) has status proposed, not accepted, so it cannot justify removing the charge-handler check; it does not treat RFC-0006 as current.",
202
+ "Flags that renaming amountMinor to a decimal `amount` field (e.g. 19.99) and dropping assertMinorUnits breaks RFC-0003's integer-minor-units rule for src/payments/.",
203
+ "Notes that renaming src/webhooks/sign.ts to src/webhooks/signature.ts does not change the signing decision of RFC-0004 but leaves RFC-0004's governed path and text pointing at a file that will no longer exist, and suggests updating RFC-0004 in the same PR rather than calling it a breaking change.",
204
+ "Does not claim the console.log-to-logger.info change in src/webhooks/send.ts touches any recorded decision.",
205
+ "Answers the reviewer's question directly with a short per-change verdict (breaks / touches / clean) that can be pasted as a review comment, rather than a full map of every RFC or a long essay.",
206
+ "Invents nothing not in the input: no RFC numbers beyond 0001-0006, no files, functions, thresholds or incident details that are not in pr-summary.md, docs/rfcs/ or src/."
207
+ ]
208
+ },
209
+ {
210
+ "id": 15,
211
+ "held_out": "2026-10-21",
212
+ "prompt": "I'm putting together the architecture review pack for Haulmark this Thursday and need a section on data storage. Can you go through our ADRs in doc/adr/ and give me a map of every decision we've made about where and how data is stored: what's current, what was replaced and by what, with dates. Make it something I can paste straight into the review doc (markdown is fine). If anything in the records looks off, call it out, but I mainly need the map.",
213
+ "assertions": [
214
+ "The map covers the storage-related ADRs 2, 3, 4, 6, 7, 8 and 9 with each one's status and date as recorded, and leaves out ADR 1 (recording decisions) and ADR 5 (React) or clearly marks them as not about storage.",
215
+ "Shows ADR 3 (Cassandra for telemetry, 2021-06-02) as replaced by ADR 8 (TimescaleDB, 2023-04-11), with the supersession recorded on both sides, and notes services/telemetry/store.py matches ADR 8.",
216
+ "Flags that ADR 9 says it supersedes ADR 4 (Redis sessions) but ADR 4's own Status still reads Accepted, so it is recorded on one side only; it presents ADR 4 as replaced in the map and recommends updating ADR 4's status.",
217
+ "Flags that ADR 2 (PostgreSQL for shipments) and ADR 7 (MongoDB for shipments) are both Accepted and both govern services/shipments/, and that the code (services/shipments/db.py, the JSONB custom_fields migration in migrations.sql, deploy/services.yaml) uses PostgreSQL only, so ADR 7 looks unimplemented or abandoned; it does not present MongoDB as the current shipment store.",
218
+ "Flags that ADR 6 (nightly archiving to object storage) is Accepted but names services/archiver/, which does not exist in the repository and is absent from deploy/services.yaml, so the record may no longer hold.",
219
+ "Flags that ADR 8 links to ADR 10 (telemetry retention and downsampling), which does not exist in doc/adr/.",
220
+ "Delivers the map itself as one pasteable markdown block (e.g. a table of ID, title, store, status, date, replaced by/replaces) with the issues in a short separate list, rather than a long narrative or per-file walkthrough; any check that needs git history (e.g. whether ADR 7 was ever implemented) is given as a command to run, not as a claimed result.",
221
+ "Invents nothing not in the input: no ADR numbers, dates, databases, services, sizes or commit details beyond what the files in doc/adr/, services/, deploy/ and web/ contain."
222
+ ]
223
+ }
224
+ ]
225
+ }
@@ -0,0 +1,19 @@
1
+ # 1. Record architecture decisions
2
+
3
+ Date: 2024-02-01
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
+
17
+ ## Consequences
18
+
19
+ Each decision gets a numbered file. A record that is replaced is marked "Superseded by" the new one.
@@ -0,0 +1,16 @@
1
+ ---
2
+ status: accepted
3
+ date: 2024-03-12
4
+ deciders: platform team
5
+ ---
6
+
7
+ # Use Postgres as the primary database
8
+
9
+ ## Context and Problem Statement
10
+
11
+ The API needs one relational store for accounts, orders and audit history.
12
+
13
+ ## Decision Outcome
14
+
15
+ Chosen option: "Postgres", because the team already runs it and it gives us transactions across
16
+ accounts and orders. Access goes through `services/api/db.py`.
@@ -0,0 +1,24 @@
1
+ # 3. Use Redis for session storage
2
+
3
+ Date: 2024-05-14
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ ## Context
10
+
11
+ Login sessions are held in process memory on each API node, so the load balancer has to pin a
12
+ user to one node. When we scale out or restart a node, everyone pinned to it is logged out.
13
+
14
+ ## Decision
15
+
16
+ Store sessions in Redis, keyed by a random session id held in an HttpOnly cookie. The code lives in
17
+ `services/auth/redis_sessions.py`. Sessions expire after 30 minutes of inactivity.
18
+
19
+ We chose Redis because "we already run it for the page cache, and a shared store removes sticky
20
+ sessions without adding a new system".
21
+
22
+ ## Consequences
23
+
24
+ Any API node can serve any user. Login now depends on Redis being up.
@@ -0,0 +1,15 @@
1
+ ---
2
+ status: accepted
3
+ date: 2024-07-02
4
+ ---
5
+
6
+ # Structured JSON logging
7
+
8
+ ## Context and Problem Statement
9
+
10
+ Log lines are free text and hard to search.
11
+
12
+ ## Decision Outcome
13
+
14
+ Every service logs one JSON object per line with `request_id`, `level` and `msg`. The shared
15
+ helper is `services/api/logging_setup.py`.
@@ -0,0 +1,22 @@
1
+ # 5. Session lifetime of eight hours
2
+
3
+ Date: 2024-09-23
4
+
5
+ ## Status
6
+
7
+ Accepted
8
+
9
+ Amends [ADR-0003](0003-use-redis-for-session-storage.md).
10
+
11
+ ## Context
12
+
13
+ Support staff using the back office were logged out every 30 minutes during long calls.
14
+
15
+ ## Decision
16
+
17
+ Sessions expire 8 hours after login instead of after 30 minutes of inactivity. Everything else in
18
+ ADR-0003 stands.
19
+
20
+ ## Consequences
21
+
22
+ A stolen session id is usable for longer. We accept that for now.
@@ -0,0 +1,16 @@
1
+ ---
2
+ status: rejected
3
+ date: 2025-03-18
4
+ ---
5
+
6
+ # Move sessions into Postgres
7
+
8
+ ## Context and Problem Statement
9
+
10
+ Proposed by the API team to drop Redis from the login path by keeping sessions in a Postgres table.
11
+
12
+ ## Decision Outcome
13
+
14
+ Rejected. Session reads happen on every request, and "putting that read load on the primary
15
+ database is a worse risk than the one we are trying to remove". Sessions stay as described in
16
+ ADR-0003 for now.
@@ -0,0 +1,35 @@
1
+ ---
2
+ status: accepted
3
+ date: 2025-11-04
4
+ deciders: platform team, security
5
+ ---
6
+
7
+ # Stateless signed session cookies
8
+
9
+ ## Context and Problem Statement
10
+
11
+ On 2025-08-19 a Redis failover took 40 minutes. Every user was logged out and nobody could log
12
+ back in until it recovered. Login should not depend on a shared store.
13
+
14
+ ## Considered Options
15
+
16
+ * Keep Redis and add a replica
17
+ * Sessions in Postgres (already rejected in ADR-0006)
18
+ * Signed, stateless session cookies
19
+
20
+ ## Decision Outcome
21
+
22
+ Chosen option: "Signed, stateless session cookies", because "login should depend on nothing but
23
+ the auth service and its signing key; a replica makes the outage rarer but keeps the dependency".
24
+
25
+ Supersedes [ADR-0003](0003-use-redis-for-session-storage.md). The 8-hour lifetime from ADR-0005
26
+ carries over as the cookie expiry.
27
+
28
+ The new code is `services/auth/cookie_sessions.py`. `services/auth/redis_sessions.py` is removed
29
+ once every client is on cookie sessions.
30
+
31
+ ### Consequences
32
+
33
+ * Good, because an outage of Redis no longer logs anyone out.
34
+ * Bad, because revoking a single session now needs a deny-list of session ids.
35
+ * Redis stays in use for the page cache.