pattyeng 1.0.4 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -43
- package/bin/pattyeng.js +25 -14
- package/lib/skills.js +198 -0
- package/lib/upgrade.js +46 -0
- package/package.json +5 -3
- package/skills/.system/.codex-system-skills.marker +1 -0
- package/skills/.system/imagegen/LICENSE.txt +201 -0
- package/skills/.system/imagegen/SKILL.md +356 -0
- package/skills/.system/imagegen/agents/openai.yaml +6 -0
- package/skills/.system/imagegen/assets/imagegen-small.svg +5 -0
- package/skills/.system/imagegen/assets/imagegen.png +0 -0
- package/skills/.system/imagegen/references/cli.md +242 -0
- package/skills/.system/imagegen/references/codex-network.md +33 -0
- package/skills/.system/imagegen/references/image-api.md +90 -0
- package/skills/.system/imagegen/references/prompting.md +118 -0
- package/skills/.system/imagegen/references/sample-prompts.md +433 -0
- package/skills/.system/imagegen/scripts/image_gen.py +995 -0
- package/skills/.system/imagegen/scripts/remove_chroma_key.py +440 -0
- package/skills/.system/openai-docs/LICENSE.txt +201 -0
- package/skills/.system/openai-docs/SKILL.md +167 -0
- package/skills/.system/openai-docs/agents/openai.yaml +14 -0
- package/skills/.system/openai-docs/assets/openai-small.svg +3 -0
- package/skills/.system/openai-docs/assets/openai.png +0 -0
- package/skills/.system/openai-docs/references/latest-model.md +37 -0
- package/skills/.system/openai-docs/references/prompting-guide.md +244 -0
- package/skills/.system/openai-docs/references/upgrade-guide.md +181 -0
- package/skills/.system/openai-docs/scripts/fetch-codex-manual.mjs +598 -0
- package/skills/.system/openai-docs/scripts/resolve-latest-model-info.js +147 -0
- package/skills/.system/plugin-creator/SKILL.md +243 -0
- package/skills/.system/plugin-creator/agents/openai.yaml +6 -0
- package/skills/.system/plugin-creator/assets/plugin-creator-small.svg +3 -0
- package/skills/.system/plugin-creator/assets/plugin-creator.png +0 -0
- package/skills/.system/plugin-creator/references/installing-and-updating.md +143 -0
- package/skills/.system/plugin-creator/references/plugin-json-spec.md +194 -0
- package/skills/.system/plugin-creator/scripts/create_basic_plugin.py +324 -0
- package/skills/.system/plugin-creator/scripts/read_marketplace_name.py +48 -0
- package/skills/.system/plugin-creator/scripts/update_plugin_cachebuster.py +78 -0
- package/skills/.system/plugin-creator/scripts/validate_plugin.py +586 -0
- package/skills/.system/skill-creator/SKILL.md +416 -0
- package/skills/.system/skill-creator/agents/openai.yaml +5 -0
- package/skills/.system/skill-creator/assets/skill-creator-small.svg +3 -0
- package/skills/.system/skill-creator/assets/skill-creator.png +0 -0
- package/skills/.system/skill-creator/license.txt +202 -0
- package/skills/.system/skill-creator/references/openai_yaml.md +49 -0
- package/skills/.system/skill-creator/scripts/generate_openai_yaml.py +226 -0
- package/skills/.system/skill-creator/scripts/init_skill.py +400 -0
- package/skills/.system/skill-creator/scripts/quick_validate.py +101 -0
- package/skills/.system/skill-installer/LICENSE.txt +202 -0
- package/skills/.system/skill-installer/SKILL.md +58 -0
- package/skills/.system/skill-installer/agents/openai.yaml +5 -0
- package/skills/.system/skill-installer/assets/skill-installer-small.svg +3 -0
- package/skills/.system/skill-installer/assets/skill-installer.png +0 -0
- package/skills/.system/skill-installer/scripts/github_utils.py +21 -0
- package/skills/.system/skill-installer/scripts/install-skill-from-github.py +308 -0
- package/skills/.system/skill-installer/scripts/list-skills.py +107 -0
- package/skills/cap/SKILL.md +77 -0
- package/skills/caveman/SKILL.md +49 -0
- package/skills/code-review/SKILL.md +46 -0
- package/skills/codebook/SKILL.md +184 -0
- package/skills/doc-review/SKILL.md +147 -0
- package/skills/feature-research/SKILL.md +34 -0
- package/skills/file-op/SKILL.md +116 -0
- package/skills/grill-me/SKILL.md +10 -0
- package/skills/grill-with-docs/ADR-FORMAT.md +47 -0
- package/skills/grill-with-docs/CONTEXT-FORMAT.md +60 -0
- package/skills/grill-with-docs/SKILL.md +88 -0
- package/skills/handoff/SKILL.md +17 -0
- package/skills/improve-codebase/SKILL.md +79 -0
- package/skills/linear/SKILL.md +107 -0
- package/skills/next-step/SKILL.md +61 -0
- package/skills/no-reinvent/SKILL.md +131 -0
- package/skills/no-wall/SKILL.md +146 -0
- package/skills/online/SKILL.md +54 -0
- package/skills/plan-review/SKILL.md +55 -0
- package/skills/professional/SKILL.md +111 -0
- package/skills/promise-tracking/SKILL.md +131 -0
- package/skills/prove/SKILL.md +135 -0
- package/skills/read-before-write/SKILL.md +123 -0
- package/skills/review/SKILL.md +78 -0
- package/skills/review-mp/SKILL.md +78 -0
- package/skills/scope-boundary/SKILL.md +121 -0
- package/skills/semble-search/SKILL.md +40 -0
- package/skills/sitrep/SKILL.md +126 -0
- package/skills/structure-code/SKILL.md +116 -0
- package/skills/surface-assumptions/SKILL.md +139 -0
- package/skills/teach/GLOSSARY-FORMAT.md +35 -0
- package/skills/teach/LEARNING-RECORD-FORMAT.md +46 -0
- package/skills/teach/MISSION-FORMAT.md +31 -0
- package/skills/teach/RESOURCES-FORMAT.md +32 -0
- package/skills/teach/SKILL.md +131 -0
- package/skills/team-protocol/SKILL.md +172 -0
- package/skills/tech-lead/SKILL.md +332 -0
- package/skills/to-issues/SKILL.md +83 -0
- package/skills/to-prd/SKILL.md +74 -0
- package/skills/vectorbt-expert/SKILL.md +253 -0
- package/skills/verify-done/SKILL.md +128 -0
- package/skills/work-log/SKILL.md +141 -0
- package/skills/work-log/template.html +496 -0
- package/skills/zoom-out/SKILL.md +7 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vectorbt-expert
|
|
3
|
+
description: 'Project-specific VectorBT sleeve-screener expert for the t1 Korean-equity (KRX) runner. Use when asked to sweep sleeve variants, write/edit config/sleeves/*.yaml, run scripts/backtest/run_vbt_sweep.py, debug src/t1/backtest/vbt/, build feature tensors, wire TA-Lib indicators into the sleeve expression DSL, wire cross-sectional cs_* ops, run the top-N recall gate vs the live Runner, replay a live spec, or reason about Tier-0 fidelity boundaries. ALWAYS use TA-Lib for technical indicators — never VectorBT built-ins. KRX symbols (stock_code), not Indian/US tickers.'
|
|
4
|
+
user-invocable: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# VectorBT Sleeve-Screener Expert (t1 / KRX)
|
|
8
|
+
|
|
9
|
+
## What this is
|
|
10
|
+
|
|
11
|
+
This project has a **project-specific VectorBT integration** — a Tier-0 fast sleeve-screener that ranks strategy variants and is **recall-gated against the exact live Runner**, not a generic backtest harness. It lives in `src/t1/backtest/vbt/` and runs in a dedicated `.venv-vbt`.
|
|
12
|
+
|
|
13
|
+
**Indicator layer — TA-Lib is MANDATED.** This project uses **TA-Lib for ALL technical indicators** (EMA, SMA, RSI, MACD, BBANDS, ATR, ADX, STDDEV, MOM, etc.). NEVER use `vbt.MA.run()`, `vbt.RSI.run()`, or any other VectorBT built-in indicator — always compute via `talib`. The proprietary `path_*` features are being retired as the indicator layer; standard TA-Lib indicators are the source of truth going forward.
|
|
14
|
+
|
|
15
|
+
**Do NOT use these (project-specific guardrails):**
|
|
16
|
+
- ❌ VectorBT built-in indicators (`vbt.MA`, `vbt.RSI`, `vbt.MACD`, …) — use TA-Lib instead, always.
|
|
17
|
+
- ❌ OpenAlgo / yfinance / CCXT — the only data source is Postgres `market_data.raw_minute_bars` (+ synthetic demo).
|
|
18
|
+
- ❌ Plotly / candlestick charts — output is ranked tables + optional `--emit-events` JSONL + `--trades-csv`.
|
|
19
|
+
- ❌ Indian market (STT, Rs 20, NIFTY) / US / Crypto — this is **Korean equity (KRX)**, symbols are `stock_code` (e.g. `005930` = Samsung), session 09:00–15:30 KST, cost ~42 bps roundtrip.
|
|
20
|
+
- ❌ Per-strategy `backtest.py` template scripts — strategies are **declarative sleeve YAML** (`config/sleeves/*.yaml`).
|
|
21
|
+
|
|
22
|
+
If you find yourself reaching for a VectorBT built-in indicator, **stop** — use TA-Lib. For the broader harness (sleeve YAML, recall gate, fidelity boundaries), read the runbook (`docs/vbt-sleeve-screener-runbook.md`) and the engine design (`docs/vectorized-backtest-engine-design.md`).
|
|
23
|
+
|
|
24
|
+
## Environment — the dedicated `.venv-vbt`
|
|
25
|
+
|
|
26
|
+
VectorBT 1.0.0 requires `pandas<3.0`, but the repo's `uv.lock` resolves `pandas 3.0.3`. So the screener runs in its **own venv**, deliberately decoupled from the repo lock. Local dev and the GPU box use the **same spec** (`requirements-vbt.txt`).
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# one-time setup
|
|
30
|
+
uv venv .venv-vbt --python 3.12
|
|
31
|
+
uv pip install --python .venv-vbt/bin/python -r requirements-vbt.txt
|
|
32
|
+
|
|
33
|
+
# always invoke the screener through this python — NOT the repo default
|
|
34
|
+
PYTHONPATH=src .venv-vbt/bin/python scripts/backtest/run_vbt_sweep.py ...
|
|
35
|
+
|
|
36
|
+
# tests
|
|
37
|
+
PYTHONPATH=src .venv-vbt/bin/python -m pytest tests/vbt -q # ~132 tests
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`requirements-vbt.txt` pins: `numpy>=2.0`, `pandas>=2.2,<3.0`, `vectorbt==1.0.0`, `TA-Lib>=0.4.28`, `pyarrow>=14.0`, `PyYAML>=6.0`, `pytest>=8.0`. No numba-pin surprises — vectorbt pulls numba+llvmlite, which is acceptable **here** (research screener) because this is NOT the production fill engine (the "no numba" rule in the engine design doc is about byte-parity in the live Runner, a different scope).
|
|
41
|
+
|
|
42
|
+
**⚠ TA-Lib native C library required (one-time, per host).** The `TA-Lib` pip package is a Python binding over a C library; `pip install TA-Lib` will FAIL to build until the C library is installed first. Install the C library on each host:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# macOS (Homebrew)
|
|
46
|
+
brew install ta-lib
|
|
47
|
+
|
|
48
|
+
# Linux (GPU box) — build from source
|
|
49
|
+
curl -L https://github.com/TA-Lib/ta-lib/releases/download/v0.4.0/ta-lib-0.4.0-src.tar.gz | tar xzf -
|
|
50
|
+
cd ta-lib && ./configure --prefix=/usr && make && sudo make install
|
|
51
|
+
|
|
52
|
+
# THEN install the Python binding into .venv-vbt
|
|
53
|
+
uv pip install --python .venv-vbt/bin/python TA-Lib
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Verify: `.venv-vbt/bin/python -c "import talib; print(talib.__version__)"`. If a fresh agent session reports `ModuleNotFoundError: No module named 'talib'`, the fix is the native C lib install above — not a code change.
|
|
57
|
+
|
|
58
|
+
## The CLI — `scripts/backtest/run_vbt_sweep.py`
|
|
59
|
+
|
|
60
|
+
Always go through this CLI. It expands variant grids, builds each day's feature tensor **once** and reuses it across variants, runs every (sleeve, variant, date) through the vbt engine, and prints sleeves ranked by total net PnL with per-day positive-day count and drop-biggest-day robustness.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Local demo (synthetic data, no DB) — always start here
|
|
64
|
+
PYTHONPATH=src .venv-vbt/bin/python scripts/backtest/run_vbt_sweep.py \
|
|
65
|
+
--config config/sleeves/example.yaml --demo
|
|
66
|
+
|
|
67
|
+
# Real data (this Mac via Tailscale, or the GPU box — same T1_POSTGRES_DSN)
|
|
68
|
+
PYTHONPATH=src .venv-vbt/bin/python scripts/backtest/run_vbt_sweep.py \
|
|
69
|
+
--config config/sleeves/micro_only.yaml \
|
|
70
|
+
--universe config/universe-daily-2026-06-18.txt \
|
|
71
|
+
--dates 2026-06-18 \
|
|
72
|
+
--trades-csv /tmp/micro-2026-06-18.csv
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Flags
|
|
76
|
+
|
|
77
|
+
| Flag | Purpose |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `--config` | sleeve sweep YAML (required) |
|
|
80
|
+
| `--runner-config` | runner.yaml for sizing/cost/hold defaults (default `config/runner.yaml`) |
|
|
81
|
+
| `--universe` | one KRX symbol per line |
|
|
82
|
+
| `--dates` | comma-separated YYYY-MM-DD, range `A:B`, or `@file` |
|
|
83
|
+
| `--corpus` | OHLCV corpus (default `tradable`) |
|
|
84
|
+
| `--until HH:MM` | KST cutoff — no new entries past it; open positions force-close at it |
|
|
85
|
+
| `--trades-csv PATH` | dump every per-trade row |
|
|
86
|
+
| `--emit-events DIR` | write score_sweep-compatible JSONL |
|
|
87
|
+
| `--deep-stats` | per-variant deep diagnostics |
|
|
88
|
+
| `--deep-on` | `{passing,all,<list>}` — which variants get deep stats |
|
|
89
|
+
| `--baseline` | baseline sleeve for diff |
|
|
90
|
+
| `--demo` | synthetic data, no DB |
|
|
91
|
+
|
|
92
|
+
**Bootstrap note:** the CLI injects repo root + `src/` into `sys.path` before importing `t1.*`, so both `PYTHONPATH=src python …` and `.venv-vbt/bin/python …` work. Don't "fix" that bootstrap — without it `_try_import_full_day_loader` silently ImportError→None and Postgres raises "loader unavailable".
|
|
93
|
+
|
|
94
|
+
## Sizing / cost / hold — `config/runner.yaml` is the single source of truth
|
|
95
|
+
|
|
96
|
+
The screener inherits from the **live runner's own config** so it cannot drift from production. Sleeve YAML overrides are for grid sweeps only.
|
|
97
|
+
|
|
98
|
+
| `config/runner.yaml` field | Screener inheritance |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `trading.budget_won` | `per_pick_won = budget_won / target_concurrent_positions` |
|
|
101
|
+
| `trading.target_concurrent_positions` | default `slots` per sleeve |
|
|
102
|
+
| `trading.hold_minutes` | default hold when sleeve YAML omits it |
|
|
103
|
+
| `cost_per_trade_bps` | default `cost_bps` per sleeve (production value `42.0`) |
|
|
104
|
+
|
|
105
|
+
Engine contract (`simulate_day`): `cash_sharing=False` (positions do NOT pool cash, matching Runner's `budget/N`), cost wedge is per-leg value-proportional `cost_bps/2` (round-trip ≈ `cost_bps` on flat notional; slightly more for winners, monotone in return so it does not change **ranking**). Only traded columns are simulated (a 500-symbol universe filling a couple of slots avoids building four 500-wide DataFrames per call).
|
|
106
|
+
|
|
107
|
+
## Sleeve YAML structure
|
|
108
|
+
|
|
109
|
+
Declarative. Each entry under `sleeves` is a sleeve; a `grid` expands cartesian variants (e.g. `hold_minutes × cost_bps`).
|
|
110
|
+
|
|
111
|
+
```yaml
|
|
112
|
+
cadence: 1 # decide every minute (Runner decides every decision minute)
|
|
113
|
+
|
|
114
|
+
sleeves:
|
|
115
|
+
- name: capbounce
|
|
116
|
+
filter: "path_ret_10m_bps < -300 and path_ret_second_half_10m_bps < -200 and path_range_expansion_10m > 1.5"
|
|
117
|
+
score: "path_ret_10m_bps"
|
|
118
|
+
score_direction: asc # most-negative first
|
|
119
|
+
grid:
|
|
120
|
+
hold_minutes: [5, 8, 10, 12, 15]
|
|
121
|
+
|
|
122
|
+
- name: momentum
|
|
123
|
+
filter: "path_ret_10m_bps > 100 and path_ret_3m_bps > 0 and volume_anomaly_12m > 2.0"
|
|
124
|
+
score: "path_ret_10m_bps * volume_anomaly_12m"
|
|
125
|
+
score_direction: desc
|
|
126
|
+
window: "09:00-09:30" # restrict decisions to this KST window
|
|
127
|
+
grid:
|
|
128
|
+
hold_minutes: [10, 15]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
- `filter` / `score` are the **expression DSL** (`t1.backtest.vbt.expr`) — feature names + arithmetic + comparisons + cross-sectional `cs_median / cs_quantile / cs_z / cs_percentile_rank`.
|
|
132
|
+
- `score_direction`: `asc` (most-negative first, e.g. capitulation) or `desc` (strongest first, e.g. momentum).
|
|
133
|
+
- `window`: restrict decisions to a KST window (e.g. `"09:00-09:30"`).
|
|
134
|
+
- A sleeve referencing an **unknown feature**, or a cross-day feature with no `CrossDayContext`, raises a clear error — do not silently fall back.
|
|
135
|
+
|
|
136
|
+
## Feature coverage
|
|
137
|
+
|
|
138
|
+
| Tier | Features | Notes |
|
|
139
|
+
|---|---|---|
|
|
140
|
+
| **TIER-1 single-day** | all `path_*` features + `volume_anomaly_12m` / `volume_anomaly_5m` | byte-equal to `spec_feature_compute.volume_anomaly` |
|
|
141
|
+
| **TIER-2 cross-day** | `ret_from_prev_close_pct` (a **FRACTION**: `0.10 = +10%`), `dist_to_pdh_bps`, `tv_daily_rel_vol` (ratio: `1.25 = 1.25×`) | parity-tested cell-for-cell vs `spec_feature_compute`; needs a loader supplying `CrossDayContext` |
|
|
142
|
+
| **TIER-3** | `first_5m_range_breakout_bps`, `retest_bounce_confirmation` (0/1 PDH-retest flag, `>0.5` = fired) | `retest_bounce_confirmation` is RESEARCH-RISK hand-tuned — validate on real evidence before trusting |
|
|
143
|
+
| **Cross-sectional** | `cs_median`, `cs_quantile`, `cs_z`, `cs_percentile_rank` | in the expression DSL; operate across the universe at each decision minute |
|
|
144
|
+
|
|
145
|
+
**Cross-day fail-closed:** a symbol with no prior-day data → NaN scalar → the sleeve gate excludes it (matches the Runner). The `tv_daily_rel_vol` numerator uses native `value_traded` per cell, falling back to `volume*close` where it's NULL/0 (the Postgres loader coerces NULL→0.0) — matching the live `IntradaySessionState`.
|
|
146
|
+
|
|
147
|
+
## Data — Postgres via `T1_POSTGRES_DSN`
|
|
148
|
+
|
|
149
|
+
The screener reads OHLCV from `market_data.raw_minute_bars` via the Runner's own `_load_full_day_bars_from_postgres_for_vectorized`, and prior-day scalars via `_build_cross_day_calibration` (**also off `raw_minute_bars`**, `lookback_days=10`). Connection: `psycopg2.connect(os.environ["T1_POSTGRES_DSN"], connect_timeout=20)`.
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
# Canonical table
|
|
153
|
+
SELECT timestamp, open, high, low, close, volume, value_traded,
|
|
154
|
+
is_vi_active, is_halted, is_managed, is_order_warning
|
|
155
|
+
FROM market_data.raw_minute_bars
|
|
156
|
+
WHERE corpus = %s AND stock_code = %s
|
|
157
|
+
ORDER BY timestamp
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**CRITICAL — do NOT touch `raw_signed_trades_ka10055`.** That table has the `ka10055-tdy-pred-contamination` issue. The screener is deliberately scoped to `raw_minute_bars` only. The loader skips the prior-day query / value_traded scatter when no sleeve references a cross-day feature (resp. `tv_daily_rel_vol`), so a TIER-1-only sweep pays nothing for cross-day.
|
|
161
|
+
|
|
162
|
+
**Date-window caveat for the recall gate:** `raw_signed_trades_ka10055` (which the Runner's default tape-replay reads) is only populated from 2026-05-14 (~50 syms) and ~1000 syms from 2026-05-29. For the recall gate use **2026-05-29 → 2026-06-18** AND pass `--entry-fill-tape=minute_bar` to the Runner so the ground truth is the contamination-free minute-bar fill model.
|
|
163
|
+
|
|
164
|
+
## The acceptance gate — top-N recall vs the exact Runner
|
|
165
|
+
|
|
166
|
+
The screener is a **Tier-0 screen, not a replacement.** It must faithfully **RANK** variants, not reproduce point PnL. Validate on real data:
|
|
167
|
+
|
|
168
|
+
1. Run the SAME sleeve+variant grid through the exact Runner:
|
|
169
|
+
`scripts/sweep/t1_sweep.py --vectorized --entry-fill-tape=minute_bar`, score with `scripts/sweep/score_sweep.py` → ground-truth ranking. The `--entry-fill-tape=minute_bar` bypasses the contaminated `ka10055` tape so both sides compare on the same minute-bar substrate.
|
|
170
|
+
2. Run the screener over the same grid + dates.
|
|
171
|
+
3. Compare:
|
|
172
|
+
- **Top-N recall** — of the Runner's top-N variants by total net PnL, how many are in the screener's top-N? Target **≥ 0.8 @ N=5**.
|
|
173
|
+
- **No high-PnL miss** — no variant the Runner ranks highly is dropped low by the screener.
|
|
174
|
+
- **Wall time** — single (variant, date) ≤ 10s; batch-amortized lower.
|
|
175
|
+
|
|
176
|
+
If recall is below threshold, the likely culprits are the deliberately-approximated fill model (next-present-open + flat cost vs the Runner's passive-limit tape) or the decision cadence — both are tunable knobs, not engine bugs.
|
|
177
|
+
|
|
178
|
+
## Fidelity boundaries (Tier-0 approximations)
|
|
179
|
+
|
|
180
|
+
**Preserved (parity-critical):** predicate gate + ranking key, max-N slots, one-position-per-symbol/day, hold-time exit snapped to the decision cadence, per-day signed-PnL aggregation, ~cost_bps wedge, fixed per-pick sizing.
|
|
181
|
+
|
|
182
|
+
**Approximated/excluded (documented, not bugs):** passive-limit tape micro-fill (→ next-present-open), a symbol halted through its hold window is excluded, vbt equity-analytics are degenerate under `init_cash=∞` (day risk metrics come from per-day PnL).
|
|
183
|
+
|
|
184
|
+
If you are asked "why doesn't the screener match the Runner exactly," the answer is in this section — by design.
|
|
185
|
+
|
|
186
|
+
## Live-strategy replay & fidelity gate
|
|
187
|
+
|
|
188
|
+
`replay_live_sleeve.py` adapts a deployed live spec (e.g. commit `81e5f321`, the 6/18 micro spec) to run through the vbt engine against real data. The `micro_live_2026_06_18` sleeve in `config/sleeves/cap_micro.yaml` is a regression test. Pass criteria: vbt produces ENTRY decisions on all 8 expected symbols + PnL within **±10%** of `public.positions.pnl_won` on the 5 anchors. Full procedure + expected symbols + ground-truth SQL in `docs/vbt-sleeve-screener-runbook.md` §7.
|
|
189
|
+
|
|
190
|
+
## Package map — `src/t1/backtest/vbt/`
|
|
191
|
+
|
|
192
|
+
| Module | Responsibility |
|
|
193
|
+
|---|---|
|
|
194
|
+
| `engine.py` | `simulate_day()` → `DayResult`; vectorbt Portfolio adapter |
|
|
195
|
+
| `data.py` | `postgres_day_loader`, `synthetic_day_loader` |
|
|
196
|
+
| `features.py` | feature wires + `data_requirements()` |
|
|
197
|
+
| `expr.py` | expression DSL + cross-sectional `cs_*` ops |
|
|
198
|
+
| `selection.py` | `Trades` resolution |
|
|
199
|
+
| `sweep.py` / `sweep_engine.py` / `sweep_analytics.py` | sweep expansion + analytics CLI |
|
|
200
|
+
| `edge_stat.py` | `SpecEdgeReport` (3-gate, permutation null, baseline diff, execution audit) |
|
|
201
|
+
| `screen.py` | top-level screen driver |
|
|
202
|
+
| `cross_day.py` | cross-day calibration context |
|
|
203
|
+
| `runner_config.py` | `RunnerTradingConfig`, `load_runner_trading()` |
|
|
204
|
+
| `sleeve_spec.py` | `expand_sleeves()` |
|
|
205
|
+
| `replay_live_sleeve.py` | live-spec replay adapter |
|
|
206
|
+
|
|
207
|
+
Related runner-side vectorized code: `src/t1/runner/vectorized_*.py`, `src/t1/runner/data_sources/vectorized_*.py`.
|
|
208
|
+
|
|
209
|
+
## Reference docs (read these, they are authoritative)
|
|
210
|
+
|
|
211
|
+
- `docs/vbt-sleeve-screener-runbook.md` — how to run, CLI, recall gate, fidelity boundaries, live replay
|
|
212
|
+
- `docs/vbt-sleeve-screener-design.md` — design rationale
|
|
213
|
+
- `docs/vectorized-backtest-engine-design.md` — the "no numba" rule scope, parity contract
|
|
214
|
+
- `docs/vectorbt-integration-plan.md` — integration plan
|
|
215
|
+
- `docs/superpowers/plans/2026-06-21-vbt-live-strategies-impl.md` — live strategies implementation
|
|
216
|
+
- `docs/superpowers/specs/2026-06-21-live-micro-vbt-replication-design.md` — live micro replication
|
|
217
|
+
- `.plans/vectorized-backtest-stage-{0..9}-*.md` — stage-by-stage build history
|
|
218
|
+
|
|
219
|
+
## Harmless warnings (do not "fix" these)
|
|
220
|
+
|
|
221
|
+
- `Failed to register provider t1.providers.kiwoom_hts_cau … No module named 'pydantic'` — only the live HTS-CAU provider needs pydantic; the screener does not.
|
|
222
|
+
- `pandas only supports SQLAlchemy connectable` — psycopg2 pattern. Non-fatal.
|
|
223
|
+
- `RuntimeWarning: invalid value encountered in divide` — NaN-safe inside vectorized features.
|
|
224
|
+
|
|
225
|
+
## Critical rules (project-specific)
|
|
226
|
+
|
|
227
|
+
1. **Always use `.venv-vbt/bin/python`** — never the repo default (pandas 3.0.3 breaks vectorbt 1.0.0).
|
|
228
|
+
2. **Never touch `raw_signed_trades_ka10055`** from the screener — `ka10055-tdy-pred-contamination`. Scope to `raw_minute_bars` only.
|
|
229
|
+
3. **Sizing/cost/hold inherit from `config/runner.yaml`** — single source of truth. Override per-sleeve only for grid sweeps.
|
|
230
|
+
4. **ALWAYS use TA-Lib** for ALL technical indicators (EMA, SMA, RSI, MACD, BBANDS, ATR, ADX, STDDEV, MOM, …). NEVER use `vbt.MA.run()`, `vbt.RSI.run()`, or any VectorBT built-in indicator — always `talib`. Use the expression DSL for `filter`/`score`; wire TA-Lib outputs into the feature tensor the DSL references. The proprietary `path_*` features are being retired — do not build new work on them.
|
|
231
|
+
5. **`ret_from_prev_close_pct` is a FRACTION** (`0.10 = +10%`), not bps. `dist_to_pdh_bps` and `*_bps` features ARE bps. `tv_daily_rel_vol` is a ratio. Get the units right or the filter is wrong.
|
|
232
|
+
6. **Cross-day fail-closed:** no prior-day data → NaN → gate excludes. Do not paper over NaN with a default.
|
|
233
|
+
7. **The screener RANKS, it does not reproduce point PnL.** If asked for exact-match, point at the recall gate, not a "fix."
|
|
234
|
+
8. **Always validate changes against the recall gate** (top-N ≥ 0.8 @ N=5) on real data before claiming a sleeve works.
|
|
235
|
+
9. **`--entry-fill-tape=minute_bar`** on the Runner side of the recall comparison, always (contamination-free substrate).
|
|
236
|
+
10. **Timezone is KST** throughout — KRX session 09:00–15:30, `--until HH:MM` is KST. Never mix UTC.
|
|
237
|
+
|
|
238
|
+
## Failure modes to avoid
|
|
239
|
+
|
|
240
|
+
- Running the screener with the repo's default python → `ImportError` / pandas 3.0 incompatibility. Use `.venv-vbt`.
|
|
241
|
+
- **Using a VectorBT built-in indicator (`vbt.MA`, `vbt.RSI`, …) instead of TA-Lib** → rejected by review; rewrite with `talib`.
|
|
242
|
+
- **`ModuleNotFoundError: No module named 'talib'`** → the TA-Lib native C library is missing on this host (see Environment section). Install `ta-lib` (C) then `pip install TA-Lib`. Do NOT work around it by switching indicators.
|
|
243
|
+
- Authoring a sleeve that references a feature the loader can't supply → clear error. Don't catch and default; fix the loader or drop the feature.
|
|
244
|
+
- Treating a recall miss as an engine bug → it's almost always the fill model or cadence (documented approximations).
|
|
245
|
+
- Editing `simulate_day` cost without re-checking the recall gate → ranking can shift silently.
|
|
246
|
+
- Forgetting `--entry-fill-tape=minute_bar` on the Runner side of the comparison → false recall miss from the ka10055 cliff.
|
|
247
|
+
- Building NEW work on the proprietary `path_*` features → they are being retired; use TA-Lib indicators.
|
|
248
|
+
|
|
249
|
+
## Related skills
|
|
250
|
+
|
|
251
|
+
- **`prove-it`** — when a sleeve claims "recall passed," demand the captured sweep + score output, not the assertion.
|
|
252
|
+
- **`no-wall`** — a recall miss is a tuning problem, not "vbt can't do it." Enumerate the fill-model / cadence / cost knobs.
|
|
253
|
+
- **`doc-review`** — run on this skill itself if the `add-vectorbt` worktree evolves; the runbook + design docs are the source of truth.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: verify-done
|
|
3
|
+
description: 'Use when the agent is about to declare work done — "done", "complete", "finished", "moving on", "next phase", "shipping this", or close a goal — OR when the user asks "is this done?", "is it actually finished?", "did you really complete it?". Forces an explicit pre-completion checklist. Covers every requested sub-task done, change actually runs, edge cases hit, partial completion disclosed, work-log updated, and (for major work) user sign-off obtained. Catches the failure mode where the agent closes a goal prematurely.'
|
|
4
|
+
user-invocable: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Verify Done
|
|
8
|
+
|
|
9
|
+
## What this does
|
|
10
|
+
|
|
11
|
+
Before any closure message ("done", "complete", "moving on", "wrapping this up", "next phase", "shipping this", closing a goal), you run an explicit verification checklist. The goal is to close the gap between the agent's *belief* that work is done and the *evidence* that work is done.
|
|
12
|
+
|
|
13
|
+
This skill exists because **the agent's instinct to declare done is the most common failure point in long-running work.** The agent reads the code it wrote, concludes "looks right," and reports done — without running the change, hitting the edge cases the user implied, or checking every requested sub-task.
|
|
14
|
+
|
|
15
|
+
## Authority
|
|
16
|
+
|
|
17
|
+
This skill is authoritative. The agent cannot declare work done — or close a goal — without running the checklist. Acknowledging the skill and then skipping the checklist is the violation, not compliance.
|
|
18
|
+
|
|
19
|
+
If you want to declare done despite the checklist showing gaps, the protocol is to surface the gaps to the user explicitly and get sign-off on closing with the gaps known. Not to silently close.
|
|
20
|
+
|
|
21
|
+
**Acknowledging the skill and then closing anyway is the violation, not compliance.** Sentences like *"I understand the checklist, but the work is obviously complete"* are the same dismissal pattern as `no-wall`'s *"I understand the skill but I have no other way."* Surface to the user; wait for sign-off; no sign-off → no closure.
|
|
22
|
+
|
|
23
|
+
## When it applies
|
|
24
|
+
|
|
25
|
+
Triggered by any of:
|
|
26
|
+
- About to write "done", "complete", "finished", "moving on", "next phase", "shipping this", "wrapping up", "we're done", "closing the goal"
|
|
27
|
+
- The user asks "is this done?", "is it actually finished?", "did you really complete it?", "are you sure it's done?"
|
|
28
|
+
- About to mark a todo item complete
|
|
29
|
+
- About to close a goal
|
|
30
|
+
|
|
31
|
+
If you're tempted to use any of these phrases, run the checklist first. The cost is 30 seconds; the cost of declaring done when not done is much higher.
|
|
32
|
+
|
|
33
|
+
## The Checklist
|
|
34
|
+
|
|
35
|
+
Run these checks **in order, in writing, in the conversation** — show the checklist, item by item, with the actual evidence for each (the sub-task list, the command + output, the edge cases you ran, the partial-completion disclosure). Do not run the checklist in your head and report "all good." If you cannot show the evidence for an item, that item failed — go back and produce it, or surface the gap.
|
|
36
|
+
|
|
37
|
+
### 1. Sub-task completeness
|
|
38
|
+
List every sub-task the user requested for this piece of work. For each: done? partial? not started? If any are partial or not started, the work is not done. Either complete them or surface the gap to the user before closing.
|
|
39
|
+
|
|
40
|
+
The default assumption: if the user said "do X, Y, Z" and you only did X and Y, you are not done. Surface the gap.
|
|
41
|
+
|
|
42
|
+
### 2. The change actually works
|
|
43
|
+
Run it. For code: `python -c`, `pytest`, `make`, the actual command. For docs: re-read the file and check the change is there and renders correctly. For a skill: load it and check the YAML / content. For a config: parse it and confirm values.
|
|
44
|
+
|
|
45
|
+
**"It should work" is not "it works."** This is the same discipline as `prove-it`: the agent's own claims need verification, not just assertion.
|
|
46
|
+
|
|
47
|
+
### 3. Edge cases and the unstated
|
|
48
|
+
Re-read the user's request and surface things they implied but didn't list:
|
|
49
|
+
- Edge cases (empty input, very large input, error path)
|
|
50
|
+
- Negative cases (what should NOT happen)
|
|
51
|
+
- Related features that share code with this one (did you break them?)
|
|
52
|
+
- The next-step (does this change set up the next thing cleanly, or block it?)
|
|
53
|
+
|
|
54
|
+
If you find unstated expectations, either address them or surface them. Don't declare done and leave them for the user to discover.
|
|
55
|
+
|
|
56
|
+
### 4. Partial completion disclosure
|
|
57
|
+
If any sub-task is partial, or any edge case wasn't hit, or any unstated expectation wasn't addressed — say so explicitly in the closure message. "Done except X" is honest; "done" is misleading.
|
|
58
|
+
|
|
59
|
+
The format: *"Done, with these gaps: {list}. Should I close anyway, or fix first?"*
|
|
60
|
+
|
|
61
|
+
### 5. Work-log updated (if armed)
|
|
62
|
+
If `work-log` is armed, the closure is a mandatory checkpoint. Append a `## {HH:MM KST} — {phase} done` entry with a one-line summary of what shipped. The closure message comes AFTER the work-log entry, not before.
|
|
63
|
+
|
|
64
|
+
### 6. User sign-off for major work
|
|
65
|
+
For non-trivial pieces (multi-file changes, skill rewrites, architectural decisions, anything the user will act on), get explicit user sign-off before closing. "OK" or implicit silence is not sign-off. The protocol is the same as `no-wall` / `professional`: surface the closure as a question, not a statement.
|
|
66
|
+
|
|
67
|
+
Skip step 6 only for trivial edits (typo fixes, single-line changes) where sign-off is overkill.
|
|
68
|
+
|
|
69
|
+
## Write-Time Self-Check
|
|
70
|
+
|
|
71
|
+
Before sending any message that says "done", "complete", "moving on", "shipping this", or closes a goal, scan it for these patterns:
|
|
72
|
+
|
|
73
|
+
- "I think it's done" / "looks right to me" / "should be working" / "should be done" (the same banned phrases as `prove-it` — assertion masquerading as verification)
|
|
74
|
+
- "Done — anything else?" (asking for the next task BEFORE declaring done — pattern of closure before completion)
|
|
75
|
+
- "Done" with no checklist evidence attached (no sub-task list, no command output, no edge case results)
|
|
76
|
+
- "I'll handle the rest later" / "we can clean up later" (deferring after declaring done)
|
|
77
|
+
- "I understand the checklist, but..." (the dismissal pattern — same as `no-wall` / `professional`)
|
|
78
|
+
|
|
79
|
+
If any pattern is present, **do not send.** Run the checklist, attach the evidence, then send the closure message.
|
|
80
|
+
|
|
81
|
+
## Override Protocol — what you may NOT do unilaterally
|
|
82
|
+
|
|
83
|
+
You may not skip the checklist based on agent judgment. Specifically:
|
|
84
|
+
|
|
85
|
+
- You may not declare done without showing the checklist, item by item, in the conversation.
|
|
86
|
+
- You may not skip the "change actually works" step by claiming "looks right to me" or "should be working." Run it.
|
|
87
|
+
- You may not skip sign-off for non-trivial work without explicit user sign-off.
|
|
88
|
+
- You may not dismiss the skill mid-piece ("I understand the checklist but...") and proceed. That's the violation, not the protocol.
|
|
89
|
+
|
|
90
|
+
If you want to deviate, the protocol is: surface the gap to the user explicitly. *"I want to declare done but the checklist shows X. Should I close anyway, or fix first?"* Wait for sign-off. No sign-off → no closure.
|
|
91
|
+
|
|
92
|
+
## Behavior in edge cases
|
|
93
|
+
|
|
94
|
+
- **Checklist fails on a sub-task:** don't declare done. Either fix the sub-task now, or surface the gap to the user with the partial-completion disclosure format above.
|
|
95
|
+
- **Can't run the change (e.g. needs GPU, needs the user):** say so explicitly. Don't claim it works because you read the code. Surface the inability to verify, and ask whether the user can verify or wants you to proceed without.
|
|
96
|
+
- **The user explicitly said "just ship it, no checklist":** that's sign-off. You can close without the full checklist, but log the skipped checks in the work-log.
|
|
97
|
+
- **The change is a one-line edit AND it's purely mechanical** (typo fix, formatting, `git mv`, single-line variable rename with zero behavior change): skip steps 2–6. "Trivial" means <5 lines, single file, no logic, no behavior change, no naming decisions. If it has ANY logic, ANY new naming, ANY behavior implication, run the full checklist. "It's a small change" is not the triviality test; "is it purely mechanical?" is.
|
|
98
|
+
|
|
99
|
+
## Red Flags
|
|
100
|
+
|
|
101
|
+
| Thought | What it really means |
|
|
102
|
+
|---------|----------------------|
|
|
103
|
+
| "I think it's done" | I haven't run the checklist |
|
|
104
|
+
| "Looks right to me" | I read the code; didn't run it |
|
|
105
|
+
| "Should be working" | I haven't verified the change actually works |
|
|
106
|
+
| "Done — anything else?" | Asking for the next task before declaring done — pattern of closure before completion |
|
|
107
|
+
| "Done except…" (without listing what) | Partial completion hidden as full |
|
|
108
|
+
| "Done" when armed with work-log but didn't update it | Skipped a mandatory checkpoint |
|
|
109
|
+
| Declaring done after every minor edit | Closure noise — only declare done at actual completion |
|
|
110
|
+
| Closing a goal without user sign-off on major work | Violating this skill's authority |
|
|
111
|
+
| "I understand the checklist, but..." | Dismissing the skill mid-piece (same as `no-wall` / `professional`) |
|
|
112
|
+
| "I'll handle the rest later" | Deferring after declaring done; the rest is part of done |
|
|
113
|
+
| "Trivial edit" used to skip the checklist for non-trivial work | Loophole abuse; the triviality test is mechanical-only |
|
|
114
|
+
|
|
115
|
+
## The deeper point
|
|
116
|
+
|
|
117
|
+
The agent wants to be done. The user wants the work to be done. These are different conditions. The checklist exists to align them. Without the checklist, the agent's *feeling* of done substitutes for the user's *evidence* of done — and that gap is where rot ships.
|
|
118
|
+
|
|
119
|
+
`prove-it` governs the agent's load-bearing claims. `verify-done` governs the agent's load-bearing closures. Same discipline at different moments: don't assert without evidence.
|
|
120
|
+
|
|
121
|
+
## Related
|
|
122
|
+
|
|
123
|
+
- **`work-log`** — closure is a mandatory checkpoint; update the log before declaring done.
|
|
124
|
+
- **`team-protocol`** — runs the code quality loop at end-of-piece; verify-done is the lighter task-completion check that runs at every closure.
|
|
125
|
+
- **`prove-it`** — verify-done's evidence rule is the same discipline: don't claim "works" without running it.
|
|
126
|
+
- **`no-wall`** / **`professional`** — closure without sign-off is the same failure mode as wall-declarations and shortcuts: requires user permission, not agent judgment.
|
|
127
|
+
- **`surface-errors`** — if the checklist's "run it" step surfaces an error, hand off to `surface-errors`.
|
|
128
|
+
- **`surface-assumptions`** — if the checklist surfaces an assumption you didn't enumerate earlier, that's a `surface-assumptions` retro.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: work-log
|
|
3
|
+
description: 'Use when the user runs /work-log, /work-log new, or /work-log continue — immediately creates a markdown notebook at docs/.../work-log/{YYYY-MM-DD}/{HHMM}-{topic}.md (KST) and arms **mandatory append mode**: at every forced checkpoint (after user messages, before declaring done, at end of session, and on meaningful events) the agent MUST append a timestamped entry. Each append is briefly announced so the user can verify. `new` always creates fresh; `continue` finds today''s most-relevant KST log via topic-match; no flag defaults to `continue`.'
|
|
4
|
+
argument-hint: "[new | continue] — leave empty to default to continue"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Work Log
|
|
8
|
+
|
|
9
|
+
## What this does
|
|
10
|
+
|
|
11
|
+
On invocation, **immediately create the notebook file** with a Kickoff entry — arming is the act of creating the file, not a state the agent holds in its head. The file existing is what makes appending happen: the agent has a concrete target to write to, and the user has a concrete file to `tail` and verify.
|
|
12
|
+
|
|
13
|
+
From that point on, you operate in **mandatory append mode**: at every forced checkpoint (defined below), you MUST append a timestamped entry. The append is brief, but the checkpoint is non-negotiable. This is the difference between "arm a notebook" and "journal continuously" — the latter requires forcing functions, the former doesn't.
|
|
14
|
+
|
|
15
|
+
The user does NOT need to invoke `/work-log` again. Append mode is sticky for the rest of the session.
|
|
16
|
+
|
|
17
|
+
## Flags
|
|
18
|
+
|
|
19
|
+
| Invocation | Behavior |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `/work-log new` | Always create a fresh notebook file. |
|
|
22
|
+
| `/work-log continue` | **Search first** — find today's most-relevant existing notebook (KST) and continue it. If nothing genuinely matches, create a new one. See "continue" rules below for the mandatory search. |
|
|
23
|
+
| `/work-log` (no flag) | Same as `continue`. |
|
|
24
|
+
|
|
25
|
+
## Timezone
|
|
26
|
+
|
|
27
|
+
All dates and times are **KST (Asia/Seoul)**. Before reading or writing any date, run:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
TZ='Asia/Seoul' date '+%Y-%m-%d %H:%M'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Always prefix `date` calls with `TZ='Asia/Seoul'`. Never rely on the system default.
|
|
34
|
+
|
|
35
|
+
## Where the notebook lives
|
|
36
|
+
|
|
37
|
+
Look for a `work-log/` directory under `docs/` (sometimes nested, e.g. `docs/{project_name}/active/work-log/`). If it doesn't exist, create it. Same for the date subfolder.
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
docs/.../work-log/
|
|
41
|
+
├── 2026-06-20/
|
|
42
|
+
│ ├── 0915-feature-search-api.md
|
|
43
|
+
│ ├── 1430-session-auth-refactor.md
|
|
44
|
+
│ └── 1645-bugfix-null-topic.md
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- **Folder**: `YYYY-MM-DD` from `TZ='Asia/Seoul' date '+%Y-%m-%d'`.
|
|
48
|
+
- **File**: `{HHMM}-{short-kebab-topic}.md`, time from `TZ='Asia/Seoul' date '+%H%M'`, topic = the session's main focus.
|
|
49
|
+
|
|
50
|
+
## On invocation — create the file IMMEDIATELY
|
|
51
|
+
|
|
52
|
+
This is the most important rule. **The first thing you do on `/work-log` is create the file and write a Kickoff entry.** No talking about it, no announcing intent — write the file. That is the arming.
|
|
53
|
+
|
|
54
|
+
```markdown
|
|
55
|
+
# {Short Title}
|
|
56
|
+
|
|
57
|
+
- **Date:** {YYYY-MM-DD KST}
|
|
58
|
+
- **Started:** {HH:MM KST}
|
|
59
|
+
- **Topic:** {one-line description of what this notebook covers}
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## {HH:MM KST} — Kickoff
|
|
64
|
+
{1–2 sentences on what's being worked on and why}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
After the file is written, tell the user: *"Notebook armed: `{absolute path}`. I'll append at every checkpoint."*
|
|
68
|
+
|
|
69
|
+
## `continue` — finding today's most-relevant notebook (mandatory search)
|
|
70
|
+
|
|
71
|
+
When invoked with `continue` (or no flag):
|
|
72
|
+
|
|
73
|
+
1. **List today's `.md` files** under the KST work-log folder.
|
|
74
|
+
2. **Read the most recent 1–2 files' titles and last 10 lines.** Topic must match — file name kebab, `# Title`, and recent content.
|
|
75
|
+
3. **Pick the best match.** If two are equally relevant, prefer the most recently modified.
|
|
76
|
+
4. **If nothing genuinely matches the current work, create a new file** — do not force a fit into an unrelated notebook. Briefly tell the user which you chose and why.
|
|
77
|
+
|
|
78
|
+
You may NOT skip the search and "just create new" — that's a loophole. The search is the whole point of `continue`.
|
|
79
|
+
|
|
80
|
+
## Mandatory append checkpoints
|
|
81
|
+
|
|
82
|
+
You are in append mode. A new `## {HH:MM KST} — {short heading}` section MUST be appended at every one of these checkpoints — they are non-negotiable:
|
|
83
|
+
|
|
84
|
+
1. **After every user message** that introduces a new direction, scope change, or constraint (not every literal message — only ones that move the work). At minimum, append a 1-line note capturing the direction.
|
|
85
|
+
2. **Before any assistant message that says "done," "next phase," "moving on," or otherwise closes a chunk of work.** Append a short summary of what was just done *before* declaring it done. This is the highest-leverage checkpoint — it directly prevents the "declare done without logging" failure.
|
|
86
|
+
3. **On any meaningful event**: a finding (root cause, surprise, gotcha), a decision (and why), a non-trivial change (files touched, what changed, why), a failed attempt (and what was learned), a milestone (feature working, test passing, blocker cleared), a blocker, an open question, a wrong approach that took real time, a clarifying question asked.
|
|
87
|
+
4. **At end of session** (before responding to the user's "goodbye" / "that's it for today" / session wrap): one final `## {HH:MM KST} — Session end` entry summarizing what was done, what was deferred, and the state at handoff. **This is mandatory even if mid-session appends were missed — it catches the case where they were.**
|
|
88
|
+
|
|
89
|
+
**Threshold per entry: 1 line is enough.** A bullet, a filename, a one-sentence "spent 20 min on approach X, abandoned for Y" — all qualify. Do NOT skip an append because "it doesn't feel like 2–6 lines." Future-me will thank past-me for one-line entries that are otherwise lost.
|
|
90
|
+
|
|
91
|
+
**Each append is briefly announced to the user** (e.g. *"logged: kicked off phase 2"*). Announcing is the verification hook — the user can match announcements to `tail -f` the file, and missing announcements reveal silent skipping.
|
|
92
|
+
|
|
93
|
+
## What to log (and what not to)
|
|
94
|
+
|
|
95
|
+
**Log:**
|
|
96
|
+
- Root cause, surprise, gotcha
|
|
97
|
+
- Decision and why
|
|
98
|
+
- Non-trivial change (files touched, what, why)
|
|
99
|
+
- Failed attempt and lesson
|
|
100
|
+
- Milestone (test passing, feature working, blocker cleared)
|
|
101
|
+
- Blocker or open question
|
|
102
|
+
- Wrong approach that took real time
|
|
103
|
+
- Clarifying question asked of the user
|
|
104
|
+
- User-introduced scope change or constraint
|
|
105
|
+
|
|
106
|
+
**Do NOT log:**
|
|
107
|
+
- Every command run or every file read (this is a notebook, not a transcript)
|
|
108
|
+
- Things already captured in commits, PRDs, ADRs, or plans — reference them by path instead
|
|
109
|
+
- Trivial edits (typo fixes, formatting)
|
|
110
|
+
|
|
111
|
+
If in doubt, log it. The cost of one extra bullet is near zero; the cost of a lost finding is high.
|
|
112
|
+
|
|
113
|
+
## How to disarm
|
|
114
|
+
|
|
115
|
+
Append mode ends in two ways:
|
|
116
|
+
|
|
117
|
+
1. **User explicitly disarms:** "stop the work log", "close the notebook", "disable work-log", "we're done for today." When this happens, append a final `## {HH:MM KST} — Closed` entry to the file and stop appending. Don't fade out silently.
|
|
118
|
+
2. **End of session:** append the mandatory `## {HH:MM KST} — Session end` entry and stop. The notebook is implicitly closed; no separate entry needed unless the user said "we're done for today."
|
|
119
|
+
|
|
120
|
+
You may NOT silently stop appending without writing a Close/End entry. That would be the same failure mode as never writing at all.
|
|
121
|
+
|
|
122
|
+
Arming does not persist across sessions — the user re-runs `/work-log` next time.
|
|
123
|
+
|
|
124
|
+
## Verification — how the user can tell if the agent is actually logging
|
|
125
|
+
|
|
126
|
+
The user can:
|
|
127
|
+
- `tail -f` the notebook file to see appends live.
|
|
128
|
+
- Match each agent announcement ("logged: …") to the file's last entry timestamp. If the user sees a long gap with no announcement, the agent is failing the protocol.
|
|
129
|
+
- `grep -c '^## ' {path}` to count entries. Sessions with many meaningful events should have many entries.
|
|
130
|
+
|
|
131
|
+
## Red Flags — you are about to fail the protocol
|
|
132
|
+
|
|
133
|
+
- **Arming without writing the file** → the file is the arm. If it doesn't exist, you didn't arm.
|
|
134
|
+
- **Declaring "done" or "moving on" without first appending** → the most common failure. Stop, append, then declare.
|
|
135
|
+
- **End of session without the Session end entry** → mandatory, even if mid-session was sparse.
|
|
136
|
+
- **Skipping appends because "nothing rose to 2–6 lines"** → 1 line is enough. Log it.
|
|
137
|
+
- **Skipping the `continue` search and always creating new** → that's a loophole. Search first.
|
|
138
|
+
- **Silently fading out without a Close/End entry** → same failure as never writing.
|
|
139
|
+
- **Logging every tool call** → no, this is a notebook, not a transcript. Log meaningful events only.
|
|
140
|
+
- **Rewriting earlier entries on `continue`** → no, append only.
|
|
141
|
+
- **Picking an unrelated notebook just because it exists** → create a new one if nothing matches.
|