@ericrisco/rsc 0.1.50 → 0.1.52

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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: hiring
3
- description: "Use when there's an open role and you need to write the job post, screen inbound candidates, structure the interview loop, or build a scorecard to reach a fair hire decision; symptoms: gut-feel ratings, every interviewer asking the same question, a bloated requirements list, no consistent screen. Triggers: 'write a job description', 'screen these CVs', 'build an interview scorecard', 'structure the interview panel', 'redacta la oferta de empleo', 'necesito una scorecard', plus the non-obvious 'four people interviewed and we still can't decide' and 'is our AI résumé filter legal'. NOT managing the person after they're hired — onboarding, payroll, performance (that is people-ops)."
3
+ description: "Use when a role is open and you must write the job post, screen inbound candidates, structure the interview loop, or score them to a defensible Hire / On-Hold / No-Hire — including whether an AI résumé filter is legal. NOT after the offer is accepted — onboarding, payroll, performance (that is `people-ops`), NOT offer terms (that is `contracts`)."
4
4
  tags: [hiring, recruiting, job-description, interview-scorecard, candidate-screening, structured-interview]
5
5
  recommends: [people-ops, brand-voice, contracts, compliance, cold-outreach, calendar-scheduling]
6
6
  profiles: []
@@ -17,8 +17,7 @@ No-Hire with the reason written down.
17
17
 
18
18
  Hard boundary: the moment the offer is accepted, you are done. Onboarding,
19
19
  payroll, equipment, performance reviews, PTO — that is `../people-ops/SKILL.md`.
20
- Hiring gets the right person in the door; people-ops takes it from day one. Do
21
- not draft offer-letter terms here either; that is `../contracts/SKILL.md`.
20
+ Do not draft offer-letter terms here either; that is `../contracts/SKILL.md`.
22
21
 
23
22
  ## The funnel (the spine)
24
23
 
@@ -35,7 +34,7 @@ One rule per stage, with the why:
35
34
  named. Write the 3–6 competencies before the post, because they drive the
36
35
  post, the questions, and the scorecard.
37
36
  - **Write the post from the competencies.** A post is the competencies turned
38
- outward, not a wish list. See "Write the job post".
37
+ outward, not a wish list.
39
38
  - **Screen against one rubric.** Same criteria, same order, every candidate, or
40
39
  the comparison is meaningless.
41
40
  - **Run a structured loop.** Same questions, same rubric, every candidate —
@@ -45,18 +44,6 @@ One rule per stage, with the why:
45
44
  - **Score independently, then calibrate.** Each interviewer submits before the
46
45
  group talks. Debrief is calibration, not a re-vote.
47
46
 
48
- ### Screen decision table
49
-
50
- For each candidate at the screen stage:
51
-
52
- | Signal | Decision |
53
- |---|---|
54
- | Meets the must-haves on job-related evidence | Advance to loop |
55
- | Strong on most, one must-have unclear | Send a short work-sample / structured task to resolve it |
56
- | Misses a hard must-have (verified skill, legal eligibility) | Reject, with the job-related reason logged |
57
- | Borderline, more reqs open soon | Parking lot — note why, revisit, do not silently ghost |
58
- | Non-job factor (school name, age, gap, "vibe", name) | Ignore it — it is not in the rubric |
59
-
60
47
  ## Write the job post
61
48
 
62
49
  The job post is the top of the funnel and it leaks candidates if you write it
@@ -102,7 +89,8 @@ How to apply: send a short note + anything you've shipped.
102
89
  ## Screen the pile
103
90
 
104
91
  Score every applicant against the **same job-related rubric** you derived from
105
- the competencies. No bespoke criteria per candidate.
92
+ the competencies (template: `references/templates.md`). No bespoke criteria per
93
+ candidate.
106
94
 
107
95
  - **Blind to non-job factors.** School prestige, name, age, employment gaps,
108
96
  photo — none of it is in the rubric, so it does not enter the decision.
@@ -116,8 +104,15 @@ the competencies. No bespoke criteria per candidate.
116
104
  criminal-history box on the application form. (Candidate-data retention and
117
105
  consent: `../gdpr-privacy/SKILL.md`.)
118
106
 
119
- Use the screen decision table above for the advance / work-sample / reject /
120
- parking-lot call.
107
+ For each candidate, the call:
108
+
109
+ | Signal | Decision |
110
+ |---|---|
111
+ | Meets the must-haves on job-related evidence | Advance to loop |
112
+ | Strong on most, one must-have unclear | Send a short work-sample / structured task to resolve it |
113
+ | Misses a hard must-have (verified skill, legal eligibility) | Reject, with the job-related reason logged |
114
+ | Borderline, more reqs open soon | Parking lot — note why, revisit, do not silently ghost |
115
+ | Non-job factor (school name, age, gap, "vibe", name) | Ignore it — it is not in the rubric |
121
116
 
122
117
  ## Structure the interview loop
123
118
 
@@ -239,10 +234,3 @@ This skill *follows* the rules; it does not run the legal program — that is
239
234
  | Screening on school / name / gap | Non-job factor, not in the rubric | Blind to it; rubric only |
240
235
  | Deleting interview notes | Breaks EEOC retention; no defense | Retain ≥1 yr (2 yr for fed contractors) |
241
236
  | Drifting into onboarding/payroll | Out of scope, wrong skill | Stop at the decision → `../people-ops/SKILL.md` |
242
-
243
- ## References
244
-
245
- - `references/templates.md` — full anchored scorecard (one competency at all
246
- five levels), the structured question bank by competency, a fill-in job-post
247
- skeleton with the gender-coded word do/don't list, and a screening rubric
248
- template.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: instagram-api
3
- description: "Use when wiring an agent into Instagram's Graph API to publish a Reel from a video URL, pull per-media insights (reach, views, watch-time, saves, shares, total_interactions), check the 24-hour publish cap, or ingest Reel performance into 02-DOCS/wiki/shortform. Triggers: 'publish this Reel via the API', 'pull reach and average watch time for these media IDs', 'why does /insights?metric=plays return an error', 'my container is stuck IN_PROGRESS', 'how many posts left in the 24h publish window', 'publica este Reel por la API', 'ingesta el rendimiento dels Reels al wiki'. NOT TikTok publishing (that is tiktok-api), NOT a posting calendar/cadence (that is social-publisher), NOT YouTube uploads/stats (that is youtube-api)."
3
+ description: "Use when wiring an agent into Instagram's Graph API: publishing a Reel through the create/poll/publish container dance, reading per-media insights, checking the 24h publish cap, or ingesting Reel metrics into 02-DOCS/wiki/shortform. NOT TikTok (that is `tiktok-api`), NOT YouTube (that is `youtube-api`), NOT cross-platform cadence (that is `social-publisher`)."
4
4
  tags: [instagram, graph-api, content-publishing, reels, insights, shortform]
5
5
  recommends: [tiktok-api, youtube-api, social-publisher, shortform-strategy, api-connector-builder]
6
6
  origin: risco
@@ -12,15 +12,10 @@ The wire between an agent and Instagram's Graph API: publish Reels, pull the met
12
12
 
13
13
  All facts below are pinned to **Graph API v25.0** (current as of 2026-06-02). When you generate code, pin the version explicitly; Meta breaks metrics on version boundaries.
14
14
 
15
- ## When to use / when NOT
15
+ ## Route out
16
16
 
17
- | The ask | Route |
17
+ | The ask | Skill |
18
18
  |---|---|
19
- | Publish a Reel from a public `video_url` to an IG professional account | **here** |
20
- | Pull reach / views / watch-time / saves / shares for media IDs | **here** |
21
- | `/insights?metric=plays` (or `impressions`) suddenly errors | **here** (deprecation trap) |
22
- | Check the 24h publish cap before a batch | **here** |
23
- | Long-lived token exchange / refresh, scope wiring | **here** |
24
19
  | Post the same clip to **TikTok** | `tiktok-api` |
25
20
  | Upload to **YouTube** / pull YouTube stats | [`youtube-api`](../youtube-api/SKILL.md) |
26
21
  | Cadence, best-time, multi-platform calendar | [`social-publisher`](../social-publisher/SKILL.md) |
@@ -125,6 +120,8 @@ Bad: video_url behind auth or a 30s signed URL -> container stalls in ERROR.
125
120
  Good: a plain public MP4 that stays reachable for the full ~5 min window.
126
121
  ```
127
122
 
123
+ Full container field reference (reels / carousel / story), cover & thumb handling, error codes, retry/backoff, and batch publish with cap check → `references/publish-reel.md`.
124
+
128
125
  ## Status polling rules
129
126
 
130
127
  `status_code` is the only honest signal. Branch on it, do not guess from timing.
@@ -180,6 +177,8 @@ Requesting any retired metric does not return null — it **400s the entire insi
180
177
 
181
178
  If a previously-working call started erroring, this table is almost certainly why: a metric you used to request was retired on a version boundary. Swap to `views` and drop the dead names.
182
179
 
180
+ Complete current metric tables per media type, the full deprecated→replacement map with dates, version-gated 2025–2026 additions, and the `02-DOCS/wiki/shortform/` ingest schema spec → `references/insights-metrics.md`.
181
+
183
182
  ## Ingest into 02-DOCS/wiki/shortform/
184
183
 
185
184
  This is the checkable deliverable. One file per media id, idempotent overwrite (re-running a pull refreshes `pulled_at` and metrics, never duplicates).
@@ -222,14 +221,6 @@ current valid Reels set; no deprecated names requested.
222
221
 
223
222
  `type` is the only required OKF v0.1 field; `title`/`description`/`tags`/`timestamp` are the recommended OKF surface (`timestamp` mirrors the pull instant). The DOMAIN keys below are mandatory and stay byte-for-byte — `verify.sh` requires a pinned `graph_version` and greps the `metrics` block for deprecated names; `pulled_at` is the API-pull instant verify/diff rely on. Keep both `pulled_at` and `timestamp`. Why front-matter + media-id filename: the wiki is queried by key, and re-pulls must be diffable, not additive (the idempotent overwrite re-stamps `timestamp` and `pulled_at` together).
224
223
 
225
- ## Migration & gotchas
226
-
227
- - **Scopes:** replace `instagram_basic` → `instagram_business_basic`, `instagram_content_publish` → `instagram_business_content_publish`. Old names grant nothing post-2025-01-27.
228
- - **Host:** chosen by login path, not per call. Do not send a `graph.instagram.com` token to `graph.facebook.com`.
229
- - **Token:** refresh the 60-day long-lived token before expiry; expired tokens fail every call with an auth error, not a 404.
230
- - **Reel eligibility:** 9:16, 5–90s, H.264/HEVC. A non-conforming source surfaces as container `ERROR`, not a clean validation message.
231
- - **New 2025–2026 metrics** (Reels skip rate, repost counts, crossposted views): optional and version-gated. Confirm they exist on `GRAPH_VERSION` before requesting, or they trip the same 400 trap.
232
-
233
224
  ## Anti-patterns
234
225
 
235
226
  | Anti-pattern | Why it bites | Do instead |
@@ -239,10 +230,9 @@ current valid Reels set; no deprecated names requested.
239
230
  | Leaving `GRAPH_VERSION` blank / using default | Metric set silently shifts on Meta's rollout | Pin `v25.0` in every call |
240
231
  | Signed/auth-gated `video_url` | Container stalls in `ERROR` | Plain public MP4 for the full window |
241
232
  | Batch publishing without cap check | Hit #51 mid-run, half-published queue | `content_publishing_limit` before the loop |
242
- | Old scopes (`instagram_basic`) | Grant nothing since 2025-01-27 | `instagram_business_*` scopes |
233
+ | Old scopes (`instagram_basic`, `instagram_content_publish`) | Grant nothing since 2025-01-27 | `instagram_business_basic` / `instagram_business_content_publish` |
243
234
  | Storing the container id as "the post" | It's not the published media id | Persist the `media_publish` id |
244
-
245
- ## References
246
-
247
- - `references/publish-reel.md` — full container field reference (reels / carousel / story), cover & thumb handling, error codes, retry/backoff, batch publish with cap check.
248
- - `references/insights-metrics.md` — complete current metric tables per media type, the full deprecated→replacement map with dates, version-gated 2025–2026 additions, and the `02-DOCS/wiki/shortform/` ingest schema spec.
235
+ | Sending a `graph.instagram.com` token to `graph.facebook.com` | Host is fixed by the login path, not chosen per call | Pick the host with the auth path and stay on it |
236
+ | Letting the 60-day long-lived token lapse | Every call fails with an auth error, not a 404 | Refresh before expiry |
237
+ | A source video outside Reel eligibility | Surfaces as container `ERROR`, not a clean validation message | 9:16, 5–90s, H.264/HEVC |
238
+ | Requesting the 2025–2026 additions (Reels skip rate, repost counts, crossposted views) blind | Version-gated — trips the same 400 trap as a deprecated name | Confirm they exist on `GRAPH_VERSION` first |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: machine-learning
3
- description: "Use when the task is a classic/tabular machine-learning problem — predict a column from rows of features with trees and scikit-learn: fit a RandomForest / XGBoost / LightGBM classifier or regressor, build a leak-proof Pipeline + ColumnTransformer, choose a cross-validation scheme (stratified / k-fold / time-series / grouped), pick the right metric on imbalanced classes (precision/recall/F1/ROC-AUC/PR-AUC, not accuracy), or debug a model that aced CV then collapsed in production. Triggers: 'train a model to predict churn/fraud/price', 'my ROC-AUC is 0.99 — is that leakage', 'which metric for imbalanced classes', 'cross-validation without leaking', 'XGBoost vs LightGBM', 'add a DummyClassifier baseline', 'entrena un modelo de clasificación tabular con scikit-learn'. NOT neural-net / PyTorch training (that is deep-learning), NOT cleaning the raw dirty table first (that is data-cleaning), NOT BI dashboards or forecasting a dated series (that is analytics/forecasting), NOT text/token modeling (that is nlp)."
3
+ description: "Use when predicting a column from rows of tabular features with classic models — scikit-learn pipelines, RandomForest, XGBoost/LightGBM, leak-free cross-validation, metrics for imbalanced classes, or a model that aced CV then collapsed in production. NOT PyTorch neural nets (that is `deep-learning`), NOT cleaning the dirty table first (that is `data-cleaning`), NOT forecasting a dated series (that is `forecasting`), NOT text/token modeling (that is `nlp`)."
4
4
  tags: [machine-learning, scikit-learn, sklearn, xgboost, lightgbm, tabular, gbdt, cross-validation, data-leakage, classification, regression, pipeline]
5
5
  recommends: [deep-learning, data-cleaning, python, training-data]
6
6
  origin: risco
@@ -21,9 +21,9 @@ once isn't a result — it's a leak you haven't found yet.
21
21
  | Rows of features, predict a column, with trees / linear models / sklearn | **machine-learning** (this skill) |
22
22
  | Images, audio, long text, sequences, or you need a neural net / PyTorch | [`deep-learning`](../deep-learning/SKILL.md) |
23
23
  | The table is still dirty (nulls, dupes, mixed types, bad dates) | [`data-cleaning`](../data-cleaning/SKILL.md) **first** — it hands you a validated table |
24
- | Text/token classification, NER, tokenization, LLM-adjacent NLP metrics | [`nlp`](../nlp/SKILL.md) |
25
- | KPIs, dashboards, "explain the business" | `analytics` / `business-intelligence` |
26
- | Forecast a dated series forward (revenue next quarter) | `forecasting` |
24
+ | Text/token classification, NER, tokenization, LLM-adjacent NLP metrics | [`nlp`](../nlp/SKILL.md) (a TF-IDF + linear/GBDT baseline still lives happily in this skill's pipeline) |
25
+ | KPIs, dashboards, "explain the business" | [`analytics`](../analytics/SKILL.md) / [`business-intelligence`](../business-intelligence/SKILL.md) |
26
+ | Forecast a dated series forward (revenue next quarter) | [`forecasting`](../forecasting/SKILL.md) |
27
27
  | Building a training corpus of JSONL messages / preference pairs for an LLM | [`training-data`](../training-data/SKILL.md) |
28
28
 
29
29
  This skill **starts** at a clean, validated table (rows × features + a target) and **ends** at a fitted,
@@ -36,8 +36,9 @@ Verified 2026-07: **scikit-learn current major ~1.9** (1.9.0 shipped 2026-06-02,
36
36
  NOT pin from memory; check the current stable at scikit-learn.org, the 1.x line ships every few months.
37
37
  GBDTs: **XGBoost 3.x** and **LightGBM 4.x** (`xgboost` 3.3, `lightgbm` 4.6 current), plus sklearn's own
38
38
  **`HistGradientBoostingClassifier`/`...Regressor`** — a fast native GBDT that eats NaN and (with
39
- `categorical_features="from_dtype"`) categoricals with **no** preprocessing. Pin what you ship; state
40
- versions as "~X (verify)", never as frozen fact.
39
+ `categorical_features="from_dtype"`) categoricals with **no** preprocessing. Pin what you ship
40
+ ([`python`](../python/SKILL.md) owns the environment and the pinning); state versions as "~X (verify)",
41
+ never as frozen fact.
41
42
 
42
43
  ## The one rule everything else serves: fit on train only
43
44
 
@@ -107,7 +108,7 @@ functions**. Start with a GBDT; reach for `deep-learning` on tabular only with a
107
108
  All three expose the sklearn estimator API, so they drop into the pipeline and CV below unchanged. Don't
108
109
  agonize over XGBoost-vs-LightGBM before you have a baseline and a leak-free CV — split discipline dwarfs the
109
110
  library choice. Tuning knobs (`learning_rate`, `num_leaves`/`max_depth`, early stopping, `monotonic_cst`)
110
- → [references/gbdt-and-tuning.md](references/gbdt-and-tuning.md).
111
+ and importance/SHAP → [references/gbdt-and-tuning.md](references/gbdt-and-tuning.md).
111
112
 
112
113
  ## Leakage-safe feature engineering
113
114
 
@@ -174,19 +175,21 @@ The default 0.5 threshold is a *choice*: tune it on validation to hit your preci
174
175
  Regression uses `root_mean_squared_error` now (`mean_squared_error(squared=False)` is gone). Threshold
175
176
  tuning, calibration, `class_weight`/resampling → [references/metrics-and-imbalance.md](references/metrics-and-imbalance.md).
176
177
 
177
- ## Cardinal sins (the anti-pattern table)
178
+ ## Anti-patterns — the cardinal sins
178
179
 
179
- | Rationalization | Reality → STOP |
180
+ | Anti-pattern | Do instead |
180
181
  | --- | --- |
181
- | "I scaled/encoded/selected features, then split." | **Leakage (#1 sin).** Test statistics are now in train. Split first; put every learned transform *inside* the `Pipeline` so CV re-fits per fold. |
182
- | "This feature is amazingly predictive." | Suspect **target leakage** — a column derived from the label or unavailable at prediction time. Audit provenance before you celebrate. |
183
- | "99% accuracy!" (on 1% positives) | The **accuracy trap**. A constant predictor matches it. Report PR-AUC / precision / recall / F1 and a `confusion_matrix`. |
184
- | "The classes are imbalanced, so I `SMOTE`'d the whole dataset." | Resampling *before* the split, or on the test fold, leaks and evaluates on synthetic rows. Resample **inside CV, on the train fold only** (imblearn `Pipeline`), or just use `class_weight="balanced"`. |
185
- | "CV score is 0.95, ship it." | You never touched a **held-out test set**, or you peeked at it while tuning. One final, untouched test number — or the estimate is optimistic. |
186
- | "Random `KFold` on my time-series / multi-user data." | Future or same-group rows leak into train. Use `TimeSeriesSplit` / `GroupKFold`. |
187
- | "Big train/test gap? It'll generalize." | **Overfitting.** Regularize, reduce capacity (`max_depth`, `min_samples_leaf`), get more data, or use early stopping. Watch `return_train_score`. |
188
- | "Straight to XGBoost, no baseline." | Without a **`DummyClassifier(strategy="most_frequent")`** / `DummyRegressor` floor (and a simple linear model), you can't tell if the fancy model adds anything. |
189
- | "I'll grid-search 10k combos on all the data." | Tuning against the test set *is* fitting to it. Tune with CV on train, confirm once on test; consider nested CV. |
182
+ | Modeling straight off the raw, dirty table | This skill starts at a **clean, validated frame**. Run [`data-cleaning`](../data-cleaning/SKILL.md) first — nulls, dupes and mixed dtypes are its job, not a modeling problem. |
183
+ | Scaling / encoding / selecting features, *then* splitting | **Leakage (#1 sin).** Test statistics are now in train. Split first; put every learned transform *inside* the `Pipeline` so CV re-fits per fold. |
184
+ | Celebrating an amazingly predictive feature | Suspect **target leakage** — a column derived from the label or unavailable at prediction time. Audit provenance before you celebrate. |
185
+ | Reporting 99% accuracy on 1% positives | The **accuracy trap**. A constant predictor matches it. Report PR-AUC / precision / recall / F1 and a `confusion_matrix`. |
186
+ | `SMOTE`-ing the whole dataset because the classes are imbalanced | Resampling *before* the split, or on the test fold, leaks and evaluates on synthetic rows. Resample **inside CV, on the train fold only** (imblearn `Pipeline`), or just use `class_weight="balanced"`. |
187
+ | Shipping on the CV score alone | You never touched a **held-out test set**, or you peeked at it while tuning. One final, untouched test number — or the estimate is optimistic. |
188
+ | Random `KFold` on time-series / multi-user data | Future or same-group rows leak into train. Use `TimeSeriesSplit` / `GroupKFold`. |
189
+ | Waving off a big train/test gap | **Overfitting.** Regularize, reduce capacity (`max_depth`, `min_samples_leaf`), get more data, or use early stopping. Watch `return_train_score`. |
190
+ | Going straight to XGBoost with no baseline | Without a **`DummyClassifier(strategy="most_frequent")`** / `DummyRegressor` floor (and a simple linear model), you can't tell if the fancy model adds anything. |
191
+ | Grid-searching 10k combos over all the data | Tuning against the test set *is* fitting to it. Tune with CV on train, confirm once on test; consider nested CV. |
192
+ | Unset `random_state`, unpinned versions | Folds and fits stop being reproducible and re-trains stop being comparable. Set an integer `random_state` on splitters *and* estimators; pin the versions you ship. |
190
193
 
191
194
  ## Worked lifecycle (end to end)
192
195
 
@@ -216,41 +219,6 @@ print("TEST PR-AUC:", round(average_precision_score(y_test, proba), 3))
216
219
  print(classification_report(y_test, (proba >= 0.5).astype(int))) # threshold is a choice — tune it
217
220
  ```
218
221
 
219
- ## Related skills
220
-
221
- - [`deep-learning`](../deep-learning/SKILL.md) — PyTorch neural nets. Cross the boundary for images, audio,
222
- long text, sequences; on *tabular* data, stay here (Grinsztajn: trees win).
223
- - [`data-cleaning`](../data-cleaning/SKILL.md) — upstream; produces the validated table this skill trains
224
- on. Don't re-teach nulls/dupes/dtypes here.
225
- - [`nlp`](../nlp/SKILL.md) — text/token modeling, NER, tokenization, task metrics (a TF-IDF + linear/GBDT
226
- baseline still lives happily in this skill's pipeline).
227
- - [`python`](../python/SKILL.md) — environment, packaging, pinning the versions you ship.
228
- - [`training-data`](../training-data/SKILL.md) — if the goal is an LLM corpus (JSONL messages / preference
229
- pairs), not a tabular predictor. BI/forecasting products → `analytics` / `business-intelligence` / `forecasting`.
230
-
231
- ## Checklist
232
-
233
- - [ ] Input is a clean, validated table (from `data-cleaning`), not raw dirty rows.
234
- - [ ] A **test set** was held out **once, up front**, stratified, and left untouched until the final score.
235
- - [ ] Every learned transform (impute/scale/encode/select/target-encode) lives **inside** the `Pipeline`.
236
- - [ ] CV runs on the training portion only, via `cross_validate`/`GridSearchCV` over the *pipeline*.
237
- - [ ] Splitter matches the data: `StratifiedKFold` (imbalanced), `TimeSeriesSplit` (time), `GroupKFold` (clustered).
238
- - [ ] A `DummyClassifier`/`DummyRegressor` baseline (and a simple linear model) is beaten, not skipped.
239
- - [ ] Metric fits the task — **not accuracy on imbalanced data**; PR-AUC/precision/recall/F1 as appropriate.
240
- - [ ] Target-leakage audit done: no label-derived / future / not-at-prediction-time features.
241
- - [ ] `random_state` set on splitters and estimators; versions pinned for what ships.
242
- - [ ] Train-vs-test gap inspected; overfitting addressed before shipping.
243
-
244
- ## References
245
-
246
- - [references/pipelines-and-cv.md](references/pipelines-and-cv.md) — `Pipeline`/`ColumnTransformer` patterns,
247
- `FunctionTransformer`, `TargetEncoder` cross-fitting, `GridSearchCV`/`RandomizedSearchCV`/`HalvingRandomSearchCV`,
248
- nested CV, `TimeSeriesSplit`/`GroupKFold` recipes.
249
- - [references/metrics-and-imbalance.md](references/metrics-and-imbalance.md) — metric selection, threshold
250
- tuning, probability calibration, `class_weight`/`sample_weight`, leak-free resampling (imbalanced-learn `Pipeline`).
251
- - [references/gbdt-and-tuning.md](references/gbdt-and-tuning.md) — HistGBDT vs XGBoost vs LightGBM parameter
252
- maps, early stopping, native categoricals, monotonic constraints, permutation importance vs SHAP.
253
-
254
222
  ## Project grounding (02-DOCS + CLAUDE.md)
255
223
 
256
224
  In a project with a `02-DOCS/` layer (the [`harness`](../harness/SKILL.md) wiki), record the modeling
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: observability
3
- description: "Use when instrumenting a service from the inside so an incident can be explained from telemetry alone — wiring OpenTelemetry logs, metrics and traces, standing up a Collector, exporting via OTLP, and defining telemetry-driven alerts. Triggers: 'add OpenTelemetry to this service', 'we can't tell why requests are slow across services — add distributed tracing', 'replace our print/console.log with structured logs correlated to traces', 'stand up an OTel Collector and export to Grafana/Datadog/Honeycomb', 'instrument our LLM calls so each request is a span with token counts', 'define RED metrics and a burn-rate alert from the telemetry', 'instrumenta el servei amb OpenTelemetry i exporta a Grafana', 'añade trazas distribuidas y métricas'. NOT outside-in uptime probes, on-call rotation, or who-gets-paged (that is monitoring)."
3
+ description: "Use when instrumenting a service from the inside so an incident can be explained from telemetry alone — wiring OpenTelemetry logs, metrics and traces, standing up a Collector, exporting via OTLP, and defining telemetry-driven alerts. NOT outside-in uptime probes, on-call rotation, or who-gets-paged (that is `monitoring`)."
4
4
  tags: [observability, opentelemetry, tracing, metrics, structured-logging]
5
5
  recommends: [monitoring, error-handling, performance, cost-tracking, docker]
6
6
  origin: risco
@@ -8,9 +8,7 @@ origin: risco
8
8
 
9
9
  # Observability
10
10
 
11
- You are wiring the *inside* view of a service: when something breaks at 3am, an engineer must be able to answer "what happened, where, and why" from telemetry alone — without adding a `console.log` and redeploying into the fire. This skill emits a concrete artifact: SDK init code, instrumentation (spans/metrics/structured logs), a Collector config, and alert rules that the instrumentation makes possible.
12
-
13
- It is the inside-out half of running in production. The outside half — is it up, who gets paged, on-call rotation — is `../monitoring/SKILL.md`. The clean test: if the deliverable is *"a human gets paged,"* that is monitoring. If it is *"the data that explains the page exists and is queryable,"* that is here.
11
+ You are wiring the *inside* view of a service: when something breaks at 3am, an engineer must be able to answer "what happened, where, and why" from telemetry alone — without adding a `console.log` and redeploying into the fire. This skill emits a concrete artifact: SDK init code, instrumentation (spans/metrics/structured logs), a Collector config, and alert rules that the instrumentation makes possible. The outside-in half — is it up, who gets paged — is `../monitoring/SKILL.md`.
14
12
 
15
13
  ## The one rule
16
14
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: rag
3
- description: "Use when building grounded Q&A over your own documents — handbook, support tickets, PDFs, policies — and the answers must come only from the corpus with citations; when retrieval surfaces the right document but the answer is still wrong; when the model invents facts that are not in the sources; when you need to measure whether retrieval is any good; when the right document is found but the wrong passage is used. Triggers: 'build a bot that answers from our docs with citations', 'my RAG returns the right document but the answer is wrong', 'how do I stop the model hallucinating facts not in the corpus', 'context recall vs context precision', 'add contextual retrieval / prepend chunk context before embedding', 'hybrid search plus rerank pipeline', 'respuestas con citas sobre nuestros documentos', 'el bot s'inventa coses que no surten als documents'. NOT operating the vector store itself — collection schema, HNSW ef_search, quantization (that is vector-db)."
3
+ description: "Use when building grounded Q&A over your own corpus — chunk, retrieve hybrid, rerank, ground, cite chunk ids, refuse when the sources fall short — or when the right document is retrieved but the answer is still wrong, invented, or unmeasured. NOT operating the store itself — collection schema, HNSW ef_search, quantization (that is `vector-db`)."
4
4
  tags: [rag, retrieval-augmented-generation, chunking, hybrid-search, reranking, grounding, citations, faithfulness, contextual-retrieval]
5
5
  recommends: [vector-db, embeddings-search, document-processing, chatbot, agent-eval]
6
6
  origin: risco
@@ -8,15 +8,14 @@ origin: risco
8
8
 
9
9
  # rag — own the retrieve → rerank → ground → cite → refuse pipeline
10
10
 
11
- You own the **pipeline** that turns a corpus plus a question into a grounded, cited answer.
12
- You do **not** own the store underneath it (`../vector-db/SKILL.md`) nor the embedding and
13
- chunk-sizing science beside it (`embeddings-search`). Your job is the glue: chunk, optionally
14
- contextualize, index, retrieve hybrid, rerank, assemble a grounded prompt, cite the sources,
15
- and **refuse** when the context does not contain the answer.
11
+ You own the **pipeline** that turns a corpus plus a question into a grounded, cited answer: chunk,
12
+ optionally contextualize, index, retrieve hybrid, rerank, assemble a grounded prompt, cite the
13
+ sources, and **refuse** when the context does not contain the answer.
16
14
 
17
15
  You are judged by **retrieval quality and answer faithfulness**, not by raw vector math. If you
18
- find yourself tuning HNSW parameters, you wandered into `vector-db`. If you are comparing
19
- embedding models or chunk sizes, that is `embeddings-search`.
16
+ find yourself tuning HNSW parameters, you wandered into the store underneath you
17
+ (`../vector-db/SKILL.md`). If you are comparing embedding models or chunk sizes, that is the
18
+ science beside you (`embeddings-search`).
20
19
 
21
20
  ## The pipeline, and where each stage hands off
22
21
 
@@ -25,19 +24,21 @@ delegate to a sibling skill rather than living here.
25
24
 
26
25
  | Stage | What you do | Hands off to |
27
26
  |---|---|---|
28
- | Ingest | Get clean text out of PDFs/DOCX/HTML/OCR | `../document-processing/SKILL.md` |
29
- | Chunk | Heading/semantic-aware splits with overlap, stable ids | chunk-size science → `embeddings-search` |
27
+ | Ingest | Get clean text out of PDFs/DOCX/HTML/OCR | you assume text exists → `../document-processing/SKILL.md` |
28
+ | Chunk | Heading/semantic-aware splits with overlap, stable ids | model, dims + chunk-size science → `embeddings-search` |
30
29
  | Contextualize | Prepend an LLM-written context blurb per chunk (optional) | stays here |
31
- | Index | Embed + write dense vectors and a BM25/keyword index | the store → `../vector-db/SKILL.md` |
30
+ | Index | Embed + write dense vectors and a BM25/keyword index | you upsert, it owns the knobs → `../vector-db/SKILL.md` |
32
31
  | Retrieve | Hybrid dense + BM25, fuse with RRF, top ~150 | hybrid query mechanics → `../vector-db/SKILL.md` |
33
32
  | Rerank | Cross-encoder over the 150, keep top ~20 | stays here |
34
33
  | Ground + cite | System prompt: answer only from context, cite chunk ids | stays here |
35
34
  | Refuse | Output "I don't have enough information" on weak context | stays here |
36
35
  | Evaluate | Faithfulness, answer relevancy, context precision/recall | general harness → `agent-eval` |
37
36
 
38
- Surfacing this answer inside a chat product (sessions, channels, UI) is `../chatbot/SKILL.md`;
39
- pulling schema-constrained fields out of text is `structured-extraction`. `rag` is the
40
- retrieval brain those products call.
37
+ Three neighbors are not stages at all. Surfacing this answer inside a chat product (sessions,
38
+ channels, UI) is `../chatbot/SKILL.md` — it calls you, not the reverse. A multi-step tool loop with
39
+ state, where retrieval is one tool among many, is `../building-agents/SKILL.md`. Pulling
40
+ schema-constrained fields out of text instead of a grounded prose answer is
41
+ `structured-extraction`. `rag` is the retrieval brain those products call.
41
42
 
42
43
  ## Retrieval is the bottleneck — measure recall before touching the prompt
43
44
 
@@ -87,8 +88,8 @@ def chunk_markdown(doc_id, text, target=800, overlap=120):
87
88
  return out
88
89
  ```
89
90
 
90
- For the deep "what window/overlap maximizes recall for *this* corpus" study, that is
91
- `embeddings-search`. Here you just need structurally sane chunks that keep their ids.
91
+ The "what window/overlap maximizes recall for *this* corpus" study is `embeddings-search`; here you
92
+ just need structurally sane chunks that keep their ids.
92
93
 
93
94
  ## Contextual retrieval — prepend context before you embed
94
95
 
@@ -107,7 +108,8 @@ document for search retrieval. Answer only with the context, nothing else.
107
108
  ```
108
109
 
109
110
  Embed `context + "\n" + chunk_text` (not the bare chunk). The full implementation — caching the
110
- document prompt, batching, the BM25 side — lives in `references/pipeline.md`.
111
+ document prompt, batching, the BM25 side, and a runnable retrieve → rerank → answer skeleton —
112
+ lives in `references/pipeline.md`.
111
113
 
112
114
  ## Hybrid retrieval + RRF + rerank
113
115
 
@@ -144,8 +146,8 @@ top = [candidates[r.index] for r in ranked.results] # each still carries chunk_
144
146
 
145
147
  Properly grounded RAG reduces hallucination rates by up to ~71%; poorly grounded pipelines still
146
148
  hallucinate in up to ~40% of responses *even with the right doc retrieved* (Confident AI / Maxim
147
- 2025, accessed 2026-06-02). The prompt must do three non-negotiable things: bind the answer to
148
- the context, force inline citations, and provide an explicit refusal path.
149
+ 2025, accessed 2026-06-02). The prompt must do three things: bind the answer to the context, force
150
+ inline citations, and provide an explicit refusal path.
149
151
 
150
152
  ```text
151
153
  You answer ONLY using the information inside <context>. Do not use prior knowledge.
@@ -205,22 +207,3 @@ the RAG-specific metrics live here.
205
207
  | Embedding the query differently from the corpus | Query and chunks land in different spaces | Same model + same preprocessing both sides |
206
208
  | Dense-only, ignoring BM25/keyword | Misses exact codes/names/error strings | Hybrid dense + BM25 fused with RRF |
207
209
  | Tuning temperature to fix wrong answers | Generation is rarely the bottleneck | Measure context recall first |
208
-
209
- ## Wiring map
210
-
211
- - **Ingestion (file → text, OCR, tables):** `../document-processing/SKILL.md` — you assume text
212
- already exists; send raw PDFs/DOCX/scans there first.
213
- - **The store (collection, index, hybrid query, quantization):** `../vector-db/SKILL.md` — you
214
- call it to upsert and query; it owns the knobs.
215
- - **Embedding model + chunk-size science:** `embeddings-search` — picking the model, dims,
216
- cost, and the semantic-vs-fixed chunking experiments.
217
- - **Chat product surface (sessions, channels, UI):** `../chatbot/SKILL.md` — wraps the answer
218
- you return; it calls you, not the reverse.
219
- - **Multi-step tool/agent loop with state:** `../building-agents/SKILL.md` — when retrieval is
220
- one tool among many in a larger loop.
221
- - **General eval framework:** `agent-eval` — RAG-specific metrics are here; the harness is there.
222
- - **Schema-constrained field extraction:** `structured-extraction` — when the goal is fields,
223
- not a grounded prose answer.
224
-
225
- See `references/pipeline.md` for the full runnable retrieve → rerank → answer skeleton and
226
- `references/evaluation.md` for the metric formulas, thresholds, and CI gate.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: security-scan
3
- description: "Use when running automated security scanners over a repo or app and turning the raw output into a triaged, ranked, gate-able report: scan for vulnerabilities before shipping, audit dependencies/lockfiles for known CVEs, find secrets committed to the tree or git history, run SAST, or wire scanners into CI. Triggers: 'scan this repo for vulnerabilities', 'check my package-lock for CVEs', 'did anyone commit AWS keys', 'scan git history for leaked keys', 'my lockfile has a transitive CVE', 'is aquasecurity/trivy-action@latest safe', 'set up Semgrep/gitleaks to fail CI', 'escanea el repo en busca de vulnerabilidades', 'audita las dependencias', 'analitza les dependències'. NOT threat-modeling, OWASP design reasoning, or authoring the fix (that is secure-coding)."
3
+ description: "Use when automated scanners drive a security sweep of a repo or app — SAST, dependency/lockfile CVEs, secrets in the tree or git history, IaC misconfig — and the raw output has to become one deduped, exploitability-ranked report CI can gate on. NOT threat-modeling, OWASP design reasoning, or hand-authoring the fix (that is `secure-coding`)."
4
4
  tags: [security, sast, sca, secrets, scanning, owasp]
5
5
  recommends: [secure-coding, github-actions, verify]
6
6
  origin: risco
@@ -15,40 +15,28 @@ finding comes from a **tool run**, not a hunch — if you are reasoning about a
15
15
  design or hand-writing a fix, that is [`secure-coding`](../secure-coding/SKILL.md),
16
16
  not this skill.
17
17
 
18
- Your job is orchestration + triage. Not eyeballing code, not authoring patches.
19
-
20
- ## Operating posture
21
-
22
- - **Read-only by default.** Scan, triage, report. Apply fixes (version bumps,
23
- rotation, `.gitignore` edits) only when the user asks. *Why:* a security sweep
24
- that silently mutates the tree destroys the evidence and the trust.
25
- - **Machine-first.** Every finding must trace to a scanner run with a `ruleId`
26
- and a source location. *Why:* "I think this looks injectable" is design
27
- reasoning — route it to `secure-coding`. This skill ships reproducible output.
28
- - **Pin and verify your scanners.** Pin exact versions, verify checksums/SHAs,
29
- never pull `@latest` GitHub Actions. *Why:* in **March 2026 Trivy was
30
- supply-chain compromised** — malicious releases `v0.69.4/0.69.5/0.69.6` and a
31
- hijacked `aquasecurity/trivy-action` exfiltrated CI secrets. Your scanner runs
32
- with repo + CI-secret access; an unpinned scanner is itself the attack surface.
33
- - **SARIF everything.** Make every tool emit SARIF (or JSON you normalize to it).
34
- *Why:* a common schema is what lets you merge four tools, dedupe, and feed one
35
- artifact into CI instead of four incompatible logs.
36
- - **Triage before you report.** Raw scanner output is high-noise. Rank by
37
- exploitability and dedupe overlap; never dump 400 raw findings on the user.
38
-
39
- ## The four scan classes
40
-
41
- | Class | What it catches | Primary tool | Backup / fast pass |
42
- |---|---|---|---|
43
- | **SAST** | injection, XSS, path traversal in *first-party* code | Semgrep | — |
44
- | **SCA / deps** | known CVEs in dependency manifests + lockfiles | osv-scanner | `npm audit`, `pip-audit` |
45
- | **Secrets** | credentials in the tree **or git history** | gitleaks (speed) | TruffleHog (depth + live verification) |
46
- | **Misconfig / IaC** | Dockerfile, k8s, Terraform, exposed config | Trivy `config` | Semgrep rulesets |
47
-
48
- ### Tool selection by ecosystem
49
-
50
- Pick by what is in the repo. This is the real branch point — match the tool to
51
- the manifest, do not run everything everywhere.
18
+ Your job is orchestration + triage: every finding traces to a scanner run with a
19
+ `ruleId` and a source location, so the output is reproducible. Not eyeballing
20
+ code, not authoring patches.
21
+
22
+ **Read-only by default.** Scan, triage, report. Apply fixes (version bumps,
23
+ rotation, `.gitignore` edits) only when the user asks — a security sweep that
24
+ silently mutates the tree destroys the evidence and the trust.
25
+
26
+ **Pin and verify your scanners.** Exact versions, verified checksums/SHAs, never
27
+ `@latest` GitHub Actions. In **March 2026 Trivy was supply-chain compromised** —
28
+ malicious releases `v0.69.4/0.69.5/0.69.6` and a hijacked
29
+ `aquasecurity/trivy-action` exfiltrated CI secrets. Your scanner runs with repo +
30
+ CI-secret access; an unpinned scanner is itself the attack surface.
31
+
32
+ ## Scan classes and tool selection
33
+
34
+ Four classes: **SAST** (injection, XSS, path traversal in *first-party* code),
35
+ **SCA / deps** (known CVEs in dependency manifests + lockfiles), **Secrets**
36
+ (credentials in the tree **or git history**), **Misconfig / IaC** (Dockerfile,
37
+ k8s, Terraform, exposed config). Pick tools by what is in the repo. This is the
38
+ real branch point — match the tool to the manifest, do not run everything
39
+ everywhere.
52
40
 
53
41
  | Repo contains | SAST | SCA | Secrets | Misconfig |
54
42
  |---|---|---|---|---|
@@ -56,15 +44,17 @@ the manifest, do not run everything everywhere.
56
44
  | Python (`poetry.lock`/`requirements.txt`) | Semgrep | osv-scanner + `pip-audit` (fast) | gitleaks → TruffleHog | Trivy |
57
45
  | Go (`go.mod`/`go.sum`) | Semgrep | osv-scanner (+ `govulncheck` for reachability) | gitleaks | Trivy |
58
46
  | Containers (`Dockerfile`, images) | — | Trivy `fs`/`image` | Trivy `--scanners secret` | Trivy `config` |
59
- | IaC (Terraform/k8s/Helm) | Semgrep (IaC rules) | — | gitleaks | Trivy `config` |
47
+ | IaC (Terraform/k8s/Helm) | Semgrep (IaC rules) | — | gitleaks | Trivy `config`, Semgrep rulesets |
60
48
  | Monorepo (mixed) | Semgrep `auto` | osv-scanner (multi-ecosystem) | gitleaks → TruffleHog | Trivy |
61
49
 
62
50
  Full install (pinned), flag matrix, and suppression syntax: `references/tools.md`.
63
51
 
64
52
  ## Run recipes
65
53
 
66
- All recipes emit SARIF or JSON so they merge into one report. **Pin the version
67
- shown** — the placeholders below mark where to lock an exact tag/digest.
54
+ All recipes emit SARIF (or JSON you normalize to it) — a common schema is what
55
+ lets you merge four tools, dedupe, and feed one artifact into CI instead of four
56
+ incompatible logs. **Pin the version shown**; the placeholders below mark where
57
+ to lock an exact tag/digest.
68
58
 
69
59
  ### SAST — Semgrep
70
60
 
@@ -107,10 +97,10 @@ gitleaks detect --redact --report-format sarif --report-path secrets.sarif
107
97
  trufflehog git file://. --only-verified --json > trufflehog.json
108
98
  ```
109
99
 
110
- ### Misconfig / IaC — Trivy (PINNED — see the caveat)
100
+ ### Misconfig / IaC — Trivy (PINNED — see the caveat above)
111
101
 
112
102
  Trivy scans filesystems, images, and IaC and finds transitive CVEs `npm audit`
113
- misses. After the March 2026 compromise, **never** run an unpinned Trivy.
103
+ misses.
114
104
 
115
105
  ```bash
116
106
  # Pin the EXACT version (NOT v0.69.4/.5/.6 — those were the malicious releases).
@@ -200,17 +190,17 @@ Emit one `security-scan-report.json` — the machine-checkable contract CI gates
200
190
 
201
191
  ## Anti-patterns
202
192
 
203
- | Rationalization | Reality |
193
+ | Anti-pattern | Do instead |
204
194
  |---|---|
205
- | "Pull `aquasecurity/trivy-action@latest`, it's official." | March 2026: a hijacked tag stole CI secrets. Pin a full SHA, verify provenance. |
206
- | "Every scanner finding is a bug to fix." | Most are noise. Rank by reachable + exposed + sensitive sink; report the few that matter. |
207
- | "Scanned the working tree, no secrets." | History holds the deleted keys. Scan git history; a removed-in-HEAD key is still leaked and live. |
208
- | "`npm audit` is clean, deps are fine." | Native auditors miss transitive CVEs. Run osv-scanner/Trivy too; native is the fast pass, not the only pass. |
209
- | "Commit a blanket `.semgrepignore` to quiet CI." | A blanket ignore hides the next real bug. Suppress per-finding with a written justification + expiry. |
210
- | "We found a verified key, I deleted it from the file." | Deleting ≠ safe. Rotate the credential first, then scrub history. The committed value is already compromised. |
211
- | "Trust the SARIF `level`, that's the severity." | Tools disagree. Normalize to one scale before you rank or gate. |
212
- | "Dump all four tool outputs in the PR, let the reviewer sort it." | The reviewer won't. Merge, dedupe, rank, and emit one report. |
213
- | "Run the scan; it'll auto-fix the deps." | Read-only by default. Propose bumps; apply only when asked — never mutate during a sweep. |
195
+ | Pulling `aquasecurity/trivy-action@latest` because it is the official action | March 2026: a hijacked tag stole CI secrets. Pin a full SHA, verify provenance. |
196
+ | Treating every scanner finding as a bug to fix | Most are noise. Rank by reachable + exposed + sensitive sink; report the few that matter. |
197
+ | Calling the repo clean after scanning only the working tree | History holds the deleted keys. Scan git history; a removed-in-HEAD key is still leaked and live. |
198
+ | Declaring deps fine because `npm audit` is clean | Native auditors miss transitive CVEs. Run osv-scanner/Trivy too; native is the fast pass, not the only pass. |
199
+ | Committing a blanket `.semgrepignore` to quiet CI | A blanket ignore hides the next real bug. Suppress per-finding with a written justification + expiry. |
200
+ | Deleting a verified key from the file and moving on | Deleting ≠ safe. Rotate the credential first, then scrub history. The committed value is already compromised. |
201
+ | Taking the SARIF `level` as the severity | Tools disagree. Normalize to one scale before you rank or gate. |
202
+ | Dumping all four tool outputs in the PR for the reviewer to sort | The reviewer won't. Merge, dedupe, rank, and emit one report. |
203
+ | Letting the scan auto-fix the deps it finds | Read-only by default. Propose bumps; apply only when asked — never mutate during a sweep. |
214
204
 
215
205
  ## Project grounding (02-DOCS + CLAUDE.md)
216
206
 
@@ -218,23 +208,12 @@ In a project with a `02-DOCS/` layer (the [`harness`](../harness/SKILL.md)
218
208
  Karpathy wiki), record the scanner choices, pinned versions, gate thresholds, and
219
209
  any accepted-risk suppressions in `02-DOCS/wiki/stack/security-scan.md`, and index
220
210
  it in `02-DOCS/wiki/index.md` (the Knowledge map; root `CLAUDE.md` keeps only a short
221
- pointer to it). Read it first on every run so the
222
- next agent inherits the pinned tools and thresholds instead of re-deriving them.
223
- No `02-DOCS/`? Skip silently. Conventions are recorded, not gated — never block
224
- the scan on this.
211
+ pointer to it). Read it first on every run so the next agent inherits the pinned
212
+ tools and thresholds instead of re-deriving them. No `02-DOCS/`? Skip silently.
213
+ Conventions are recorded, not gated — never block the scan on this.
225
214
 
226
215
  ## See Also
227
216
 
228
- - [`secure-coding`](../secure-coding/SKILL.md) — the human-reasoning sibling:
229
- threat-model a feature, hand-write the vulnerable→fixed diff. *If the answer
230
- comes from a tool run it's this skill; if it comes from reasoning about the
231
- design it's secure-coding.*
232
- - [`review`](../review/SKILL.md) — adversarial review of a diff against a spec.
233
- - [`code-review`](../code-review/SKILL.md) — general correctness/quality review.
234
- - [`verify`](../verify/SKILL.md) — the broader lint/type/test green gate this
235
- feeds into.
236
- - **References** — `references/tools.md` (pinned installs, flag matrix,
237
- suppression syntax); `references/triage.md` (ranking rubric, dedupe keying,
238
- severity map, full report schema).
239
- </content>
240
- </invoke>
217
+ Reviewing a diff rather than scanning a repo: [`code-review`](../code-review/SKILL.md)
218
+ for correctness and quality, [`review`](../review/SKILL.md) for adversarial review
219
+ against a spec.
@@ -95,4 +95,3 @@ trivy image --format sarif --output trivy-img.sarif <pinned-image@sha256:...>
95
95
  - Every recipe emits SARIF 2.1.0 so findings merge into one report. Where a tool
96
96
  only emits native JSON (`npm audit`, `pip-audit`, TruffleHog), normalize it to
97
97
  the report schema in `triage.md` rather than gating on its raw shape.
98
- </content>
@@ -90,4 +90,3 @@ This is the contract `scripts/verify.sh` gates on.
90
90
  - **Gate:** any `findings[]` with `status: "open"` and `severity: "critical"`
91
91
  → fail. Strict mode also fails on `open` + `high`. `suppressed`/`fixed` never
92
92
  fail. An empty/clean report exits `0`.
93
- </content>