skilldrop-cli 1.0.1 → 1.1.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 (262) hide show
  1. package/package.json +1 -1
  2. package/packs/core/pack.json +2 -2
  3. package/packs/{solution-architect → core}/skills/context-graph/SKILL.md +10 -4
  4. package/packs/{solution-architect → core}/skills/context-graph/evals/eval_queries.json +4 -1
  5. package/packs/{solution-architect → core}/skills/context-graph/evals/evals.json +30 -0
  6. package/packs/core/skills/context-graph/evals/files/16/README.md +4 -0
  7. package/packs/core/skills/context-graph/evals/files/16/docs/adr/0001-record-architecture-decisions.md +12 -0
  8. package/packs/core/skills/context-graph/evals/files/16/docs/adr/0002-postgres-for-the-ledger.md +11 -0
  9. package/packs/core/skills/context-graph/evals/files/16/docs/adr/0003-redis-for-ephemeral-state.md +12 -0
  10. package/packs/core/skills/context-graph/evals/files/16/docs/adr/0004-idempotency-keys-for-payment-creation.md +28 -0
  11. package/packs/core/skills/context-graph/evals/files/16/git-history.json +62 -0
  12. package/packs/core/skills/context-graph/evals/files/16/services/payments/api/create.py +7 -0
  13. package/packs/core/skills/context-graph/evals/files/16/services/payments/ledger.py +9 -0
  14. package/packs/core/skills/context-graph/evals/files/17/README.md +5 -0
  15. package/packs/core/skills/context-graph/evals/files/17/docs/adr/0001-record-architecture-decisions.md +9 -0
  16. package/packs/core/skills/context-graph/evals/files/17/docs/adr/0002-email-via-smtp-relay.md +9 -0
  17. package/packs/core/skills/context-graph/evals/files/17/docs/adr/0003-rabbitmq-for-async-messaging.md +9 -0
  18. package/packs/core/skills/context-graph/evals/files/17/docs/adr/0004-email-via-provider-api.md +11 -0
  19. package/packs/core/skills/context-graph/evals/files/17/docs/adr/0005-server-side-template-rendering.md +10 -0
  20. package/packs/core/skills/context-graph/evals/files/17/docs/adr/0006-notification-retry-backoff.md +10 -0
  21. package/packs/core/skills/context-graph/evals/files/17/docs/adr/0007-kafka-for-event-streaming.md +12 -0
  22. package/packs/core/skills/context-graph/evals/files/17/docs/rfcs/RFC-012-unified-retry-policy.md +10 -0
  23. package/packs/core/skills/context-graph/evals/files/17/packages/notification-templates/README.md +4 -0
  24. package/packs/core/skills/context-graph/evals/files/17/packages/notification-templates/invoice_issued.html +2 -0
  25. package/packs/core/skills/context-graph/evals/files/17/packages/notification-templates/welcome.html +2 -0
  26. package/packs/core/skills/context-graph/evals/files/17/services/billing/retry.py +17 -0
  27. package/packs/core/skills/context-graph/evals/files/17/services/notifications/consumer.py +18 -0
  28. package/packs/core/skills/context-graph/evals/files/17/services/notifications/dispatch.py +21 -0
  29. package/packs/core/skills/context-graph/evals/files/17/services/notifications/email/sender.py +17 -0
  30. package/packs/core/skills/context-graph/evals/files/17/services/notifications/render.py +12 -0
  31. package/packs/core/skills/context-graph/evals/files/17/services/notifications/retry.py +14 -0
  32. package/packs/core/skills/context-graph/examples/inputs/order-events/services/notifications/receipts.py +0 -0
  33. package/packs/core/skills/context-graph/examples/inputs/order-events/services/orders/publisher.py +0 -0
  34. package/packs/{solution-architect → core}/skills/context-graph/manifest.json +3 -3
  35. package/packs/{solution-architect → core}/skills/context-graph/reference.md +28 -0
  36. package/packs/{solution-architect → core}/skills/context-graph/scripts/context_graph.py +105 -5
  37. package/packs/dev-team/loops/modernize/LOOP.md +11 -1
  38. package/packs/dev-team/loops/modernize/evals/evals.json +12 -0
  39. package/packs/dev-team/loops/modernize/loop.json +3 -3
  40. package/packs/solution-architect/loops/design/LOOP.md +14 -5
  41. package/packs/solution-architect/loops/design/evals/evals.json +12 -0
  42. package/packs/solution-architect/loops/design/loop.json +5 -5
  43. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/docs/adr/0001-record-architecture-decisions.md +0 -0
  44. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/docs/adr/0002-postgres-as-primary-database.md +0 -0
  45. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/docs/adr/0003-use-redis-for-session-storage.md +0 -0
  46. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/docs/adr/0004-structured-json-logging.md +0 -0
  47. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/docs/adr/0005-session-lifetime-eight-hours.md +0 -0
  48. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/docs/adr/0006-move-sessions-to-postgres.md +0 -0
  49. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/docs/adr/0007-stateless-signed-session-cookies.md +0 -0
  50. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/services/api/__init__.py +0 -0
  51. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/services/api/db.py +0 -0
  52. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/services/api/logging_setup.py +0 -0
  53. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/services/auth/__init__.py +0 -0
  54. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/services/auth/cookie_sessions.py +0 -0
  55. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/1/services/auth/redis_sessions.py +0 -0
  56. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/10/README.md +0 -0
  57. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/10/docs/adr/0001-record-architecture-decisions.md +0 -0
  58. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/10/docs/adr/0004-service-auth-hmac-shared-keys.md +0 -0
  59. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/10/docs/adr/0007-secrets-from-vault-agent.md +0 -0
  60. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/10/docs/adr/0011-service-auth-mtls.md +0 -0
  61. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/10/services/billing-api/app.py +0 -0
  62. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/10/services/billing-api/auth/__init__.py +0 -0
  63. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/10/services/billing-api/auth/hmac_verify.py +0 -0
  64. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/10/services/billing-api/config/settings.py +0 -0
  65. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/10/services/ledger-worker/auth/__init__.py +0 -0
  66. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/10/services/ledger-worker/auth/mtls.py +0 -0
  67. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/11/README.md +0 -0
  68. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/11/app/models/base.py +0 -0
  69. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/11/app/models/line_item.py +0 -0
  70. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/11/app/models/order.py +0 -0
  71. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/11/eng/decisions/DR-003-money-as-minor-units.md +0 -0
  72. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/11/eng/decisions/DR-005-orders-typed-columns-only.md +0 -0
  73. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/11/eng/decisions/DR-009-line-items-immutable.md +0 -0
  74. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/11/eng/decisions/DR-014-optional-order-attributes-json.md +0 -0
  75. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/11/eng/decisions/DR-016-order-attributes-table.md +0 -0
  76. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/11/migrations/0007_create_orders.sql +0 -0
  77. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/11/migrations/0012_add_order_attributes.sql +0 -0
  78. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/README.md +0 -0
  79. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/config/delivery.yaml +0 -0
  80. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/config/export.yaml +0 -0
  81. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/config/partners.yaml +0 -0
  82. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/docs/adr/0001-record-architecture-decisions.md +0 -0
  83. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/docs/adr/0002-postgres-delivery-log.md +0 -0
  84. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/docs/adr/0003-redis-idempotency-keys.md +0 -0
  85. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/docs/adr/0004-retry-policy.md +0 -0
  86. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/docs/adr/0005-hmac-signed-payloads.md +0 -0
  87. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/docs/adr/0006-postgres-idempotency.md +0 -0
  88. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/docs/adr/0007-sftp-batch-export.md +0 -0
  89. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/docs/adr/0008-partner-config-in-yaml.md +0 -0
  90. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/docs/adr/0009-partner-config-admin-api.md +0 -0
  91. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/migrations/003_idempotency_keys.sql +0 -0
  92. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/migrations/004_partners.sql +0 -0
  93. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/src/delivery/dispatcher.py +0 -0
  94. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/src/delivery/retry.py +0 -0
  95. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/src/delivery/signing.py +0 -0
  96. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/src/export/s3_export.py +0 -0
  97. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/src/idempotency/pg_store.py +0 -0
  98. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/src/idempotency/redis_store.py +0 -0
  99. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/src/partners/loader.py +0 -0
  100. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/12/src/store/delivery_log.py +0 -0
  101. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/13/README.md +0 -0
  102. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/13/config/cache.yaml +0 -0
  103. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/13/config/settings.yaml +0 -0
  104. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/13/docs/decisions/RFC-008-pricing-from-erp.md +0 -0
  105. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/13/docs/decisions/RFC-012-pricing-cache.md +0 -0
  106. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/13/docs/decisions/RFC-015-checkout-price-lock.md +0 -0
  107. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/13/docs/decisions/RFC-019-pricing-service.md +0 -0
  108. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/13/shopfront/catalog/views.py +0 -0
  109. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/13/shopfront/checkout/lock.py +0 -0
  110. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/13/shopfront/pricing/cache.py +0 -0
  111. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/13/shopfront/pricing/client.py +0 -0
  112. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/docs/rfcs/0001-idempotency-keys.md +0 -0
  113. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/docs/rfcs/0002-processor-retry-policy.md +0 -0
  114. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/docs/rfcs/0003-money-in-minor-units.md +0 -0
  115. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/docs/rfcs/0004-webhook-signing.md +0 -0
  116. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/docs/rfcs/0005-retry-with-jitter.md +0 -0
  117. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/docs/rfcs/0006-idempotency-at-gateway.md +0 -0
  118. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/pr-summary.md +0 -0
  119. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/src/payments/amount.ts +0 -0
  120. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/src/payments/charge.ts +0 -0
  121. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/src/payments/idempotency.ts +0 -0
  122. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/src/payments/retry.ts +0 -0
  123. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/src/webhooks/send.ts +0 -0
  124. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/14/src/webhooks/sign.ts +0 -0
  125. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/deploy/services.yaml +0 -0
  126. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/doc/adr/0001-record-architecture-decisions.md +0 -0
  127. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/doc/adr/0002-use-postgresql-for-shipment-data.md +0 -0
  128. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/doc/adr/0003-store-vehicle-telemetry-in-cassandra.md +0 -0
  129. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/doc/adr/0004-use-redis-for-session-storage.md +0 -0
  130. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/doc/adr/0005-use-react-for-dispatcher-dashboard.md +0 -0
  131. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/doc/adr/0006-archive-delivered-shipments-to-object-storage.md +0 -0
  132. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/doc/adr/0007-move-shipment-records-to-mongodb.md +0 -0
  133. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/doc/adr/0008-store-vehicle-telemetry-in-timescaledb.md +0 -0
  134. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/doc/adr/0009-stateless-sessions-with-signed-cookies.md +0 -0
  135. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/services/api/session.py +0 -0
  136. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/services/shipments/db.py +0 -0
  137. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/services/shipments/migrations.sql +0 -0
  138. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/services/telemetry/store.py +0 -0
  139. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/15/web/dashboard/App.jsx +0 -0
  140. /package/packs/{solution-architect/skills/context-graph/evals/files/2/libs/money → core/skills/context-graph/evals/files/16/services/payments}/__init__.py +0 -0
  141. /package/packs/{solution-architect/skills/context-graph/evals/files/3/services/notifications → core/skills/context-graph/evals/files/16/services/payments/api}/__init__.py +0 -0
  142. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/docs/adr/0001-record-architecture-decisions.md +0 -0
  143. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/docs/adr/0002-rabbitmq-for-background-jobs.md +0 -0
  144. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/docs/adr/0003-thumbnail-service.md +0 -0
  145. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/docs/adr/0004-money-as-integer-minor-units.md +0 -0
  146. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/docs/adr/0005-worker-retries.md +0 -0
  147. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/docs/adr/0006-fx-amounts-with-four-decimals.md +0 -0
  148. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/docs/adr/0007-feature-flags.md +0 -0
  149. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/docs/adr/0008-retire-legacy-search.md +0 -0
  150. /package/packs/{solution-architect/skills/context-graph/evals/files/3/services/payments → core/skills/context-graph/evals/files/2/libs/money}/__init__.py +0 -0
  151. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/libs/money/amount.py +0 -0
  152. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/services/checkout/flags.py +0 -0
  153. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/services/checkout/publish.py +0 -0
  154. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/services/media/resize.py +0 -0
  155. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/2/services/worker/consumer.py +0 -0
  156. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/3/docs/rfcs/0001-how-we-write-rfcs.md +0 -0
  157. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/3/docs/rfcs/0002-payments-service-boundary.md +0 -0
  158. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/3/docs/rfcs/0003-webhook-retries-fixed-interval.md +0 -0
  159. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/3/docs/rfcs/0004-webhook-idempotency-keys.md +0 -0
  160. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/3/docs/rfcs/0005-notification-retries.md +0 -0
  161. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/3/docs/rfcs/0006-webhook-retry-backoff.md +0 -0
  162. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/3/docs/rfcs/0007-webhooks-on-the-job-queue.md +0 -0
  163. /package/packs/{solution-architect/skills/context-graph/evals/files/3/services/payments/webhooks → core/skills/context-graph/evals/files/3/services/notifications}/__init__.py +0 -0
  164. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/3/services/notifications/retry.py +0 -0
  165. /package/packs/{solution-architect/skills/context-graph/evals/files/4/src/ledgerline → core/skills/context-graph/evals/files/3/services/payments}/__init__.py +0 -0
  166. /package/packs/{solution-architect/skills/context-graph/evals/files/4/src/ledgerline/scheduler → core/skills/context-graph/evals/files/3/services/payments/webhooks}/__init__.py +0 -0
  167. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/3/services/payments/webhooks/retry.py +0 -0
  168. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/3/services/payments/webhooks/send.py +0 -0
  169. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/4/docs/adr/0001-record-architecture-decisions.md +0 -0
  170. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/4/docs/adr/0002-postgres-as-system-of-record.md +0 -0
  171. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/4/docs/adr/0004-redis-locks-for-scheduler.md +0 -0
  172. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/4/docs/adr/0007-remove-redis.md +0 -0
  173. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/4/docs/adr/0009-money-as-integer-minor-units.md +0 -0
  174. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/4/docs/onboarding.md +0 -0
  175. /package/packs/{solution-architect/skills/context-graph/examples/inputs/order-events/services/notifications/receipts.py → core/skills/context-graph/evals/files/4/src/ledgerline/__init__.py} +0 -0
  176. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/4/src/ledgerline/db/__init__.py +0 -0
  177. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/4/src/ledgerline/invoicing.py +0 -0
  178. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/4/src/ledgerline/money.py +0 -0
  179. /package/packs/{solution-architect/skills/context-graph/examples/inputs/order-events/services/orders/publisher.py → core/skills/context-graph/evals/files/4/src/ledgerline/scheduler/__init__.py} +0 -0
  180. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/4/src/ledgerline/scheduler/lock.py +0 -0
  181. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/4/src/ledgerline/scheduler/runner.py +0 -0
  182. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/5/lib/types/index.ts +0 -0
  183. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/5/rfcs/0001-service-layout.md +0 -0
  184. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/5/rfcs/0003-ingest-retry-policy.md +0 -0
  185. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/5/rfcs/0006-shared-retry-library.md +0 -0
  186. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/5/rfcs/0008-outbound-http-client.md +0 -0
  187. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/5/services/export/client.ts +0 -0
  188. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/5/services/export/retry.ts +0 -0
  189. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/5/services/ingest/client.ts +0 -0
  190. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/5/services/ingest/retry.ts +0 -0
  191. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/README.md +0 -0
  192. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/docs/adr/0001-monorepo-layout.md +0 -0
  193. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/docs/adr/0002-billing-on-postgres.md +0 -0
  194. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/docs/adr/0004-ledger-sync-nightly-batch.md +0 -0
  195. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/docs/rfcs/RFC-0003-invoice-ids.md +0 -0
  196. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/docs/rfcs/RFC-0007-invoice-ids-ulid.md +0 -0
  197. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/docs/rfcs/RFC-0009-billing-event-store.md +0 -0
  198. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/docs/rfcs/RFC-0010-revenue-service.md +0 -0
  199. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/libs/money/ulid.py +0 -0
  200. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/services/billing/src/events.py +0 -0
  201. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/services/billing/src/store.py +0 -0
  202. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/services/invoicing/ids/generator.py +0 -0
  203. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/services/ledger/README.md +0 -0
  204. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/6/services/ledger/sync.py +0 -0
  205. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/README.md +0 -0
  206. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/db/queries/orders.sql +0 -0
  207. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/db/sharding/router.py +0 -0
  208. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/design/decisions/DD-001-postgres-primary.md +0 -0
  209. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/design/decisions/DD-002-kafka-event-bus.md +0 -0
  210. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/design/decisions/DD-003-no-orm.md +0 -0
  211. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/design/decisions/DD-006-tenant-sharding.md +0 -0
  212. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/design/decisions/DD-011-orm-for-admin-console.md +0 -0
  213. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/pipelines/fanout/router.py +0 -0
  214. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/pipelines/ingest/consumer.py +0 -0
  215. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/pipelines/ingest/topics.yaml +0 -0
  216. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/rfcs/0004-region-sharding.md +0 -0
  217. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/services/admin-console/models.py +0 -0
  218. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/7/services/orders/repo.py +0 -0
  219. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/README.md +0 -0
  220. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/api/ledger.proto +0 -0
  221. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/config/http.yaml +0 -0
  222. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/config/messaging.yaml +0 -0
  223. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/docs/adr/0001-record-architecture-decisions.md +0 -0
  224. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/docs/adr/0002-postgresql-for-ledger.md +0 -0
  225. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/docs/adr/0003-rabbitmq-domain-events.md +0 -0
  226. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/docs/adr/0004-integer-minor-units.md +0 -0
  227. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/docs/adr/0005-provider-http-retries.md +0 -0
  228. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/docs/adr/0006-openapi-generated-clients.md +0 -0
  229. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/docs/adr/0007-kafka-domain-events.md +0 -0
  230. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/docs/adr/0008-structured-logging.md +0 -0
  231. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/docs/rfcs/RFC-012-idempotency-keys.md +0 -0
  232. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/services/ledger/api/idempotency.py +0 -0
  233. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/services/ledger/api/server.py +0 -0
  234. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/services/ledger/clients/provider.py +0 -0
  235. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/services/ledger/db/migrations/0001_init.sql +0 -0
  236. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/services/ledger/db/migrations/0008_idempotency_keys.sql +0 -0
  237. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/services/ledger/db/migrations/0009_fx_entries.sql +0 -0
  238. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/services/ledger/events/publisher.py +0 -0
  239. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/services/ledger/logging.py +0 -0
  240. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/8/services/ledger/models/entry.py +0 -0
  241. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/.env.example +0 -0
  242. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/README.md +0 -0
  243. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/docker-compose.yml +0 -0
  244. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/docs/decisions/001-session-storage.md +0 -0
  245. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/docs/decisions/002-api-rate-limiting.md +0 -0
  246. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/docs/decisions/003-jwt-sessions.md +0 -0
  247. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/docs/decisions/004-catalog-cache.md +0 -0
  248. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/src/catalog/cache.ts +0 -0
  249. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/src/catalog/repository.ts +0 -0
  250. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/src/jobs/email.ts +0 -0
  251. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/src/jobs/export.ts +0 -0
  252. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/src/jobs/queue.ts +0 -0
  253. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/src/jobs/worker.ts +0 -0
  254. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/src/lib/db.ts +0 -0
  255. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/src/lib/redis.ts +0 -0
  256. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/src/middleware/rateLimit.ts +0 -0
  257. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/src/server.ts +0 -0
  258. /package/packs/{solution-architect → core}/skills/context-graph/evals/files/9/src/session/store.ts +0 -0
  259. /package/packs/{solution-architect → core}/skills/context-graph/examples/inputs/order-events/docs/adr/0004-kafka-for-order-events.md +0 -0
  260. /package/packs/{solution-architect → core}/skills/context-graph/examples/inputs/order-events/docs/adr/0006-email-receipts.md +0 -0
  261. /package/packs/{solution-architect → core}/skills/context-graph/examples/inputs/order-events/docs/adr/0009-sqs-for-order-events.md +0 -0
  262. /package/packs/{solution-architect → core}/skills/context-graph/examples/order-events.md +0 -0
@@ -30,6 +30,7 @@ Every `.md` file in them, recursively, is a record, except:
30
30
  | missing paths | a path that looks like the repository's (its first part is a top-level folder that exists) but doesn't exist |
31
31
  | moved | for a missing path, an existing sibling with a close name (`services/ledger-sync` → `services/ledger`), where the code may have gone |
32
32
  | commits | with `--git`: commits whose subject or body mentions the id, newest first, up to 20 |
33
+ | drift | with `--git`, for a current record that governs a path: the commits that changed those paths since the record's date, newest first. When the record has no date, they count from when its file was first committed. Each has its author and whether it cites the record. Also gives the authors and their counts, the last change, and when the record file was last edited. Merges are left out |
33
34
 
34
35
  **Statuses, normalised:**
35
36
 
@@ -81,6 +82,11 @@ A file that isn't UTF-8 is skipped, with a note in the report.
81
82
  "date": "2025-03-02", "path": "docs/adr/0004-….md",
82
83
  "supersedes": [], "superseded_by": [], "amends": [], "cites": [], "cited_by": [],
83
84
  "governs": ["services/orders/"], "missing_paths": [], "commits": [],
85
+ "drift": {"since": "2025-03-02", "since_from": "record", "count": 3, "not_citing_record": 2,
86
+ "authors": [{"name": "Ben", "commits": 2}, {"name": "Ana", "commits": 1}],
87
+ "last_change": "2026-06-04", "record_last_edited": "2025-03-02",
88
+ "commits": [{"sha": "a1b2c3d", "date": "2026-06-04", "author": "Ben", "subject": "…",
89
+ "cites_record": false}]},
84
90
  "successors": ["ADR-0009"], "successors_only_claimed_by_successor": ["ADR-0009"],
85
91
  "moved": {"services/kafka-bridge": ["services/bridge"]}
86
92
  }],
@@ -91,9 +97,31 @@ A file that isn't UTF-8 is skipped, with a note in the report.
91
97
  }
92
98
  ```
93
99
 
100
+ `drift` is `null` without `--git`, and for a record that isn't current or governs no path.
101
+
94
102
  `successors` joins a record's own "superseded by" with every record that says it supersedes this
95
103
  one. The second list holds the ones only the newer record records.
96
104
 
105
+ ## Code changed since each decision (`--git`)
106
+
107
+ The full report gains a table of the current decisions whose governed code has changed since
108
+ they were made, most changed first:
109
+
110
+ | Column | Meaning |
111
+ |---|---|
112
+ | Decided | the record's date; `*` when it has none and the date is when the record was first committed |
113
+ | Commits since | commits to the governed paths since that date, merges left out |
114
+ | Not citing it | how many of those don't mention the record's id: the changes made without reference to it |
115
+ | By | the authors, with their counts, most first |
116
+ | Last change | the newest of those commits |
117
+ | Record last edited | the last commit to the record file itself |
118
+
119
+ `--why` adds a "Changed since" line under each current decision, and `--record` lists up to 10
120
+ of the commits. The Markdown table shows 15 rows; `--json` has them all.
121
+
122
+ A commit to a decision's code is a reason to check it, not drift by itself. Drift is a
123
+ requirement in the record that the code no longer meets.
124
+
97
125
  ## Limits
98
126
 
99
127
  - **A decision made in a ticket or a chat, and never written down, isn't in the graph.** The
@@ -3,13 +3,14 @@
3
3
 
4
4
  Reads decision records (ADRs, RFCs, design decisions) as Markdown, finds each one's id, title,
5
5
  status and date, and the edges between them: what supersedes or amends what, which records cite
6
- which, the files and folders each one governs, and, with --git, the commits that mention it.
6
+ which, the files and folders each one governs, and, with --git, the commits that mention it and
7
+ the commits that changed each current decision's code since it was made, and who made them.
7
8
  Then it checks the graph for what goes wrong as a codebase ages: a supersession only one side
8
9
  records, a current decision pointing at code that is gone, two current decisions governing the
9
10
  same path, references to records that don't exist.
10
11
 
11
12
  python3 context_graph.py # find records under ./docs, check them
12
- python3 context_graph.py --root repo --git # and the commits that mention each record
13
+ python3 context_graph.py --root repo --git # and the commits behind each record, and since it
13
14
  python3 context_graph.py --why src/auth/session.py
14
15
  python3 context_graph.py --record ADR-0004
15
16
  python3 context_graph.py --docs architecture/decisions --json -o graph.json --mermaid graph.mmd
@@ -191,7 +192,7 @@ def parse_record(path, root, text):
191
192
  rec = {"id": rid, "title": title_of(meta, body, stem.replace("-", " ")), "status": status,
192
193
  "status_text": raw_status, "date": date_of(meta, body), "path": rel,
193
194
  "supersedes": [], "superseded_by": [], "amends": [], "cites": [], "governs": [],
194
- "missing_paths": [], "commits": []}
195
+ "missing_paths": [], "commits": [], "drift": None}
195
196
  rec["supersedes"] += list_ids(meta.get("supersedes", "")) + list_ids(meta.get("replaces", ""))
196
197
  rec["superseded_by"] += list_ids(meta.get("superseded_by", "")) + list_ids(meta.get("replaced_by", ""))
197
198
  rec["amends"] += list_ids(meta.get("amends", ""))
@@ -290,6 +291,69 @@ def git_commits(root, records, limit):
290
291
  return None
291
292
 
292
293
 
294
+ def _git(root, *args):
295
+ """stdout of a git command in root, or None when git is missing or the command fails."""
296
+ try:
297
+ out = subprocess.run(["git", "-C", root, *args], capture_output=True, text=True,
298
+ encoding="utf-8", errors="replace", timeout=60)
299
+ except (OSError, subprocess.SubprocessError):
300
+ return None
301
+ return out.stdout if out.returncode == 0 else None
302
+
303
+
304
+ def git_drift(root, records, limit):
305
+ """For each current decision that governs code: the commits that changed that code since the
306
+ decision was made, who made them, and when the record itself was last edited. Code that keeps
307
+ changing under a record nobody revisits is where a decision quietly stops being true."""
308
+ for r in records:
309
+ if r["status"] not in CURRENT or r["successors"] or not r["governs"]:
310
+ continue
311
+ since, source = r["date"], "record"
312
+ if not since: # no date in the record: when the record was first committed
313
+ added = _git(root, "log", "--diff-filter=A", "--follow", "--date=short", "--format=%ad", "--", r["path"])
314
+ since, source = ((added or "").split() or [""])[-1], "git"
315
+ if not since:
316
+ r["drift"] = {"since": None, "note": "the record has no date and isn't committed, so changes since it can't be dated"}
317
+ continue
318
+ log = _git(root, "log", "--no-merges", "--since=%s 00:00" % since, "-n", str(limit), "--date=short",
319
+ "--format=%h%x1f%ad%x1f%an%x1f%s%x1f%b%x1e", "--", *[g.rstrip("/") or "." for g in r["governs"]])
320
+ commits = []
321
+ for entry in (log or "").split("\x1e"):
322
+ parts = entry.strip("\n").split("\x1f")
323
+ if len(parts) < 4:
324
+ continue
325
+ body = parts[4] if len(parts) > 4 else ""
326
+ commits.append({"sha": parts[0], "date": parts[1], "author": parts[2], "subject": parts[3][:120],
327
+ "cites_record": r["id"] in ids_in(parts[3] + "\n" + body)})
328
+ authors = {}
329
+ for c in commits:
330
+ authors[c["author"]] = authors.get(c["author"], 0) + 1
331
+ edited = (_git(root, "log", "-1", "--date=short", "--format=%ad", "--", r["path"]) or "").strip()
332
+ r["drift"] = {
333
+ "since": since, "since_from": source, "count": len(commits),
334
+ "not_citing_record": sum(1 for c in commits if not c["cites_record"]),
335
+ "authors": [{"name": n, "commits": k} for n, k in sorted(authors.items(), key=lambda x: (-x[1], x[0]))],
336
+ "last_change": commits[0]["date"] if commits else None,
337
+ "record_last_edited": edited or None,
338
+ "commits": commits[:20],
339
+ }
340
+
341
+
342
+ def drift_line(d):
343
+ """One line: '12 commits by Ana (9), Ben (3) since 2026-02-10, the last on 2026-09-30'."""
344
+ if not d or d.get("since") is None:
345
+ return (d or {}).get("note", "")
346
+ if not d["count"]:
347
+ return "no commits have changed its code since %s" % d["since"]
348
+ who = ", ".join("%s (%d)" % (a["name"], a["commits"]) for a in d["authors"][:4]) + (" …" if len(d["authors"]) > 4 else "")
349
+ cite = "" if not d["not_citing_record"] else ("; %d don't cite the record" % d["not_citing_record"]
350
+ if d["not_citing_record"] < d["count"] else "; none cites the record")
351
+ return "%d commit%s by %s since %s%s, the last on %s%s" % (
352
+ d["count"], "" if d["count"] == 1 else "s", who, d["since"],
353
+ " (when the record was committed; it has no date)" if d.get("since_from") == "git" else "",
354
+ d["last_change"], cite)
355
+
356
+
293
357
  SKIP_DIRS = {".git", "node_modules", "vendor", "dist", "build", ".venv", "venv", "__pycache__", "target"}
294
358
 
295
359
 
@@ -432,7 +496,8 @@ def why(records, path, root):
432
496
  hits.sort(key=lambda h: (0 if live(h[0]) else 1, rank.get(h[0]["status"], 2),
433
497
  -int(h[0]["date"].replace("-", "") or 0)))
434
498
  return p, [{"id": r["id"], "title": r["title"], "status": r["status"], "date": r["date"], "path": r["path"],
435
- "via": g, "superseded_by": sorted(set(succ.get(r["id"], []))), "current": live(r)} for r, g in hits]
499
+ "via": g, "superseded_by": sorted(set(succ.get(r["id"], []))), "current": live(r),
500
+ "drift": r.get("drift")} for r, g in hits]
436
501
 
437
502
 
438
503
  def mermaid(records):
@@ -479,6 +544,8 @@ def report(records, findings, note, query, dirs, root):
479
544
  state = h["status"] + (", current" if h["current"] else "")
480
545
  out.append("- **%s %s** (%s%s), via `%s`: %s" % (
481
546
  h["id"], h["title"], state, ", " + h["date"] if h["date"] else "", h["via"], h["path"]))
547
+ if h.get("drift"):
548
+ out.append(" - Changed since: %s" % drift_line(h["drift"]))
482
549
  if not cur:
483
550
  out.append("\nNone of these is current: the decisions that governed it were superseded, "
484
551
  "deprecated or never accepted.")
@@ -502,6 +569,13 @@ def report(records, findings, note, query, dirs, root):
502
569
  out.append("- %s: %s" % (label, ", ".join(r[k])))
503
570
  for c in r["commits"]:
504
571
  out.append("- Commit %s %s: %s" % (c["sha"], c["date"], c["subject"]))
572
+ if r.get("drift"):
573
+ out.append("- Code changed since the decision: %s" % drift_line(r["drift"]))
574
+ if r["drift"].get("record_last_edited"):
575
+ out.append("- Record last edited: %s" % r["drift"]["record_last_edited"])
576
+ for c in r["drift"].get("commits", [])[:10]:
577
+ out.append(" - %s %s %s: %s%s" % (c["sha"], c["date"], c["author"], c["subject"],
578
+ " (cites it)" if c["cites_record"] else ""))
505
579
  out.append("")
506
580
  counts = {}
507
581
  for r in records:
@@ -516,6 +590,28 @@ def report(records, findings, note, query, dirs, root):
516
590
  out += ["- %s %s" % (rid, msg) for _, rid, msg in probs] or ["None."]
517
591
  out.append("\n## Warnings (%d)\n" % len(warns))
518
592
  out += ["- %s %s" % (rid, msg) for _, rid, msg in warns] or ["None."]
593
+ drifted = sorted((r for r in records if r.get("drift") and r["drift"].get("count")),
594
+ key=lambda r: (-r["drift"]["count"], r["id"]))
595
+ if not query and any(r.get("drift") for r in records):
596
+ out.append("\n## Code changed since each decision\n")
597
+ if not drifted:
598
+ out.append("No commit has changed the code a current decision governs since it was made.")
599
+ else:
600
+ out.append("Current decisions whose code has changed since they were made, most changed first. "
601
+ "Each is a place to check that the code still does what the record says.\n")
602
+ out.append("| Record | Decided | Commits since | Not citing it | By | Last change | Record last edited |")
603
+ out.append("|---|---|---|---|---|---|---|")
604
+ for r in drifted[:15]:
605
+ d = r["drift"]
606
+ out.append("| %s %s | %s%s | %d | %d | %s | %s | %s |" % (
607
+ r["id"], r["title"].replace("|", "/")[:50], d["since"], "*" if d["since_from"] == "git" else "",
608
+ d["count"], d["not_citing_record"],
609
+ ", ".join("%s (%d)" % (a["name"].replace("|", "/"), a["commits"]) for a in d["authors"][:3])
610
+ + (" …" if len(d["authors"]) > 3 else ""), d["last_change"], d["record_last_edited"] or "-"))
611
+ if len(drifted) > 15:
612
+ out.append("\n…and %d more; `--json` lists them all." % (len(drifted) - 15))
613
+ if any(r["drift"]["since_from"] == "git" for r in drifted[:15]):
614
+ out.append("\n\\* The record has no date, so this counts from when it was first committed.")
519
615
  if not query:
520
616
  out.append("\n## Graph\n")
521
617
  out.append("| Record | Status | Date | Supersedes | Superseded by | Governs |")
@@ -536,7 +632,9 @@ def _main(argv=None):
536
632
  q = ap.add_mutually_exclusive_group()
537
633
  q.add_argument("--why", metavar="PATH", help="list the decisions that govern a file or folder")
538
634
  q.add_argument("--record", metavar="ID", help="show one record and its neighbours, e.g. ADR-0004")
539
- ap.add_argument("--git", action="store_true", help="also read commit messages for record ids")
635
+ ap.add_argument("--git", action="store_true",
636
+ help="also read the commits that mention each record, and those that changed each current "
637
+ "decision's code since it was made")
540
638
  ap.add_argument("--git-limit", type=int, default=5000)
541
639
  ap.add_argument("--json", action="store_true", help="print the graph as JSON instead of Markdown")
542
640
  ap.add_argument("--mermaid", metavar="FILE", help="also write a Mermaid flowchart of the graph")
@@ -579,6 +677,8 @@ def _main(argv=None):
579
677
  claimed = [o["id"] for o in records if r["id"] in o["supersedes"]]
580
678
  r["successors"] = sorted(set(r["superseded_by"]) | set(claimed))
581
679
  r["successors_only_claimed_by_successor"] = sorted(set(claimed) - set(r["superseded_by"]))
680
+ if a.git and not any("no commits were read" in n for n in notes):
681
+ git_drift(root, records, a.git_limit)
582
682
  # Guides and READMEs that still cite a superseded decision may still teach it.
583
683
  by_id = {r["id"]: r for r in records}
584
684
  docs = other_docs(root, {r["path"] for r in records})
@@ -16,7 +16,7 @@ can accept what the recordings don't cover and approve every intended change.
16
16
 
17
17
  | # | Stage | Type | Skills | Gate |
18
18
  |---|---|---|---|---|
19
- | 1 | `survey` | generate | [`codebase-tour`](../../skills/codebase-tour/SKILL.md) | — |
19
+ | 1 | `survey` | generate | [`codebase-tour`](../../skills/codebase-tour/SKILL.md), [`context-graph`](../../../core/skills/context-graph/SKILL.md) | — |
20
20
  | 2 | `plan` | generate | [`refactor-plan`](../../skills/refactor-plan/SKILL.md), [`migration-plan`](../../skills/migration-plan/SKILL.md) | — |
21
21
  | 3 | `capture` | generate | [`behaviour-equivalence`](../../skills/behaviour-equivalence/SKILL.md) | — |
22
22
  | 4 | `rebuild` | generate | [`feature-implement-loop`](../../skills/feature-implement-loop/SKILL.md) | — |
@@ -29,6 +29,15 @@ can accept what the recordings don't cover and approve every intended change.
29
29
  must end with the boundary it will be swapped at (an HTTP API, a function signature, a
30
30
  batch file, a queue) and every caller and side effect that crosses it, each cited to a
31
31
  file. A boundary nobody can name means the component isn't ready to be replaced.
32
+
33
+ Then run `context-graph` on the same component, with git history. It finds the recorded
34
+ decisions that govern it: why it was built this way, what was tried before, and the
35
+ constraints the rewrite must keep. It also finds where the code has changed since those
36
+ decisions were made, and who changed it. Carry every constraint a current decision sets
37
+ into `plan`. A behaviour the old code has that contradicts its decision is a question for
38
+ the owner before `capture`: record it as it is, and ask whether the rewrite should keep it.
39
+ Each person who changed the code since the decision is worth asking what the records don't
40
+ say.
32
41
  2. **Plan the work.**
33
42
  - Restructuring the code in place → `refactor-plan`.
34
43
  - Moving data, a schema or a platform → `migration-plan`.
@@ -122,3 +131,4 @@ The log holds verdicts only: never recordings, code or data.
122
131
  - ❌ **Rebuilding everything, then comparing once.** Each planned step merges on its own and is compared again.
123
132
  - ❌ **Calling the migration done at G10.** Equivalence on the recordings is evidence; the cutover is a person's decision, with a rollback.
124
133
  - ❌ **Skipping `survey` because the old code is "well known".** The callers and side effects nobody remembers are the ones that break.
134
+ - ❌ **Rewriting without reading the decisions behind the old code.** A constraint someone recorded years ago, such as a retention period or an ordering guarantee, is easy to drop in a rewrite and expensive to rediscover in production.
@@ -22,6 +22,18 @@
22
22
  "Says a new or wider normalisation rule is a return to capture, not a fix",
23
23
  "Counts the return under the cap of 3"
24
24
  ]
25
+ },
26
+ {
27
+ "id": "survey-reads-the-recorded-decisions",
28
+ "prompt": "Run the modernize loop. We're replacing services/billing (a Python 2 batch job) with a Go service. The repo has ADRs under docs/adr.",
29
+ "assertions": [
30
+ "Surveys the boundary and every caller and side effect that crosses it, each cited to a file, before planning",
31
+ "Reads the ADRs that govern services/billing and names the current one by id, status and date",
32
+ "Carries each constraint the current decision sets into the plan",
33
+ "Says where the code has changed since the decision was made, from the git history, and who changed it, or says git history wasn't available",
34
+ "Treats a behaviour that contradicts the recorded decision as a question for the owner before capture, not as something to fix silently in the rewrite",
35
+ "Does not invent decisions, ids, commits or people that are not in the repository"
36
+ ]
25
37
  }
26
38
  ]
27
39
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$comment": "RFC-0057. A legacy component replaced without changing what it does. The old system's behaviour is recorded before anything is rebuilt, a script decides G10 from the recordings, and a person decides the cutover, because only they can accept the coverage and the listed changes.",
3
3
  "name": "modernize",
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "description": "Replace or rewrite a legacy component without changing what it does: orient in the old code, plan the restructuring and the move, record the old system's behaviour before anything is rebuilt, rebuild in small steps, prove the new one gives the same results on the recordings, and cut over only when a person accepts the evidence. Use when the user is migrating, rewriting or porting a legacy service, batch job or module (COBOL to Java, Python 2 to 3, a monolith to a service, one framework to another), says \"run the modernize loop\", or asks how to replace old code without breaking what depends on it.",
6
6
  "entrypoint": "LOOP.md",
7
7
  "kind": "loop",
@@ -10,8 +10,8 @@
10
10
  {
11
11
  "id": "survey",
12
12
  "type": "generate",
13
- "intent": "Find the boundary the component is replaced at, what crosses it, who calls it, and the traps in the old code, each cited to a file.",
14
- "skills": ["codebase-tour"]
13
+ "intent": "Find the boundary the component is replaced at, what crosses it, who calls it, and the traps in the old code, each cited to a file; then the recorded decisions that govern it, and which of them the code has drifted from.",
14
+ "skills": ["codebase-tour", "context-graph"]
15
15
  },
16
16
  {
17
17
  "id": "plan",
@@ -14,16 +14,19 @@ a script, and why the decision is recorded only *after* the panel agrees.
14
14
 
15
15
  | # | Stage | Type | Skills | Gate |
16
16
  |---|---|---|---|---|
17
- | 1 | `constrain` | generate | [`nfr-spec`](../../skills/nfr-spec/SKILL.md) | — |
17
+ | 1 | `constrain` | generate | [`context-graph`](../../../core/skills/context-graph/SKILL.md), [`nfr-spec`](../../skills/nfr-spec/SKILL.md) | — |
18
18
  | 2 | `shape` | generate | [`design-doc`](../../skills/design-doc/SKILL.md), [`architecture-diagrams`](../../skills/architecture-diagrams/SKILL.md) | — |
19
19
  | 3 | `threat` | verify | [`threat-model`](../../skills/threat-model/SKILL.md) | — |
20
20
  | 4 | `ratify` | gate | [`council-review`](../../../core/skills/council-review/SKILL.md) | **G1** review |
21
- | 5 | `record` | generate | [`adr-generator`](../../skills/adr-generator/SKILL.md) | — |
21
+ | 5 | `record` | generate | [`adr-generator`](../../skills/adr-generator/SKILL.md), [`context-graph`](../../../core/skills/context-graph/SKILL.md) | — |
22
22
 
23
23
  ## How to run this loop
24
24
 
25
- 1. **Constrain before shaping.** `nfr-spec` first, always. A design produced before its
26
- quality targets exist gets judged on taste, and taste does not survive a review panel.
25
+ 1. **Constrain before shaping.** First run `context-graph` where the design will land. List the
26
+ decisions already in force there, each by id, and any the code has drifted from. A new
27
+ design either keeps each one or says which it supersedes; when the repo has no records,
28
+ say so. Then run `nfr-spec`, always. A design produced before its quality targets exist
29
+ gets judged on taste, and taste does not survive a review panel.
27
30
  2. **Shape prose and picture together.** `design-doc` and `architecture-diagrams` are one
28
31
  artifact in two renderings. A diagram that disagrees with the doc is a defect in both.
29
32
  3. **Attack it before ratifying.** `threat-model` consumes the design directly. Running it
@@ -33,7 +36,10 @@ a script, and why the decision is recorded only *after* the panel agrees.
33
36
  `REVISE` returns to `shape`. `SPLIT` and `RECONSIDER` leave the loop.
34
37
  5. **Record last.** `adr-generator` writes the decision *after* it is a decision, with the
35
38
  rejected options and the reasoning that killed them. An ADR written before G1 is a proposal
36
- wearing an ADR's clothes.
39
+ wearing an ADR's clothes. Then run `context-graph` again. Every record the new ADR
40
+ supersedes must now say "Superseded by" it, and the new ADR must name the code it governs.
41
+ A supersession recorded on one side only is the most common way a decision log starts to
42
+ lie.
37
43
 
38
44
  ## Verdicts
39
45
 
@@ -74,10 +80,13 @@ which end in `BLOCKED`.
74
80
  - **The ADR names what was rejected and why.** A decision record with one option is a description of what happened, not a decision.
75
81
  - **Dissent is recorded, not resolved away.** A panel that always reaches consensus is not seating real positions.
76
82
  - **The diagram and the doc say the same thing.** They are checked against each other before G1, not after someone builds from the wrong one.
83
+ - **The design names the decisions already in force where it lands,** and which of them it keeps or supersedes.
84
+ - **After `record`, the records agree with each other:** each record the new ADR supersedes says so too.
77
85
 
78
86
  ## Anti-patterns to avoid
79
87
 
80
88
  - ❌ **Writing the ADR before G1.** It pre-commits the panel to a decision it has not made, and every reviewer can feel it.
81
89
  - ❌ **Running `threat-model` after ratification.** The panel then ratified an unattacked design, which is the failure this ordering exists to prevent.
82
90
  - ❌ **Treating `PROCEED WITH CONDITIONS` as `PROCEED`.** The conditions must reach the ADR; dropping them is how a conditional approval silently becomes unconditional.
91
+ - ❌ **Designing over a decision nobody read.** A new design that quietly contradicts a current ADR leaves two decisions in force on one system, and the next reader can't tell which one wins.
83
92
  - ❌ **Skipping `constrain` because the NFRs are "obvious".** Obvious targets are the ones nobody writes down and everybody remembers differently.
@@ -21,6 +21,18 @@
21
21
  "Carries the named condition into the ADR as part of the decision",
22
22
  "Proceeds to `record` rather than looping back to `shape`"
23
23
  ]
24
+ },
25
+ {
26
+ "id": "reads-existing-decisions-and-closes-the-supersession",
27
+ "prompt": "Run the design loop for moving order events from Kafka to SQS. The repo has ADRs under docs/adr, and ADR-0004 chose Kafka.",
28
+ "assertions": [
29
+ "Before setting targets, lists the decisions already in force for order events by id, including ADR-0004",
30
+ "States whether the new design keeps or supersedes each of those decisions",
31
+ "Runs nfr-spec and expresses targets as numbers, not adjectives",
32
+ "Writes the ADR only after G1, and the new ADR says it supersedes ADR-0004",
33
+ "After writing the ADR, checks that ADR-0004 is marked superseded by the new record, and gives the exact edit when it isn't",
34
+ "Does not invent records, ids or dates that are not in the repository"
35
+ ]
24
36
  }
25
37
  ]
26
38
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$comment": "RFC-0028. The loop with the worst reversibility profile: a design mistake surfaces months later in code nobody wants to unwind. That is why its gate is a panel, not a script.",
3
3
  "name": "design",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "description": "Take a ratified requirement to a recorded architectural decision — constraints, structure, diagrams, threats, then a panel that must agree before the decision is written down. Use when the user is designing a system, choosing an architecture, or asking how something should be built.",
6
6
  "entrypoint": "LOOP.md",
7
7
  "kind": "loop",
@@ -10,8 +10,8 @@
10
10
  {
11
11
  "id": "constrain",
12
12
  "type": "generate",
13
- "intent": "Name the quality targets before the structure, so the design is judged against numbers rather than taste.",
14
- "skills": ["nfr-spec"]
13
+ "intent": "Read the decisions already in force where the design will land, then name the quality targets before the structure, so the design is judged against numbers and the existing decisions rather than taste.",
14
+ "skills": ["context-graph", "nfr-spec"]
15
15
  },
16
16
  {
17
17
  "id": "shape",
@@ -40,8 +40,8 @@
40
40
  {
41
41
  "id": "record",
42
42
  "type": "generate",
43
- "intent": "Write the decision down with its rejected alternatives, so the next team inherits the reasoning and not just the outcome.",
44
- "skills": ["adr-generator"]
43
+ "intent": "Write the decision down with its rejected alternatives, so the next team inherits the reasoning and not just the outcome, then check the records still agree with each other.",
44
+ "skills": ["adr-generator", "context-graph"]
45
45
  }
46
46
  ]
47
47
  }