Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
日本語の概要は準備中です。原文の説明を表示しています。
Use when building or changing features, preprocessing, encoders, resampling or train/validation/test splits — keep every fitted transform inside a Pipeline fitted on training folds only, and build time and group features without seeing the future or the same entity twice
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Leakage is information in training that will not exist at prediction time. It produces a great offline score and a model that fails in production — and no test fails, because the code does exactly what it was told. The three sources: transforms fitted on rows they later score, features computed from the future, and the same entity on both sides of a split.
Core principle: split first; everything that learns from data (scalers, imputers, encoders, selectors, resamplers) is fitted inside the training fold only — in practice, inside one scikit-learn Pipeline that is cross-validated and shipped as a single artifact.
# ❌ the scaler and the selector have seen the test rows
X_scaled = StandardScaler().fit_transform(X)
X_sel = SelectKBest(k=20).fit_transform(X_scaled, y)
X_train, X_test, y_train, y_test = train_test_split(X_sel, y)
# ✅ split once, then everything learned lives in the pipeline
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=seed
)
preprocess = ColumnTransformer([
("num", make_pipeline(SimpleImputer(strategy="median"), StandardScaler()), numeric_cols),
("cat", OneHotEncoder(handle_unknown="ignore", min_frequency=20), categorical_cols),
])
model = make_pipeline(preprocess, SelectKBest(k=20), LogisticRegression(max_iter=1000))
scores = cross_validate(model, X_train, y_train, cv=cv, scoring="average_precision")
cross_validate refits the whole pipeline per fold, so imputation medians, category vocabularies and selected features are learned from that fold's training part only. Use set_output(transform="pandas") when you need column names downstream.
TargetEncoder.fit_transform uses internal cross-fitting; fit(X, y).transform(X) on the same rows does not and leaks the target. Inside a Pipeline, fit calls fit_transform, which is the safe path. Never compute per-category target means with a groupby over the full table.class_weight="balanced" or threshold tuning. Oversampling (SMOTE) goes inside an imblearn.pipeline.Pipeline only if the repository already depends on imbalanced-learn; oversampling before the split copies near-identical rows into validation.When rows are ordered in time, the split, the features and the label each respect it.
cv = TimeSeriesSplit(n_splits=5, gap=horizon_rows)
Point-in-time joins: attach the latest feature value strictly before the prediction timestamp.
# ❌ joins the customer's current tier, which may have changed after the snapshot
df = snapshots.merge(customers[["customer_id", "tier"]], on="customer_id")
# ✅ as-of join against the tier history (both frames sorted by the `on` key)
df = pd.merge_asof(
snapshots.sort_values("snapshot_ts"),
tier_history.sort_values("changed_at"),
left_on="snapshot_ts", right_on="changed_at",
by="customer_id", direction="backward", allow_exact_matches=False,
)
Rolling features exclude the current row and anything after it:
def spend_7d(events: pd.DataFrame) -> pd.Series:
events = events.sort_values(["user_id", "ts"])
rolled = (
events.set_index("ts")
.groupby("user_id")["amount"]
.rolling("7D", closed="left")
.sum()
.fillna(0.0)
)
return pd.Series(rolled.to_numpy(), index=events.index, name="spend_7d")
The feature window ends before the label window starts; a label that becomes final 60 days later means the last 60 days of snapshots cannot be training rows yet.
If a user, patient, device or store appears in many rows, a random split puts the same entity in train and validation and the model memorises it.
cv = StratifiedGroupKFold(n_splits=5, shuffle=True, random_state=seed)
cross_validate(model, X, y, groups=df["user_id"], cv=cv, scoring="average_precision")
Also deduplicate exact and near-exact rows before the split; duplicates across the split are the same leak in a different form.
A future-rows test pins the time logic:
def test_spend_7d_ignores_rows_after_prediction_time() -> None:
events = pd.DataFrame({
"user_id": ["a", "a", "a"],
"ts": pd.to_datetime(["2026-01-01", "2026-01-03", "2026-01-05"]),
"amount": [10.0, 20.0, 30.0],
})
later = pd.DataFrame({"user_id": ["a"], "ts": pd.to_datetime(["2026-01-06"]), "amount": [1e6]})
before = spend_7d(events)
after = spend_7d(pd.concat([events, later], ignore_index=True))
assert before.tolist() == [0.0, 10.0, 30.0]
pd.testing.assert_series_equal(after.loc[before.index], before)
A shuffled-label test catches leaks you did not think of: train the real pipeline on permuted labels with the real CV; the score must fall to the baseline. If it does not, something in the features encodes the row order, an ID or the label.
def test_pipeline_cannot_learn_shuffled_labels(train_fixture) -> None:
X, y = train_fixture
y_shuffled = np.random.default_rng(0).permutation(y)
score = cross_val_score(build_model(seed=0), X, y_shuffled, cv=5, scoring="roc_auc").mean()
assert score < 0.6
The fitted pipeline is the artifact. Serving calls pipeline.predict on the same raw columns training used — it never re-implements the preprocessing in SQL or in the API handler. A test feeds one fixture row through the batch path and the serving path and asserts identical output (model-serving-and-monitoring).
fit_transform on the full dataset "just for scaling".user_total_spend) computed over the whole history, including after the snapshot.KFold on time-ordered or repeated-entity data.train_test_split without random_state, so the split differs every run.まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
日本語の概要は準備中です。原文の説明を表示しています。
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
日本語の概要は準備中です。原文の説明を表示しています。
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
日本語の概要は準備中です。原文の説明を表示しています。
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
日本語の概要は準備中です。原文の説明を表示しています。
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
日本語の概要は準備中です。原文の説明を表示しています。
Use when deciding whether a request needs an analiz task before implementation - the conditions that require the architect's analysis versus going straight to implementation
日本語の概要は準備中です。原文の説明を表示しています。