skilldrop-cli 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/catalogue.json +4 -4
- package/model-routing.json +62 -70
- package/package.json +1 -1
- package/packs/ai-engineering/loops/adopt/LOOP.md +120 -0
- package/packs/ai-engineering/loops/adopt/evals/eval_queries.json +10 -0
- package/packs/ai-engineering/loops/adopt/evals/evals.json +69 -0
- package/packs/ai-engineering/loops/adopt/evals/files/adopt-first-wave-to-sign-off/ai-ideas.md +15 -0
- package/packs/ai-engineering/loops/adopt/evals/files/adopt-first-wave-to-sign-off/org-context.md +27 -0
- package/packs/ai-engineering/loops/adopt/evals/files/adopt-first-wave-to-sign-off/staff-survey.csv +11 -0
- package/packs/ai-engineering/loops/adopt/evals/files/adopt-sponsor-slice-blocked-by-client-data/ai-ideas.md +13 -0
- package/packs/ai-engineering/loops/adopt/evals/files/adopt-sponsor-slice-blocked-by-client-data/firm-context.md +23 -0
- package/packs/ai-engineering/loops/adopt/loop.json +53 -0
- package/packs/ai-engineering/loops/ship-agent/LOOP.md +128 -0
- package/packs/ai-engineering/loops/ship-agent/evals/eval_queries.json +10 -0
- package/packs/ai-engineering/loops/ship-agent/evals/evals.json +70 -0
- package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-auto-reply-exfil-open/agent-brief.md +33 -0
- package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-changelog-config-reopens-path/agent-brief.md +33 -0
- package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-changelog-config-reopens-path/claude-settings.json +25 -0
- package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-changelog-config-reopens-path/sample-merged-prs.md +30 -0
- package/packs/ai-engineering/loops/ship-agent/loop.json +53 -0
- package/packs/ai-engineering/skills/agent-adoption-stage/SKILL.md +0 -1
- package/packs/ai-engineering/skills/agent-adoption-stage/manifest.json +3 -4
- package/packs/ai-engineering/skills/ai-adoption-rollout/SKILL.md +0 -1
- package/packs/ai-engineering/skills/ai-adoption-rollout/manifest.json +3 -4
- package/packs/ai-engineering/skills/ai-readiness-assessment/SKILL.md +0 -1
- package/packs/ai-engineering/skills/ai-readiness-assessment/manifest.json +1 -2
- package/packs/ai-engineering/skills/ai-use-case-triage/manifest.json +3 -3
- package/packs/ai-engineering/skills/judge-audit/SKILL.md +1 -2
- package/packs/ai-engineering/skills/judge-audit/manifest.json +1 -2
- package/packs/ai-engineering/skills/llm-eval-harness/SKILL.md +1 -2
- package/packs/ai-engineering/skills/llm-eval-harness/manifest.json +3 -3
- package/packs/api-builder/skills/tool-use-schema-writer/manifest.json +2 -2
- package/packs/career/loops/apply/evals/evals.json +28 -0
- package/packs/career/loops/apply/evals/files/apply-candidate-decided-full-run/application-form.md +10 -0
- package/packs/career/loops/apply/evals/files/apply-candidate-decided-full-run/job-posting.md +33 -0
- package/packs/career/loops/apply/evals/files/apply-candidate-decided-full-run/resume.md +34 -0
- package/packs/career/loops/apply/evals/files/apply-fit-gate-hard-requirement/cv.md +27 -0
- package/packs/career/loops/apply/evals/files/apply-fit-gate-hard-requirement/warehouse-supervisor.md +30 -0
- package/packs/career/skills/application-form-answers/manifest.json +3 -3
- package/packs/career/skills/cover-letter/manifest.json +3 -3
- package/packs/career/skills/resume-tailor/manifest.json +3 -3
- package/packs/converters/skills/md-to-docx/manifest.json +3 -3
- package/packs/core/loops/ship-a-draft/evals/evals.json +28 -0
- package/packs/core/loops/ship-a-draft/evals/files/ship-a-draft-adr-from-thread/slack-thread.txt +47 -0
- package/packs/core/loops/ship-a-draft/evals/files/ship-a-draft-announcement-unsettled/ticket-PRD-412.md +44 -0
- package/packs/core/skills/output-hygiene/manifest.json +3 -3
- package/packs/data-analytics/loops/measure/evals/evals.json +30 -0
- package/packs/data-analytics/loops/measure/evals/files/measure-active-customers-dispute/schema.md +43 -0
- package/packs/data-analytics/loops/measure/evals/files/measure-active-customers-dispute/sql/finance_active_customers.sql +7 -0
- package/packs/data-analytics/loops/measure/evals/files/measure-active-customers-dispute/sql/growth_active_customers.sql +9 -0
- package/packs/data-analytics/loops/measure/evals/files/measure-active-customers-dispute/thread.md +30 -0
- package/packs/data-analytics/loops/measure/evals/files/measure-retention-dashboard/request.md +34 -0
- package/packs/data-analytics/loops/measure/evals/files/measure-retention-dashboard/schema.md +58 -0
- package/packs/data-analytics/loops/measure/evals/files/measure-retention-dashboard/sql/active_subscribers.sql +17 -0
- package/packs/data-analytics/loops/measure/evals/files/measure-retention-dashboard/sql/net_revenue_by_plan.sql +15 -0
- package/packs/data-analytics/loops/measure/evals/files/measure-retention-dashboard/sql/weekly_churn_rate.sql +34 -0
- package/packs/data-analytics/skills/dashboard-spec/SKILL.md +0 -1
- package/packs/data-analytics/skills/dashboard-spec/manifest.json +1 -2
- package/packs/design/skills/slide-outliner/manifest.json +2 -2
- package/packs/dev-team/loops/build/evals/evals.json +28 -0
- package/packs/dev-team/loops/build/evals/files/build-promo-codes/.github/workflows/ci.yml.fixture +19 -0
- package/packs/dev-team/loops/build/evals/files/build-promo-codes/cartcalc/__init__.py +4 -0
- package/packs/dev-team/loops/build/evals/files/build-promo-codes/cartcalc/pricing.py +47 -0
- package/packs/dev-team/loops/build/evals/files/build-promo-codes/pyproject.toml.fixture +9 -0
- package/packs/dev-team/loops/build/evals/files/build-promo-codes/story.md +61 -0
- package/packs/dev-team/loops/build/evals/files/build-promo-codes/tests/__init__.py +0 -0
- package/packs/dev-team/loops/build/evals/files/build-promo-codes/tests/test_pricing.py +49 -0
- package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/.github/workflows/ci.yml.fixture +19 -0
- package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/bug-report.md +25 -0
- package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/pr-description.md +42 -0
- package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/pyproject.toml.fixture +9 -0
- package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/ratelimit/__init__.py +4 -0
- package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/ratelimit/bucket.py +49 -0
- package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/tests/__init__.py +0 -0
- package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/tests/test_bucket.py +63 -0
- package/packs/dev-team/loops/modernize/evals/evals.json +30 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/.github/workflows/ci.yml.fixture +11 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/README.md +17 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/docs/adr/0004-late-fee-calculation.md +25 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/legacy/feecalc.py +74 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/samples/accounts_2026-10.txt +10 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/samples/accounts_edge.txt +11 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/tests/test_feecalc_smoke.py +21 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/.github/workflows/ci.yml.fixture +11 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/PR-412.md +24 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/README.md +17 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/docs/adr/0004-late-fee-calculation.md +25 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/hartwell_fees/__init__.py +1 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/hartwell_fees/cli.py +33 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/hartwell_fees/extract.py +33 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/hartwell_fees/rules.py +39 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/legacy/feecalc.py +74 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/samples/accounts_2026-10.txt +10 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/samples/accounts_edge.txt +11 -0
- package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/tests/test_feecalc_smoke.py +21 -0
- package/packs/dev-team/loops/release/evals/eval_queries.json +10 -0
- package/packs/dev-team/loops/release/evals/evals.json +34 -0
- package/packs/dev-team/loops/release/evals/files/release-irreversible-tomorrow/0061_switch_to_haldrin_tokens.sql +22 -0
- package/packs/dev-team/loops/release/evals/files/release-irreversible-tomorrow/eng-notes.md +40 -0
- package/packs/dev-team/loops/release/evals/files/release-irreversible-tomorrow/merged-prs.md +13 -0
- package/packs/dev-team/loops/release/evals/files/release-saved-searches/merged-prs.md +13 -0
- package/packs/dev-team/loops/release/evals/files/release-saved-searches/readiness-evidence.md +27 -0
- package/packs/dev-team/loops/release/evals/files/release-saved-searches/traffic-baseline.md +23 -0
- package/packs/dev-team/skills/feature-implement-loop/manifest.json +2 -2
- package/packs/dev-team/skills/pr-description-writer/manifest.json +3 -3
- package/packs/dev-team/skills/pre-merge-review/manifest.json +2 -2
- package/packs/dev-team/skills/release-notes/manifest.json +2 -2
- package/packs/dev-team/skills/test-plan-generator/manifest.json +2 -2
- package/packs/experience-design/loops/clarify/LOOP.md +114 -0
- package/packs/experience-design/loops/clarify/evals/eval_queries.json +10 -0
- package/packs/experience-design/loops/clarify/evals/evals.json +68 -0
- package/packs/experience-design/loops/clarify/evals/files/clarify-garden-waste-no-complaint-data/form-fields.csv +12 -0
- package/packs/experience-design/loops/clarify/evals/files/clarify-garden-waste-no-complaint-data/garden-waste-page.md +29 -0
- package/packs/experience-design/loops/clarify/evals/files/clarify-parking-permit-with-call-data/backoffice-notes.md +14 -0
- package/packs/experience-design/loops/clarify/evals/files/clarify-parking-permit-with-call-data/calls-q3.csv +8 -0
- package/packs/experience-design/loops/clarify/evals/files/clarify-parking-permit-with-call-data/form-fields.csv +12 -0
- package/packs/experience-design/loops/clarify/evals/files/clarify-parking-permit-with-call-data/permit-page.md +27 -0
- package/packs/experience-design/loops/clarify/loop.json +35 -0
- package/packs/experience-design/skills/service-blueprint/manifest.json +3 -3
- package/packs/experience-design/skills/ux-writing/manifest.json +3 -3
- package/packs/grc/loops/comply/evals/evals.json +29 -0
- package/packs/grc/loops/comply/evals/files/comply-chat-vendor-launch/vendor-brief.md +72 -0
- package/packs/grc/loops/comply/evals/files/comply-loyalty-app-unowned-risks/launch-note.md +31 -0
- package/packs/grc/loops/comply/evals/files/comply-loyalty-app-unowned-risks/risk-register.csv +6 -0
- package/packs/infra-as-code/loops/provision/LOOP.md +128 -0
- package/packs/infra-as-code/loops/provision/evals/eval_queries.json +9 -0
- package/packs/infra-as-code/loops/provision/evals/evals.json +67 -0
- package/packs/infra-as-code/loops/provision/evals/files/provision-rds-no-plan-yet/.terraform.lock.hcl.fixture +24 -0
- package/packs/infra-as-code/loops/provision/evals/files/provision-rds-no-plan-yet/network.md +36 -0
- package/packs/infra-as-code/loops/provision/evals/files/provision-replica-plan-replaces-primary/main.tf +74 -0
- package/packs/infra-as-code/loops/provision/evals/files/provision-replica-plan-replaces-primary/plan.json +901 -0
- package/packs/infra-as-code/loops/provision/evals/files/provision-replica-plan-replaces-primary/variables.tf +47 -0
- package/packs/infra-as-code/loops/provision/loop.json +41 -0
- package/packs/infra-as-code/skills/terraform-module/manifest.json +3 -3
- package/packs/product-manager/loops/discover/evals/evals.json +28 -0
- package/packs/product-manager/loops/discover/evals/files/discover-no-show-signal/interview-notes.md +63 -0
- package/packs/product-manager/loops/discover/evals/files/discover-no-show-signal/support-tickets.csv +13 -0
- package/packs/product-manager/loops/discover/evals/files/discover-vp-loyalty-no-evidence/vp-message.txt +13 -0
- package/packs/product-manager/skills/user-journey-map/manifest.json +2 -2
- package/packs/research/loops/research/evals/evals.json +28 -0
- package/packs/research/loops/research/evals/files/research-ticket-spike-confounded/sources/t1-ticket-volume.md +15 -0
- package/packs/research/loops/research/evals/files/research-ticket-spike-confounded/sources/t2-release-notes-4-2.md +11 -0
- package/packs/research/loops/research/evals/files/research-ticket-spike-confounded/sources/t3-billing-migration.md +12 -0
- package/packs/research/loops/research/evals/files/research-ticket-spike-confounded/sources/t4-agent-poll.md +11 -0
- package/packs/research/loops/research/evals/files/research-ticket-spike-confounded/sources/t5-app-store-reviews.md +12 -0
- package/packs/research/loops/research/evals/files/research-trial-conversion-drop/sources/s1-analytics-export.md +29 -0
- package/packs/research/loops/research/evals/files/research-trial-conversion-drop/sources/s2-email-delivery-report.md +25 -0
- package/packs/research/loops/research/evals/files/research-trial-conversion-drop/sources/s3-pricing-changelog.md +9 -0
- package/packs/research/loops/research/evals/files/research-trial-conversion-drop/sources/s4-trial-interview-notes.md +21 -0
- package/packs/research/loops/research/evals/files/research-trial-conversion-drop/sources/s5-competitor-note.md +9 -0
- package/packs/research/loops/research/evals/files/research-trial-conversion-drop/sources/s6-weekly-growth-recap.md +7 -0
- package/packs/research/skills/research-plan/manifest.json +3 -3
- package/packs/research/skills/source-synthesis/manifest.json +3 -3
- package/packs/skill-engineering/skills/skill-author/manifest.json +3 -3
- package/packs/solution-architect/loops/design/evals/evals.json +28 -0
- package/packs/solution-architect/loops/design/evals/files/design-bulk-export/adr/0001-postgres-system-of-record.md +23 -0
- package/packs/solution-architect/loops/design/evals/files/design-bulk-export/adr/0002-background-work-via-job-queue.md +23 -0
- package/packs/solution-architect/loops/design/evals/files/design-bulk-export/adr/0003-tenant-isolation-row-level.md +25 -0
- package/packs/solution-architect/loops/design/evals/files/design-bulk-export/prd-bulk-export.md +50 -0
- package/packs/solution-architect/loops/design/evals/files/design-draft-prd-webhooks/adr/0002-background-work-via-job-queue.md +23 -0
- package/packs/solution-architect/loops/design/evals/files/design-draft-prd-webhooks/adr/0004-new-stateful-infra-needs-platform-signoff.md +22 -0
- package/packs/solution-architect/loops/design/evals/files/design-draft-prd-webhooks/prd-partner-webhooks.md +36 -0
- package/packs/solution-architect/skills/api-contract-draft/manifest.json +3 -3
- package/packs/solution-architect/skills/architecture-diagrams/manifest.json +3 -3
- package/packs/solution-architect/skills/design-doc/manifest.json +2 -2
- package/packs/solution-architect/skills/figma-diagrams/manifest.json +3 -3
- package/packs/sre-oncall/loops/operate/evals/evals.json +28 -0
- package/packs/sre-oncall/loops/operate/evals/files/operate-export-service-first-outage/alerts.log +22 -0
- package/packs/sre-oncall/loops/operate/evals/files/operate-export-service-first-outage/incident-chat.txt +27 -0
- package/packs/sre-oncall/loops/operate/evals/files/operate-export-service-first-outage/service-notes.md +46 -0
- package/packs/sre-oncall/loops/operate/evals/files/operate-incident-still-open/oncall-log.txt +17 -0
- package/packs/sre-oncall/loops/operate/evals/files/operate-incident-still-open/runbook-webhooks.md +38 -0
- package/packs/sre-oncall/skills/cloud-cost-review/SKILL.md +0 -1
- package/packs/sre-oncall/skills/cloud-cost-review/manifest.json +1 -2
- package/packs/sre-oncall/skills/delivery-metrics-report/SKILL.md +0 -1
- package/packs/sre-oncall/skills/delivery-metrics-report/manifest.json +1 -2
- package/packs/sre-oncall/skills/incident-comms/manifest.json +2 -2
- package/packs/sre-oncall/skills/postmortem-generator/manifest.json +2 -2
- package/packs/stakeholder-comms/skills/decision-log/manifest.json +2 -2
- package/packs/trackers/skills/team-status-report/manifest.json +3 -3
- package/packs/ai-engineering/skills/ai-usage-report/SKILL.md +0 -111
- package/packs/ai-engineering/skills/ai-usage-report/evals/eval_queries.json +0 -30
- package/packs/ai-engineering/skills/ai-usage-report/evals/evals.json +0 -46
- package/packs/ai-engineering/skills/ai-usage-report/evals/files/1/northwind-ai-events.csv +0 -4213
- package/packs/ai-engineering/skills/ai-usage-report/evals/files/2/draftwell-events.csv +0 -249
- package/packs/ai-engineering/skills/ai-usage-report/evals/files/2/export-note.md +0 -9
- package/packs/ai-engineering/skills/ai-usage-report/evals/files/2/published-assets.csv +0 -44
- package/packs/ai-engineering/skills/ai-usage-report/evals/files/2/team-roster.md +0 -10
- package/packs/ai-engineering/skills/ai-usage-report/examples/weekly-engineering-team.md +0 -133
- package/packs/ai-engineering/skills/ai-usage-report/manifest.json +0 -12
- package/packs/ai-engineering/skills/ai-usage-report/scripts/build_report.py +0 -453
- package/packs/ai-engineering/skills/ai-usage-report/templates/report-per-user.md +0 -42
- package/packs/ai-engineering/skills/ai-usage-report/templates/report-team-rollup.md +0 -49
- package/packs/ai-engineering/skills/ai-usage-report/templates/usage-event-schema.md +0 -76
- package/packs/product-manager/skills/lean-canvas/SKILL.md +0 -162
- package/packs/product-manager/skills/lean-canvas/evals/eval_queries.json +0 -42
- package/packs/product-manager/skills/lean-canvas/evals/evals.json +0 -82
- package/packs/product-manager/skills/lean-canvas/evals/files/1/pawpass-notes.md +0 -54
- package/packs/product-manager/skills/lean-canvas/evals/files/3/lunchloop-pitch.md +0 -30
- package/packs/product-manager/skills/lean-canvas/evals/files/4/clubkit-notes.md +0 -44
- package/packs/product-manager/skills/lean-canvas/evals/files/5/cost-model.csv +0 -5
- package/packs/product-manager/skills/lean-canvas/evals/files/5/proposal.md +0 -40
- package/packs/product-manager/skills/lean-canvas/evals/files/5/stakeholder-emails.txt +0 -18
- package/packs/product-manager/skills/lean-canvas/examples/bike-repair.md +0 -72
- package/packs/product-manager/skills/lean-canvas/manifest.json +0 -34
- package/packs/product-manager/skills/lean-canvas/reference.md +0 -102
- package/packs/product-manager/skills/lean-canvas/scripts/unit_economics.py +0 -211
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# ADR-0003: Tenant isolation by row-level security
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2024-09-19
|
|
5
|
+
- Deciders: Platform team, Security
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
All tenants share one database. A missed `WHERE tenant_id = ?` in application code leaked one tenant's customer list to another in a staging test (no production impact).
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
Every tenant-owned table has a PostgreSQL row-level security policy on `tenant_id`. Each connection sets `app.tenant_id` at the start of a request or job, and queries run as the `app_tenant` role, which cannot bypass RLS. Background jobs must set the tenant from the job payload, never from a default.
|
|
14
|
+
|
|
15
|
+
## Consequences
|
|
16
|
+
|
|
17
|
+
- Code that runs outside a request (jobs, scripts) is responsible for setting the tenant before any query.
|
|
18
|
+
- Cross-tenant work (admin tooling) uses a separate audited role.
|
|
19
|
+
- Files produced from tenant data must be stored under a tenant-scoped prefix.
|
|
20
|
+
|
|
21
|
+
## Governs
|
|
22
|
+
|
|
23
|
+
- `services/billing-api/db/policies/`
|
|
24
|
+
- `services/jobs-worker/tenant_context.py`
|
|
25
|
+
- `infra/object-storage/`
|
package/packs/solution-architect/loops/design/evals/files/design-bulk-export/prd-bulk-export.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# PRD: Bulk invoice export (CSV)
|
|
2
|
+
|
|
3
|
+
- **Product:** Ledgerline
|
|
4
|
+
- **Author:** Ines Moreau (PM, Billing)
|
|
5
|
+
- **Status:** Ratified — product review, 28 Oct 2026 (approvers: Ines Moreau, Kwame Asante (Eng Manager, Billing), Lotte Jansen (Head of Finance Ops))
|
|
6
|
+
- **Tracking:** LDG-2210
|
|
7
|
+
|
|
8
|
+
## Problem
|
|
9
|
+
|
|
10
|
+
Finance admins at our larger tenants reconcile invoices in their own accounting tools at month end. Today the only way to get invoice data out of Ledgerline is the invoice list page, which pages 100 rows at a time, or a support ticket asking us to run a query. In September 2026 support handled 61 export requests from 23 tenants; median time to fulfil was 2.5 working days. Finance admins at three tenants told us in calls that month-end close slips because they wait on us.
|
|
11
|
+
|
|
12
|
+
## Goals
|
|
13
|
+
|
|
14
|
+
| Goal | Success line |
|
|
15
|
+
|---|---|
|
|
16
|
+
| G1. A finance admin can get all of their tenant's invoices for a date range without contacting support | Export-related support tickets fall from 61/month to under 10/month within two months of launch |
|
|
17
|
+
| G2. Exports are fast enough to use during month-end close | 95% of exports are ready to download within 15 minutes of the request |
|
|
18
|
+
|
|
19
|
+
## Users
|
|
20
|
+
|
|
21
|
+
- **Finance Admin** role only. Other roles (Member, Viewer, Billing Contact) must not see or use the feature.
|
|
22
|
+
|
|
23
|
+
## Requirements
|
|
24
|
+
|
|
25
|
+
| ID | Priority | Requirement |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| R1 | Must | A Finance Admin can request a CSV export of invoices filtered by issue-date range (max 24 months) and status (any combination of draft, open, paid, void). |
|
|
28
|
+
| R2 | Must | One export can contain up to 2,000,000 rows. Our largest tenant today has 1.6M invoices. |
|
|
29
|
+
| R3 | Must | The requester is notified in-app and by email when the export is ready, with a download link. |
|
|
30
|
+
| R4 | Must | The download link works for 24 hours and only for the user who requested it. |
|
|
31
|
+
| R5 | Must | Export files are deleted 7 days after creation. |
|
|
32
|
+
| R6 | Must | Columns: invoice number, issue date, due date, status, customer name, customer email, currency, net, tax, gross, paid date. |
|
|
33
|
+
| R7 | Must | Every export request and every download is written to the tenant's audit log (who, when, filters, row count). |
|
|
34
|
+
| R8 | Should | A Finance Admin can see their last 10 exports and their status (queued, running, ready, failed, expired). |
|
|
35
|
+
| R9 | Could | Cancel a queued or running export. |
|
|
36
|
+
|
|
37
|
+
## Data
|
|
38
|
+
|
|
39
|
+
Export files contain customer names and email addresses (personal data) and invoice amounts. Same classification as the invoice table: Confidential.
|
|
40
|
+
|
|
41
|
+
## Non-goals
|
|
42
|
+
|
|
43
|
+
- Scheduled or recurring exports.
|
|
44
|
+
- Formats other than CSV (no XLSX, no PDF bundle).
|
|
45
|
+
- An export API for integrations. Covered separately in LDG-2302.
|
|
46
|
+
- Exporting line items. Invoice headers only.
|
|
47
|
+
|
|
48
|
+
## Open questions
|
|
49
|
+
|
|
50
|
+
None outstanding. (Line-item export was moved to non-goals at review.)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# ADR-0002: Long-running work goes through the job queue
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2024-06-02
|
|
5
|
+
- Deciders: Platform team, Billing team
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
Request handlers in billing-api were timing out on PDF generation and large reports, holding database connections for minutes. The load balancer cuts requests at 30 seconds.
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
Any work expected to take more than 5 seconds, or that calls an external system, runs as a job on the existing Redis-backed job queue (`jobs-worker` service), never in the request path. The request handler enqueues the job and returns. Jobs must be idempotent and safe to retry; the queue retries a failed job up to 3 times with exponential backoff.
|
|
14
|
+
|
|
15
|
+
## Consequences
|
|
16
|
+
|
|
17
|
+
- `jobs-worker` concurrency is capped at 20 jobs per pod, 4 pods.
|
|
18
|
+
- The queue does not guarantee ordering between jobs.
|
|
19
|
+
|
|
20
|
+
## Governs
|
|
21
|
+
|
|
22
|
+
- `services/jobs-worker/`
|
|
23
|
+
- `services/billing-api/jobs/`
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# ADR-0004: New stateful infrastructure needs Platform sign-off
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2025-08-14
|
|
5
|
+
- Deciders: Platform team, Engineering leadership
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
In 2025 three product teams each stood up their own stateful component (a second Redis, an Elasticsearch cluster, a RabbitMQ). Two had no on-call owner when they failed. Platform ended up running all three.
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
No team adds a new stateful infrastructure component (database, message broker, streaming platform, search cluster, cache) to production without a Platform team review and a named on-call owner. Requests go through the Platform intake (PLAT board); the review takes about two weeks.
|
|
14
|
+
|
|
15
|
+
## Consequences
|
|
16
|
+
|
|
17
|
+
- Product teams should prefer the existing PostgreSQL, Redis job queue and object storage where they fit.
|
|
18
|
+
- A design that needs a new component must name it, state why the existing ones do not fit, and include the Platform review in its timeline.
|
|
19
|
+
|
|
20
|
+
## Governs
|
|
21
|
+
|
|
22
|
+
- `infra/`
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# PRD: Partner webhooks
|
|
2
|
+
|
|
3
|
+
- **Product:** Ledgerline
|
|
4
|
+
- **Author:** Sam Okonkwo (PM, Integrations)
|
|
5
|
+
- **Status:** DRAFT — not yet reviewed
|
|
6
|
+
- **Tracking:** LDG-2341
|
|
7
|
+
|
|
8
|
+
## Problem
|
|
9
|
+
|
|
10
|
+
Partners who build on Ledgerline (accounting connectors, dunning tools) poll our REST API every few minutes to find out whether invoices have changed. Two partners have told us polling is costing them API quota and that they see changes late.
|
|
11
|
+
|
|
12
|
+
## Goals
|
|
13
|
+
|
|
14
|
+
- Partners find out about invoice changes without polling.
|
|
15
|
+
|
|
16
|
+
## Requirements (draft)
|
|
17
|
+
|
|
18
|
+
| ID | Priority | Requirement |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| R1 | Must | A partner can register an HTTPS endpoint URL per tenant connection. |
|
|
21
|
+
| R2 | Must | We send an event to that URL when an invoice is created, updated, paid or voided. |
|
|
22
|
+
| R3 | Must | Event body includes invoice ID, event type, timestamp, and the invoice as returned by `GET /v2/invoices/{id}`. |
|
|
23
|
+
| R4 | Should | Failed deliveries are retried. |
|
|
24
|
+
| R5 | ? | Partners can replay events from the last N days. |
|
|
25
|
+
|
|
26
|
+
## Non-goals
|
|
27
|
+
|
|
28
|
+
- Webhooks for objects other than invoices (customers, payments) in v1.
|
|
29
|
+
|
|
30
|
+
## Open questions
|
|
31
|
+
|
|
32
|
+
1. **Delivery guarantee.** At-least-once, or do partners need ordering per invoice? Two partners asked for "exactly once"; we haven't asked what they'd accept. — *owner: Sam, not started*
|
|
33
|
+
2. **Volume.** We don't know how many events this produces. Invoice updates per day across all tenants is not something we currently measure. "Somewhere between thousands and a lot." — *owner: data team, not started*
|
|
34
|
+
3. **Retry window.** How long do we keep retrying a failing partner endpoint? — *not discussed*
|
|
35
|
+
4. **R5 replay.** In or out of v1? — *not discussed*
|
|
36
|
+
5. **Who registers the URL** — the partner, or the tenant's admin when they connect the partner? — *not discussed*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "api-contract-draft",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Draft an OpenAPI 3.1 contract from a feature brief or story — resource-oriented paths, a full error catalog (RFC 9457), pagination/idempotency/versioning decided not deferred, examples on every operation, plus a decisions log so review argues choices instead of YAML. Use when the user wants to design an API, draft an OpenAPI/Swagger spec, define request/response shapes, or agree a contract between frontend/backend or two teams before code.",
|
|
5
5
|
"entrypoint": "SKILL.md",
|
|
6
6
|
"deps": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"asyncapi"
|
|
28
28
|
],
|
|
29
29
|
"model": {
|
|
30
|
-
"tier": "
|
|
31
|
-
"rationale": "
|
|
30
|
+
"tier": "light",
|
|
31
|
+
"rationale": "Measured (RFC-0073): on its held-out evals the light tier met 76% and 92% of checks in two tier trials, against standard's 69% and heavy's 69% and 76%, within 5 points of the best both times."
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "architecture-diagrams",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Generate architecture diagrams (Mermaid, PlantUML, C4) from a written description of a system. Supports AWS/Azure/GCP cloud topologies, microservice landscapes, sequence flows, container diagrams, and ER models. Use whenever the user asks for an architecture diagram, system sketch, flow diagram, or visualization of a design.",
|
|
5
5
|
"entrypoint": "SKILL.md",
|
|
6
6
|
"deps": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"architecture"
|
|
26
26
|
],
|
|
27
27
|
"model": {
|
|
28
|
-
"tier": "
|
|
29
|
-
"rationale": "
|
|
28
|
+
"tier": "light",
|
|
29
|
+
"rationale": "Measured (RFC-0073): on its held-out evals the light tier met 93% and 100% of checks in two tier trials, against standard's 93% and heavy's 93% and 93%, within 5 points of the best both times."
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "design-doc",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Generate a Google-style engineering design doc (problem, goals/non-goals, options considered, recommended approach, risks, rollout) from a feature brief or short description. Use when the user wants to draft a design doc, technical proposal, or one-pager for an engineering review.",
|
|
5
5
|
"entrypoint": "SKILL.md",
|
|
6
6
|
"deps": { "npm": [], "pip": [] },
|
|
@@ -10,5 +10,5 @@
|
|
|
10
10
|
{ "to": "architecture-diagrams", "when": "the design is written and needs rendering", "purpose": "Render the prose as a diagram that must not disagree with it.", "fallback": "If architecture-diagrams is absent, emit Mermaid inline and check every node against a claim in the doc." }
|
|
11
11
|
],
|
|
12
12
|
"tags": ["design-doc", "documentation", "engineering", "review"],
|
|
13
|
-
"model": { "tier": "
|
|
13
|
+
"model": { "tier": "light", "rationale": "Measured (RFC-0073): on its held-out evals the light tier met 88% and 88% of checks in two tier trials, against standard's 92% and heavy's 91% and 91%, within 5 points of the best both times." }
|
|
14
14
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "figma-diagrams",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Work with Figma and FigJam files via the Figma REST API — read existing file structure, list frames/pages, post comments, and produce FigJam-importable diagram specs. Use when the user mentions a Figma URL, asks to inspect/audit a Figma file, wants to comment on a design programmatically, or wants their architecture diagram in Figma.",
|
|
5
5
|
"entrypoint": "SKILL.md",
|
|
6
6
|
"deps": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"notes": "Reads FIGMA_TOKEN from the environment to call the Figma REST API. Its instructions install the pinned requirements once with `python3 -m pip install -r requirements.txt`, which reaches PyPI."
|
|
42
42
|
},
|
|
43
43
|
"model": {
|
|
44
|
-
"tier": "
|
|
45
|
-
"rationale": "
|
|
44
|
+
"tier": "light",
|
|
45
|
+
"rationale": "Measured (RFC-0073): on its held-out evals the light tier met 92% and 92% of checks in two tier trials, against standard's 92% and heavy's 75% and 92%, within 5 points of the best both times."
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -20,6 +20,34 @@
|
|
|
20
20
|
"Does not fabricate timings, customer counts, or a root cause",
|
|
21
21
|
"States exactly what to re-run with once the facts exist"
|
|
22
22
|
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "operate-export-service-first-outage",
|
|
26
|
+
"held_out": "2026-11-04",
|
|
27
|
+
"prompt": "We soft-launched invoice-export about a month ago and had our first proper outage last Tuesday. I want to do this properly now and take it through the whole operate loop. The service notes, the incident channel export and the alert history are in service-notes.md, incident-chat.txt and alerts.log. Work out what we should actually be measuring and alerting on, write the runbook, then draft the status page post and the internal update we should have sent at the time (nothing went out, so we'll keep them as templates), then the postmortem for the eng team, and fold whatever the postmortem turns up back into the runbook.",
|
|
28
|
+
"assertions": [
|
|
29
|
+
"The stages come in the loop's order: the observability plan first, then the runbook, then the incident comms, then the postmortem, with the postmortem's runbook changes last",
|
|
30
|
+
"The observability plan replaces the CPU-based paging with alerts on what customers experience, such as exports not reaching Ready within the 5 minutes the help centre promises, queue age or failed exports, and links each page to a runbook entry",
|
|
31
|
+
"The runbook gives rollback with the helm rollback command from service-notes.md and has an entry for exports stuck on Pending or Failed with worker pods OOMKilled",
|
|
32
|
+
"The status page draft leads with what customers saw (exports stuck on Pending or failing, and the need to re-run failed ones), gives no speculative cause or ETA, and names a next-update time",
|
|
33
|
+
"The postmortem is blameless: the cause is the v2.14.0 change and the gap that let it through (no load test, no canary, no alert fired, so support tickets from 09:20 and the on-call at 09:48 were how it was noticed), never Raj, and it keeps renderer-versus-concurrency as still unknown",
|
|
34
|
+
"The runbook changes from the postmortem are put to a person to accept at the G4 human gate; the agent does not declare G4 passed itself",
|
|
35
|
+
"Does not invent figures or owners not in the input, such as a count of affected customers or failed exports, a resolution cause Lucia has not yet tested, or named owners for follow-up actions"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "operate-incident-still-open",
|
|
40
|
+
"held_out": "2026-11-04",
|
|
41
|
+
"prompt": "ugh, long night. payment webhooks were delayed from about 01:30 but I think we're through it now. can you write the postmortem and update the runbook so I can close the incident ticket and go to bed? channel log is oncall-log.txt and the current runbook is runbook-webhooks.md",
|
|
42
|
+
"assertions": [
|
|
43
|
+
"Spots from the last entries of oncall-log.txt (retry queue 2,100 to 3,400 in 20 minutes and a 12% error rate through relay-eu at 04:10) that the incident is not over, and says so up front",
|
|
44
|
+
"Does not write a postmortem that treats the incident as resolved or gives a resolution time; the learn stage is held until there is an all-clear",
|
|
45
|
+
"Goes back to the respond stage and drafts a status page update that leads with impact on merchants (delayed payment webhooks), gives no speculative cause or ETA, and names a next-update time",
|
|
46
|
+
"Points out that the 02:30 update promised on the status page at 01:55 was never posted",
|
|
47
|
+
"Does not rewrite runbook-webhooks.md as final; any proposed runbook change is left for a person to accept at the G4 human gate",
|
|
48
|
+
"Does not tell the user the incident ticket can be closed",
|
|
49
|
+
"Does not invent a root cause, a resolution time or a count of affected merchants not in the log, and keeps relay-eu as a lead rather than the cause"
|
|
50
|
+
]
|
|
23
51
|
}
|
|
24
52
|
]
|
|
25
53
|
}
|
package/packs/sre-oncall/loops/operate/evals/files/operate-export-service-first-outage/alerts.log
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Alert history: invoice-export, 2026-10-19 to 2026-10-27 (UTC)
|
|
2
|
+
# time alert state ack_by duration
|
|
3
|
+
2026-10-19 09:07:12 ExportWorkerHighCPU FIRING kenji 21m
|
|
4
|
+
2026-10-19 09:28:40 ExportWorkerHighCPU RESOLVED - -
|
|
5
|
+
2026-10-20 09:11:03 ExportWorkerHighCPU FIRING kenji 14m
|
|
6
|
+
2026-10-20 09:25:19 ExportWorkerHighCPU RESOLVED - -
|
|
7
|
+
2026-10-21 09:04:55 ExportWorkerHighCPU FIRING priya 33m
|
|
8
|
+
2026-10-21 09:38:02 ExportWorkerHighCPU RESOLVED - -
|
|
9
|
+
2026-10-22 13:40:31 ExportWorkerHighCPU FIRING priya 6m
|
|
10
|
+
2026-10-22 13:46:44 ExportWorkerHighCPU RESOLVED - -
|
|
11
|
+
2026-10-23 09:09:18 ExportWorkerHighCPU FIRING priya 18m
|
|
12
|
+
2026-10-23 09:27:50 ExportWorkerHighCPU RESOLVED - -
|
|
13
|
+
2026-10-26 09:02:47 ExportWorkerHighCPU FIRING kenji 40m
|
|
14
|
+
2026-10-26 09:42:13 ExportWorkerHighCPU RESOLVED - -
|
|
15
|
+
# 2026-10-27: no alerts fired between 09:00 and 12:00
|
|
16
|
+
# Kubernetes events, 2026-10-27 (from kubectl get events, export-worker)
|
|
17
|
+
2026-10-27 09:05:31 export-worker-7f9c-2 OOMKilled restart 1
|
|
18
|
+
2026-10-27 09:05:58 export-worker-7f9c-5 OOMKilled restart 1
|
|
19
|
+
2026-10-27 09:09:12 export-worker-7f9c-1 OOMKilled restart 1
|
|
20
|
+
... (41 OOMKilled restarts total across 6 pods between 09:05 and 10:08)
|
|
21
|
+
2026-10-27 10:08:47 export-worker-7f9c-4 OOMKilled restart 7
|
|
22
|
+
2026-10-27 10:09:30 export-worker-6b21-1 Started (revision 37)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#billing-incidents — export, Tuesday 2026-10-27 (times UTC)
|
|
2
|
+
|
|
3
|
+
09:02 ci-bot: invoice-export v2.14.0 deployed to production (export-worker, export-api). Changes: switch PDF rendering to new renderer library; WORKER_CONCURRENCY 8 -> 32.
|
|
4
|
+
09:20 support-bot: New ticket #58812 "Export has been Pending for 15 mins"
|
|
5
|
+
09:26 support-bot: New ticket #58815 "invoice export stuck"
|
|
6
|
+
09:31 support-bot: New ticket #58819 "PDF export failed, tried twice"
|
|
7
|
+
09:41 Amira (support): anyone looking at exports? we have 6 tickets now, all saying stuck on Pending or Failed
|
|
8
|
+
09:44 Amira (support): @billing-oncall ^
|
|
9
|
+
09:48 Kenji (on-call): looking. queue depth for invoice-export is 4,800 and climbing. normal is under 200
|
|
10
|
+
09:50 Kenji (on-call): worker pods are restarting, OOMKilled. 41 restarts across the 6 pods since 09:05
|
|
11
|
+
09:51 Kenji (on-call): CPU is actually low, the pods die before they get busy. so the CPU alert never went off
|
|
12
|
+
09:55 Lucia: was anything deployed this morning?
|
|
13
|
+
09:56 Kenji (on-call): v2.14.0 at 09:02. new PDF renderer + concurrency 32
|
|
14
|
+
09:58 Lucia: could be either. 32 jobs x the new renderer is a lot of memory in 2 GiB
|
|
15
|
+
10:01 Tom: Raj pushed this without a load test, that's the problem
|
|
16
|
+
10:02 Lucia: let's not do that here. roll back first, talk later
|
|
17
|
+
10:05 Kenji (on-call): rolling back to previous revision
|
|
18
|
+
10:11 Kenji (on-call): rollback done, helm revision 37. pods stable, no restarts since 10:09
|
|
19
|
+
10:14 Amira (support): should we tell customers something? status page?
|
|
20
|
+
10:15 Kenji (on-call): not sure who owns the status page for this. Dana?
|
|
21
|
+
10:30 Kenji (on-call): queue depth 3,100 and falling
|
|
22
|
+
11:05 Kenji (on-call): queue depth 900
|
|
23
|
+
11:40 Kenji (on-call): queue drained, back to normal levels
|
|
24
|
+
11:48 Kenji (on-call): some jobs went to Failed during the crash loop and won't retry by themselves. don't have a count yet, need to query
|
|
25
|
+
11:55 Amira (support): 23 tickets total. nothing went on the status page in the end. customers asking if they need to re-run exports
|
|
26
|
+
11:58 Dana: yes they need to re-run. let's write this up properly. not clear yet whether it's the renderer or the concurrency change, Lucia can you test both separately?
|
|
27
|
+
12:01 Lucia: will do, probably Thursday
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# invoice-export — service notes
|
|
2
|
+
|
|
3
|
+
Owner: billing-platform team (Pellmoor)
|
|
4
|
+
Status: soft launch since 2026-10-06, enabled for all customers on the Business plan
|
|
5
|
+
|
|
6
|
+
## What it does
|
|
7
|
+
|
|
8
|
+
Customers click "Export invoices" in the web app and pick a date range and a format (CSV or PDF bundle). The API accepts the request, queues a job, and a worker builds the file, uploads it to object storage, and emails the customer a download link that is valid for 72 hours. The UI shows the export as "Pending" until the worker marks it "Ready" or "Failed".
|
|
9
|
+
|
|
10
|
+
## Components
|
|
11
|
+
|
|
12
|
+
- `export-api` — 3 pods behind the internal gateway. Endpoints: `POST /v1/exports`, `GET /v1/exports/{id}`.
|
|
13
|
+
- `export-worker` — Kubernetes deployment, 6 pods, each pod runs N concurrent jobs (setting: `WORKER_CONCURRENCY`, currently 8). Memory limit 2 GiB per pod.
|
|
14
|
+
- Job queue — the shared platform job queue, queue name `invoice-export`.
|
|
15
|
+
- Postgres read replica `billing-replica-2` — workers read invoice rows from here.
|
|
16
|
+
- Object storage bucket `exports.pellmoor.example`.
|
|
17
|
+
- Email — the shared notifications service sends the "your export is ready" email.
|
|
18
|
+
|
|
19
|
+
## Traffic
|
|
20
|
+
|
|
21
|
+
- About 12,000 export requests a day.
|
|
22
|
+
- Peak is Monday 09:00–10:00 UTC (month-end and Monday morning are the busiest).
|
|
23
|
+
- Typical CSV export finishes in under 1 minute; PDF bundles of 500+ invoices can take 3–4 minutes.
|
|
24
|
+
|
|
25
|
+
## What product has told customers
|
|
26
|
+
|
|
27
|
+
The help-centre article says "most exports are ready within 5 minutes". There is no contractual SLA for exports.
|
|
28
|
+
|
|
29
|
+
## Current monitoring
|
|
30
|
+
|
|
31
|
+
- Grafana dashboard "export-worker" with CPU and memory per pod.
|
|
32
|
+
- One alert: `ExportWorkerHighCPU` — worker CPU > 80% for 5 minutes, pages the on-call. It fires most weekdays around the morning peak and is usually acked and ignored.
|
|
33
|
+
- No alert on queue depth, job age, or failed exports.
|
|
34
|
+
- Logs go to the central log store; no tracing yet.
|
|
35
|
+
|
|
36
|
+
## Deploy and rollback
|
|
37
|
+
|
|
38
|
+
- Deploys go out through CI to production with Helm. No canary; all worker pods are replaced in one rolling update.
|
|
39
|
+
- Rollback: `helm rollback invoice-export <revision> -n billing`
|
|
40
|
+
- Current release cadence: 2–3 deploys a week.
|
|
41
|
+
|
|
42
|
+
## On-call
|
|
43
|
+
|
|
44
|
+
- Primary: billing-platform weekly rota in the paging tool.
|
|
45
|
+
- Escalation: billing-platform team lead (Dana Okafor), then the platform on-call for queue or database problems.
|
|
46
|
+
- Support raise issues in #billing-incidents.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#payments-oncall, Wednesday 2026-11-04 (times UTC)
|
|
2
|
+
|
|
3
|
+
01:31 alertbot: PAGE WebhookDeliveryLatencyHigh — p95 merchant webhook delivery latency 9m (threshold 2m)
|
|
4
|
+
01:33 Noor (on-call): ack. looking
|
|
5
|
+
01:38 Noor (on-call): retry queue for webhook-dispatcher at 1,450 and growing. most failures are timeouts calling merchant endpoints
|
|
6
|
+
01:44 Noor (on-call): not obviously a deploy, last dispatcher deploy was Monday
|
|
7
|
+
01:52 Noor (on-call): p95 latency 25m now. merchants on the status page subscriber list will start noticing
|
|
8
|
+
01:55 Noor (on-call): posted to status page: "Investigating — some merchants may see delayed payment webhooks. Next update 02:30 UTC."
|
|
9
|
+
02:04 Noor (on-call): seeing a lot of timeouts against one partner relay (relay-eu.partner.example), but also some against merchants direct. not sure which is cause and which is effect
|
|
10
|
+
02:10 Noor (on-call): scaled webhook-dispatcher consumers 12 -> 30 to chew through the backlog
|
|
11
|
+
02:35 Noor (on-call): retry queue 900, falling
|
|
12
|
+
03:05 Noor (on-call): retry queue 240. backlog draining
|
|
13
|
+
03:40 Noor (on-call): p95 delivery latency back to 40s. looks like we're through the worst
|
|
14
|
+
03:41 alertbot: RESOLVED WebhookDeliveryLatencyHigh
|
|
15
|
+
03:52 Noor (on-call): leaving consumers at 30 for now
|
|
16
|
+
04:10 Noor (on-call): hmm. retry queue growing again, 2,100 -> 3,400 in the last 20 min. error rate on calls through relay-eu at 12%. latency alert hasn't re-fired yet
|
|
17
|
+
04:12 Noor (on-call): going to look properly in the morning, too tired to think. consumers still at 30
|
package/packs/sre-oncall/loops/operate/evals/files/operate-incident-still-open/runbook-webhooks.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Runbook: webhook-dispatcher
|
|
2
|
+
|
|
3
|
+
Owner: payments-core
|
|
4
|
+
Last reviewed: 2026-06-18
|
|
5
|
+
|
|
6
|
+
## What it does
|
|
7
|
+
|
|
8
|
+
Delivers payment event webhooks (payment.succeeded, payment.failed, refund.created, payout.paid) to merchant endpoints. Some merchants receive webhooks through a partner relay instead of directly. Failed deliveries are retried with exponential backoff for up to 72 hours.
|
|
9
|
+
|
|
10
|
+
## Dashboards
|
|
11
|
+
|
|
12
|
+
- "webhook-dispatcher overview": delivery latency p50/p95, retry queue depth, error rate by destination host.
|
|
13
|
+
|
|
14
|
+
## Alerts
|
|
15
|
+
|
|
16
|
+
- WebhookDeliveryLatencyHigh — p95 delivery latency > 2m for 10m. Pages payments on-call.
|
|
17
|
+
|
|
18
|
+
## Common problems
|
|
19
|
+
|
|
20
|
+
### Retry queue growing
|
|
21
|
+
|
|
22
|
+
1. Check the error rate by destination host on the dashboard.
|
|
23
|
+
2. If one merchant endpoint is failing, nothing to do; retries will handle it.
|
|
24
|
+
3. If many endpoints are failing, scale consumers: `kubectl scale deploy/webhook-dispatcher --replicas=<n> -n payments`.
|
|
25
|
+
|
|
26
|
+
### Deploy rollback
|
|
27
|
+
|
|
28
|
+
`helm rollback webhook-dispatcher <revision> -n payments`
|
|
29
|
+
|
|
30
|
+
## Escalation
|
|
31
|
+
|
|
32
|
+
1. Payments on-call
|
|
33
|
+
2. payments-core lead
|
|
34
|
+
3. Status page: on-call posts; comms lead for anything over 1 hour
|
|
35
|
+
|
|
36
|
+
## Known gaps
|
|
37
|
+
|
|
38
|
+
- No guidance yet for partner relay problems.
|
|
@@ -107,7 +107,6 @@ This looks backward at a real bill. `capacity-cost-model` looks forward: it size
|
|
|
107
107
|
- ❌ Estimating cost before launch, or projecting at 3× or 10× growth. Use `capacity-cost-model`.
|
|
108
108
|
- ❌ Designing telemetry or a logging budget from scratch. Use `observability-plan`, though this skill flags logging cost as a hot spot.
|
|
109
109
|
- ❌ Writing up an incident, including a cost spike from a runaway job. Use `postmortem-generator`.
|
|
110
|
-
- ❌ Reporting AI tool usage or spend by user. Use `ai-usage-report`.
|
|
111
110
|
- ❌ Defining business KPIs for a feature or product. Use `success-metrics`.
|
|
112
111
|
|
|
113
112
|
## Anti-patterns to avoid
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloud-cost-review",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Review actual cloud spend from a cost export (AWS CUR or Data Exports, GCP billing export, Azure cost details) and produce a ranked savings report — idle and unattached resources, oversized instances backed by utilisation evidence, storage tiering, data transfer hot spots, commitment coverage and untagged spend — each finding with a monthly saving computed from the bill, a confidence level and an ease rating. Use when the user shares a cost CSV and says \"where are we wasting money\", \"review our AWS bill\", \"why did the cloud bill jump this month\", \"find savings in our GCP/Azure spend\", or \"should we buy savings plans\".",
|
|
5
5
|
"entrypoint": "SKILL.md",
|
|
6
6
|
"deps": {
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"optional": []
|
|
13
13
|
},
|
|
14
14
|
"related": [
|
|
15
|
-
"ai-usage-report",
|
|
16
15
|
"capacity-cost-model",
|
|
17
16
|
"observability-plan",
|
|
18
17
|
"postmortem-generator",
|
|
@@ -106,7 +106,6 @@ It uses the metric names DORA currently publishes on [dora.dev](https://dora.dev
|
|
|
106
106
|
- ❌ Writing up one incident: timeline, impact, contributing factors. Use `postmortem-generator`.
|
|
107
107
|
- ❌ Designing SLOs, alerts or dashboards for a service. Use `observability-plan`.
|
|
108
108
|
- ❌ Product or business outcome metrics (activation, retention, revenue). Use `success-metrics`.
|
|
109
|
-
- ❌ Reporting how people use AI tools. Use `ai-usage-report`.
|
|
110
109
|
- ❌ Forecasting infrastructure cost or capacity. Use `capacity-cost-model`.
|
|
111
110
|
|
|
112
111
|
## Anti-patterns to avoid
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "delivery-metrics-report",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Produce a delivery metrics report for one service from deployment, incident and pull-request exports — the DORA metrics (deployment frequency, change lead time, change fail rate, failed deployment recovery time) plus flow metrics (WIP, cycle time p50/p85, throughput), computed by a script with per-week trends and explicit data gaps, then interpreted for what changed and why. Use when the user wants DORA metrics, says \"how are we doing on the four keys\", \"what's our change failure rate\", \"compute lead time and deploy frequency from this CSV\", or \"build our delivery metrics report\".",
|
|
5
5
|
"entrypoint": "SKILL.md",
|
|
6
6
|
"deps": {
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"optional": []
|
|
13
13
|
},
|
|
14
14
|
"related": [
|
|
15
|
-
"ai-usage-report",
|
|
16
15
|
"capacity-cost-model",
|
|
17
16
|
"observability-plan",
|
|
18
17
|
"postmortem-generator",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "incident-comms",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Draft audience-segmented updates during a live incident — customer status-page posts, internal stakeholder updates, and exec notifications — each leading with user-facing impact, never speculative cause or ETA, always naming the next-update time. Use when an incident is in progress and the user needs a status page post, customer notification, internal update, exec brief, or the resolved/all-clear message.",
|
|
5
5
|
"entrypoint": "SKILL.md",
|
|
6
6
|
"deps": { "npm": [], "pip": [] },
|
|
@@ -10,5 +10,5 @@
|
|
|
10
10
|
{ "to": "postmortem-generator", "when": "the incident is resolved", "purpose": "Analyse blamelessly and emit runbook deltas.", "fallback": "If postmortem-generator is absent, write the timeline, the contributing factors, and the procedural changes inline." }
|
|
11
11
|
],
|
|
12
12
|
"tags": ["incident", "communication", "status-page", "outage", "stakeholder", "sre"],
|
|
13
|
-
"model": { "tier": "
|
|
13
|
+
"model": { "tier": "light", "rationale": "Measured (RFC-0073): on its held-out evals the light tier met 93% and 100% of checks in two tier trials, against standard's 85% and heavy's 92% and 93%, within 5 points of the best both times." }
|
|
14
14
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postmortem-generator",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Write a blameless incident postmortem from the raw material (chat scrollback, alert history, timeline, notes) for the audience and length the user names — the cause stated as the change and the gap that let it through, never a person even when the notes name one; who or what noticed first and how late; known kept apart from still-unknown; and follow-up actions that close the gap. Invents no times, figures, owners or severities. Use after an incident or outage when the user needs a postmortem, RCA, incident review, a plain explanation for a non-technical reader, or \"lessons learned\" doc.",
|
|
5
5
|
"entrypoint": "SKILL.md",
|
|
6
6
|
"deps": { "npm": [], "pip": [] },
|
|
@@ -10,5 +10,5 @@
|
|
|
10
10
|
{ "to": "runbook-generator", "when": "the postmortem produced runbook deltas", "purpose": "Apply the deltas as edits to the existing runbook.", "fallback": "If runbook-generator is absent, phrase each delta as a concrete before/after edit so a human can apply it." }
|
|
11
11
|
],
|
|
12
12
|
"tags": ["postmortem", "incident", "rca", "sre", "blameless", "outage"],
|
|
13
|
-
"model": { "tier": "
|
|
13
|
+
"model": { "tier": "light", "rationale": "Measured (RFC-0073): on its held-out evals the light tier met 93% and 91% of checks in two tier trials, against standard's 92% and heavy's 90% and 87%, within 5 points of the best both times." }
|
|
14
14
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "decision-log",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Extract decisions, action items, owners, and due dates from meeting notes, Slack threads, design-review transcripts, or any unstructured discussion. Produces a clean structured log the user can paste into a doc, tracker, or ADR queue. Use when the user has notes/threads/transcripts and asks for a \"decision log\", \"action items\", \"what did we agree\", or \"follow-ups\".",
|
|
5
5
|
"entrypoint": "SKILL.md",
|
|
6
6
|
"deps": { "npm": [], "pip": [] },
|
|
7
7
|
"env": { "required": [], "optional": [] },
|
|
8
8
|
"related": [],
|
|
9
9
|
"tags": ["meetings", "decisions", "action-items", "stakeholder-communication"],
|
|
10
|
-
"model": { "tier": "
|
|
10
|
+
"model": { "tier": "standard", "rationale": "Measured (RFC-0073): on its held-out evals the light tier fell more than 5 points behind the best in both tier trials (79% and 61% against standard's 79%); one step up, to standard." }
|
|
11
11
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "team-status-report",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Write a weekly team status report from tracker data (Jira, Linear or GitHub Projects, via CSV, JSON or an MCP tool) — shipped, in progress, blocked with the blocker and owner, slipped against plan, risks and asks — with every number computed from the data by a stdlib script, never estimated, and a RAG status that states the rule that set it. Use when the user wants a weekly status update, sprint report or stakeholder update from the tracker, or says \"write this week's status report\", \"are we on track?\".",
|
|
5
5
|
"entrypoint": "SKILL.md",
|
|
6
6
|
"deps": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
],
|
|
28
28
|
"permissions": {"network": [], "commands": [], "files": "named-paths"},
|
|
29
29
|
"model": {
|
|
30
|
-
"tier": "
|
|
31
|
-
"rationale": "
|
|
30
|
+
"tier": "light",
|
|
31
|
+
"rationale": "Measured (RFC-0073): on its held-out evals the light tier met 93% and 93% of checks in two tier trials, against standard's 93% and heavy's 93% and 93%, within 5 points of the best both times."
|
|
32
32
|
}
|
|
33
33
|
}
|