@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.
- package/manifest.json +17 -17
- package/package.json +1 -1
- package/skills/forecasting/SKILL.md +17 -17
- package/skills/game-storytelling/SKILL.md +14 -39
- package/skills/gamedev-multiplayer/SKILL.md +35 -48
- package/skills/gamedev-pathing/SKILL.md +20 -29
- package/skills/gamedev-shipping/SKILL.md +28 -44
- package/skills/godot/SKILL.md +17 -36
- package/skills/grants/SKILL.md +2 -20
- package/skills/harness/SKILL.md +26 -85
- package/skills/harness/evals/cases.yaml +1 -1
- package/skills/hiring/SKILL.md +14 -26
- package/skills/instagram-api/SKILL.md +12 -22
- package/skills/machine-learning/SKILL.md +21 -53
- package/skills/observability/SKILL.md +2 -4
- package/skills/rag/SKILL.md +21 -38
- package/skills/security-scan/SKILL.md +46 -67
- package/skills/security-scan/references/tools.md +0 -1
- package/skills/security-scan/references/triage.md +0 -1
- package/skills/tauri/SKILL.md +6 -11
- package/skills/webhooks/SKILL.md +17 -34
package/skills/hiring/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hiring
|
|
3
|
-
description: "Use when
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
120
|
-
|
|
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
|
|
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
|
-
##
|
|
15
|
+
## Route out
|
|
16
16
|
|
|
17
|
-
| The ask |
|
|
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 | `
|
|
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
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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
|
|
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
|
|
40
|
-
versions as "~X (verify)",
|
|
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
|
-
##
|
|
178
|
+
## Anti-patterns — the cardinal sins
|
|
178
179
|
|
|
179
|
-
|
|
|
180
|
+
| Anti-pattern | Do instead |
|
|
180
181
|
| --- | --- |
|
|
181
|
-
|
|
|
182
|
-
|
|
|
183
|
-
|
|
|
184
|
-
|
|
|
185
|
-
|
|
|
186
|
-
|
|
|
187
|
-
|
|
|
188
|
-
|
|
|
189
|
-
|
|
|
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.
|
|
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
|
|
package/skills/rag/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: rag
|
|
3
|
-
description: "Use when building grounded Q&A over your own
|
|
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
|
-
|
|
13
|
-
|
|
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
|
|
19
|
-
embedding models or chunk sizes, that is
|
|
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
|
|
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,
|
|
39
|
-
|
|
40
|
-
retrieval
|
|
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
|
-
|
|
91
|
-
|
|
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
|
|
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
|
|
148
|
-
|
|
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
|
|
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
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
67
|
-
|
|
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.
|
|
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
|
-
|
|
|
193
|
+
| Anti-pattern | Do instead |
|
|
204
194
|
|---|---|
|
|
205
|
-
|
|
|
206
|
-
|
|
|
207
|
-
|
|
|
208
|
-
|
|
|
209
|
-
|
|
|
210
|
-
|
|
|
211
|
-
|
|
|
212
|
-
|
|
|
213
|
-
|
|
|
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
|
-
|
|
223
|
-
|
|
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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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>
|