Compare commits
5 Commits
base/ourob
...
79ad108e2f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79ad108e2f | ||
| d9cf056df8 | |||
|
|
bd9286a39f | ||
|
|
f4f8827353 | ||
|
|
7d24f19cc4 |
@@ -42,5 +42,3 @@ Updated: 2026-03-02
|
|||||||
## 변경 이력
|
## 변경 이력
|
||||||
|
|
||||||
- 2026-03-02: `v1.0.12` 문서 검증 게이트 강화(#390) 반영에 따라 정책 문서 동기화 체크를 수행했다. (`REQ-OPS-002`)
|
- 2026-03-02: `v1.0.12` 문서 검증 게이트 강화(#390) 반영에 따라 정책 문서 동기화 체크를 수행했다. (`REQ-OPS-002`)
|
||||||
|
|
||||||
- 2026-03-04: 86_peak_probability_model_plan.md 초안 추가에 따른 정책 문서 동기화 체크를 수행했다. (REQ-OPS-002)
|
|
||||||
|
|||||||
@@ -1,168 +0,0 @@
|
|||||||
<!--
|
|
||||||
Doc-ID: DOC-PLAN-086
|
|
||||||
Version: 0.1.0
|
|
||||||
Status: draft
|
|
||||||
Owner: strategy
|
|
||||||
Updated: 2026-03-02
|
|
||||||
-->
|
|
||||||
|
|
||||||
# 고점 확률 모델 도입 계획 (초안)
|
|
||||||
|
|
||||||
작성일: 2026-03-02
|
|
||||||
목적: 기존 계획(v2)의 "모델 보조 신호"를, 실운용 가능한 단순한 형태로 재정의한다.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. 한 줄 요약
|
|
||||||
|
|
||||||
- 목표는 "지금이 고점(또는 고점 근처)일 확률"을 예측해 익절/축소/오버나잇 리스크 결정을 보조하는 것이다.
|
|
||||||
- 1차는 정규장 중심으로 시작하고, NXT/US_PRE 등 확장세션은 이후 분리 대응한다.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. 왜 바꾸는가
|
|
||||||
|
|
||||||
- 기존 논의는 범위가 넓어 구현/검증 비용이 컸다.
|
|
||||||
- 현재 로그 구조에서도 빠르게 시작 가능한 타깃이 필요하다.
|
|
||||||
- 실거래 효용 기준에서 "고점 근처 감지"는 청산 품질 개선에 직접 연결된다.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. 이번 계획의 핵심 결정
|
|
||||||
|
|
||||||
### 3.1 예측 타깃 (2개)
|
|
||||||
|
|
||||||
- `p_top_d0`: 현재 시점이 "오늘 정규장 고점(근접 포함)"일 확률
|
|
||||||
- `p_top_d1`: 현재 시점이 "내일 정규장 마감까지 포함한 고점(근접 포함)"일 확률
|
|
||||||
|
|
||||||
### 3.2 모델 역할
|
|
||||||
|
|
||||||
- 단독 매도 트리거가 아니라 보조 신호로 사용한다.
|
|
||||||
- Hard stop / ATR trailing / Kill Switch 우선 원칙은 유지한다.
|
|
||||||
|
|
||||||
### 3.3 적용 순서
|
|
||||||
|
|
||||||
1. KR/US 정규장만 대상으로 MVP 구축
|
|
||||||
2. 성능/운영 안정화 후 NXT, US_PRE, US_AFTER 분리 확장
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. 데이터/라벨 정의 (MVP)
|
|
||||||
|
|
||||||
### 4.1 샘플 단위
|
|
||||||
|
|
||||||
- 단위: "시점 t의 관측값 1개"
|
|
||||||
- 대상: 주문 가능 시점 중 정책 게이트를 통과하는 시점
|
|
||||||
|
|
||||||
### 4.2 라벨 정의
|
|
||||||
|
|
||||||
- `y_d0 = 1` if `max_high(t ~ 오늘 정규장 마감) <= price_t * (1 + eps_d0)` else `0`
|
|
||||||
- `y_d1 = 1` if `max_high(t ~ 내일 정규장 마감) <= price_t * (1 + eps_d1)` else `0`
|
|
||||||
|
|
||||||
### 4.3 필수 피처 (초기)
|
|
||||||
|
|
||||||
- 가격/수익률: `current_price`, `price_change_pct`
|
|
||||||
- 미시지표: `rsi`, `volume_ratio`, `signal`, `score`
|
|
||||||
- 포트폴리오: `portfolio_pnl_pct`, `total_cash`(선택)
|
|
||||||
- 상태: `market`, `session_id`, `minutes_to_close`, `is_tradeable_now`
|
|
||||||
|
|
||||||
### 4.4 데이터 제외 규칙 (초기)
|
|
||||||
|
|
||||||
- `session_id in ('', 'UNKNOWN')` 제외
|
|
||||||
- `price <= 0` 또는 `quantity <= 0` 제외
|
|
||||||
- `rationale LIKE '[startup-sync]%'` 제외
|
|
||||||
- 라벨 윈도우 불완전(휴장/데이터 누락) 샘플 제외
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. 추론/실행 규칙 (초안)
|
|
||||||
|
|
||||||
### 5.1 추론 출력
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"p_top_d0": 0.00,
|
|
||||||
"p_top_d1": 0.00,
|
|
||||||
"model_version": "TBD"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.2 실행 반영 원칙
|
|
||||||
|
|
||||||
- `p_top_d0`가 높으면: 당일 익절/트레일링 강화
|
|
||||||
- `p_top_d1`가 높으면: 오버나잇 보유 축소/청산 우선
|
|
||||||
- 확장세션(NXT/US_PRE)은 초기엔 보수 임계치 또는 실행 제한
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. 세션 이슈 대응 원칙
|
|
||||||
|
|
||||||
### 6.1 거래 가능 세션 기준
|
|
||||||
|
|
||||||
- 달력 시간이 아니라 "종목이 실제 거래 가능한 세션" 기준으로 라벨/추론을 구성한다.
|
|
||||||
|
|
||||||
### 6.2 정규장 vs 확장세션 분리
|
|
||||||
|
|
||||||
- MVP: 정규장 전용 라벨/모델
|
|
||||||
- 확장: 세션별 헤드 또는 세션별 모델 분리 검토
|
|
||||||
|
|
||||||
### 6.3 고점 정의 분리
|
|
||||||
|
|
||||||
- `reg_high`: 정규장 고점 (주 라벨)
|
|
||||||
- `ext_high`: 확장세션 포함 고점 (보조 분석)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. 단계별 구현 계획
|
|
||||||
|
|
||||||
### Phase A: 계약 고정
|
|
||||||
|
|
||||||
- 학습용 canonical dataset 스키마 확정
|
|
||||||
- 시점 정렬(as-of) 규칙 문서화
|
|
||||||
- 라벨 생성 함수/검증 테스트 추가
|
|
||||||
|
|
||||||
### Phase B: 오프라인 검증
|
|
||||||
|
|
||||||
- Walk-forward + Purge/Embargo 평가
|
|
||||||
- `d0`, `d1` 분리 리포트
|
|
||||||
- B1(모델 없음) 대비 개선 여부 확인
|
|
||||||
|
|
||||||
### Phase C: 런타임 통합
|
|
||||||
|
|
||||||
- 추론 결과를 `pred_top_d0/pred_top_d1`로 주입
|
|
||||||
- 매도/축소 보조 규칙 연결
|
|
||||||
- Shadow 모드로 관측 후 제한적 활성화
|
|
||||||
|
|
||||||
### Phase D: 세션 확장
|
|
||||||
|
|
||||||
- NXT/US_PRE/US_AFTER 정책 분리
|
|
||||||
- 실행 게이트/임계치 세션별 튜닝
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. 지금 당장 결정할 최소 항목 (TBD)
|
|
||||||
|
|
||||||
- [ ] `eps_d0`, `eps_d1` 기본값 (`TBD`)
|
|
||||||
- [ ] `p_top_d0`, `p_top_d1` 실행 임계치 (`TBD`)
|
|
||||||
- [ ] 정규장/확장세션 대상 시장 범위 (`TBD`)
|
|
||||||
- [ ] 최소 학습 샘플 수 기준 (`TBD`)
|
|
||||||
- [ ] Shadow 관측 기간 (`TBD`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. 리스크 및 완화
|
|
||||||
|
|
||||||
- 라벨 불균형: class weight, threshold 튜닝
|
|
||||||
- 시간대 편향(장마감 근처): 시간 피처 추가 + 구간별 성능 보고
|
|
||||||
- 데이터 무결성: 제외 규칙 강제 + CI 검증
|
|
||||||
- 복잡도 증가: 정규장 MVP를 먼저 잠그고 확장세션은 후속 분리
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10. 후속 문서 연결 (예정)
|
|
||||||
|
|
||||||
- requirements registry: 신규 REQ/TASK/TEST 매핑 추가
|
|
||||||
- code-level work orders: 구현 작업 분해
|
|
||||||
- acceptance/test plan: `p_top_d0/d1` 검증 항목 추가
|
|
||||||
- implementation audit: 기존 "모델 보조 신호" 항목 업데이트
|
|
||||||
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
# Dual-Track Workflow Execution Plan (Revised)
|
|
||||||
|
|
||||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
||||||
|
|
||||||
**Goal:** Re-seed workflow planning from a clean base branch (not the temporary branch), then execute isolated `86` and `80` tracks with real-operation-confirmed closeout and related Gitea issue closure.
|
|
||||||
|
|
||||||
**Architecture:** Start from `feature/v3-session-policy-stream` and create `base/ouroboros-workflow-20260302`. Bring only two workflow plan docs as one squashed seed commit. Branch `task/86...` and `task/80...` from that base with strict file-scope separation. For `80`, update audit only after real-operation confirmation, then close related Gitea issues (children before parent). Final promotion happens by merging the validated stream to `main`.
|
|
||||||
|
|
||||||
**Tech Stack:** Git CLI, Gitea (`tea`) issue/PR workflow, Markdown docs (`docs/ouroboros`, `docs/plans`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 1: Freeze temporary branch and identify export scope
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: none
|
|
||||||
- Create: none
|
|
||||||
- Test: none
|
|
||||||
|
|
||||||
**Step 1: Inspect temporary branch state**
|
|
||||||
|
|
||||||
Run: `git status --short --branch`
|
|
||||||
Expected: current temporary branch with local changes listed.
|
|
||||||
|
|
||||||
**Step 2: Preserve changes using stash (recommended)**
|
|
||||||
|
|
||||||
Run: `git stash push -u -m "tmp-before-workflow-reseed-2026-03-02"`
|
|
||||||
Expected: stash created with tracked/untracked changes.
|
|
||||||
|
|
||||||
**Step 3: Define transferable artifacts**
|
|
||||||
|
|
||||||
Run: keep only these for reseed:
|
|
||||||
- `docs/plans/2026-03-02-ouroboros-dual-track-workflow-design.md`
|
|
||||||
- `docs/plans/2026-03-02-dual-track-workflow-execution-plan.md`
|
|
||||||
Expected: transfer scope fixed to two files.
|
|
||||||
|
|
||||||
**Step 4: Verify clean working tree**
|
|
||||||
|
|
||||||
Run: `git status --short --branch`
|
|
||||||
Expected: no local changes.
|
|
||||||
|
|
||||||
**Step 5: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# no commit in this task (stash-only preservation)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task 2: Create clean official base and seed one commit
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `docs/plans/2026-03-02-ouroboros-dual-track-workflow-design.md`
|
|
||||||
- Modify: `docs/plans/2026-03-02-dual-track-workflow-execution-plan.md`
|
|
||||||
- Test: none
|
|
||||||
|
|
||||||
**Step 1: Switch to canonical base**
|
|
||||||
|
|
||||||
Run: `git checkout feature/v3-session-policy-stream`
|
|
||||||
Expected: branch switch successful.
|
|
||||||
|
|
||||||
**Step 2: Update local base**
|
|
||||||
|
|
||||||
Run: `git pull --ff-only origin feature/v3-session-policy-stream`
|
|
||||||
Expected: up-to-date or fast-forward update.
|
|
||||||
|
|
||||||
**Step 3: Create staging base branch**
|
|
||||||
|
|
||||||
Run: `git checkout -b base/ouroboros-workflow-20260302`
|
|
||||||
Expected: new branch created from updated feature base.
|
|
||||||
|
|
||||||
**Step 4: Restore only two plan docs from temporary branch commits**
|
|
||||||
|
|
||||||
Run (example): `git checkout <temp-branch> -- docs/plans/2026-03-02-ouroboros-dual-track-workflow-design.md docs/plans/2026-03-02-dual-track-workflow-execution-plan.md`
|
|
||||||
Expected: only two files restored in working tree.
|
|
||||||
|
|
||||||
**Step 5: Create one squashed seed commit**
|
|
||||||
|
|
||||||
Run: `git add docs/plans/2026-03-02-ouroboros-dual-track-workflow-design.md docs/plans/2026-03-02-dual-track-workflow-execution-plan.md && git commit -m "docs: seed revised dual-track workflow plan"`
|
|
||||||
Expected: single commit with two files only.
|
|
||||||
|
|
||||||
**Step 6: Verify seed scope**
|
|
||||||
|
|
||||||
Run: `git show --name-only --oneline HEAD`
|
|
||||||
Expected: exactly the two plan docs listed.
|
|
||||||
|
|
||||||
**Step 7: Push official base**
|
|
||||||
|
|
||||||
Run: `git push -u origin base/ouroboros-workflow-20260302`
|
|
||||||
Expected: remote tracking set.
|
|
||||||
|
|
||||||
### Task 3: Open Track A (`86`) branch and initial PR
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `docs/ouroboros/86_peak_probability_model_plan.md`
|
|
||||||
- Test: none
|
|
||||||
|
|
||||||
**Step 1: Create Track A branch**
|
|
||||||
|
|
||||||
Run: `git checkout -b task/86-peak-probability-plan`
|
|
||||||
Expected: branch created from official base.
|
|
||||||
|
|
||||||
**Step 2: Stage only `86` document**
|
|
||||||
|
|
||||||
Run: `git add docs/ouroboros/86_peak_probability_model_plan.md`
|
|
||||||
Expected: only `86` doc staged.
|
|
||||||
|
|
||||||
**Step 3: Commit initial PR seed**
|
|
||||||
|
|
||||||
Run: `git commit -m "docs: seed peak probability model plan (#86)"`
|
|
||||||
Expected: one-document commit.
|
|
||||||
|
|
||||||
**Step 4: Push branch**
|
|
||||||
|
|
||||||
Run: `git push -u origin task/86-peak-probability-plan`
|
|
||||||
Expected: remote branch created.
|
|
||||||
|
|
||||||
**Step 5: Open PR-A**
|
|
||||||
|
|
||||||
Run: `tea pr create --base base/ouroboros-workflow-20260302 --head task/86-peak-probability-plan --title "docs: seed peak probability model plan (#86)" --description "Initial planning PR for iterative concretization."`
|
|
||||||
Expected: PR URL returned.
|
|
||||||
|
|
||||||
### Task 4: Open Track B (`80`) branch for operation-confirmed closeout
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `docs/ouroboros/80_implementation_audit.md`
|
|
||||||
- Test: operation observation evidence (outside unit-test scope)
|
|
||||||
|
|
||||||
**Step 1: Return to staging base**
|
|
||||||
|
|
||||||
Run: `git checkout base/ouroboros-workflow-20260302`
|
|
||||||
Expected: branch switch successful.
|
|
||||||
|
|
||||||
**Step 2: Create Track B branch**
|
|
||||||
|
|
||||||
Run: `git checkout -b task/80-implementation-audit-closeout`
|
|
||||||
Expected: branch created.
|
|
||||||
|
|
||||||
**Step 3: Apply closeout edits only after real-operation confirmation**
|
|
||||||
|
|
||||||
Run: edit `docs/ouroboros/80_implementation_audit.md`
|
|
||||||
Expected: status/evidence sections updated with observed behavior, confirmation timestamp, and operational proof summary.
|
|
||||||
|
|
||||||
**Step 4: Commit closeout update**
|
|
||||||
|
|
||||||
Run: `git add docs/ouroboros/80_implementation_audit.md && git commit -m "docs: close out implementation audit items after operation confirmation (#80)"`
|
|
||||||
Expected: single-scope commit.
|
|
||||||
|
|
||||||
**Step 5: Push and open PR-B**
|
|
||||||
|
|
||||||
Run: `git push -u origin task/80-implementation-audit-closeout`
|
|
||||||
Expected: remote branch created.
|
|
||||||
|
|
||||||
Run: `tea pr create --base base/ouroboros-workflow-20260302 --head task/80-implementation-audit-closeout --title "docs: close out implementation audit items (#80)" --description "Closeout based on real-operation confirmation."`
|
|
||||||
Expected: PR URL returned.
|
|
||||||
|
|
||||||
### Task 5: Close related Gitea issues after `80` confirmation
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `docs/ouroboros/80_implementation_audit.md` (reference linkage only)
|
|
||||||
- Test: issue parent-child completeness check
|
|
||||||
|
|
||||||
**Step 1: Build related issue set from updated `80` audit**
|
|
||||||
|
|
||||||
Run: parse issue references from `80` updated sections.
|
|
||||||
Expected: target open issue list prepared.
|
|
||||||
|
|
||||||
**Step 2: Close child issues first**
|
|
||||||
|
|
||||||
Run: `tea issues close <child-issue-number>` for each confirmed child.
|
|
||||||
Expected: all qualifying child issues closed.
|
|
||||||
|
|
||||||
**Step 3: Close parent issues only when all children are closed**
|
|
||||||
|
|
||||||
Run: `tea issues close <parent-issue-number>`
|
|
||||||
Expected: parent closes only after dependency check passes.
|
|
||||||
|
|
||||||
**Step 4: Record closure summary in PR comment**
|
|
||||||
|
|
||||||
Run: add PR comment with closed issue IDs and parent-child resolution note.
|
|
||||||
Expected: auditable trace for closeout.
|
|
||||||
|
|
||||||
### Task 6: Validate branch hygiene and merge path
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: none
|
|
||||||
- Test: git diff/log checks
|
|
||||||
|
|
||||||
**Step 1: Verify PR-A scope**
|
|
||||||
|
|
||||||
Run: `git diff --name-only base/ouroboros-workflow-20260302...task/86-peak-probability-plan`
|
|
||||||
Expected: only `docs/ouroboros/86_peak_probability_model_plan.md` (and intentional related plan files if any).
|
|
||||||
|
|
||||||
**Step 2: Verify PR-B scope**
|
|
||||||
|
|
||||||
Run: `git diff --name-only base/ouroboros-workflow-20260302...task/80-implementation-audit-closeout`
|
|
||||||
Expected: only `docs/ouroboros/80_implementation_audit.md` (and intentional related plan files if any).
|
|
||||||
|
|
||||||
**Step 3: Merge both PRs into staging base**
|
|
||||||
|
|
||||||
Run: GitHub merge flow for PR-A and PR-B
|
|
||||||
Expected: staging base includes both tracks without cross-file contamination.
|
|
||||||
|
|
||||||
**Step 4: Promote validated stream to `main`**
|
|
||||||
|
|
||||||
Run: open PR from `feature/v3-session-policy-stream` (or its validated promotion branch) to `main`
|
|
||||||
Expected: merge-based history preservation with no cherry-pick/rebase surgery.
|
|
||||||
|
|
||||||
**Step 5: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# no additional commit required in this task
|
|
||||||
```
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
# Live Operation Issue Tracking Design
|
|
||||||
|
|
||||||
**Date:** 2026-03-02
|
|
||||||
**Scope:** Real-operation confirmation tracking for all open Gitea issues, tied to `task/80-implementation-audit-closeout`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Goal
|
|
||||||
|
|
||||||
Define an issue-by-issue tracking method for real-operation confirmation so that:
|
|
||||||
|
|
||||||
- every open issue is tracked with explicit lifecycle states,
|
|
||||||
- parent-child close order is enforced,
|
|
||||||
- and final closeout is reflected in `80` audit work without loss.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Target Set
|
|
||||||
|
|
||||||
- Coverage target: all current open Gitea issues (`318~381`, and future open issues during this closeout window).
|
|
||||||
- Tracking starts from open set snapshot and stays synced until closeout completion.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Tracking Architecture
|
|
||||||
|
|
||||||
- Primary log: direct comments on each issue ticket.
|
|
||||||
- Aggregate log: single summary comment on the `80` PR (`task/80-implementation-audit-closeout`).
|
|
||||||
- No separate tracking doc as source of truth during execution.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. State Model and Criteria
|
|
||||||
|
|
||||||
State machine:
|
|
||||||
|
|
||||||
- `NOT_STARTED`
|
|
||||||
- `OBSERVING`
|
|
||||||
- `CONFIRMED`
|
|
||||||
- `CLOSED`
|
|
||||||
|
|
||||||
Rules:
|
|
||||||
|
|
||||||
- `CONFIRMED` requires one real-operation observation evidence item.
|
|
||||||
- `CLOSED` requires close conditions satisfied and ticket close action executed.
|
|
||||||
- Parent issue cannot become `CLOSED` until all child issues are `CLOSED`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Issue Comment Template
|
|
||||||
|
|
||||||
Each issue update comment uses:
|
|
||||||
|
|
||||||
- `Status: <STATE>`
|
|
||||||
- `Observed At: <KST>, <UTC>`
|
|
||||||
- `Environment: live`
|
|
||||||
- `Evidence: <log/query/order-execution identifier>`
|
|
||||||
- `Next: <single next action>`
|
|
||||||
|
|
||||||
This template is reused for every transition for consistent auditability.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Parent-Child Policy
|
|
||||||
|
|
||||||
- Parent issue comment must list child issue IDs.
|
|
||||||
- Child issues transition independently.
|
|
||||||
- Parent close gate:
|
|
||||||
- if any child is not `CLOSED`, parent remains at most `CONFIRMED`;
|
|
||||||
- when all children are `CLOSED`, parent can transition to `CLOSED` and be closed.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. Operational Loop
|
|
||||||
|
|
||||||
1. Initialize all open issues with `NOT_STARTED` comment.
|
|
||||||
2. Move active issues to `OBSERVING` when live confirmation begins.
|
|
||||||
3. Move to `CONFIRMED` after one real-operation evidence capture.
|
|
||||||
4. Close child issues first, then close parent issue(s).
|
|
||||||
5. Update the single `80` PR summary comment whenever issue state changes.
|
|
||||||
6. Reflect final confirmed/closed outcomes in `docs/ouroboros/80_implementation_audit.md`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Evidence and Time Rules
|
|
||||||
|
|
||||||
- Evidence must be replayable/referenceable by identifier (not vague narrative only).
|
|
||||||
- Every update includes both KST and UTC timestamps.
|
|
||||||
- Use absolute dates (example: `2026-03-02`) to avoid ambiguity in session handoff.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. Completion Conditions
|
|
||||||
|
|
||||||
Tracking design is complete when:
|
|
||||||
|
|
||||||
- all open issues are represented in issue comments with valid lifecycle state,
|
|
||||||
- parent-child closure constraints are respected,
|
|
||||||
- `80` PR summary comment reflects current global status,
|
|
||||||
- and final `80` audit document update is ready for closeout commit.
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
# Live Operation Issue Tracking Implementation Plan
|
|
||||||
|
|
||||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
||||||
|
|
||||||
**Goal:** Track real-operation confirmation for all open Gitea issues with per-issue comments and a synchronized summary on the `80` PR, then close issues in dependency-safe order.
|
|
||||||
|
|
||||||
**Architecture:** Use issue tickets as the primary state log with a strict four-state lifecycle. Maintain one aggregate status comment on `task/80-implementation-audit-closeout` PR. Enforce child-first closure and parent close gating.
|
|
||||||
|
|
||||||
**Tech Stack:** Git CLI, Gitea CLI (`tea`), Markdown (`docs/ouroboros/80_implementation_audit.md`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 1: Snapshot open issues and classify parent-child graph
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: none
|
|
||||||
- Modify: none
|
|
||||||
- Test: `tea issues ls` output inspection
|
|
||||||
|
|
||||||
**Step 1: Capture open issue list**
|
|
||||||
|
|
||||||
Run: `tea issues ls --state open --limit 200`
|
|
||||||
Expected: list of all open issues (including `318~381`).
|
|
||||||
|
|
||||||
**Step 2: Fetch details for each issue**
|
|
||||||
|
|
||||||
Run: `for n in $(tea issues ls --state open --limit 200 --output json | jq -r '.[].number'); do tea issue view "$n"; done`
|
|
||||||
Expected: issue bodies/comments available for relation parsing.
|
|
||||||
|
|
||||||
**Step 3: Extract parent-child references**
|
|
||||||
|
|
||||||
Run: parse issue text for relation keywords (`parent`, `child`, `depends on`, `blocks`).
|
|
||||||
Expected: dependency map ready.
|
|
||||||
|
|
||||||
**Step 4: Validate unresolved dependency edges**
|
|
||||||
|
|
||||||
Run: verify each parent references only existing issue numbers.
|
|
||||||
Expected: no dangling child references.
|
|
||||||
|
|
||||||
**Step 5: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# no commit (discovery task)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task 2: Initialize per-issue tracking comments (`NOT_STARTED`)
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: none
|
|
||||||
- Modify: none
|
|
||||||
- Test: issue comment presence check
|
|
||||||
|
|
||||||
**Step 1: Prepare standard template text**
|
|
||||||
|
|
||||||
```text
|
|
||||||
Status: NOT_STARTED
|
|
||||||
Observed At: <KST>, <UTC>
|
|
||||||
Environment: live
|
|
||||||
Evidence: N/A
|
|
||||||
Next: Begin live observation for this issue.
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 2: Post initialization comment to each open issue**
|
|
||||||
|
|
||||||
Run: `tea issues comment <issue-number> --message "<template>"`
|
|
||||||
Expected: each open issue has one initialization comment.
|
|
||||||
|
|
||||||
**Step 3: Verify comment coverage**
|
|
||||||
|
|
||||||
Run: sample-check each issue (`tea issue view <issue-number>`) for latest status comment.
|
|
||||||
Expected: 100% coverage across open issues.
|
|
||||||
|
|
||||||
**Step 4: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# no commit (ticket operations)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task 3: Create and maintain `80` PR aggregate status comment
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `docs/ouroboros/80_implementation_audit.md` (final sync only, not this task)
|
|
||||||
- Test: PR comment contains full issue table
|
|
||||||
|
|
||||||
**Step 1: Identify PR number for `task/80-implementation-audit-closeout`**
|
|
||||||
|
|
||||||
Run: `tea pr ls --state open`
|
|
||||||
Expected: PR number for `task/80...` identified.
|
|
||||||
|
|
||||||
**Step 2: Post initial summary comment**
|
|
||||||
|
|
||||||
Run: `tea pr comment <pr-number> --message "<issue-state-summary-table>"`
|
|
||||||
Expected: one aggregate comment listing `issue | state | last observed at | parent/child`.
|
|
||||||
|
|
||||||
**Step 3: Define update protocol**
|
|
||||||
|
|
||||||
Run: update same summary comment on every issue state change.
|
|
||||||
Expected: summary remains single-source aggregate view.
|
|
||||||
|
|
||||||
**Step 4: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# no commit (ticket/PR operations)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task 4: Execute live observation loop and mark `OBSERVING` -> `CONFIRMED`
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: none
|
|
||||||
- Modify: none
|
|
||||||
- Test: evidence-backed state transitions present in issue comments
|
|
||||||
|
|
||||||
**Step 1: Mark active issue as `OBSERVING`**
|
|
||||||
|
|
||||||
Run: `tea issues comment <issue-number> --message "Status: OBSERVING ..."`
|
|
||||||
Expected: issue history shows observation started.
|
|
||||||
|
|
||||||
**Step 2: Capture one real-operation evidence item**
|
|
||||||
|
|
||||||
Run: collect log/query/order identifier tied to issue behavior.
|
|
||||||
Expected: one concrete evidence reference captured.
|
|
||||||
|
|
||||||
**Step 3: Mark issue `CONFIRMED`**
|
|
||||||
|
|
||||||
Run: `tea issues comment <issue-number> --message "Status: CONFIRMED ... Evidence: <id> ..."`
|
|
||||||
Expected: issue has explicit confirmed state.
|
|
||||||
|
|
||||||
**Step 4: Sync PR aggregate summary**
|
|
||||||
|
|
||||||
Run: update `80` PR summary comment row for that issue.
|
|
||||||
Expected: PR summary and issue status aligned.
|
|
||||||
|
|
||||||
**Step 5: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# no commit (ticket operations)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task 5: Close issues with child-first dependency enforcement
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: none
|
|
||||||
- Modify: none
|
|
||||||
- Test: parent close attempted only after all children closed
|
|
||||||
|
|
||||||
**Step 1: Close confirmed child issues first**
|
|
||||||
|
|
||||||
Run: `tea issues close <child-issue-number>`
|
|
||||||
Expected: child issue state becomes closed.
|
|
||||||
|
|
||||||
**Step 2: Verify all children for each parent**
|
|
||||||
|
|
||||||
Run: evaluate dependency map for remaining non-closed children.
|
|
||||||
Expected: parent close gate decision available.
|
|
||||||
|
|
||||||
**Step 3: Close eligible parent issues**
|
|
||||||
|
|
||||||
Run: `tea issues close <parent-issue-number>`
|
|
||||||
Expected: parent is closed only when all children are closed.
|
|
||||||
|
|
||||||
**Step 4: Post closure comment and sync PR summary**
|
|
||||||
|
|
||||||
Run: comment `Status: CLOSED` on closed issue and update PR summary row.
|
|
||||||
Expected: closure trace exists in both issue and PR aggregate.
|
|
||||||
|
|
||||||
**Step 5: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# no commit (ticket operations)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Task 6: Reflect final tracked outcomes in `80` audit and commit
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `docs/ouroboros/80_implementation_audit.md`
|
|
||||||
- Test: markdown consistency + traceability check
|
|
||||||
|
|
||||||
**Step 1: Update `80` with final live-confirmed statuses**
|
|
||||||
|
|
||||||
Run: edit status lines and evidence summary sections.
|
|
||||||
Expected: document reflects final issue states and confirmation notes.
|
|
||||||
|
|
||||||
**Step 2: Add issue closure summary block**
|
|
||||||
|
|
||||||
Run: include closed child/parent sequence summary.
|
|
||||||
Expected: audit reader can verify closure logic quickly.
|
|
||||||
|
|
||||||
**Step 3: Validate references**
|
|
||||||
|
|
||||||
Run: ensure issue numbers in doc match actual closed/open states.
|
|
||||||
Expected: no mismatch between doc and Gitea.
|
|
||||||
|
|
||||||
**Step 4: Commit closeout doc update**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add docs/ouroboros/80_implementation_audit.md
|
|
||||||
git commit -m "docs: finalize 80 audit with live-operation issue confirmations"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 5: Push branch**
|
|
||||||
|
|
||||||
Run: `git push`
|
|
||||||
Expected: closeout commit available on `task/80-implementation-audit-closeout`.
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
# Ouroboros Dual-Track Workflow Design (Revised)
|
|
||||||
|
|
||||||
**Date:** 2026-03-02
|
|
||||||
**Scope:** `docs/ouroboros/86_peak_probability_model_plan.md` and `docs/ouroboros/80_implementation_audit.md`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Goal
|
|
||||||
|
|
||||||
Prevent work loss and history contamination while running two parallel tracks, while correcting an invalid starting condition (design commits created on a disposable temporary branch):
|
|
||||||
|
|
||||||
- Track A: open and iterate the `86` plan as a dedicated PR.
|
|
||||||
- Track B: finalize `80` only after real-operation behavior is confirmed, then reflect completion and close related Gitea open issues.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Constraints and Current Context
|
|
||||||
|
|
||||||
- Current temporary branch is disposable and must not remain the authoritative base.
|
|
||||||
- Canonical base line for current work is `feature/v3-session-policy-stream`.
|
|
||||||
- Final integration strategy is to merge the full `feature/v3-session-policy-stream` line into `main` after operation-level validation is complete.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Approaches Considered
|
|
||||||
|
|
||||||
1. Keep using temporary branch and continue from existing design commits.
|
|
||||||
2. Create a clean base from `feature/v3-session-policy-stream` and move only plan artifacts as one commit (recommended).
|
|
||||||
3. Split into two fresh bases (`86` and `80` separately) immediately.
|
|
||||||
|
|
||||||
Recommendation rationale:
|
|
||||||
|
|
||||||
- Approach 2 removes temporary-branch contamination risk.
|
|
||||||
- It preserves clean lineage with a single "official starting point" commit.
|
|
||||||
- It keeps downstream split for `86` and `80` straightforward.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Approved Branch and PR Topology
|
|
||||||
|
|
||||||
- Long-lived source baseline: `feature/v3-session-policy-stream`
|
|
||||||
- New official base: `base/ouroboros-workflow-20260302` (from `feature/v3-session-policy-stream`)
|
|
||||||
- Official base contains only two workflow plan docs squashed into one commit.
|
|
||||||
- Track A branch: `task/86-peak-probability-plan` (from official base)
|
|
||||||
- Track B branch: `task/80-implementation-audit-closeout` (from official base)
|
|
||||||
|
|
||||||
PR direction:
|
|
||||||
|
|
||||||
- PR-A (`86`): `task/86-peak-probability-plan -> base/ouroboros-workflow-20260302`
|
|
||||||
- PR-B (`80`): `task/80-implementation-audit-closeout -> base/ouroboros-workflow-20260302`
|
|
||||||
- Final integration: `feature/v3-session-policy-stream` line merged into `main`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Completion Criteria per Track
|
|
||||||
|
|
||||||
### Track A (`86`)
|
|
||||||
|
|
||||||
- Open initial PR early with the planning document.
|
|
||||||
- Continue iterative concretization in follow-up commits on the same branch.
|
|
||||||
|
|
||||||
### Track B (`80`)
|
|
||||||
|
|
||||||
- Do not close based on test-command artifacts alone.
|
|
||||||
- Close only when modified behavior is confirmed in real operation.
|
|
||||||
- Update `80_implementation_audit.md` with:
|
|
||||||
- observed behavior changes,
|
|
||||||
- confirmation timing,
|
|
||||||
- operation-side evidence summary.
|
|
||||||
- After `80` real-operation confirmation and doc update, close related Gitea open issues immediately (same phase).
|
|
||||||
- Parent issues close only when all child issues are confirmed closed.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Loss-Prevention Rules
|
|
||||||
|
|
||||||
- Preserve temporary-branch unmerged changes first (stash or archival commit).
|
|
||||||
- Exclude `workflow/session-handover.md` and `docs/ouroboros/86_peak_probability_model_plan.md` from official base-seeding commit.
|
|
||||||
- Enforce file-scope separation:
|
|
||||||
- PR-A should avoid `80` edits.
|
|
||||||
- PR-B should avoid `86` edits.
|
|
||||||
- Keep commit messages scoped to one track per commit.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. Merge Strategy Decision
|
|
||||||
|
|
||||||
- For this workflow, prefer merge-based lineage preservation.
|
|
||||||
- Because the final promotion unit is the full `feature/v3-session-policy-stream` stream, avoid unnecessary cherry-pick/rebase-surgery unless a contamination incident occurs.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Immediate Next Actions
|
|
||||||
|
|
||||||
1. Seed `base/ouroboros-workflow-20260302` from `feature/v3-session-policy-stream` with one squashed workflow-doc commit.
|
|
||||||
2. Verify seed commit file scope contains only two plan docs.
|
|
||||||
3. Create and open PR-A for `86`.
|
|
||||||
4. Complete real-operation confirmation for `80`, update audit doc, then close related Gitea issues (children first, then parent).
|
|
||||||
5. Merge validated `feature/v3-session-policy-stream` line into `main`.
|
|
||||||
@@ -5,6 +5,8 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
@@ -12,11 +14,31 @@ from pathlib import Path
|
|||||||
|
|
||||||
HEADER_PATTERN = re.compile(r"^##\s+\S+", re.MULTILINE)
|
HEADER_PATTERN = re.compile(r"^##\s+\S+", re.MULTILINE)
|
||||||
LIST_ITEM_PATTERN = re.compile(r"^\s*(?:-|\*|\d+\.)\s+\S+", re.MULTILINE)
|
LIST_ITEM_PATTERN = re.compile(r"^\s*(?:-|\*|\d+\.)\s+\S+", re.MULTILINE)
|
||||||
|
FENCED_CODE_PATTERN = re.compile(r"```.*?```", re.DOTALL)
|
||||||
|
INLINE_CODE_PATTERN = re.compile(r"`[^`]*`")
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_code_segments(text: str) -> str:
|
||||||
|
without_fences = FENCED_CODE_PATTERN.sub("", text)
|
||||||
|
return INLINE_CODE_PATTERN.sub("", without_fences)
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_tea_binary() -> str:
|
||||||
|
tea_from_path = shutil.which("tea")
|
||||||
|
if tea_from_path:
|
||||||
|
return tea_from_path
|
||||||
|
|
||||||
|
tea_home = Path.home() / "bin" / "tea"
|
||||||
|
if tea_home.exists() and tea_home.is_file() and os.access(tea_home, os.X_OK):
|
||||||
|
return str(tea_home)
|
||||||
|
|
||||||
|
raise RuntimeError("tea binary not found (checked PATH and ~/bin/tea)")
|
||||||
|
|
||||||
|
|
||||||
def validate_pr_body_text(text: str) -> list[str]:
|
def validate_pr_body_text(text: str) -> list[str]:
|
||||||
errors: list[str] = []
|
errors: list[str] = []
|
||||||
if "\\n" in text and "\n" not in text:
|
searchable = _strip_code_segments(text)
|
||||||
|
if "\\n" in searchable:
|
||||||
errors.append("body contains escaped newline sequence (\\n)")
|
errors.append("body contains escaped newline sequence (\\n)")
|
||||||
if text.count("```") % 2 != 0:
|
if text.count("```") % 2 != 0:
|
||||||
errors.append("body has unbalanced fenced code blocks (``` count is odd)")
|
errors.append("body has unbalanced fenced code blocks (``` count is odd)")
|
||||||
@@ -28,10 +50,11 @@ def validate_pr_body_text(text: str) -> list[str]:
|
|||||||
|
|
||||||
|
|
||||||
def fetch_pr_body(pr_number: int) -> str:
|
def fetch_pr_body(pr_number: int) -> str:
|
||||||
|
tea_binary = resolve_tea_binary()
|
||||||
try:
|
try:
|
||||||
completed = subprocess.run(
|
completed = subprocess.run(
|
||||||
[
|
[
|
||||||
"tea",
|
tea_binary,
|
||||||
"api",
|
"api",
|
||||||
"-R",
|
"-R",
|
||||||
"origin",
|
"origin",
|
||||||
@@ -41,7 +64,7 @@ def fetch_pr_body(pr_number: int) -> str:
|
|||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
)
|
)
|
||||||
except (subprocess.CalledProcessError, FileNotFoundError) as exc:
|
except (subprocess.CalledProcessError, FileNotFoundError, PermissionError) as exc:
|
||||||
raise RuntimeError(f"failed to fetch PR #{pr_number}: {exc}") from exc
|
raise RuntimeError(f"failed to fetch PR #{pr_number}: {exc}") from exc
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -24,9 +24,24 @@ def test_validate_pr_body_text_detects_escaped_newline() -> None:
|
|||||||
assert any("escaped newline" in err for err in errors)
|
assert any("escaped newline" in err for err in errors)
|
||||||
|
|
||||||
|
|
||||||
def test_validate_pr_body_text_allows_literal_sequence_when_multiline() -> None:
|
def test_validate_pr_body_text_detects_escaped_newline_in_multiline_body() -> None:
|
||||||
module = _load_module()
|
module = _load_module()
|
||||||
text = "## Summary\n- escaped sequence example: \\\\n"
|
text = "## Summary\n- first line\n- broken line with \\n literal"
|
||||||
|
errors = module.validate_pr_body_text(text)
|
||||||
|
assert any("escaped newline" in err for err in errors)
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate_pr_body_text_allows_escaped_newline_in_code_blocks() -> None:
|
||||||
|
module = _load_module()
|
||||||
|
text = "\n".join(
|
||||||
|
[
|
||||||
|
"## Summary",
|
||||||
|
"- example uses `\\n` for explanation",
|
||||||
|
"```bash",
|
||||||
|
"printf 'line1\\nline2\\n'",
|
||||||
|
"```",
|
||||||
|
]
|
||||||
|
)
|
||||||
assert module.validate_pr_body_text(text) == []
|
assert module.validate_pr_body_text(text) == []
|
||||||
|
|
||||||
|
|
||||||
@@ -63,12 +78,13 @@ def test_fetch_pr_body_reads_body_from_tea_api(monkeypatch) -> None:
|
|||||||
module = _load_module()
|
module = _load_module()
|
||||||
|
|
||||||
def fake_run(cmd, check, capture_output, text): # noqa: ANN001
|
def fake_run(cmd, check, capture_output, text): # noqa: ANN001
|
||||||
assert "tea" in cmd[0]
|
assert cmd[0] == "/tmp/tea-bin"
|
||||||
assert check is True
|
assert check is True
|
||||||
assert capture_output is True
|
assert capture_output is True
|
||||||
assert text is True
|
assert text is True
|
||||||
return SimpleNamespace(stdout=json.dumps({"body": "## Summary\n- item"}))
|
return SimpleNamespace(stdout=json.dumps({"body": "## Summary\n- item"}))
|
||||||
|
|
||||||
|
monkeypatch.setattr(module, "resolve_tea_binary", lambda: "/tmp/tea-bin")
|
||||||
monkeypatch.setattr(module.subprocess, "run", fake_run)
|
monkeypatch.setattr(module.subprocess, "run", fake_run)
|
||||||
assert module.fetch_pr_body(391) == "## Summary\n- item"
|
assert module.fetch_pr_body(391) == "## Summary\n- item"
|
||||||
|
|
||||||
@@ -79,6 +95,32 @@ def test_fetch_pr_body_rejects_non_string_body(monkeypatch) -> None:
|
|||||||
def fake_run(cmd, check, capture_output, text): # noqa: ANN001
|
def fake_run(cmd, check, capture_output, text): # noqa: ANN001
|
||||||
return SimpleNamespace(stdout=json.dumps({"body": 123}))
|
return SimpleNamespace(stdout=json.dumps({"body": 123}))
|
||||||
|
|
||||||
|
monkeypatch.setattr(module, "resolve_tea_binary", lambda: "/tmp/tea-bin")
|
||||||
monkeypatch.setattr(module.subprocess, "run", fake_run)
|
monkeypatch.setattr(module.subprocess, "run", fake_run)
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
module.fetch_pr_body(391)
|
module.fetch_pr_body(391)
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_tea_binary_falls_back_to_home_bin(monkeypatch, tmp_path) -> None:
|
||||||
|
module = _load_module()
|
||||||
|
tea_home = tmp_path / "bin" / "tea"
|
||||||
|
tea_home.parent.mkdir(parents=True)
|
||||||
|
tea_home.write_text("#!/usr/bin/env bash\n", encoding="utf-8")
|
||||||
|
tea_home.chmod(0o755)
|
||||||
|
|
||||||
|
monkeypatch.setattr(module.shutil, "which", lambda _: None)
|
||||||
|
monkeypatch.setattr(module.Path, "home", lambda: tmp_path)
|
||||||
|
assert module.resolve_tea_binary() == str(tea_home)
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_tea_binary_rejects_non_executable_home_bin(monkeypatch, tmp_path) -> None:
|
||||||
|
module = _load_module()
|
||||||
|
tea_home = tmp_path / "bin" / "tea"
|
||||||
|
tea_home.parent.mkdir(parents=True)
|
||||||
|
tea_home.write_text("not executable\n", encoding="utf-8")
|
||||||
|
tea_home.chmod(0o644)
|
||||||
|
|
||||||
|
monkeypatch.setattr(module.shutil, "which", lambda _: None)
|
||||||
|
monkeypatch.setattr(module.Path, "home", lambda: tmp_path)
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
|
module.resolve_tea_binary()
|
||||||
|
|||||||
Reference in New Issue
Block a user