@ericrisco/rsc 0.1.44 → 0.1.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/manifest.json +110 -86
- package/package.json +1 -1
- package/scripts/lib/domains.js +1 -1
- package/scripts/skill-migration-brief.md +192 -0
- package/skills/ab-testing/SKILL.md +9 -41
- package/skills/accessibility/SKILL.md +5 -7
- package/skills/ads/SKILL.md +9 -24
- package/skills/agent-eval/SKILL.md +7 -33
- package/skills/agent-safety/SKILL.md +7 -14
- package/skills/ai-media/SKILL.md +4 -20
- package/skills/analytics/SKILL.md +8 -30
- package/skills/analyze/SKILL.md +24 -59
- package/skills/angular/SKILL.md +12 -25
- package/skills/api-connector-builder/SKILL.md +10 -27
- package/skills/api-design/SKILL.md +7 -14
- package/skills/article-writing/SKILL.md +1 -18
- package/skills/astro/SKILL.md +36 -54
- package/skills/author-skill/SKILL.md +41 -74
- package/skills/author-skill/evals/README.md +5 -5
- package/skills/author-skill/evals/cases.yaml +8 -8
- package/skills/author-skill/references/description-recipe.md +25 -26
- package/skills/author-skill/references/eval-authoring.md +1 -1
- package/skills/author-skill/references/rsc-conventions.md +1 -1
- package/skills/automation-flows/SKILL.md +6 -16
- package/skills/automation-strategy/SKILL.md +1 -9
- package/skills/aws-essentials/SKILL.md +6 -23
- package/skills/backups/SKILL.md +1 -7
- package/skills/bash-scripting/SKILL.md +5 -9
- package/skills/bookkeeping/SKILL.md +2 -10
- package/skills/brand-identity/SKILL.md +18 -44
- package/skills/brand-voice/SKILL.md +4 -31
- package/skills/building-agents/SKILL.md +20 -103
- package/skills/business-intelligence/SKILL.md +9 -23
- package/skills/calendar-scheduling/SKILL.md +11 -27
- package/skills/case-studies/SKILL.md +3 -8
- package/skills/chatbot/SKILL.md +6 -23
- package/skills/chrome-extension/SKILL.md +2 -2
- package/skills/clarify/SKILL.md +31 -72
- package/skills/clickhouse-analytics/SKILL.md +2 -8
- package/skills/client-onboarding/SKILL.md +17 -19
- package/skills/cloudflare/SKILL.md +3 -8
- package/skills/code-review/SKILL.md +10 -23
- package/skills/codebase-onboarding/SKILL.md +2 -7
- package/skills/cold-outreach/SKILL.md +9 -30
- package/skills/community/SKILL.md +4 -31
- package/skills/competitor-watch/SKILL.md +20 -35
- package/skills/compliance/SKILL.md +10 -37
- package/skills/compose-multiplatform/SKILL.md +1 -1
- package/skills/constitution/SKILL.md +8 -35
- package/skills/content-engine/SKILL.md +4 -16
- package/skills/context-budget/SKILL.md +3 -21
- package/skills/continuous-learning/SKILL.md +10 -40
- package/skills/contracts/SKILL.md +6 -17
- package/skills/coolify/SKILL.md +8 -14
- package/skills/cost-tracking/SKILL.md +3 -11
- package/skills/course-builder/SKILL.md +17 -45
- package/skills/course-storytelling/SKILL.md +26 -94
- package/skills/cpp/SKILL.md +26 -71
- package/skills/csharp-dotnet/SKILL.md +19 -38
- package/skills/customer-support/SKILL.md +14 -37
- package/skills/dashboard/SKILL.md +6 -26
- package/skills/data-cleaning/SKILL.md +37 -63
- package/skills/data-policy/SKILL.md +8 -21
- package/skills/data-scraper/SKILL.md +1 -7
- package/skills/debug/SKILL.md +10 -49
- package/skills/deployment/SKILL.md +38 -101
- package/skills/design/SKILL.md +34 -116
- package/skills/fable-operator/SKILL.md +1 -4
- package/skills/fastapi/SKILL.md +50 -82
- package/skills/flutter/SKILL.md +41 -89
- package/skills/go/SKILL.md +57 -105
- package/skills/harness/SKILL.md +52 -68
- package/skills/implement/SKILL.md +1 -1
- package/skills/init/SKILL.md +152 -168
- package/skills/marketing/SKILL.md +30 -80
- package/skills/nextjs/SKILL.md +42 -116
- package/skills/orient/SKILL.md +25 -20
- package/skills/parallel/SKILL.md +9 -75
- package/skills/plan/SKILL.md +92 -165
- package/skills/postgresdb/SKILL.md +52 -72
- package/skills/presentations/SKILL.md +49 -87
- package/skills/python/SKILL.md +23 -72
- package/skills/react/SKILL.md +19 -67
- package/skills/review/SKILL.md +22 -52
- package/skills/rust/SKILL.md +40 -115
- package/skills/sdd-init/SKILL.md +9 -14
- package/skills/secure-coding/SKILL.md +80 -109
- package/skills/ship/SKILL.md +25 -55
- package/skills/tasks/SKILL.md +37 -61
- package/skills/typescript/SKILL.md +22 -55
- package/skills/verify/SKILL.md +8 -32
- package/skills/viral-score/SKILL.md +122 -0
- package/skills/viral-score/evals/README.md +16 -0
- package/skills/viral-score/evals/cases.yaml +50 -0
- package/skills/vue-nuxt/SKILL.md +45 -106
- package/skills/worktrees/SKILL.md +24 -69
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: csharp-dotnet
|
|
3
|
-
description: "Use when writing, reviewing, testing, or shipping C# / .NET code
|
|
3
|
+
description: "Use when writing, reviewing, testing, or shipping C# / .NET code — ASP.NET Core APIs (minimal APIs vs controllers), EF Core data access, async correctness, solution layout in .cs/.csproj/.sln. NOT a Java/Spring backend (that is spring-boot), NOT a Node/TypeScript backend (that is nestjs), NOT framework-neutral REST naming (that is api-design)."
|
|
4
4
|
tags: [csharp, dotnet, aspnetcore, efcore, async]
|
|
5
5
|
recommends: [postgresdb, secure-coding, deployment]
|
|
6
6
|
origin: risco
|
|
@@ -20,17 +20,6 @@ support but shorter-lived. Features gate on the target framework moniker (TFM):
|
|
|
20
20
|
use a C# 14 feature (`field`, extension members, null-conditional assignment), say
|
|
21
21
|
which TFM it requires.
|
|
22
22
|
|
|
23
|
-
## When to use
|
|
24
|
-
|
|
25
|
-
- Authoring/reviewing/refactoring any `.cs`, `.csproj`, or `.sln`.
|
|
26
|
-
- ASP.NET Core: minimal APIs vs controllers, route groups, endpoint filters,
|
|
27
|
-
validation, ProblemDetails, OpenAPI.
|
|
28
|
-
- EF Core: `DbContext` design, LINQ queries, migrations, tracking, N+1.
|
|
29
|
-
- async/await correctness: `CancellationToken` plumbing, `async void`, deadlocks,
|
|
30
|
-
`IAsyncEnumerable`, `ValueTask`.
|
|
31
|
-
- `dotnet` CLI workflow, solution layout, NuGet, central package management.
|
|
32
|
-
- Idiom review: records, pattern matching, nullable reference types (NRT).
|
|
33
|
-
|
|
34
23
|
## When NOT to use — delegate
|
|
35
24
|
|
|
36
25
|
| Situation | Route to |
|
|
@@ -45,29 +34,7 @@ which TFM it requires.
|
|
|
45
34
|
|
|
46
35
|
The .NET *expression* of an API contract and async correctness live HERE. Resource
|
|
47
36
|
naming theory lives in `api-design`; the JVM and Node counterparts are `spring-boot`
|
|
48
|
-
and `nestjs`.
|
|
49
|
-
disk as siblings, so only those are linked as `../<id>/SKILL.md`.
|
|
50
|
-
|
|
51
|
-
## Decision rules — apply on every C# edit
|
|
52
|
-
|
|
53
|
-
1. **NRT on.** `<Nullable>enable</Nullable>` in the csproj. Why: the compiler turns
|
|
54
|
-
whole classes of `NullReferenceException` into build-time warnings. Never disable it
|
|
55
|
-
to silence a warning — fix the nullability.
|
|
56
|
-
2. **Async all the way, flow the token.** I/O methods are `async Task`, every call is
|
|
57
|
-
`await`ed, and a `CancellationToken` threads from the endpoint down to
|
|
58
|
-
`SaveChangesAsync`/queries/HTTP calls. Why: a dropped token means requests keep
|
|
59
|
-
running after the client gives up.
|
|
60
|
-
3. **Records for DTOs and immutable data.** `public record ProductDto(int Id, string Name);`.
|
|
61
|
-
Why: value equality + `with` expressions + concise; never reuse an EF entity as the
|
|
62
|
-
wire DTO (see anti-patterns).
|
|
63
|
-
4. **Parameterize every query.** EF LINQ and `FromSql` interpolation parameterize for
|
|
64
|
-
you; never string-concatenate SQL. Why: SQL injection.
|
|
65
|
-
5. **Deterministic disposal.** `using`/`await using` (or `using` declarations) for
|
|
66
|
-
anything `IDisposable`/`IAsyncDisposable`. Why: leaked connections/handles.
|
|
67
|
-
6. **One `DbContext` per request (scoped).** Why: `DbContext` is not thread-safe;
|
|
68
|
-
sharing across requests corrupts change tracking.
|
|
69
|
-
7. **Minimal APIs for new services** unless you need MVC features (views, model
|
|
70
|
-
binders, action filters at scale). Why: less ceremony, first-class in .NET 10.
|
|
37
|
+
and `nestjs`.
|
|
71
38
|
|
|
72
39
|
## Project & solution layout + dotnet CLI
|
|
73
40
|
|
|
@@ -101,6 +68,10 @@ Central package management: turn it on with `<ManagePackageVersionsCentrally>tru
|
|
|
101
68
|
and list versions once in `Directory.Packages.props`. Why: one source of truth, no
|
|
102
69
|
version drift across projects.
|
|
103
70
|
|
|
71
|
+
NRT on for every project — `<Nullable>enable</Nullable>` in `Directory.Build.props`.
|
|
72
|
+
Why: the compiler turns whole classes of `NullReferenceException` into build-time
|
|
73
|
+
warnings. Never disable it to silence a warning — fix the nullability.
|
|
74
|
+
|
|
104
75
|
## Modern C# idioms (C# 14 / .NET 10)
|
|
105
76
|
|
|
106
77
|
DTO as a record, not a class:
|
|
@@ -113,6 +84,9 @@ public class ProductDto { public int Id { get; set; } public string Name { get;
|
|
|
113
84
|
public record ProductDto(int Id, string Name, decimal Price);
|
|
114
85
|
```
|
|
115
86
|
|
|
87
|
+
Why: value equality, `with` expressions, no boilerplate — and never reuse an EF entity
|
|
88
|
+
as the wire DTO (see anti-patterns).
|
|
89
|
+
|
|
116
90
|
Pattern matching over if-chains:
|
|
117
91
|
|
|
118
92
|
```csharp
|
|
@@ -154,6 +128,9 @@ Prefer NRT annotations over defensive null checks: declare `string? note` when n
|
|
|
154
128
|
valid and let the compiler force callers to handle it, instead of `if (x == null)`
|
|
155
129
|
guards scattered everywhere.
|
|
156
130
|
|
|
131
|
+
Dispose deterministically: `using` / `await using` (or `using` declarations) for
|
|
132
|
+
anything `IDisposable`/`IAsyncDisposable`. Why: leaked connections and handles.
|
|
133
|
+
|
|
157
134
|
## async/await correctness
|
|
158
135
|
|
|
159
136
|
This is the highest-leverage area to get right. Core rules in body; the full catalog
|
|
@@ -173,7 +150,9 @@ public IActionResult Get() => Ok(_svc.LoadAsync().Result);
|
|
|
173
150
|
public async Task<IActionResult> Get(CancellationToken ct) => Ok(await _svc.LoadAsync(ct));
|
|
174
151
|
```
|
|
175
152
|
|
|
176
|
-
- **Flow `CancellationToken`** from the endpoint into every async call
|
|
153
|
+
- **Flow `CancellationToken`** from the endpoint down into every async call —
|
|
154
|
+
`SaveChangesAsync`, queries, outbound HTTP. Why: a dropped token means the request
|
|
155
|
+
keeps running after the client gives up.
|
|
177
156
|
- **`ValueTask` only for hot paths** that usually complete synchronously; default to
|
|
178
157
|
`Task`. Never `await` a `ValueTask` twice.
|
|
179
158
|
- **`IAsyncEnumerable<T>` for streaming** results instead of materializing a huge list.
|
|
@@ -182,6 +161,7 @@ public async Task<IActionResult> Get(CancellationToken ct) => Ok(await _svc.Load
|
|
|
182
161
|
|
|
183
162
|
Decision: **minimal API** for new services; **controllers** only when you need MVC
|
|
184
163
|
machinery (model binding conventions, action filters at scale, views). Both can coexist.
|
|
164
|
+
Why minimal by default: less ceremony, first-class in .NET 10.
|
|
185
165
|
|
|
186
166
|
Production minimal API shape — route group + DataAnnotations validation (built in for
|
|
187
167
|
minimal API parameters in .NET 10) + ProblemDetails + OpenAPI 3.1:
|
|
@@ -215,7 +195,8 @@ app.Run();
|
|
|
215
195
|
```
|
|
216
196
|
|
|
217
197
|
DI lifetimes: `Singleton` (one for the app), `Scoped` (one per request — `DbContext`
|
|
218
|
-
lives here
|
|
198
|
+
lives here; it is not thread-safe, so sharing one across requests corrupts change
|
|
199
|
+
tracking), `Transient` (new each resolve). Never inject a `Scoped` service into a
|
|
219
200
|
`Singleton` (captive dependency — see anti-patterns). Middleware ordering, endpoint
|
|
220
201
|
filters, the options pattern, and auth defaults are in **references/aspnetcore.md**.
|
|
221
202
|
|
|
@@ -252,7 +233,7 @@ Keep only the .NET-specific controls here; threat modeling and OWASP review go t
|
|
|
252
233
|
`../secure-coding/SKILL.md`.
|
|
253
234
|
|
|
254
235
|
- **Parameterized data access** — EF LINQ / parameterized `FromSql` / ADO.NET
|
|
255
|
-
`SqlParameter`. Never concatenate user input into SQL.
|
|
236
|
+
`SqlParameter`. Never concatenate user input into SQL. Why: SQL injection.
|
|
256
237
|
- **Secrets** — `dotnet user-secrets` in dev, Key Vault / environment in prod. Never in
|
|
257
238
|
`appsettings.json` or source.
|
|
258
239
|
- **Antiforgery** for cookie-auth browser POSTs; **Data Protection** for cookies/tokens
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: customer-support
|
|
3
|
-
description: "Use when a support ticket
|
|
3
|
+
description: "Use when a live support ticket needs triage (intent, P1–P4 priority, SLA clock), an on-voice reply, not a raw template, de-escalation of an angry or churn-risk customer, or escalation with a handoff packet. NOT the help-center article it links to (that is `technical-writing`), a win-back program (`retention`), or the auto-answer bot (`chatbot`)."
|
|
4
4
|
tags: [customer-support, helpdesk, ticket-triage, sla, escalation, macros, de-escalation, csat]
|
|
5
5
|
recommends: [technical-writing, client-onboarding, retention, chatbot, rag, brand-voice]
|
|
6
6
|
origin: risco
|
|
@@ -8,22 +8,8 @@ origin: risco
|
|
|
8
8
|
|
|
9
9
|
# Customer Support — Run the Desk on a Live Ticket
|
|
10
10
|
|
|
11
|
-
*A ticket just came in. Triage it, answer it on-voice, escalate it if it needs a human, and keep the SLA from blowing. This skill handles the live ticket — it does not write the article the ticket links to.*
|
|
12
|
-
|
|
13
11
|
You own the **support desk as an operation**: take an incoming ticket, assign priority and intent, start the SLA clock, draft the reply (macro or bespoke), enforce tone, and decide escalation with a clean handoff. The output is a triaged, answered ticket — human judgment, not a code artifact.
|
|
14
12
|
|
|
15
|
-
## What this owns vs. what it does not
|
|
16
|
-
|
|
17
|
-
| You reach for this when | Route elsewhere when |
|
|
18
|
-
|---|---|
|
|
19
|
-
| A ticket needs triage, a reply, an escalation call | Authoring the KB / help-center article a ticket links to → `technical-writing` |
|
|
20
|
-
| One churn-risk ticket needs de-escalation **now** | Running a win-back / renewal **program** → `retention` |
|
|
21
|
-
| You need macros, SLA targets, a handoff packet | Onboarding a brand-new customer (welcome, activation) → `client-onboarding` |
|
|
22
|
-
| A human (or assisted) reply against the brand voice | Building the autonomous auto-answer bot → `chatbot` + `rag` |
|
|
23
|
-
| Applying the voice to this reply | Authoring the voice guide itself → [`../brand-voice/SKILL.md`](../brand-voice/SKILL.md) |
|
|
24
|
-
|
|
25
|
-
The line: **writing the help-center article a ticket links to is `technical-writing`'s job; `customer-support` only handles the live ticket.** This skill *consumes* the KB to answer; it never writes the docs.
|
|
26
|
-
|
|
27
13
|
## The triage-to-reply loop (the spine)
|
|
28
14
|
|
|
29
15
|
Run every ticket through these six steps in order. Skipping triage to "just reply fast" is how you send the wrong tone to a P1.
|
|
@@ -37,29 +23,22 @@ Run every ticket through these six steps in order. Skipping triage to "just repl
|
|
|
37
23
|
6 Escalate or send → trigger met? hand off with the packet. else send + log.
|
|
38
24
|
```
|
|
39
25
|
|
|
40
|
-
|
|
26
|
+
## Priority, SLA, and the escalation call
|
|
41
27
|
|
|
42
|
-
|
|
43
|
-
|---|---|---|---|
|
|
44
|
-
| Production down / data loss / many users blocked | P1 | 15–30 min | Yes → tier-2/eng + the packet |
|
|
45
|
-
| Enterprise/VIP account, or "cancel / refund / lawyer / unacceptable" | P1–P2 | 30 min – 1 h | Yes → owner + tier-2 |
|
|
46
|
-
| One user blocked, no workaround | P2 | 1–2 h | Only if unresolved past target |
|
|
47
|
-
| Question with a workaround, billing query | P3 | 4–8 h | No, unless policy claim is unverifiable |
|
|
48
|
-
| FAQ, cosmetic, feature request | P4 | ~1 business day | No |
|
|
28
|
+
The branch is at step 6. This table sets priority, both SLA clocks, and whether the ticket leaves your hands:
|
|
49
29
|
|
|
50
|
-
|
|
30
|
+
| Signal in the ticket | Priority | First response (FRT) | Resolution target | Escalate? |
|
|
31
|
+
|---|---|---|---|---|
|
|
32
|
+
| Production down / data loss / payments broken / many users blocked | P1 critical | 15–30 min | ASAP, status updates every 30–60 min | Yes → tier-2/eng + the packet |
|
|
33
|
+
| Enterprise/VIP account, or "cancel / refund / lawyer / unacceptable" | P1–P2 | 30 min – 1 h | Same business day | Yes → owner + tier-2 |
|
|
34
|
+
| One user blocked, no workaround | P2 high | 1–2 h | Same business day | Only if unresolved past target |
|
|
35
|
+
| Question with a workaround, billing query | P3 medium | 4–8 h | 1–2 business days | No, unless policy claim is unverifiable |
|
|
36
|
+
| FAQ, cosmetic, feature request | P4 low | ~1 business day | Best effort | No |
|
|
51
37
|
|
|
52
|
-
|
|
38
|
+
**Why pick the FRT target before drafting:** the SLA decides your tone and length. A P1 gets a two-line acknowledgment in 20 minutes, not a polished essay in two hours.
|
|
53
39
|
|
|
54
40
|
Use **3–4 priority tiers, never a flat SLA.** Too many tiers confuse the desk; too few don't differentiate the outage from the typo (Emailmeter / Hiver, 2026-06-02).
|
|
55
41
|
|
|
56
|
-
| Priority | Meaning | First-response (FRT) | Resolution target |
|
|
57
|
-
|---|---|---|---|
|
|
58
|
-
| P1 critical | Outage, data loss, payments broken | 15–30 min | ASAP, status updates every 30–60 min |
|
|
59
|
-
| P2 high | One user blocked, no workaround | 1–2 h | Same business day |
|
|
60
|
-
| P3 medium | Workaround exists, billing/how-to | 4–8 h | 1–2 business days |
|
|
61
|
-
| P4 low | Cosmetic, FAQ, feature request | ~1 business day | Best effort |
|
|
62
|
-
|
|
63
42
|
**Acknowledge fast even when you cannot resolve fast.** First-response and resolution are *separate, linked* SLAs: FRT sets the expectation, resolution is the outcome. 89% of customers feel valued by a fast first response even when the full fix takes longer (getMonetizely / Hiver, 2026-06-02). So: acknowledge inside the FRT window with an honest "here's what I know and when I'll update you," then resolve honestly. Never go silent to wait for a perfect answer.
|
|
64
43
|
|
|
65
44
|
Full P1–P4 matrix by channel (email/chat/phone) lives in [`references/macros-and-sla.md`](references/macros-and-sla.md).
|
|
@@ -126,6 +105,8 @@ Banned phrases — they escalate, not de-escalate:
|
|
|
126
105
|
|
|
127
106
|
Checklist before send: feeling acknowledged · first-person ownership · one timed next step · no banned phrase · no `{{placeholder}}` left.
|
|
128
107
|
|
|
108
|
+
De-escalating *this* ticket is the job here; running a win-back or renewal **program** is `retention`.
|
|
109
|
+
|
|
129
110
|
## Escalation
|
|
130
111
|
|
|
131
112
|
Escalate on **explicit conditions, not vibes.** Standard tiers: T1 frontline/common, T2 specialist/complex, T3 engineering or exec/critical (Kapture / Hiver, 2026-06-02). Hand off when any trigger fires:
|
|
@@ -158,7 +139,7 @@ The full escalation matrix (trigger → tier → owner) is in [`references/macro
|
|
|
158
139
|
- If it is not in the KB, say "let me confirm" and escalate — do not fill the gap with a plausible guess.
|
|
159
140
|
- Deflection is **bounded by KB quality.** Triage-only without a strong KB deflects ~20–30%; well-organized KBs push assisted/auto resolution to 50–80% (Zendesk / Intercom / Fini Labs, 2026-06-02). A bad answer fast is worse than a correct answer slightly slower.
|
|
160
141
|
|
|
161
|
-
If the article the customer needs does not exist,
|
|
142
|
+
This skill *consumes* the KB; it never writes it. If the article the customer needs does not exist, flag the gap — authoring it is a `technical-writing` job, and building the autonomous auto-answer bot on top of the KB is `chatbot` + `rag`.
|
|
162
143
|
|
|
163
144
|
## Metrics — what to watch and when
|
|
164
145
|
|
|
@@ -187,7 +168,3 @@ Rule of thumb: optimize **FRT** for reassurance (the customer feeling handled),
|
|
|
187
168
|
| "Please calm down" / "as I said" | Tells them their feeling is the fault | De-escalation moves; banned-phrase swaps |
|
|
188
169
|
| Promise a fix you can't verify | Breaks trust when it slips | Promise the *next update time*, not the fix |
|
|
189
170
|
| Chase NPS off a single ticket | Wrong altitude metric | CSAT/FCR per ticket; NPS at relationship level |
|
|
190
|
-
|
|
191
|
-
## References
|
|
192
|
-
|
|
193
|
-
- [`references/macros-and-sla.md`](references/macros-and-sla.md) — the full macro skeleton library (10+ ready replies), the complete P1–P4 SLA matrix by channel, and the escalation matrix with the handoff-packet template. Pulled out because it is long, branch-specific lookup material you reach for mid-ticket, not flow you read top-to-bottom.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dashboard
|
|
3
|
-
description: "Use when building or fixing a KPI dashboard
|
|
3
|
+
description: "Use when building or fixing a KPI dashboard decision-makers must read in one screen: which metrics earn a tile, how each tile is framed to answer a decision, and which chart fits it. NOT defining the metrics or their targets (that is kpi-framework), wiring the data (that is analytics), or writing a narrative status report (that is reporting)."
|
|
4
4
|
tags: [kpi-dashboard, data-visualization, executive-dashboard, chart-selection, dashboard-design, at-a-glance]
|
|
5
5
|
recommends: [kpi-framework, analytics, reporting, forecasting, business-intelligence, ab-testing, design, spreadsheet-ops]
|
|
6
6
|
origin: risco
|
|
@@ -15,19 +15,11 @@ A dashboard is read in **5 seconds by someone who will not scroll**. If a busy r
|
|
|
15
15
|
|
|
16
16
|
You do **not** decide which metrics matter (that is [kpi-framework](../kpi-framework/SKILL.md)) and you do **not** wire the data source (that is [analytics](../analytics/SKILL.md)). You take a metric set that already exists and make it readable at a glance.
|
|
17
17
|
|
|
18
|
-
Run `scripts/verify.sh dashboard.yaml` before you hand off. It checks shape and discipline
|
|
19
|
-
|
|
20
|
-
## The one rule: the 5-second read
|
|
21
|
-
|
|
22
|
-
A dashboard is a **glance, not a report**. The reader looks at the top-left, gets the headline, and decides whether anything needs their attention. Everything you do serves that.
|
|
23
|
-
|
|
24
|
-
- One north-star tile, read first, top-left. Why: a screen with no clear entry point forces the reader to hunt, and they won't.
|
|
25
|
-
- If a tile does not change a decision, it is decoration. Cut it (Decision Test below).
|
|
26
|
-
- A bare number is not actionable. Every number carries a comparison.
|
|
18
|
+
Run `scripts/verify.sh dashboard.yaml` before you hand off. It checks shape and discipline — tile count 1-9, exactly one `north_star: true`, the required keys on every tile, no banned charts — never whether the numbers are correct.
|
|
27
19
|
|
|
28
20
|
## The Decision Test gate
|
|
29
21
|
|
|
30
|
-
No tile exists until its metric names the **action it drives**. Ask: *what does someone do differently based on this number?* If the answer is vague ("good to know", "shows we're growing"), the metric is vanity — cut it or convert it.
|
|
22
|
+
No tile exists until its metric names the **action it drives**. Ask: *what does someone do differently based on this number?* If the answer is vague ("good to know", "shows we're growing"), the metric is vanity — cut it or convert it. A tile that changes no decision is decoration.
|
|
31
23
|
|
|
32
24
|
| Vanity metric (Bad) | Actionable conversion (Good) | Decision it drives |
|
|
33
25
|
| --- | --- | --- |
|
|
@@ -94,12 +86,7 @@ Choose the chart from the **shape of the question**, not from what looks impress
|
|
|
94
86
|
| Correlation | Scatter | Shows relationship between two measures |
|
|
95
87
|
| Distribution | Histogram | Shape of spread, not just average |
|
|
96
88
|
|
|
97
|
-
Kill-list (verify.sh
|
|
98
|
-
|
|
99
|
-
- No `pie` beyond 5 categories — slices become unreadable. Use a sorted bar.
|
|
100
|
-
- No `gauge` / `dial` — they waste space and resist comparison. Use a **bullet chart**.
|
|
101
|
-
- No dual-axis trickery — two y-axes invent correlations that aren't there.
|
|
102
|
-
- No 3D, no donut-with-center-number gimmicks.
|
|
89
|
+
Kill-list: no `pie` beyond 5 categories (sorted bar instead) and no `gauge` / `dial` (bullet chart instead) — verify.sh rejects both; no dual-axis, which invents correlations that aren't there; no 3D and no donut-with-center-number gimmicks.
|
|
103
90
|
|
|
104
91
|
## Layout & data-ink
|
|
105
92
|
|
|
@@ -177,7 +164,7 @@ layout:
|
|
|
177
164
|
groups: [growth, revenue, health]
|
|
178
165
|
```
|
|
179
166
|
|
|
180
|
-
verify.sh
|
|
167
|
+
The keys verify.sh requires on every tile: `metric`, `chart`, `comparison`, `owner`, `refresh`, `decision`.
|
|
181
168
|
|
|
182
169
|
## Anti-patterns
|
|
183
170
|
|
|
@@ -195,11 +182,4 @@ verify.sh parses this, counts tiles (must be 1-9), checks exactly one `north_sta
|
|
|
195
182
|
|
|
196
183
|
## Handoff
|
|
197
184
|
|
|
198
|
-
|
|
199
|
-
- No data behind the tiles? Instrument events, funnels, attribution → [analytics](../analytics/SKILL.md).
|
|
200
|
-
- Need a written status with commentary on *why* a number moved → [reporting](../reporting/SKILL.md).
|
|
201
|
-
- Projecting a metric forward under scenarios → [forecasting](../forecasting/SKILL.md).
|
|
202
|
-
- Self-serve slice-and-dice / semantic layer → [business-intelligence](../business-intelligence/SKILL.md).
|
|
203
|
-
- Reading out an experiment / variant significance → [ab-testing](../ab-testing/SKILL.md).
|
|
204
|
-
- Visual polish, spacing, type scale of the rendered screen → [design](../design/SKILL.md).
|
|
205
|
-
- Pulling/joining the underlying numbers in a sheet → [spreadsheet-ops](../spreadsheet-ops/SKILL.md).
|
|
185
|
+
Beyond the routes named above: reading out an experiment or variant significance → [ab-testing](../ab-testing/SKILL.md); visual polish, spacing and type scale of the rendered screen → [design](../design/SKILL.md); pulling or joining the underlying numbers in a sheet → [spreadsheet-ops](../spreadsheet-ops/SKILL.md).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: data-cleaning
|
|
3
|
-
description: "Use when a raw
|
|
3
|
+
description: "Use when a raw table is too dirty to trust — nulls, sentinels, duplicate rows, category sprawl, mixed types, bad dates — and you need a re-runnable clean() plus a schema gate that fails loud. NOT emitting .xlsx (that is spreadsheet-ops), NOT acquiring rows (that is data-scraper), NOT parsing PDF/HTML into rows (that is structured-extraction)."
|
|
4
4
|
tags: [data-cleaning, data-quality, pandas, pandera, validation, deduplication, reproducibility, polars]
|
|
5
5
|
recommends: [duckdb, spreadsheet-ops, structured-extraction, data-scraper, analytics, business-intelligence, forecasting, python]
|
|
6
6
|
profiles: []
|
|
@@ -16,28 +16,17 @@ the same input always yields the same output: versions pinned, sorts determinist
|
|
|
16
16
|
a seed. If you can't re-run it tomorrow and get the identical result, you haven't cleaned the data — you've
|
|
17
17
|
edited a snapshot.
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
Cleaning **starts** once you hold tabular rows and **ends** at a validated table/DataFrame/Parquet. Before
|
|
20
|
+
that boundary the job is acquisition ([`data-scraper`](../data-scraper/SKILL.md),
|
|
21
|
+
[`structured-extraction`](../structured-extraction/SKILL.md)); after it, consumption
|
|
22
|
+
([`spreadsheet-ops`](../spreadsheet-ops/SKILL.md), [`analytics`](../analytics/SKILL.md),
|
|
23
|
+
[`business-intelligence`](../business-intelligence/SKILL.md),
|
|
24
|
+
[`forecasting`](../forecasting/SKILL.md)). Multi-GB analytical SQL is an engine choice, not a cleaning one
|
|
25
|
+
— [`duckdb`](../duckdb/SKILL.md).
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
| --- | --- |
|
|
31
|
-
| Rows are dirty (nulls, dupes, mixed types, bad dates) and you want a re-runnable clean + a gate | **data-cleaning** (this skill) |
|
|
32
|
-
| You need an `.xlsx` / formula / styled sheet / chart *out* | [`spreadsheet-ops`](../spreadsheet-ops/SKILL.md) |
|
|
33
|
-
| The data is still on a website — you have to *acquire* it | [`data-scraper`](../data-scraper/SKILL.md) |
|
|
34
|
-
| Fields are trapped in PDF/HTML/free text and must be *parsed into rows* | `structured-extraction` |
|
|
35
|
-
| Multi-GB analytical SQL / heavy groupby-join is the actual bottleneck | [`duckdb`](../duckdb/SKILL.md) |
|
|
36
|
-
| The table is already clean and you want charts / KPIs / a model | [`analytics`](../analytics/SKILL.md), `business-intelligence`, `forecasting` |
|
|
37
|
-
|
|
38
|
-
Cleaning **starts** once you hold tabular rows and **ends** at a validated table/DataFrame/Parquet. The
|
|
39
|
-
boundary with every consumer sibling is that validated table. (Some routed siblings may not be built in
|
|
40
|
-
this collection yet; the routing decision still holds.)
|
|
27
|
+
Current stack (verified 2026-06-02): **pandas 3.0.x** (3.0.0 shipped 2026-01-21) and **pandera 0.31.1**
|
|
28
|
+
(supports pandas ≥ 3) for in-pipeline schema validation; **Polars** and **DuckDB** when pandas runs out of
|
|
29
|
+
RAM. Pin them: `pandas==3.0.3`, `pandera==0.31.1`.
|
|
41
30
|
|
|
42
31
|
## The pipeline shape
|
|
43
32
|
|
|
@@ -73,18 +62,19 @@ df = pd.read_csv("raw.csv")
|
|
|
73
62
|
# GOOD — explicit, deterministic, real nullable types
|
|
74
63
|
df = pd.read_csv(
|
|
75
64
|
"raw.csv",
|
|
76
|
-
dtype_backend="pyarrow", # real nullable ints/strings; no silent float-cast
|
|
65
|
+
dtype_backend="pyarrow", # real nullable ints/strings; no silent float-cast
|
|
77
66
|
na_values=["", "N/A", "NA", "null", "-1", "999"], # YOUR sentinels become real NA
|
|
78
67
|
keep_default_na=True, # keep pandas' default NA tokens too
|
|
79
68
|
encoding="utf-8", # state it; don't let locale decide
|
|
80
69
|
)
|
|
81
70
|
```
|
|
82
71
|
|
|
83
|
-
pandas 3.0
|
|
84
|
-
|
|
85
|
-
`
|
|
86
|
-
|
|
87
|
-
|
|
72
|
+
Two pandas 3.0 facts that read depends on. `dtype_backend="pyarrow"` only works if pyarrow is actually
|
|
73
|
+
installed — PDEP-14 deliberately kept a NumPy-object fallback so PyArrow stays *recommended, not required*
|
|
74
|
+
— so `pip install pyarrow` for the faster backed path, or pass `dtype_backend="numpy_nullable"` when it is
|
|
75
|
+
absent. And the default `str` dtype (PyArrow-backed when pyarrow is present, NumPy-object-backed otherwise)
|
|
76
|
+
uses **`NaN` missing-value semantics** like every other default dtype: test for null with `pd.isna()`, never
|
|
77
|
+
by comparing against whichever null token happened to appear.
|
|
88
78
|
|
|
89
79
|
## Profile before you fix
|
|
90
80
|
|
|
@@ -146,6 +136,10 @@ assert bad.sum() == 0, f"{bad.sum()} dates failed the expected format — inspec
|
|
|
146
136
|
df["signup"] = parsed
|
|
147
137
|
```
|
|
148
138
|
|
|
139
|
+
Copy-paste versions of all of these — category mapping with unmapped→quarantine, a robust date parser,
|
|
140
|
+
unicode/encoding repair, a sentinel→NA table, numeric clip-vs-reject, plus Polars equivalents — are in
|
|
141
|
+
[references/normalization-recipes.md](references/normalization-recipes.md).
|
|
142
|
+
|
|
149
143
|
## Dedupe
|
|
150
144
|
|
|
151
145
|
`drop_duplicates(keep="first")` is meaningless without a defined key and a stable sort — "first" of what
|
|
@@ -210,14 +204,16 @@ except pa.errors.SchemaErrors as e:
|
|
|
210
204
|
|
|
211
205
|
`coerce=True` fixes types the contract expects; `nullable` states which columns may hold NA; field
|
|
212
206
|
`Check`s (`ge`, `le`, `isin`, `unique`) are the allowed-value rules. `strict` catches columns that
|
|
213
|
-
shouldn't be there. Together they are the data contract in code.
|
|
207
|
+
shouldn't be there. Together they are the data contract in code. Log the row-count diff on every run —
|
|
208
|
+
`in`, `out`, coerced, quarantined — so what the pipeline changed is an auditable record, not an assumption.
|
|
214
209
|
|
|
215
210
|
When to escalate beyond pandera: reach for **GX Core 1.0** (Great Expectations' rebranded OSS — Data
|
|
216
211
|
Context → Data Source → Expectation Suite → Validation Definition → Checkpoint) when you need a *shared
|
|
217
212
|
data-quality platform* across many datasets and teams with a results store and docs. Use **dbt model
|
|
218
213
|
contracts** (enforced at build) plus **dbt tests** (post-materialization) when the cleaning lives in a
|
|
219
|
-
SQL warehouse, not Python.
|
|
220
|
-
|
|
214
|
+
SQL warehouse, not Python. The full `DataFrameModel` (custom `@pa.check`, lazy `SchemaErrors` report,
|
|
215
|
+
valid/quarantine split helper), the GX checkpoint sketch, the dbt model-contract + `data_tests` YAML, and
|
|
216
|
+
the "which validator" chooser are in [references/validation-patterns.md](references/validation-patterns.md).
|
|
221
217
|
|
|
222
218
|
## Scale — when pandas hurts
|
|
223
219
|
|
|
@@ -226,28 +222,15 @@ that, or when a groupby/join dominates the runtime, switch the *mechanics* (not
|
|
|
226
222
|
|
|
227
223
|
- **Polars** for clean-at-scale: `pl.scan_csv(...)` (lazy, parallel, Rust), then `.unique()`,
|
|
228
224
|
`.drop_nulls()`, `.fill_null(...)`, `.str.*` — the same profile→normalize→dedupe→validate shape, faster.
|
|
229
|
-
pandera validates Polars frames too
|
|
225
|
+
pandera validates Polars frames too, and the
|
|
226
|
+
[recipes reference](references/normalization-recipes.md) has the Polars equivalent of every fix above.
|
|
230
227
|
- **DuckDB** when the bottleneck is analytical SQL over multi-GB files — point heavy joins/aggregations
|
|
231
228
|
there: [`duckdb`](../duckdb/SKILL.md). It is an *engine* choice; correctness/normalization is still this
|
|
232
229
|
skill's job.
|
|
233
230
|
|
|
234
|
-
Polars equivalents for every recipe above are in
|
|
235
|
-
[references/normalization-recipes.md](references/normalization-recipes.md).
|
|
236
|
-
|
|
237
|
-
## Reproducibility checklist
|
|
238
|
-
|
|
239
|
-
- [ ] Library versions pinned (`pandas==3.0.3`, `pandera==0.31.1`) — same input → same output.
|
|
240
|
-
- [ ] Read with explicit `dtype_backend` + `na_values`; no silent int→float cast.
|
|
241
|
-
- [ ] Dedupe has an explicit `subset` key AND a deterministic `sort_values(..., kind="stable")` before it.
|
|
242
|
-
- [ ] No `random` / sampling without a fixed seed; stable tie-breaks everywhere.
|
|
243
|
-
- [ ] Raw source untouched; output written to a NEW artifact.
|
|
244
|
-
- [ ] Schema validated on output; `lazy=True` so all violations surface together.
|
|
245
|
-
- [ ] Failing rows **quarantined**, not silently dropped.
|
|
246
|
-
- [ ] Row-count diff logged (`in`, `out`, coerced, quarantined) — an auditable record of what changed.
|
|
247
|
-
|
|
248
231
|
## Anti-patterns
|
|
249
232
|
|
|
250
|
-
|
|
|
233
|
+
| Anti-pattern | Why it breaks |
|
|
251
234
|
| --- | --- |
|
|
252
235
|
| "`fillna(0)` to get rid of the nulls" | Zero is a value; it distorts every mean/sum/model. Impute deliberately and add a `_was_missing` flag. |
|
|
253
236
|
| "`drop_duplicates()` — done" | No `subset`, no sort → which row survives is nondeterministic. Define the key, `sort_values(kind="stable")`, set `keep`. |
|
|
@@ -259,27 +242,18 @@ Polars equivalents for every recipe above are in
|
|
|
259
242
|
| "Validation passed, so we're good" | A gate that never fails is a no-op. Feed it a known-bad row and confirm it *rejects*. |
|
|
260
243
|
| "It's slow, rewrite everything in Polars" | Switch the engine, not the discipline — profile→normalize→dedupe→validate still applies. |
|
|
261
244
|
|
|
262
|
-
## References
|
|
263
|
-
|
|
264
|
-
- [references/validation-patterns.md](references/validation-patterns.md) — full pandera `DataFrameModel`
|
|
265
|
-
(coerce, custom `@pa.check`, lazy `SchemaErrors` report, valid/quarantine split helper), GX Core 1.0
|
|
266
|
-
checkpoint sketch, dbt model-contract + `data_tests` YAML, and the "which validator" chooser.
|
|
267
|
-
- [references/normalization-recipes.md](references/normalization-recipes.md) — copy-paste recipes: category
|
|
268
|
-
mapping with unmapped→quarantine, robust date parser, unicode/encoding repair, sentinel→NA table, numeric
|
|
269
|
-
clip-vs-reject, and Polars equivalents (`unique`, `drop_nulls`, `fill_null`, `str.*`) for scale.
|
|
270
|
-
|
|
271
245
|
## Verify
|
|
272
246
|
|
|
273
|
-
|
|
274
|
-
references present) always, and — when pandas + pandera are installed — extracts the
|
|
275
|
-
feeds it one clearly-good row and one clearly-bad row, and asserts the good row PASSES
|
|
276
|
-
bad row is FLAGGED/quarantined, proving the gate is not a no-op.
|
|
277
|
-
prints SKIP for the runtime check and still passes the static checks.
|
|
247
|
+
`scripts/verify.sh` runs from anywhere, no network. It does static structure checks on this skill
|
|
248
|
+
(frontmatter keys, references present) always, and — when pandas + pandera are installed — extracts the
|
|
249
|
+
documented pattern, feeds it one clearly-good row and one clearly-bad row, and asserts the good row PASSES
|
|
250
|
+
validation while the bad row is FLAGGED/quarantined, proving the gate is not a no-op. Without
|
|
251
|
+
pandas/pandera it prints SKIP for the runtime check and still passes the static checks.
|
|
278
252
|
|
|
279
253
|
## Project grounding (02-DOCS + CLAUDE.md)
|
|
280
254
|
|
|
281
255
|
In a project with a `02-DOCS/` layer (the [`harness`](../harness/SKILL.md) wiki), record this dataset's
|
|
282
256
|
cleaning decisions — the schema/contract, the category mapping tables, the dedupe key, the quarantine
|
|
283
|
-
location, version pins — in `02-DOCS/wiki/data/<dataset>.md
|
|
284
|
-
`## Knowledge map
|
|
257
|
+
location, version pins — in `02-DOCS/wiki/data/<dataset>.md`, link it from the root `CLAUDE.md`
|
|
258
|
+
`## Knowledge map`, and read it first on every re-run so the contract stays consistent. No `02-DOCS/`? Skip
|
|
285
259
|
silently. Conventions are recorded, never gated.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: data-policy
|
|
3
|
-
description: "Use when
|
|
3
|
+
description: "Use when building internal data-governance machinery: a retention schedule (period, lawful basis, expiry action, system where deletion runs), an Art. 6 lawful-basis register, an Art. 30 ROPA, or a consent capture/withdrawal model. NOT the public privacy notice or DSAR handling (that is `gdpr-privacy`), NOT SOC 2 posture (that is `compliance`)."
|
|
4
4
|
tags: [data-governance, retention, gdpr, ropa, consent, lawful-basis, privacy, data-minimization]
|
|
5
5
|
recommends: [gdpr-privacy, compliance, contracts, secure-coding, db-migrations, postgresdb]
|
|
6
6
|
origin: risco
|
|
@@ -8,9 +8,7 @@ origin: risco
|
|
|
8
8
|
|
|
9
9
|
# Data policy
|
|
10
10
|
|
|
11
|
-
You
|
|
12
|
-
|
|
13
|
-
One rule sits above everything else.
|
|
11
|
+
You produce the structured governance artifacts engineering and ops implement — a retention schedule, a lawful-basis register, a Record of Processing Activities (ROPA), a consent model — not the public-facing notice users read (that is `../gdpr-privacy/SKILL.md`). You are not a DPO and you never claim to be one.
|
|
14
12
|
|
|
15
13
|
**A retention rule is only real when it has all four parts: a concrete period, the lawful basis, the expiry action, and the system where deletion actually runs.** A policy that names a period but never deletes anything is a paper policy — and a paper policy is precisely what regulators fine. Cumulative GDPR fines hit ~EUR 5.65B across ~2,245 actions by March 2025, and the two failures that recur are *no systematic data classification* and *no automated deletion capability* (Secure Privacy / CMS Enforcement Tracker, 2025). Every schedule you emit ends with the DPO/counsel sign-off boundary below.
|
|
16
14
|
|
|
@@ -26,7 +24,7 @@ Map the request to one artifact before writing anything. Each routes to a sectio
|
|
|
26
24
|
| "Design consent capture / withdrawal" | Consent matrix | Consent model |
|
|
27
25
|
| "Auto-delete but keep legal holds / backups still have data" | Deletion workflow | Make it real in systems |
|
|
28
26
|
|
|
29
|
-
If
|
|
27
|
+
If they want the public privacy notice, DPA clauses, or SOC 2 readiness instead, stop and route them — see the boundary below.
|
|
30
28
|
|
|
31
29
|
## Build the retention schedule
|
|
32
30
|
|
|
@@ -88,7 +86,7 @@ Security: RBAC, encryption at rest, access logging
|
|
|
88
86
|
Lawful basis: Art. 6(1)(b) contract ← log it even though Art. 30 doesn't demand it
|
|
89
87
|
```
|
|
90
88
|
|
|
91
|
-
The full template with a second worked row is in `references/consent-and-ropa.md`.
|
|
89
|
+
The full ROPA template with a second worked row — plus the consent-matrix template and the withdrawal/refresh workflow — is in `references/consent-and-ropa.md`.
|
|
92
90
|
|
|
93
91
|
## Consent model
|
|
94
92
|
|
|
@@ -109,7 +107,7 @@ One note so you don't over-promise on cookies: the **ePrivacy Regulation was for
|
|
|
109
107
|
|
|
110
108
|
## Make it real in systems
|
|
111
109
|
|
|
112
|
-
|
|
110
|
+
The policy is worthless until deletion runs in the systems that actually hold the data — *including backups and archives*, which is exactly where regulators find data that should be gone.
|
|
113
111
|
|
|
114
112
|
Checklist:
|
|
115
113
|
|
|
@@ -134,17 +132,11 @@ State explicitly in the policy whether production data may be reused for **AI/mo
|
|
|
134
132
|
|
|
135
133
|
For cross-border transfers, name the mechanism in the ROPA row (e.g. SCCs) and point to `../gdpr-privacy/SKILL.md` for the SCC/notice depth — that is its territory, not yours.
|
|
136
134
|
|
|
137
|
-
## The boundary
|
|
138
|
-
|
|
139
|
-
Retention periods are jurisdiction- and sector-specific. **You produce governance drafts, not legal sign-off.** Every policy you emit ends with a line stating a qualified DPO or privacy counsel must validate the schedule and lawful-basis register before adoption, and that this is not legal advice. You never assert a period is universally lawful.
|
|
135
|
+
## The boundary
|
|
140
136
|
|
|
141
|
-
|
|
137
|
+
Retention periods are jurisdiction- and sector-specific, so a period you assert as final is legal advice you are not qualified to give — that is why this line has no exceptions. **You produce governance drafts, not legal sign-off.** Every policy you emit ends with a statement that a qualified DPO or privacy counsel must validate the schedule and lawful-basis register before adoption, and that this is not legal advice. You never assert a period is universally lawful.
|
|
142
138
|
|
|
143
|
-
|
|
144
|
-
- Audit posture, SOC 2 / ISO 27001, control mapping -> `../compliance/SKILL.md`.
|
|
145
|
-
- A negotiated DPA's contractual clauses or a two-party data contract -> `../contracts/SKILL.md`.
|
|
146
|
-
- Encryption, access hardening, threat controls on the systems -> `../secure-coding/SKILL.md`.
|
|
147
|
-
- The actual deletion mechanics in the database -> `../db-migrations/SKILL.md` / `../postgresdb/SKILL.md`.
|
|
139
|
+
Hand off the edges: public-facing privacy notice + data-subject access/erasure (DSAR) handling -> `../gdpr-privacy/SKILL.md`; audit posture, SOC 2 / ISO 27001, control mapping -> `../compliance/SKILL.md`; a negotiated DPA's contractual clauses or a two-party data contract -> `../contracts/SKILL.md`; encryption, access hardening, threat controls on the systems -> `../secure-coding/SKILL.md`; the actual deletion mechanics in the database -> `../db-migrations/SKILL.md` / `../postgresdb/SKILL.md`.
|
|
148
140
|
|
|
149
141
|
## Anti-patterns
|
|
150
142
|
|
|
@@ -156,8 +148,3 @@ Hand off the edges:
|
|
|
156
148
|
| No legal-hold exception in the auto-deletion job | The job destroys data under litigation hold — spoliation | Flag held rows; skip them; document the hold basis |
|
|
157
149
|
| Copy a generic retention template unchanged | Periods are jurisdiction/sector-specific; a copied period can be unlawful | Tag every period "validate vs local + sector law"; adjust |
|
|
158
150
|
| Emit the policy as final / "compliant" | Crosses into legal advice you can't give | End with DPO/counsel sign-off + not-legal-advice line |
|
|
159
|
-
|
|
160
|
-
## References
|
|
161
|
-
|
|
162
|
-
- `references/retention-schedule.md` — fillable schedule template (data category, purpose, lawful basis, period, expiry action, system of record, legal-hold flag, review date) + a populated example across HR, finance/tax, CRM, marketing, support, logs, with the delete-vs-anonymize-vs-archive note and the local + sector law validation checklist.
|
|
163
|
-
- `references/consent-and-ropa.md` — consent matrix template + worked example, the Art. 30 ROPA template + worked rows, the legitimate-interest balancing-test worksheet, and the consent withdrawal/refresh workflow.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: data-scraper
|
|
3
|
-
description: "Use when
|
|
3
|
+
description: "Use when data lives on a website with no usable API — listings, prices, public records — and the scrape must stay legal and not get blocked: legal gate, extraction path, durable selectors, pacing, resilience. NOT parsing bytes you already hold into fields (that is structured-extraction), NOT a documented API or key (that is api-connector-builder)."
|
|
4
4
|
tags: [web-scraping, crawler, anti-bot, robots-txt, gdpr-compliance, playwright, rate-limiting]
|
|
5
5
|
recommends: [api-connector-builder, structured-extraction, data-cleaning, gdpr-privacy, webhooks]
|
|
6
6
|
origin: risco
|
|
@@ -125,10 +125,4 @@ A recurring crawler must survive crashes, redeploys, and the target's schema dri
|
|
|
125
125
|
| Hardcoding one User-Agent forever | Stale UA is an easy bot tell | Current full header set; rotate when justified |
|
|
126
126
|
| Retrying with no backoff | Lockstep retries self-DDoS the host | Exponential backoff + jitter; honor `Retry-After` |
|
|
127
127
|
|
|
128
|
-
## References
|
|
129
|
-
|
|
130
|
-
- **`references/legal-compliance.md`** — robots.txt + ai.txt parsing, ToS red-flag list, GDPR lawful-basis decision flow, minimization/retention checklist, and the 2024-2025 case summaries (Meta v. Bright Data, hiQ v. LinkedIn, Reddit v. Perplexity).
|
|
131
|
-
- **`references/anti-bot.md`** — `curl_cffi` impersonation profiles with an example, realistic header sets, Playwright launch/stealth config, the proxy taxonomy (datacenter / residential / mobile) and when each is justified, and the CAPTCHA line you do not cross.
|
|
132
|
-
- **`references/frameworks.md`** — copy-paste resilient starters: Crawlee Python (`RequestQueue` + router + per-host concurrency), Playwright direct, Scrapy AUTOTHROTTLE, and an `httpx` + `selectolax` static template.
|
|
133
|
-
|
|
134
128
|
When in doubt about whether a scrape is defensible, the answer is the gate. Run it, write down the outcome, and only then send a request.
|