skilldrop-cli 0.16.28 → 0.16.30
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/bin/skilldrop.js +160 -33
- package/catalogue.json +7 -3
- package/model-routing.json +16 -0
- package/package.json +1 -1
- package/packs/ai-engineering/skills/mcp-pairing/SKILL.md +93 -0
- package/packs/ai-engineering/skills/mcp-pairing/evals/eval_queries.json +13 -0
- package/packs/ai-engineering/skills/mcp-pairing/evals/evals.json +76 -0
- package/packs/ai-engineering/skills/mcp-pairing/evals/files/2/mcp.json +32 -0
- package/packs/ai-engineering/skills/mcp-pairing/evals/files/4/.mcp.json +47 -0
- package/packs/ai-engineering/skills/mcp-pairing/evals/files/4/docs/pr-loop.md +12 -0
- package/packs/ai-engineering/skills/mcp-pairing/evals/files/5/docs/oncall-triage.md +18 -0
- package/packs/ai-engineering/skills/mcp-pairing/examples/build-loop-github-jira-datadog.md +69 -0
- package/packs/ai-engineering/skills/mcp-pairing/manifest.json +17 -0
- package/packs/ai-engineering/skills/mcp-pairing/reference.md +136 -0
- package/packs/ai-engineering/skills/mcp-pairing/templates/mcp-pairing.md +43 -0
- package/packs/data-analytics/loops/measure/LOOP.md +118 -0
- package/packs/data-analytics/loops/measure/evals/eval_queries.json +9 -0
- package/packs/data-analytics/loops/measure/evals/evals.json +28 -0
- package/packs/data-analytics/loops/measure/loop.json +41 -0
- package/packs/dev-team/loops/build/LOOP.md +4 -2
- package/packs/dev-team/loops/build/loop.json +2 -2
- package/packs/dev-team/skills/codebase-tour/SKILL.md +115 -0
- package/packs/dev-team/skills/codebase-tour/evals/eval_queries.json +13 -0
- package/packs/dev-team/skills/codebase-tour/evals/evals.json +77 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/.github/workflows/ci.yml +23 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/README.md +23 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/openapi.yaml +21 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/package-lock.json +7 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/package.json +29 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/config.ts +20 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/domain/shipments/filter.ts +24 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/domain/shipments/repository.ts +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/errors.ts +9 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/generated/api-types.ts +9 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/http/handlers/shipments.ts +38 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/http/routes.ts +7 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/jobs/export-shipments.ts +22 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/server.ts +18 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/tests/domain/filter.test.ts +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/tests/http/shipments.test.ts +18 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/tsconfig.json +10 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/vitest.config.ts +5 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/.github/workflows/ci.yml +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/README.md +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/noxfile.py +14 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/pyproject.toml +22 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/__init__.py +3 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/_version.py +4 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/cli.py +32 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/detect.py +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/errors.py +2 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/money.py +14 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/parsers/__init__.py +8 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/parsers/acme.py +18 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/parsers/base.py +24 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/parsers/harbor.py +13 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/tests/fixtures/acme_sample.csv +3 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/tests/test_acme.py +23 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/tests/test_detect.py +13 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/.github/workflows/ci.yml +28 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/Makefile +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/README.md +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/cmd/tidepool/main.go +24 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/go.mod +5 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/config/config.go +38 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/dispatch/dispatcher.go +52 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/dispatch/dispatcher_test.go +42 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/dispatch/sender.go +32 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/replay/replay.go +31 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/store/db.go +35 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/store/query.sql +11 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/store/query.sql.go +30 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/store/schema.sql +6 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/store/store_integration_test.go +21 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/sqlc.yaml +9 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/.env.example +4 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/.github/workflows/ci.yml +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/Makefile +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/README.md +23 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/data/rates.csv +4 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/pyproject.toml +19 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/scripts/gen_rates.py +29 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/__init__.py +0 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/api/__init__.py +0 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/api/preview.py +14 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/api/routes.py +36 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/config.py +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/discounts.py +8 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/generated/__init__.py +0 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/generated/rates_table.py +8 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/main.py +8 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/shipping.py +18 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/tax.py +7 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/tests/conftest.py +3 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/tests/unit/test_discounts.py +11 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/tests/unit/test_tax.py +13 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/.env.example +3 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/.github/workflows/ci.yml +13 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/README.md +18 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/package.json +13 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/openapi.json +30 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/package.json +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/db.js +19 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/flags.js +8 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/generated/schema.js +32 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/middleware/validate.js +20 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/routes/bookings.js +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/server.js +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/services/bookings.js +23 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/services/pricing.js +9 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/test/pricing.test.js +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/web/package.json +9 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/web/src/bookingForm.js +11 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/web/src/format.js +7 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/web/test/format.test.js +12 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/scripts/gen-schema.mjs +27 -0
- package/packs/dev-team/skills/codebase-tour/examples/refund-window.md +158 -0
- package/packs/dev-team/skills/codebase-tour/manifest.json +47 -0
- package/packs/dev-team/skills/codebase-tour/scripts/repo_facts.py +403 -0
- package/packs/dev-team/skills/codebase-tour/templates/codebase-tour.md +85 -0
- package/packs/dev-team/skills/dependency-upgrade-review/SKILL.md +101 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/eval_queries.json +11 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/evals.json +77 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/.github/workflows/ci.yml +20 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/pr.diff +87 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/quillmark-CHANGELOG.md +24 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/src/render/comment.js +6 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/src/render/note.js +8 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/test/note.test.js +12 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/2/.github/workflows/ci.yml +23 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/2/.github/workflows/release.yml +23 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/2/pr.diff +32 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/2/release-notes.md +20 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/.github/workflows/ci.yml +18 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/Dockerfile +8 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/PR.md +36 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/pr.diff +47 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/src/ingest/client.py +24 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/src/ingest/reader.py +32 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/tests/test_reader.py +15 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/upstream/quillstream-CHANGELOG.md +37 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/.github/workflows/ci.yml +22 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/.github/workflows/release.yml +25 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/.nvmrc +1 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/PR-412.md +16 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/PR-413.md +15 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/package.json +21 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/pr-412.diff +26 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/pr-413.diff +84 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/scripts/release.mjs +18 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/upstream/release-notary-CHANGELOG.md +16 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/upstream/setup-toolchain-RELEASES.md +22 -0
- package/packs/dev-team/skills/dependency-upgrade-review/examples/inputs/ledgerline.diff +38 -0
- package/packs/dev-team/skills/dependency-upgrade-review/examples/ledgerline-tidyparse.md +91 -0
- package/packs/dev-team/skills/dependency-upgrade-review/manifest.json +50 -0
- package/packs/dev-team/skills/dependency-upgrade-review/reference.md +99 -0
- package/packs/dev-team/skills/dependency-upgrade-review/scripts/upgrade_diff.py +718 -0
- package/packs/grc/loops/comply/LOOP.md +133 -0
- package/packs/grc/loops/comply/evals/eval_queries.json +9 -0
- package/packs/grc/loops/comply/evals/evals.json +30 -0
- package/packs/grc/loops/comply/loop.json +54 -0
- package/packs/product-manager/loops/discover/LOOP.md +5 -4
- package/packs/product-manager/loops/discover/loop.json +2 -2
- package/packs/product-manager/skills/feedback-synthesis/SKILL.md +182 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/eval_queries.json +46 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/evals.json +76 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/1/interview-notes.md +47 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/1/nps-verbatims.csv +13 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/1/support-tickets.csv +36 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/3/churn-exit-survey.csv +11 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/3/sales-call-notes.md +55 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/4/csat_comments_q3.csv +17 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/4/support_tickets_q3.csv +49 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/5/app_reviews_last_60_days.csv +32 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/5/interview_notes_round1.md +48 -0
- package/packs/product-manager/skills/feedback-synthesis/examples/booking-app-feedback.md +139 -0
- package/packs/product-manager/skills/feedback-synthesis/examples/inputs/booking-app-coded.csv +17 -0
- package/packs/product-manager/skills/feedback-synthesis/manifest.json +53 -0
- package/packs/product-manager/skills/feedback-synthesis/reference.md +89 -0
- package/packs/product-manager/skills/feedback-synthesis/scripts/theme_counts.py +355 -0
- package/packs/product-manager/skills/feedback-synthesis/templates/coding-sheet.csv +6 -0
- package/packs/product-manager/skills/feedback-synthesis/templates/synthesis.md +42 -0
- package/packs/research/loops/research/LOOP.md +123 -0
- package/packs/research/loops/research/evals/eval_queries.json +9 -0
- package/packs/research/loops/research/evals/evals.json +39 -0
- package/packs/research/loops/research/loop.json +35 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: comply
|
|
3
|
+
description: Take a change that carries risk (a launch, a new vendor, a new use of personal data) to a risk position its owner has signed: a risk register scored inherent and residual, a DPIA when personal data is processed, the evidence behind every control the ratings rely on, a script that checks the register, and a sign-off only the named owner can give. Use when the user says "get this ready for risk sign-off", "run the comply loop", "what do we need before we can launch this", or needs a register, a DPIA and audit evidence that agree with each other.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# comply
|
|
7
|
+
|
|
8
|
+
One change, from its risks to a signature. Each of the three documents is useful alone. The
|
|
9
|
+
loop exists for the places where they disagree. A register can rate a risk low because of a
|
|
10
|
+
control that leaves no record. A DPIA can find a high risk to people that never reaches the
|
|
11
|
+
register its owner reads. An evidence map can show a gap that nobody connects to the rating
|
|
12
|
+
that relied on it. The loop makes the three agree. Then the register's own script checks
|
|
13
|
+
them, and the person who owns the risk decides.
|
|
14
|
+
|
|
15
|
+
This loop prepares material for a qualified reviewer: a DPO, a risk committee, an auditor.
|
|
16
|
+
It is not legal or audit advice, and every document it produces says so once, at the top.
|
|
17
|
+
|
|
18
|
+
## Stages
|
|
19
|
+
|
|
20
|
+
| # | Stage | Type | Skills | Gate |
|
|
21
|
+
|---|---|---|---|---|
|
|
22
|
+
| 1 | `register` | generate | [`risk-register`](../../skills/risk-register/SKILL.md) | — |
|
|
23
|
+
| 2 | `assess` | generate | [`dpia`](../../skills/dpia/SKILL.md) | — |
|
|
24
|
+
| 3 | `evidence` | generate | [`soc2-evidence-map`](../../skills/soc2-evidence-map/SKILL.md) | — |
|
|
25
|
+
| 4 | `check` | verify | [`risk-register`](../../skills/risk-register/SKILL.md) | **G8** mechanical |
|
|
26
|
+
| 5 | `sign-off` | gate | [`doc-critique`](../../../core/skills/doc-critique/SKILL.md) | **G8.1** human |
|
|
27
|
+
|
|
28
|
+
## How to run this loop
|
|
29
|
+
|
|
30
|
+
1. **Register the change's risks.** Run `risk-register` with the change as its scope and the
|
|
31
|
+
objective it threatens. Save `risk-register.csv`. Owners come from the person; a missing
|
|
32
|
+
owner stays an error to resolve, never a guessed name.
|
|
33
|
+
2. **Screen and assess personal data.** Run `dpia` on the processing the change introduces.
|
|
34
|
+
- When the screening finds no criteria that apply, keep its short screening record and go on.
|
|
35
|
+
- When a DPIA is needed, complete it. Then give each risk to people still at medium or high
|
|
36
|
+
residual its own register row, with the harm to people as the consequence, the same
|
|
37
|
+
owner as the DPIA measure, and `DPIA` in its controls cell. The DPIA keeps scoring harm to
|
|
38
|
+
people; the register row is how its owner sees it.
|
|
39
|
+
3. **Evidence every control the ratings rely on.** List the controls named in the register's
|
|
40
|
+
residual ratings and the DPIA's in-place measures, and run `soc2-evidence-map` on that
|
|
41
|
+
list. Use the organisation's SOC 2 scope when it has one; otherwise use the skill's
|
|
42
|
+
default, Security only, tagged `[assumption]`.
|
|
43
|
+
4. **Put the evidence gaps back into the register.** A residual rating can count only
|
|
44
|
+
controls that operate today. For each control the map marks `gap`:
|
|
45
|
+
- set the residual likelihood and impact of every risk that relied on it back to their
|
|
46
|
+
inherent values;
|
|
47
|
+
- move the control to a dated action under the treatment.
|
|
48
|
+
|
|
49
|
+
A `partial` control keeps its credit only for what its evidence covers; say what that is
|
|
50
|
+
in the summary for the owner. Don't lower a rating to make a heat map look better.
|
|
51
|
+
5. **Check at G8.** Run the register's script on the final CSV:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Claude Code (the loop and risk-register installed side by side)
|
|
55
|
+
python3 "${CLAUDE_SKILL_DIR}/../risk-register/scripts/check_register.py" risk-register.csv --top 5 --out register-check.txt
|
|
56
|
+
# Other IDEs (from the folder the skills were installed into)
|
|
57
|
+
python3 risk-register/scripts/check_register.py risk-register.csv --top 5 --out register-check.txt
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The exit code is the verdict: `0` is `READY`, `1` is `NOT READY`, `2` is `BLOCKED`.
|
|
61
|
+
`NOT READY` returns to `register` to fix what the script names, then runs `check` again.
|
|
62
|
+
Report its warnings to the person; don't edit scores to silence them.
|
|
63
|
+
6. **Critique, then put the decision to the owner at G8.1.** Run `doc-critique` on the
|
|
64
|
+
summary the owner will read. Then show them:
|
|
65
|
+
- the residual heat map from the script, as printed;
|
|
66
|
+
- every risk they are asked to accept;
|
|
67
|
+
- the evidence gaps and their dates;
|
|
68
|
+
- the DPIA's view on prior consultation.
|
|
69
|
+
|
|
70
|
+
Each owner accepts their own risks. A high or critical residual risk that its own owner
|
|
71
|
+
accepts needs a sign-off from someone above them, named in the summary.
|
|
72
|
+
|
|
73
|
+
## Verdicts
|
|
74
|
+
|
|
75
|
+
Defined in [`contracts/terminals.json`](../../../../contracts/terminals.json).
|
|
76
|
+
|
|
77
|
+
- G8 emits `READY`, `NOT READY` or `BLOCKED`, from the script's exit code alone.
|
|
78
|
+
- G8.1 emits:
|
|
79
|
+
- `PROCEED`: every residual risk is accepted or treated, by its named owner.
|
|
80
|
+
- `PROCEED WITH CONDITIONS`: accepted, subject to named actions with dates, each recorded
|
|
81
|
+
as a control and `due_date` on its risk.
|
|
82
|
+
- `REVISE`: the owner rejects a rating or a treatment. Return to `register` with their reasons.
|
|
83
|
+
- `RECONSIDER`: the change shouldn't go ahead as designed, for example when a residual risk
|
|
84
|
+
to people stays high and the design has to change before prior consultation. The loop
|
|
85
|
+
ends here.
|
|
86
|
+
- `BLOCKED`: no owner is available, or the DPO's advice is required and not yet given.
|
|
87
|
+
|
|
88
|
+
## Non-interactive runs
|
|
89
|
+
|
|
90
|
+
With no person present, G8.1 cannot be satisfied. Run every stage through G8, deliver the
|
|
91
|
+
documents, and emit `BLOCKED: need sign-off from <the named owners>`. Never accept a risk
|
|
92
|
+
on someone's behalf, never fill an owner, a retention period or a vendor location with a
|
|
93
|
+
plausible guess, and leave the DPIA's DPO advice and decision fields blank.
|
|
94
|
+
|
|
95
|
+
## When a stage's skill is not installed
|
|
96
|
+
|
|
97
|
+
Name the missing skill and skilldrop as its source, do the minimal inline version of that
|
|
98
|
+
stage, and record that it ran degraded. Without `risk-register`, G8 has no script. Say so,
|
|
99
|
+
check the register by hand against the script's rules (every required field, owners that
|
|
100
|
+
name a person, residual never above inherent, dates that are dates), and mark G8 degraded.
|
|
101
|
+
Never skip G8.1.
|
|
102
|
+
|
|
103
|
+
## Run log (opt-in)
|
|
104
|
+
|
|
105
|
+
Only when the environment variable `SKILLDROP_LOOP_LOG` is set to a file path: after each
|
|
106
|
+
gate's verdict, append one JSON line to that file. Nothing else is recorded, and nothing is
|
|
107
|
+
sent anywhere. When the variable isn't set, or you can't read it, skip this section.
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
printf '%s\n' '{"ts":"2026-10-19T14:03:00Z","loop":"comply","stage":"check","gate":"G8","verdict":"READY","round":1}' >> "$SKILLDROP_LOOP_LOG"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Fields: `ts` (UTC), `loop`, `stage`, `gate` (`null` for a stage without one), `verdict` (the
|
|
114
|
+
gate's exact word), and `round` (1 for the first attempt, counting returns under the cap).
|
|
115
|
+
The log holds verdicts only: never a risk, an owner's name or any personal data.
|
|
116
|
+
`skilldrop loop-stats` summarises the file.
|
|
117
|
+
|
|
118
|
+
## Quality bar
|
|
119
|
+
|
|
120
|
+
- **The three documents agree.** Every DPIA risk at medium or high residual has a register row, and every control a residual rating relies on appears in the evidence map.
|
|
121
|
+
- **A residual rating counts only evidenced controls.** A control with an evidence gap gives no credit until the evidence exists, and the gap has a dated action.
|
|
122
|
+
- **G8 is the script's exit code.** The register reaches its owner only with zero errors.
|
|
123
|
+
- **Only a named owner accepts a risk.** High and critical residual risks accepted by their own owner carry a second, named sign-off.
|
|
124
|
+
- **Not legal or audit advice, said once.** The DPO's advice, the decision and the sign-off fields are left for the people who give them.
|
|
125
|
+
|
|
126
|
+
## Anti-patterns to avoid
|
|
127
|
+
|
|
128
|
+
- ❌ **Filing the DPIA beside the register instead of into it.** A high risk to people that isn't on the owner's list doesn't get signed off; it gets missed.
|
|
129
|
+
- ❌ **Leaving a residual rating on a control the evidence map marked `gap`.** That is a planned control scored as a real one, the exact thing the register bans.
|
|
130
|
+
- ❌ **Editing the register to turn G8 green.** Fix the risk the script names; don't delete the row or soften the score.
|
|
131
|
+
- ❌ **Running the evidence map on the whole SOC 2 scope.** The loop needs evidence for the controls this change relies on; a full readiness assessment is a separate piece of work.
|
|
132
|
+
- ❌ **Self-signing at G8.1.** A clean check says the register is well-formed. It cannot say the risk is acceptable.
|
|
133
|
+
- ❌ **Writing a guessed vendor location or retention period** to complete the DPIA. It stays `[to confirm: …]` and becomes a DPO question.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
[
|
|
2
|
+
{"query": "get the new payroll vendor ready for risk sign-off", "should_trigger": true},
|
|
3
|
+
{"query": "run the comply loop on our launch of in-store facial recognition", "should_trigger": true},
|
|
4
|
+
{"query": "what do we need before we can launch this feature that profiles customers?", "should_trigger": true},
|
|
5
|
+
{"query": "I need a risk register, a DPIA and the audit evidence for this change, and they have to agree", "should_trigger": true},
|
|
6
|
+
{"query": "score these five risks on a 5x5", "should_trigger": false},
|
|
7
|
+
{"query": "do we need a DPIA for the new CRM?", "should_trigger": false},
|
|
8
|
+
{"query": "fill in this customer's security questionnaire", "should_trigger": false}
|
|
9
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"loop_name": "comply",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": "evidence-gap-reverts-the-rating",
|
|
6
|
+
"prompt": "Run the comply loop. We're moving payroll to a new SaaS vendor, Paywell, on 1 December. It will hold names, bank details, salaries and sickness absence for 420 UK staff; Paywell's support team is in India. The HR director, Priya Shah, owns the change. Our controls: SSO with MFA for HR users (Okta), quarterly access reviews (we've done one, in March), and an annual vendor security review (not yet done for Paywell).",
|
|
7
|
+
"assertions": [
|
|
8
|
+
"Writes each risk as cause, event and consequence with a named owner, inherent and residual scores on a stated scale",
|
|
9
|
+
"Finds that a DPIA is needed (special category health data, transfer outside the UK) and completes it, leaving the DPO advice and decision blank",
|
|
10
|
+
"Adds a register row for each DPIA risk to people left at medium or high residual",
|
|
11
|
+
"Marks the quarterly access review as partial or a gap for a Type II period (one review since March) and the Paywell vendor review as a gap",
|
|
12
|
+
"Sets the residual rating of any risk relying on the missing vendor review back to its inherent rating",
|
|
13
|
+
"Runs check_register.py and reports G8 from its exit code",
|
|
14
|
+
"Stops at G8.1 with BLOCKED or a request for Priya Shah's decision; does not accept any risk on the owner's behalf",
|
|
15
|
+
"Does not invent Paywell's data centre location or a retention period; marks them [to confirm: ...]"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "script-failure-returns-to-register",
|
|
20
|
+
"prompt": "Continuing the comply loop. The check exited 1 and printed: \"line 5 [R-004]: owner 'IT' is not a named person or role\" and \"line 8 [R-007]: residual score 12 is higher than inherent score 9\". Fix it.",
|
|
21
|
+
"assertions": [
|
|
22
|
+
"Treats the output as G8 NOT READY and returns to the register stage",
|
|
23
|
+
"Asks for or names a person or role to own R-004 rather than inventing one",
|
|
24
|
+
"Corrects R-007 by revisiting its scores or controls, not by deleting the row",
|
|
25
|
+
"Re-runs the script and reports the new exit code before going to sign-off",
|
|
26
|
+
"Counts this as round 2 under the cap of 3"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "RFC-0052. A change to a risk position its owner has signed. The register's own script decides G8, so a register with a guessed owner or a residual above its inherent cannot reach the person signing; that person decides G8.1, because accepting a risk is theirs alone.",
|
|
3
|
+
"name": "comply",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Take a change that carries risk (a launch, a new vendor, a new use of personal data) to a risk position its owner has signed: a risk register scored inherent and residual, a DPIA when personal data is processed, the evidence behind every control the ratings rely on, a script that checks the register, and a sign-off only the named owner can give. Use when the user says \"get this ready for risk sign-off\", \"run the comply loop\", \"what do we need before we can launch this\", or needs a register, a DPIA and audit evidence that agree with each other.",
|
|
6
|
+
"entrypoint": "LOOP.md",
|
|
7
|
+
"kind": "loop",
|
|
8
|
+
"cap": 3,
|
|
9
|
+
"stages": [
|
|
10
|
+
{
|
|
11
|
+
"id": "register",
|
|
12
|
+
"type": "generate",
|
|
13
|
+
"intent": "Write the change's risks as cause, event and consequence, scored inherent and residual on a stated scale, each with a named owner and a treatment.",
|
|
14
|
+
"skills": ["risk-register"]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": "assess",
|
|
18
|
+
"type": "generate",
|
|
19
|
+
"intent": "Screen for a DPIA and, where one is needed, score the harm to people; each risk to people left at medium or high gets its own row in the register.",
|
|
20
|
+
"skills": ["dpia"]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "evidence",
|
|
24
|
+
"type": "generate",
|
|
25
|
+
"intent": "For every control the residual ratings and the DPIA's measures rely on, name the evidence that it operates today, and mark the gaps.",
|
|
26
|
+
"skills": ["soc2-evidence-map"]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "check",
|
|
30
|
+
"type": "verify",
|
|
31
|
+
"intent": "Run the register's own check, after evidence gaps have put residual ratings back where the evidence leaves them.",
|
|
32
|
+
"skills": ["risk-register"],
|
|
33
|
+
"gate": {
|
|
34
|
+
"id": "G8",
|
|
35
|
+
"kind": "mechanical",
|
|
36
|
+
"script": "packs/grc/skills/risk-register/scripts/check_register.py",
|
|
37
|
+
"verdicts": ["READY", "NOT READY", "BLOCKED"],
|
|
38
|
+
"revise_to": "register"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "sign-off",
|
|
43
|
+
"type": "gate",
|
|
44
|
+
"intent": "The named owner accepts each residual risk, or doesn't. The critique informs that decision; it does not make it.",
|
|
45
|
+
"skills": ["doc-critique"],
|
|
46
|
+
"gate": {
|
|
47
|
+
"id": "G8.1",
|
|
48
|
+
"kind": "human",
|
|
49
|
+
"verdicts": ["PROCEED", "PROCEED WITH CONDITIONS", "REVISE", "RECONSIDER", "BLOCKED"],
|
|
50
|
+
"revise_to": "register"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
@@ -13,7 +13,7 @@ script: no check can tell you that you solved the wrong problem well.
|
|
|
13
13
|
|
|
14
14
|
| # | Stage | Type | Skills | Gate |
|
|
15
15
|
|---|---|---|---|---|
|
|
16
|
-
| 1 | `gather` | generate | [`requirements-interview`](../../skills/requirements-interview/SKILL.md), [`user-journey-map`](../../skills/user-journey-map/SKILL.md), [`strategy-analysis`](../../skills/strategy-analysis/SKILL.md) | — |
|
|
16
|
+
| 1 | `gather` | generate | [`requirements-interview`](../../skills/requirements-interview/SKILL.md), [`user-journey-map`](../../skills/user-journey-map/SKILL.md), [`strategy-analysis`](../../skills/strategy-analysis/SKILL.md), [`feedback-synthesis`](../../skills/feedback-synthesis/SKILL.md) | — |
|
|
17
17
|
| 2 | `structure` | generate | [`brief-intake`](../../../core/skills/brief-intake/SKILL.md) | — |
|
|
18
18
|
| 3 | `specify` | generate | [`prd-draft`](../../skills/prd-draft/SKILL.md) | — |
|
|
19
19
|
| 4 | `ratify` | gate | [`doc-critique`](../../../core/skills/doc-critique/SKILL.md) | **G0** human |
|
|
@@ -22,8 +22,9 @@ script: no check can tell you that you solved the wrong problem well.
|
|
|
22
22
|
|
|
23
23
|
1. **Gather from whichever direction the signal arrives.** A stakeholder conversation →
|
|
24
24
|
`requirements-interview`. An existing experience with known friction → `user-journey-map`.
|
|
25
|
-
An open strategic question → `strategy-analysis`.
|
|
26
|
-
|
|
25
|
+
An open strategic question → `strategy-analysis`. A pile of tickets, survey verbatims or
|
|
26
|
+
interview notes already collected → `feedback-synthesis`. Run one; running several on the
|
|
27
|
+
same input produces several views of the same thing and no more information.
|
|
27
28
|
2. **Structure once.** `brief-intake` tags every field `[explicit]` / `[implied]` /
|
|
28
29
|
`[inferred]` / `[missing]` with verbatim quotes. The tags are the deliverable — an
|
|
29
30
|
untagged brief hides which parts are somebody's assumption.
|
|
@@ -75,7 +76,7 @@ which end in `BLOCKED`.
|
|
|
75
76
|
|
|
76
77
|
## Anti-patterns to avoid
|
|
77
78
|
|
|
78
|
-
- ❌ **Running
|
|
79
|
+
- ❌ **Running every `gather` skill to be thorough.** Three lenses on one input is not three inputs; pick the one that matches where the signal came from.
|
|
79
80
|
- ❌ **Letting `prd-draft` fill a `[missing]` field.** That converts an open question into a fact nobody agreed to.
|
|
80
81
|
- ❌ **Treating `doc-critique`'s `SHIP IT` as ratification.** The critique judges the document; G0 judges the problem.
|
|
81
82
|
- ❌ **Returning `REVISE` to `specify`.** Re-writing the PRD from the same thin brief reproduces the same gaps in better prose.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "RFC-0028. The first loop of the lifecycle: nothing is designed or built until a human has ratified what problem is being solved. Cheapest loop to redo and the most expensive to skip.",
|
|
3
3
|
"name": "discover",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"description": "Take raw signal — interviews, journeys, a strategy question — to a requirement a human has ratified, so design starts from an agreed problem rather than an assumed one. Use when the user is deciding what to build, scoping a feature, or turning stakeholder conversations into requirements.",
|
|
6
6
|
"entrypoint": "LOOP.md",
|
|
7
7
|
"kind": "loop",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"id": "gather",
|
|
12
12
|
"type": "generate",
|
|
13
13
|
"intent": "Collect the raw signal from whichever direction it arrives: a stakeholder conversation, an existing user journey, or a strategic question.",
|
|
14
|
-
"skills": ["requirements-interview", "user-journey-map", "strategy-analysis"]
|
|
14
|
+
"skills": ["requirements-interview", "user-journey-map", "strategy-analysis", "feedback-synthesis"]
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
"id": "structure",
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: feedback-synthesis
|
|
3
|
+
description: Turn raw customer feedback — interview notes, support tickets, NPS or CSAT verbatims, app-store reviews, sales-call notes — into ranked themes a product decision can rest on, each a problem statement rather than a feature request, counted by distinct people or accounts not mentions, with segments, severity kept separate from frequency, verbatim quotes with source IDs, what people value, where sources disagree, what the sample cannot tell, and the questions for the next interviews. A stdlib script computes the counts. Use when the user says "what are customers telling us", "synthesise this feedback", "find the themes in these tickets / reviews / NPS comments", "affinity map these interview notes", or "what should we fix first based on feedback".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# feedback-synthesis
|
|
7
|
+
|
|
8
|
+
Feedback arrives as a pile of tickets, survey comments, reviews and notes, and the loudest
|
|
9
|
+
thing in the pile is rarely the most important. This skill turns the pile into a short list of
|
|
10
|
+
problems worth acting on, with numbers that are counted rather than guessed and quotes that can
|
|
11
|
+
be traced to the item they came from. It feeds discovery: the themes go to `brief-intake` to
|
|
12
|
+
become a brief, and the open questions go into the next round of interviews.
|
|
13
|
+
|
|
14
|
+
## How to respond
|
|
15
|
+
|
|
16
|
+
**Five rules come before the steps and outrank them:**
|
|
17
|
+
|
|
18
|
+
- **Answer what was asked, first.** Open with what to act on and why, in plain words. If the
|
|
19
|
+
data contradicts the user's premise ("the CSV export is our biggest problem"), say so in the
|
|
20
|
+
opening lines, with the count that shows it.
|
|
21
|
+
- **Count people, not mentions.** One customer filing six tickets is one customer. Every number
|
|
22
|
+
in the reply is a count of distinct people or accounts, computed, and says which.
|
|
23
|
+
- **Use only what the input contains.** No quote, count, segment, customer name, revenue figure
|
|
24
|
+
or reason that isn't in the feedback. What is missing goes in **What this can't tell us** and
|
|
25
|
+
the interview questions, never into a theme.
|
|
26
|
+
- **Deliver from what there is.** Feedback without IDs, segments or a stated decision still gets
|
|
27
|
+
a synthesis, with the limit named once. Ask first only when there is no feedback at all.
|
|
28
|
+
- **Write for someone who has never heard of this skill.** No skill names, file paths, script
|
|
29
|
+
output, theme codes or "S2" shorthand without its meaning. A next step is one plain sentence
|
|
30
|
+
at the end.
|
|
31
|
+
|
|
32
|
+
1. **Read every item before coding any.** List the sources and, for each, what an item is
|
|
33
|
+
(a ticket, a response, an interview, a review), what identifies the person (account ID,
|
|
34
|
+
respondent ID, reviewer name, nothing), and what segment fields exist (plan, role, region,
|
|
35
|
+
tenure, company size, score). Decide the counting unit: **accounts** for B2B feedback where
|
|
36
|
+
account IDs exist (two staff from one customer are one account), **people** otherwise.
|
|
37
|
+
Match people across sources only on a shared ID: an interviewee whose account ID appears in
|
|
38
|
+
the tickets is the same account. Anonymous rows are never merged by guesswork. A rep's or
|
|
39
|
+
interviewer's guess about what someone needs ("they'll probably need SSO") is not that
|
|
40
|
+
person's feedback: leave it uncoded and say so if it matters to the answer.
|
|
41
|
+
|
|
42
|
+
2. **Write the codebook as problem statements.** 4–12 themes, each one sentence saying who hits
|
|
43
|
+
what and what it costs them, plus a short code. A theme must be something the next interview
|
|
44
|
+
could prove wrong.
|
|
45
|
+
- ✅ *"Clients in the EU can't complete card payments; the error says authentication failed
|
|
46
|
+
and payment arrives weeks later by transfer."*
|
|
47
|
+
- ❌ *"Payment issues"* / *"Users want a better experience"* / *"Improve usability"* — banned:
|
|
48
|
+
nothing could disprove them.
|
|
49
|
+
- **A feature request is evidence of a need, not the need.** Rewrite it into the job behind
|
|
50
|
+
it and keep the request as a quote. ✅ *"Changing a rate means editing every recurring
|
|
51
|
+
invoice by hand — 30 to 58 invoices per price change"*, with "Please add bulk edit"
|
|
52
|
+
quoted as evidence. ❌ Theme title *"Bulk edit"*. Never let the loudest proposed solution
|
|
53
|
+
become the title.
|
|
54
|
+
- **A request with no stated reason is not a theme.** Three "add dark mode" comments with no
|
|
55
|
+
context go under **Requests with no stated need**, and the reason becomes an interview
|
|
56
|
+
question. Don't invent the need.
|
|
57
|
+
- Code what people value as themes too, prefixed `+` (`+reminders`). These become **What
|
|
58
|
+
not to break**.
|
|
59
|
+
|
|
60
|
+
3. **Rate severity per item, separately from frequency.** From what happened to the person, not
|
|
61
|
+
how angry they sound; capitals and exclamation marks don't raise it.
|
|
62
|
+
|
|
63
|
+
| Level | Meaning | Example |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| **S1 — blocker** | A core job can't be done, or money, data, security or compliance is at stake | Clients can't pay; data lost; can't log in |
|
|
66
|
+
| **S2 — major** | Done only through a costly recurring workaround, or the person says they'll leave over it | Reformatting an export by hand every month |
|
|
67
|
+
| **S3 — minor** | Slower or annoying; the workaround is quick | An extra click to find a report |
|
|
68
|
+
| **S4 — cosmetic** | Looks, wording, preference, no stated cost | Blurry logo on a PDF |
|
|
69
|
+
|
|
70
|
+
More rules and edge cases in [`reference.md`](reference.md).
|
|
71
|
+
|
|
72
|
+
4. **Fill the coding sheet and run the counts.** One row per item in the shape of
|
|
73
|
+
[`templates/coding-sheet.csv`](templates/coding-sheet.csv): `item_id`, `person_id` (blank
|
|
74
|
+
when the source has none), `source`, the segment columns, `themes` separated by `;` (a code
|
|
75
|
+
may carry its own severity as `code:S1`), and `severity`. When a raw segment is too fine to
|
|
76
|
+
show a pattern, add a derived column beside it (country → `market` EU / UK / US; employee
|
|
77
|
+
count → `size` band). Then run:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Claude Code
|
|
81
|
+
python3 "${CLAUDE_SKILL_DIR}/scripts/theme_counts.py" coded.csv --person-label account -o counts.md
|
|
82
|
+
# Other IDEs (from the skill folder)
|
|
83
|
+
python3 scripts/theme_counts.py coded.csv --person-label account -o counts.md
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
It prints per theme the distinct people with an ID, the items with no ID (beside the count,
|
|
87
|
+
never added to it), mentions, repeat filers, sources, the segment breakdown with a flag when
|
|
88
|
+
a theme sits in one segment only, the ranking severity, and the items with no theme. If no script can run, count by hand from the sheet and show the
|
|
89
|
+
tally per theme. Above about 300 items, code the most recent full period or a stated sample,
|
|
90
|
+
and say the counts cover that sample.
|
|
91
|
+
|
|
92
|
+
5. **Read the counts, then fix the codebook.** Re-read the unthemed items: three or more about
|
|
93
|
+
the same thing is a missing theme. Where one person drives most of a theme's mentions, the
|
|
94
|
+
theme is ranked on its people count. Where a theme lives in one segment, that is a finding
|
|
95
|
+
(✅ *"Only EU accounts: DE, FR, NL"*), not a footnote. Rerun after any recode.
|
|
96
|
+
|
|
97
|
+
6. **Rank: severity first, then distinct people.** A theme's severity is the worst level at
|
|
98
|
+
least two people reached; a theme raised by one person takes that person's level and is
|
|
99
|
+
labelled *one report — confirm before acting*. The script's ranking severity column applies
|
|
100
|
+
this rule. A rare issue that stops payment outranks a common cosmetic gripe: say so in those
|
|
101
|
+
words when the ranking differs from the volume order.
|
|
102
|
+
|
|
103
|
+
7. **Write the reply in the shape of [`templates/synthesis.md`](templates/synthesis.md)**,
|
|
104
|
+
sized to the ask (a few bullets when asked for bullets):
|
|
105
|
+
- **Headline** — what to act on first and why, correcting the premise if needed.
|
|
106
|
+
- **Themes, ranked** — problem statement; distinct people or accounts, plus mentions when
|
|
107
|
+
they differ; segments; severity in words; sources.
|
|
108
|
+
- **Evidence per theme** — 1–3 verbatim quotes, each followed by its source ID:
|
|
109
|
+
*"Took most of a Friday." (I-2)*. The quote is an exact substring of the item; cut with
|
|
110
|
+
"…", never reword, never stitch two items into one quote. An interviewer's or rep's summary
|
|
111
|
+
is reported without quotation marks and attributed to them. The requests behind the theme
|
|
112
|
+
are quoted here too.
|
|
113
|
+
- **What not to break** — what people value, with counts and quotes.
|
|
114
|
+
- **Where the sources disagree** — ✅ *"Interviewees call reminders the reason they stay;
|
|
115
|
+
four accounts report reminders going to a former contact."* Both sides, counted.
|
|
116
|
+
- **What this can't tell us** — each source's sampling bias in one line, and the
|
|
117
|
+
conclusions it rules out. No percentage of the user base from a self-selected sample:
|
|
118
|
+
✅ *"7 of the 29 accounts that raised a ticket"* — ❌ *"24% of customers"*. Anonymous rows
|
|
119
|
+
that may overlap with identified ones are reported beside the count, never added to it:
|
|
120
|
+
✅ *"3 accounts, plus one anonymous NPS comment that may be one of them"*.
|
|
121
|
+
- **Questions for the next interviews** — 3–6, each tied to a theme, open, non-leading, and
|
|
122
|
+
at least one that could disconfirm the top theme. ✅ *"Walk me through the last time a
|
|
123
|
+
client couldn't pay you. What happened next?"* — ❌ *"Would a fix for card payments help?"*
|
|
124
|
+
|
|
125
|
+
8. **Keep the machinery out of the reply.** Theme codes, the coding sheet and the script's report
|
|
126
|
+
are working files; save them only when the user asked. The reply carries the answer.
|
|
127
|
+
|
|
128
|
+
**Non-interactive runs** (subagent, CI, headless): with no feedback items at all, emit
|
|
129
|
+
`BLOCKED: need the feedback itself (tickets, survey verbatims, interview notes or reviews)`,
|
|
130
|
+
because a synthesis of what customers "usually say" is fabrication. A missing decision or
|
|
131
|
+
audience becomes an `[assumption]` stated at the top (default: *"feeds next quarter's
|
|
132
|
+
prioritisation"*). Missing person IDs or segment fields are not blockers: proceed, and state
|
|
133
|
+
that the counts are mentions or unsegmented.
|
|
134
|
+
|
|
135
|
+
## Useful references in this skill
|
|
136
|
+
|
|
137
|
+
- [`reference.md`](reference.md) — the severity scale with edge cases, sampling bias by source, rewriting requests into problems, codebook rules, counting across sources
|
|
138
|
+
- [`templates/coding-sheet.csv`](templates/coding-sheet.csv) — the CSV the script reads
|
|
139
|
+
- [`templates/synthesis.md`](templates/synthesis.md) — the reply skeleton
|
|
140
|
+
- [`scripts/theme_counts.py`](scripts/theme_counts.py) — distinct-person counts per theme, segments, severity, unthemed items (stdlib, Python 3.9+)
|
|
141
|
+
- [`examples/booking-app-feedback.md`](examples/booking-app-feedback.md) — worked example: 16 items from three sources, the coding sheet, the real script output, and the finished reply
|
|
142
|
+
|
|
143
|
+
## Quality bar
|
|
144
|
+
|
|
145
|
+
- **Every count is distinct people or accounts,** computed from the coded items, and says which unit; mentions appear only beside it.
|
|
146
|
+
- **The ranking puts severity before frequency** and says so where the two disagree.
|
|
147
|
+
- **Every theme title is a falsifiable problem statement** naming who and what it costs; no theme is titled with a proposed feature.
|
|
148
|
+
- **Every quote is verbatim with a source ID;** paraphrase never sits inside quotation marks.
|
|
149
|
+
- **Segments are reported per theme,** and a one-segment theme is called out.
|
|
150
|
+
- **Each source's sampling bias is named,** and no percentage of the whole user base is drawn from a self-selected sample.
|
|
151
|
+
- **What people value and where the sources disagree** are both present.
|
|
152
|
+
- **Interview questions are tied to themes,** open, and include one that could disconfirm the top theme.
|
|
153
|
+
- **Nothing is invented:** no quote, count, segment, reason or customer that isn't in the input.
|
|
154
|
+
|
|
155
|
+
## When to use this skill
|
|
156
|
+
|
|
157
|
+
- ✅ A pile of support tickets, NPS or CSAT comments, reviews or interview notes, and the question "what are customers telling us?"
|
|
158
|
+
- ✅ Checking a stakeholder's claim ("everyone asks for SSO") against the feedback before it goes into a brief
|
|
159
|
+
- ✅ Affinity-mapping interview notes after a discovery round
|
|
160
|
+
- ✅ Choosing what to fix first from a quarter's feedback
|
|
161
|
+
|
|
162
|
+
## When NOT to use this skill
|
|
163
|
+
|
|
164
|
+
- ❌ Planning or running the interviews themselves, or writing the question guide — `requirements-interview`
|
|
165
|
+
- ❌ Mapping the stages of a journey a customer goes through — `user-journey-map`
|
|
166
|
+
- ❌ Answering a research question from papers, reports or articles — `source-synthesis`
|
|
167
|
+
- ❌ Ranking rival explanations for a metric change ("why did churn rise in March?") — `hypothesis-comparison`
|
|
168
|
+
- ❌ Turning agreed findings into a brief for a PRD or design doc — `brief-intake`
|
|
169
|
+
- ❌ Cleaning up a tracker backlog: duplicates, stale tickets, ordering — `backlog-triage`
|
|
170
|
+
|
|
171
|
+
## Anti-patterns to avoid
|
|
172
|
+
|
|
173
|
+
- ❌ **Counting tickets as customers.** "CSV export: 7 tickets, our biggest issue" when six came from one account.
|
|
174
|
+
- ❌ **Ranking by volume alone.** Seven blurry-logo complaints above three accounts whose clients can't pay.
|
|
175
|
+
- ❌ **The feature as the theme.** "Users want bulk edit" — the theme is the hours lost re-pricing recurring invoices.
|
|
176
|
+
- ❌ **Inventing the need behind a bare request.** "Users want dark mode for eye strain" when nobody said why.
|
|
177
|
+
- ❌ **Quotation marks around a summary.** A rep's note or the agent's paraphrase presented as the customer's words.
|
|
178
|
+
- ❌ **Percentages of the base from a self-selected sample.** "40% of users want an Apple Watch app" from fifteen reviews.
|
|
179
|
+
- ❌ **Merging anonymous rows into identified counts** by guessing who wrote them.
|
|
180
|
+
- ❌ **Only problems.** Leaving out what people value invites the fix that breaks it.
|
|
181
|
+
- ❌ **Vague themes.** "Pricing concerns", "usability", "better experience": name who, what happened, and what it cost.
|
|
182
|
+
- ❌ **Leading interview questions.** "Would you use bulk edit?" confirms nothing.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"query": "Here are 200 support tickets and last quarter's NPS comments. What are customers actually telling us?",
|
|
4
|
+
"should_trigger": true
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
"query": "Affinity map these eight interview notes into themes with quotes",
|
|
8
|
+
"should_trigger": true
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"query": "Find the themes in our app store reviews and tell me what to fix first",
|
|
12
|
+
"should_trigger": true
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"query": "Sales says every prospect wants SSO. Check that against the call notes and churn survey before it goes in the brief",
|
|
16
|
+
"should_trigger": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"query": "Synthesise this CSAT export into the top customer pain points by segment",
|
|
20
|
+
"should_trigger": true
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"query": "Write me an interview guide for talking to churned customers next week",
|
|
24
|
+
"should_trigger": false
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"query": "Map our customer's onboarding journey from sign-up to first invoice, with pains at each stage",
|
|
28
|
+
"should_trigger": false
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"query": "Summarise what these five industry reports say about four-day weeks",
|
|
32
|
+
"should_trigger": false
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"query": "Churn jumped 3 points in August. Which of these explanations fits the evidence best?",
|
|
36
|
+
"should_trigger": false
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"query": "Clean up our Jira backlog: duplicates, stale tickets and what to pull next",
|
|
40
|
+
"should_trigger": false
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"query": "Turn this Slack thread about the export bug into a brief for the PRD",
|
|
44
|
+
"should_trigger": false
|
|
45
|
+
}
|
|
46
|
+
]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "feedback-synthesis",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "I'm the PM for Tallyhouse, our invoicing app for small businesses. Q4 planning is next week and I need to know what customers actually told us in Q3. It's all in this folder: support-tickets.csv (35 tickets), nps-verbatims.csv (the 12 NPS responses that left a comment; the survey is anonymous) and interview-notes.md (5 customer interviews). What are the themes, and which should we act on first? The loudest thing in support is the CSV export, so I'm assuming that's number one.",
|
|
7
|
+
"assertions": [
|
|
8
|
+
"It corrects the premise: the CSV export problem comes from 2 accounts, and 6 of its 7 tickets are from one account (A-1042), so it is not ranked first on volume",
|
|
9
|
+
"It ranks card payments failing for clients (3 accounts: A-1107, A-1220, A-1315) above the blurry PDF logo (7 accounts), stating that payment failure blocks getting paid while the logo is cosmetic",
|
|
10
|
+
"It says the card payment failures come only from EU accounts (Germany, France, Netherlands), and reports the anonymous NPS comment N-06 beside the 3 accounts rather than adding it to make 4",
|
|
11
|
+
"It states the bulk-edit requests as the problem behind them (changing a rate means editing each recurring invoice by hand, 30 to 58 invoices) and keeps 'bulk edit' only as a quoted request",
|
|
12
|
+
"It does not make dark mode a theme with an invented reason: it reports the three anonymous NPS requests as having no stated need and turns the reason into an interview question",
|
|
13
|
+
"It names automatic payment reminders as something customers value and should not be broken, and notes the conflict with the accounts reporting reminders sent to a former contact",
|
|
14
|
+
"It names the limits of each source (tickets come from people with problems, 12 self-selected anonymous NPS comments, 5 interviews) and gives no percentage of the customer base",
|
|
15
|
+
"Every quotation is verbatim from the files with its ticket, response or interview ID, interviewer summaries are not put in quotation marks, and it invents no quotes or counts not in the input"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": 2,
|
|
20
|
+
"prompt": "Here are our 15 App Store reviews for Stridewell (running app) from September. Which 3 features should we build next, and roughly what % of our users want each? Bullets please, it's going in Slack.\n\n1. RunnerJo, 2 stars: \"Please sync with Strava! I have to upload every run twice.\"\n2. Mo_K, 5 stars: \"The training plans are brilliant. Got me from 5k to 10k.\"\n3. hilltrotter, 1 star: \"Lost my whole 21k long run when I went through the woods with no signal. Recording just stopped. Gutted.\"\n4. Bex R, 4 stars: \"Need an Apple Watch app so I can leave my phone at home.\"\n5. RunnerJo, 2 stars: \"Still no Strava sync. Updating my review.\"\n6. dawnpatrol, 3 stars: \"Apple Watch app please\"\n7. Sam T, 5 stars: \"Training plans adapt when I miss a session, love it.\"\n8. trailmix, 1 star: \"Run recording cuts out in the hills where there's no reception. Lost two runs this month.\"\n9. Kez, 4 stars: \"Would be 5 stars with Apple Watch support.\"\n10. NightOwl, 3 stars: \"Font on the run screen is too small to read mid-run.\"\n11. pacepal, 3 stars: \"Strava sync would be nice.\"\n12. Lou, 4 stars: \"Apple Watch app!!\"\n13. GreenMile, 5 stars: \"Best plans of any running app I've tried.\"\n14. ahmedruns, 2 stars: \"Make it work offline.\"\n15. Fenn, 4 stars: \"Great app, but add dark mode.\"",
|
|
21
|
+
"assertions": [
|
|
22
|
+
"It gives no percentage of users for any item, says 15 self-selected reviews cannot support one, and gives counts of reviewers instead",
|
|
23
|
+
"It counts the Strava request as 2 reviewers, not 3, because RunnerJo wrote two of the reviews",
|
|
24
|
+
"It ranks runs being lost where there is no signal (hilltrotter, trailmix) at or near the top as a data-loss problem, ahead of more often requested items that block nothing",
|
|
25
|
+
"It states the lost-runs and Apple Watch items as problems (recording stops without signal; running without the phone) rather than as 'offline mode' and 'Apple Watch app', and notes only one of the four Apple Watch reviews says why",
|
|
26
|
+
"It names the training plans as what reviewers value and should not be broken",
|
|
27
|
+
"It keeps to short bullets suitable for a Slack message, without a long report",
|
|
28
|
+
"Quotations are verbatim from the reviews, and it invents no reviews, reasons or counts not in the prompt"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": 3,
|
|
33
|
+
"prompt": "Our Head of Sales keeps saying every enterprise prospect asks for SSO and it's costing us deals, and she wants it at the top of the Q1 brief for Fieldnote. Before I write the brief, pull the themes out of sales-call-notes.md (eight calls from September) and churn-exit-survey.csv (the ten exit surveys from Q3). I need something I can hand straight to whoever writes the brief.",
|
|
34
|
+
"assertions": [
|
|
35
|
+
"It counts SSO by distinct prospect: Harrowgate Logistics' two calls (C-01, C-03) count once, and the rep's own note on Norland (C-06) is not counted as a prospect asking, giving 2 prospects (Harrowgate and Brightwater)",
|
|
36
|
+
"It reports that SSO came only from prospects with 650 or more staff, that Norland (900 staff) did not raise it, and that no churned customer mentions it while noting that no churned respondent is in that size band",
|
|
37
|
+
"It identifies double-booking or clashes when jobs are reassigned as the most common churn theme (5 of the 10 exit responses: X-02, X-03, X-05, X-06, X-09) and notes that two prospects (C-02, C-07) raised the same problem",
|
|
38
|
+
"It states themes as problems (enterprise IT won't approve a rollout without central sign-in; reassigning a sick technician's jobs creates double bookings) rather than as feature names",
|
|
39
|
+
"It names the sampling limits: sales notes are prospects' words filtered through reps, and the exit survey covers leavers only",
|
|
40
|
+
"It does not put a rep's summary (such as C-08's pricing note or C-06's SSO note) inside quotation marks as the prospect's words, and every quotation carries its call or response ID",
|
|
41
|
+
"It states plainly how the evidence compares with the claim that every enterprise prospect asks for SSO, and ends with questions for the next interviews tied to the themes",
|
|
42
|
+
"It invents no quotes, deal values or counts not in the files; the only deal value cited is the rep's £84k estimate for Harrowgate, attributed to the rep"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": 4,
|
|
47
|
+
"held_out": "2026-10-20",
|
|
48
|
+
"prompt": "I'm the PM for Tallyweave (invoicing + expenses for small businesses). I've dropped our Q3 support ticket export in support_tickets_q3.csv and the CSAT survey comments for the same quarter in csat_comments_q3.csv. Engineering has told me we can fund exactly one fix next quarter. Can you work out what customers are actually telling us and what we should fix first? I'm taking this to quarterly planning on Thursday, so I need something I can defend in the room, not just a list of the most common ticket subjects.",
|
|
49
|
+
"assertions": [
|
|
50
|
+
"Counts the export-timeout issue by account, not by ticket: 10 tickets but only 3 accounts. It says outright that one account (ACC-1042 / Brightfen Logistics) filed 8 of those 10, and it does not rank export timeouts first because of ticket volume.",
|
|
51
|
+
"Groups the tickets worded as different feature requests ('Excel export', 'bulk edit', 'notes field', 'bank integration', the wrong balance on a statement, the overdue reminder sent after a deposit) into one problem: Tallyweave cannot record or show part-payments or instalments against an invoice. It counts this across 9 accounts in the tickets (10 distinct accounts if CSAT is included, with ACC-1023 counted once), and states it as a problem, not as a request for an Excel export.",
|
|
52
|
+
"Breaks themes down by segment and notes that the part-payment problem sits mostly in the Starter plan (7 of 9 ticket accounts). It also notes the SSO lockout affects only Enterprise accounts.",
|
|
53
|
+
"Calls out the SSO lockout (TW-4130, TW-4168: 2 Enterprise accounts, whole organisation unable to log in, no fallback) as a severe blocker. It rates severity separately from how often the issue appears, and does not bury the lockout or drop it because only 2 accounts raised it. It also says the lockout may need handling outside the one-fix-per-quarter budget, or names it as an explicit risk.",
|
|
54
|
+
"Spots that the sources disagree about receipt scanning. The tickets say it misreads amounts, while CSAT comments call it the best part of the product. It explains the gap by platform: all 7 scanning tickets (6 accounts) come from Android, and the 5 CSAT comments praising the scanner come from iOS.",
|
|
55
|
+
"Makes one clear recommendation for the single funded fix. The case rests on distinct accounts affected plus severity and business impact (e.g. churn threats, client-facing embarrassment), not raw ticket counts. It also says what evidence would change the call (e.g. account revenue, Brightfen's churn risk).",
|
|
56
|
+
"States what this sample cannot tell. Tickets only capture customers who contact support. CSAT covers a subset of accounts. The data has no revenue or seat-count weighting. It then lists specific follow-up questions or interviews to close those gaps.",
|
|
57
|
+
"Every quote is verbatim text from the two CSV files and carries its ticket_id or response_id. No count, percentage or account total is invented or fails to match the files (e.g. 48 tickets from 36 accounts; 16 CSAT responses)."
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": 5,
|
|
62
|
+
"held_out": "2026-10-20",
|
|
63
|
+
"prompt": "I'm the product designer on Basilbox, a meal-planning app. Attached are the last 60 days of App Store and Google Play reviews (app_reviews_last_60_days.csv, exported from our review tool, so reviewers only have display names) and my typed notes from the six discovery interviews I ran (interview_notes_round1.md). Could you affinity map all of this and tell me what users are telling us? I'm running round 2 of interviews in two weeks and want to know who to recruit and what to ask.",
|
|
64
|
+
"assertions": [
|
|
65
|
+
"Counts reviewers, not reviews. It notices that KitchenKween88 wrote 4 of the reviews complaining about the grocery-list paywall and ads. It reports that theme as roughly 4 to 6 distinct reviewers (depending on whether the ads-only and price-only reviews are included), not as 9 people.",
|
|
66
|
+
"Reframes the 'calendar view' requests as the problem underneath them: the number of people eating changes from night to night or week to week, so portions are wrong and food is wasted. The evidence is the review text (lowtide_lou, Priya_in_Leeds, Teo M.) and interviews P2, P4 and P5. It does not present 'build a calendar view' as the finding.",
|
|
67
|
+
"Flags the data loss after Sign in with Apple (2 App Store reviews on version 4.2.0; all saved recipes gone) as high severity despite being rare. It keeps severity separate from frequency, and may link this to P6 saying losing recipes would make them quit.",
|
|
68
|
+
"Notes that URL recipe-import failures are concentrated on one platform: all 5 such reviews are from Google Play, mostly on 4.2.0/4.2.1. It does not treat P3's smooth import on iPhone as evidence against the bug.",
|
|
69
|
+
"Surfaces the disagreement on price. Reviews call Premium too expensive and the paywall a bait-and-switch, while every interviewee calls the price fine or worth it. It explains the gap by recruitment bias: interviewees were active annual Premium subscribers. It does not declare either source right.",
|
|
70
|
+
"States what the sample cannot tell. App reviews self-select toward extremes. No free-tier or Android users were interviewed. Reviewers cannot be matched to interviewees, so people cannot be added up across the two sources. Six interviews are too few to estimate prevalence.",
|
|
71
|
+
"Gives round-2 recruitment and questions tied to the gaps found. Examples: recruit free-tier or lapsed users and Android users; ask how household headcount varies across a week and how people adjust portions now; probe the sign-in or update experience. Generic questions like 'what do you like about the app' do not count.",
|
|
72
|
+
"Every quote is verbatim text from the CSV or the interview notes, with its source (review author/date, or P1 to P6). No counts or percentages are invented or contradict the files (31 reviews, 28 distinct display names, 6 interviewees)."
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|