---
name: project-step1390-4a-pc-side-drift-v01-2026-08-23
description: STEP 1369 Phase 10 - 4A 校正機械 PC-side v0.1 spike (drift-detector) = golden baseline + LLM 応答 consistency + benchmark regression alert
metadata: 
  node_type: memory
  type: project
  originSessionId: 3acd3853-c124-47b1-974e-9d8c55c72877
  modified: 2026-08-23T01:48:29.751Z
---

# STEP 1390 — 4A PC-side v0.1 spike (STEP 1369 Phase 10, 2026-08-23)

## 契機
- STEP 1389 close report で 次候補 (1) 4A software drift v0.1 提示
- 藤本さん directive: 「1. 4A software drift v0.1 (LLM 応答 consistency + benchmark regression alert) でお願い致します」

## 実装 - scripts/drift-detector/

### drift.py

**3 mode**:
- **text**: hash equality (sha256[:12]) + Levenshtein edit distance (Wagner-Fischer stdlib)
- **hash_only**: strict hash equality only (no Levenshtein tolerance)
- **numeric**: percent delta (baseline vs actual)

**4 verdict + exit code**:
- **MATCH** (exit 0): within all tolerances / text hash equal / numeric |diff%| < tolerance/2
- **DRIFT_MINOR** (exit 1): within loose tolerance / text Levenshtein <= tolerance / numeric <= tolerance
- **DRIFT_MAJOR** (exit 2): exceeds tolerance / text hash mismatch + Levenshtein > tolerance / numeric > tolerance
- **MISSING_BASELINE** (exit 3): baseline_id 見つからない

**5 CLI subcommand**:
- `baseline set <id> --input ... --expected ... --mode {text|hash_only|numeric} --reason "..." [--metric-value N --metric-unit U --metric-name X] [--group Y]`
- `baseline list [--group X]`
- `baseline retire <id> --reason "..."`
- `check <id> --actual TEXT | --actual-value N [--tolerance-levenshtein N] [--tolerance-percent N] [--json]`
- `history <id>`
- `report [--since ISO] [--verdict V]`

**Storage** (both append-only):
- `data/drift-detector/baselines.jsonl`: baselines + retire (soft-delete via `active=false`)
- `data/drift-detector/checks.jsonl`: 全 check 結果 (drift trend 分析用)

**Reason 必須** (>= 10 chars) for baseline set + retire (5A oughtctl / 5B frames と 同 discipline)

### test_drift.py (51/51 PASS)

- **Library primitives (5)**: sha256_short (deterministic + distinct) + Levenshtein (identical/empty/kitten-sitting classic 3/hi-there-hello 7)
- **_check_text (4)**: exact match / minor within tolerance / major exceeds / strict hash_only mode
- **_check_numeric (6)**: exact / within tolerance MINOR / close to zero diff MATCH / exceeds / negative direction symmetric / zero baseline
- **CLI baseline (7)**: set text + set numeric + reason required + expected required for text + metric-value required for numeric + list shows active + retire soft-delete
- **CLI check (6)**: text match exit 0 + text major exit 2 + numeric within exit 0 + numeric exceeds exit 2 + missing baseline exit 3 + records to checks ledger
- **CLI history + report + append-only (3)**

1 debug fix: Levenshtein 「Hi there!」 vs 「Hello!」 の 手計算誤り (私が 6 と assert したが 実際は 7 edit、 algorithm 正しく test 修正)

### Live demo verified
```
$ drift baseline set inference-lat --metric-value 142.0 --metric-name inference_ms \
    --metric-unit ms --mode numeric --reason "..."
baseline set: inference-lat (mode=numeric, group=default, id=e8ee4697)

$ drift check inference-lat --actual-value 148.5 --tolerance-percent 10
{"verdict": "match", "info": {"expected": 142.0, "actual": 148.5,
 "percent_diff": 4.58, "tolerance_percent": 10.0}}
exit=0

$ drift check inference-lat --actual-value 200 --tolerance-percent 10
{"verdict": "drift_major", "info": {"percent_diff": 40.85, "tolerance_percent": 10.0}}
exit=2
```

## 4A hardware vs PC-side mapping

| Aspect | Hardware side (4A、 未取得) | PC-side (STEP 1390) |
|--------|-----------|---------|
| Reference | 電圧標準 (Fluke 5720A) / 精密抵抗 (Vishay VHP101) | user-provided golden expected/metric_value |
| Traceability | NIST-traceable calibration chain | reason field + baseline_id + append-only history |
| Check | 定期 measure vs 標準器 | drift check vs baseline |
| Alert | 校正周期内の drift 検出 | verdict DRIFT_MAJOR (exit 2) → CI fail |
| Cost | ¥万〜数百万 | ¥0 stdlib only |

## 命名予告 累計 「10 のうち 8 台 骨格実装 済」

- ✅ v0.1 spike 済: 5A/5B/5C/5D/6/SVG map + 4B PC-side + **4A PC-side (本 STEP)**
- ⏸ 命名 のみ NEITHER: 4C 時刻 + 4D 作用hw (hardware 未取得 が blocker、 PC-side 別 arc candidate)

## Honest scope

1. **Python stdlib only** (hashlib.sha256 + Levenshtein Wagner-Fischer 自前実装)、 依存なし
2. **Levenshtein O(m*n) メモリ** = 大 text (>10000 chars) では 遅い / メモリ大、 v0.2 rolling row 化 candidate
3. **golden 選定基準は user 責任** = 「なぜ この expected が golden か」 は reason 明示、 選定 protocol は 別 arc (5B 枠組み機械 領域と 重なる)
4. **numeric tolerance/2 = MATCH threshold** は heuristic (< tol/2 = 誤差、 tol/2-tol = 警戒帯、 > tol = drift 確定)、 実運用調整 candidate
5. **zero baseline** は absolute diff で 判定 (percent 計算不能)、 baseline=0 = 「変化なし=0」 と 「未実装 sentinel=0」 の 区別が つかない risk
6. **exit code semantics** は CI 統合前提 (0/1/2/3)、 MINOR = warning 扱いは CI 側依存
7. **同一 baseline_id re-set** は latest 参照 (前 record は 保持)、 意図しない上書き防止 は 未装備 (v0.2 --force flag 化 candidate)
8. **audit trail** は append-only jsonl のみ、 GPG 署名なし、 5A oughtctl approval link candidate は 未装備
9. **多重 check の 統計判定** は 本機械 scope 外 = 統計 4 primitive (Welch t / Cohen's d STEP 1376/1379) に委譲

## Integration points (別 arc)

- **5A oughtctl link**: baseline set/retire を approval 格上げ (baseline 変更 = drift history 破壊 semi-irreversible)
- **5D meaning annotate**: baseline record の interpretation field 統合 candidate
- **5B frames**: baseline identity (「Claude 4.5 baseline」 と 「Claude 4.7」 の 同一性) 判定 candidate
- **統計 4 primitive**: 多重 check 結果 → Welch t で MATCH vs DRIFT 群比較 adapter
- **STEP 1389 4B system-covariates**: drift check 実行時に covariates snapshot 併記 (CPU 負荷が drift 原因か 判別 candidate)

## SAC-4 47 教訓 Phase 3-10 8 連続 clean 成功

Phase 3-10 = 8 連続 clean commit、 全 pre-staged 0 件 confirm 後 明示 file add、 sweep-in 一切なし
- Phase 3=252+、 4=264+、 5=468+、 6=1391+、 7=1440+、 8=1266+、 9=797+、 10=942+
- 他タブ push 競合は Phase 4+8 で 各 1 度 → rebase 綺麗 integrate、 6 Phase は 競合なし

## Verify

- Site: md5 `c1dc8d71c8632a6fe431e94a3a79f409`、 886 行 (前 882 +4)
- Commit `a9b801994` push (1e7263c89..a9b801994)、 5 files/942+/10-
- CF Pages deploy 107,477 bytes、 HTTP 200
- Phase 10 marker (STEP 1390/Phase 10/drift-detector/drift.py/test 51/51/drift_major/golden baseline): 3 hits (page content 内 の 明示 mention 数)
- Test: 51/51 PASS
- URL: https://rei-aios.pages.dev/tools/step-1369-five-machines-index/

## Deferred (継続)

1. **hardware side 4A** (電圧標準 ¥万〜数百万) = 藤本さん judgment 待ち
2. **統計 4 primitive integration** = 多重 check 結果 → Welch t 群比較 adapter
3. **5A oughtctl link** = baseline set/retire の approval 格上げ
4. **5D meaning + 5B frames 統合** = baseline record の interpretation + identity 統合
5. **STEP 1389 4B covariates + drift check 併記** = drift 発生時の 環境 co-variate snapshot 付与
6. **4C timestamp provenance v0.1** = chrony/w32time wrapper + monotonic clock trust (5D 統合と 同時 arc candidate)
7. **4D 拡張** = npm/pip/docker/db/cloud API hook (STEP 1388 pattern 継承)
8. **統計 4 primitive covariates-aware 化** (STEP 1389 継承 defer)
9. **ProvenanceRecord.env_covariates schema 拡張** (STEP 1345 側)

## 関連

- [[project-step1389-4B-pc-side-v01-2026-08-23]] Phase 9 直前 (4B PC-side pattern 継承、 「PC-side = hardware 代替でない」 discipline 継承)
- [[project-step1388-5A-pathway-hook-integration-2026-08-23]] Phase 8 (5A oughtctl link candidate origin)
- [[project-step1387-ledger-machines-5B-5C-5D-v01-2026-08-23]] Phase 7 (5B frames identity + 5D meaning integration candidate origin)
- [[project-step1383-four-physical-auxiliary-machines-2026-08-23]] 4A hardware side origin (未取得)
- [[project-step1376-welch-t-primitive-2026-08-23]] Welch t (多重 drift check 統計判定 target)
- [[project-step1379-cohen-d-both-2026-08-23]] Cohen's d (drift 大きさ 効果量 判定 target)
- [[feedback-super-naming-siren-family-pattern]] 「PC-side = hardware 代替 と 誤読させない」 継承
- [[feedback-projection-self-audit-pattern]] SAC-4 47 教訓 Phase 3-10 8 連続 clean 成功
- [[feedback-no-rush-publication]] 「命名 → v0.1 spike → 実 pipeline 統合」 継続、 hardware 未取得下の 迂回路 2/4 (4A + 4B PC-side spike 済)
