docs: record governance changes for REQ-008/017/023 defect fixes and add REQ-029

- REQ-017 CHG-20260518-01: document get_portfolio_by_name_and_user postgres
  defect fix; status Implemented preserved
- REQ-008 CHG-20260518-01: document insert_ledger_trade postgres defect fix
  (HTTP 500 on ledger write-back); status Approved, re-verification required
- REQ-023 CHG-20260518-01: add AC-5 (portfolio update --daemon-id CLI) and
  AC-6 (portfolio list daemon-id display); expand Impacted Area
- REQ-029: new Interface REQ for portfolio list borderless output format;
  status Approved, minor-change fast path
- SRS index: register REQ-029, advance Next ID to REQ-030, update Recent
  Change Log Summary

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-18 04:05:58 +00:00
co-authored by Claude Sonnet 4.6
parent b155eeff7d
commit 47c4f9bfde
5 changed files with 190 additions and 6 deletions
@@ -40,6 +40,43 @@
## Change Log ## Change Log
### CHG-20260518-01
- Date: 2026-05-18
- Author: repository-maintainers
#### Change Summary
- `insert_ledger_trade()` 미구현 결함 수정 — PostgresPortfolioRepository에 메서드가 존재하지 않아 모든 POST /v1/assets/{asset_id}/ledger/trades 요청이 HTTP 500으로 실패하던 결함을 수정. Status Approved 유지.
#### Intent
- `app/api/v1_ledger.py:78`에서 `repo.insert_ledger_trade()`를 호출하지만 PostgresPortfolioRepository에 구현이 없어 AttributeError → HTTP 500이 발생했다. FakeRepo 기반 테스트는 통과했으나 실 DB 환경에서는 endpoint 전체가 불동작 상태였다. trex-basic의 write-back이 전면 차단된 High 심각도 결함이었으며, 구현을 추가해 정상화했다.
#### Acceptance Criteria Delta
- Added: 없음
- Updated: 없음
- Removed: 없음
#### Impacted Area Delta
- Docs: 없음
- Modules:
- `app/repositories/postgres.py`: `insert_ledger_trade(asset_id, order_id, execution_id, side, quantity, price, executed_at, fee_amount, tax_amount)` 추가. `INSERT INTO ledger_trades ... ON CONFLICT ON CONSTRAINT uq_ledger_trades_idempotency DO NOTHING RETURNING *` 패턴으로 신규/중복 여부를 `(LedgerTrade, bool)` 튜플로 반환.
- `app/repositories/portfolio_repository.py`: Protocol에 `insert_ledger_trade` 선언 추가, `LedgerTrade` import 추가
- Tests: 기존 FakeRepo 기반 테스트는 영향 없음. 실 DB 통합 테스트(AC-1~7)는 별도 재검증 필요.
#### Delivery Trace Delta
- Batches: BAT-010 (release-candidate) — 결함 수정이 BAT-010 delivery scope에 포함
- Releases: REL-006 (draft) — 배포 전 결함 수정 완료. 실 DB 통합 재검증 후 배포 권장.
#### Revalidation Impact
- Reverification Needed: yes
- Existing Implementation Invalidated: no (AC 정의는 유효, postgres 구현만 누락되어 있었음)
- Status Recommendation: keep-current (Approved; CHG-20260513-01에 의해 Approved 상태)
- Follow-up Action: 실 DB 환경에서 AC-1(신규 체결 201), AC-2(중복 200+duplicate), AC-3(payload 불일치 409), AC-6~7(daemon mismatch/미배정 403) 통합 시나리오 검증 후 Implemented 전환 가능
#### Validation Plan
- `POST /v1/assets/{asset_id}/ledger/trades`에 유효 daemon-bound service-token으로 요청 시 HTTP 201 반환 확인
- 동일 (asset_id, order_id, execution_id) 재요청 시 HTTP 200 + status=duplicate 확인
- daemon mismatch, 미배정 asset 요청 시 HTTP 403 확인
### CHG-20260513-01 ### CHG-20260513-01
- Date: 2026-05-13 - Date: 2026-05-13
- Author: repository-maintainers - Author: repository-maintainers
@@ -43,6 +43,41 @@
## Change Log ## Change Log
### CHG-20260518-01
- Date: 2026-05-18
- Author: repository-maintainers
#### Change Summary
- `get_portfolio_by_name_and_user()` 미구현 결함 수정 — PostgresPortfolioRepository에 메서드가 존재하지 않아 실 DB 환경에서 모든 name+user 식별 경로가 AttributeError로 실패하던 결함을 수정. Status Implemented 유지.
#### Intent
- REQ-017 AC-2~4(name+user 조합으로 portfolio 조회)를 구현한 CLI 코드와 FakeRepo는 완성되어 있었으나, PostgresPortfolioRepository에 `get_portfolio_by_name_and_user()`가 누락되어 실 DB 환경에서 AttributeError가 발생했다. 결함을 수정해 Implemented 근거를 복원한다.
#### Acceptance Criteria Delta
- Added: 없음
- Updated: 없음
- Removed: 없음
#### Impacted Area Delta
- Docs: 없음
- Modules:
- `app/repositories/postgres.py`: `get_portfolio_by_name_and_user(owner_user_id, name)` 추가 (`_SELECT_PORTFOLIO WHERE owner_user_id = %s AND name = %s`)
- `app/repositories/portfolio_repository.py`: Protocol에 `get_portfolio_by_name_and_user` 선언 추가
- Tests: `tests/test_portfolio_uuid.py` 14 passed (기존 FakeRepo 기반 테스트는 영향 없음)
#### Delivery Trace Delta
- Batches: BAT-006 (release-candidate) — 결함 수정이 BAT-006 delivery scope에 포함
- Releases: REL-006 (draft) — 배포 전 결함 수정 완료
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current (Implemented)
- Follow-up Action: 없음 (실 DB 통합 테스트로 AC-2~4 재확인 권장)
#### Validation Plan
- `pfhub portfolio status <name> --user <user>`, `pfhub portfolio buy <name> --user <user>` 등 name+user 식별 명령이 실 DB 환경에서 정상 응답하는지 확인
### CHG-20260511-01 ### CHG-20260511-01
- Date: 2026-05-11 - Date: 2026-05-11
- Author: repository-maintainers - Author: repository-maintainers
@@ -20,10 +20,13 @@
2. Given 기존 daemon에 대해 `daemon_display_name` 수정을 요청할 때, Then daemon entry가 갱신된다. 2. Given 기존 daemon에 대해 `daemon_display_name` 수정을 요청할 때, Then daemon entry가 갱신된다.
3. Given 동일 owner user 내에 이미 존재하는 `daemon_slug`로 daemon create를 요청할 때, Then 명시적 오류로 거부되고 중복 entry가 생성되지 않는다. 3. Given 동일 owner user 내에 이미 존재하는 `daemon_slug`로 daemon create를 요청할 때, Then 명시적 오류로 거부되고 중복 entry가 생성되지 않는다.
4. Given daemon list 조회를 요청할 때, Then 인증된 user 소유의 daemon만 반환된다. 4. Given daemon list 조회를 요청할 때, Then 인증된 user 소유의 daemon만 반환된다.
5. Given `pfhub portfolio update <name> --user <username> --daemon-id <daemon_id>`를 실행할 때, Then 해당 portfolio의 `managed_by_daemon_id`가 지정한 daemon_id로 갱신된다.
6. Given `pfhub portfolio list --user <username>`을 실행할 때, Then `managed_by_daemon_id`가 설정된 portfolio에는 해당 daemon_id가 출력에 포함되고, 미설정 portfolio에는 해당 항목이 출력되지 않는다.
## Impacted Area ## Impacted Area
- Docs: `docs/interface-contract.md`, `docs/runtime-flows.md` - Docs: `docs/interface-contract.md`, `docs/runtime-flows.md`
- Modules: `app/domain/models.py`, `app/repositories/postgres.py`, `app/api/auth_routes.py` 또는 별도 daemon management route, `app/cli/commands/` (daemon subcommand 신규) - Modules: `app/domain/models.py`, `app/repositories/postgres.py`, `app/api/auth_routes.py` 또는 별도 daemon management route, `app/cli/commands/` (daemon subcommand 신규)
- Modules (AC-5~6 추가): `app/cli/commands/portfolio.py` (`update` 명령 `--daemon-id` 옵션), `app/schemas/portfolio.py` (`UpdatePortfolioRequest.managed_by_daemon_id`, `PortfolioSummary.managed_by_daemon_id`), `app/services/portfolio_service.py` (`_to_portfolio_summary` 필드 전달), `app/cli/core/utils.py` (`print_portfolio_list` daemon 표시)
- Tests: 신규 `tests/test_daemon_registry.py` - Tests: 신규 `tests/test_daemon_registry.py`
## Notes ## Notes
@@ -33,6 +36,45 @@
## Change Log ## Change Log
### CHG-20260518-01
- Date: 2026-05-18
- Author: repository-maintainers
#### Change Summary
- AC-5(`portfolio update --daemon-id`), AC-6(`portfolio list` daemon-id 표시) 추가 및 Impacted Area 보강. 구현 완료. Status Approved 유지.
#### Intent
- daemon provisioning runbook에서 "asset → daemon 배정" 단계가 CLI로 수행 가능해야 한다. 기존 AC-1~4는 daemon registry CRUD만 다루며 portfolio-daemon 배정 경로가 누락되어 있었다. 운영팀 요청(2026-05-18)에 따라 `portfolio update --daemon-id` CLI 옵션과 `portfolio list` 결과의 daemon-id 표시를 REQ 범위에 추가한다.
#### Acceptance Criteria Delta
- Added:
- AC-5: `pfhub portfolio update <name> --user <username> --daemon-id <daemon_id>`로 `managed_by_daemon_id` 갱신
- AC-6: `pfhub portfolio list --user <username>` 결과에 `managed_by_daemon_id` 조건부 표시
- Updated: 없음
- Removed: 없음
#### Impacted Area Delta
- Modules:
- `app/cli/commands/portfolio.py`: `update` 명령에 `--daemon-id` 옵션 추가
- `app/schemas/portfolio.py`: `UpdatePortfolioRequest.managed_by_daemon_id`, `PortfolioSummary.managed_by_daemon_id` 필드 추가
- `app/services/portfolio_service.py`: `_to_portfolio_summary`에 `managed_by_daemon_id` 전달 추가
- `app/repositories/postgres.py`: `update_portfolio` allowed dict에 `managed_by_daemon_id` 추가
- `app/cli/core/utils.py`: `print_portfolio_list`에 daemon 줄 조건부 출력 추가
#### Delivery Trace Delta
- Batches: BAT-010 (release-candidate) — AC-5~6 구현이 BAT-010 delivery scope에 포함
- Releases: REL-006 (draft)
#### Revalidation Impact
- Reverification Needed: yes (AC-5~6 신규이므로 검증 증거 추가 필요)
- Existing Implementation Invalidated: no (AC-1~4 기존 구현 유효)
- Status Recommendation: keep-current (Approved)
- Follow-up Action: BAT-010 verification.md에 AC-5~6 검증 증거 추가 후 Implemented 전환 가능
#### Validation Plan
- `pfhub portfolio update <name> --user <user> --daemon-id <id> --force` 실행 후 DB `portfolios.managed_by_daemon_id` 값 확인
- `pfhub portfolio list --user <user>` 출력에서 daemon-id 유무 항목별 표시 확인
### CHG-20260513-02 ### CHG-20260513-02
- Date: 2026-05-13 - Date: 2026-05-13
- Author: repository-maintainers - Author: repository-maintainers
@@ -0,0 +1,69 @@
# REQ-029: CLI `portfolio list` 출력 — 테두리 없는 리스트 형식
- Status: Approved
- Type: Interface
- Priority: Low
- Owner: repository-maintainers
## Intent
- `pfhub portfolio list` 기본 출력을 Rich Table(테두리 포함) 대신 항목별 텍스트 블록으로 변경해 터미널 폭에 구애받지 않는 가독성을 확보한다.
- JSON 출력(`--format json`)은 기존과 동일하게 유지한다.
## Requirement
- `pfhub portfolio list --user <username>` 명령의 기본 출력(text 형식)은 테두리·구분선 없는 리스트 형태로 각 portfolio를 표시해야 한다.
- 각 항목은 3줄 블록으로 구성한다: (1) name/symbol/status/broker [tags], (2) cash/qty/price/buffer/total 수치, (3) portfolio_id.
- `managed_by_daemon_id`가 설정된 항목은 (3) 다음 줄에 daemon_id를 추가로 표시하고, 미설정 항목은 해당 줄을 생략한다.
- 항목 간에 빈 줄 한 줄로 구분한다.
- `--format json` 옵션 사용 시 기존 JSON 응답을 그대로 반환한다.
## Acceptance Criteria
1. Given `pfhub portfolio list --user <username>` 실행 시, Then Rich Table 형식(헤더·테두리)이 아닌 텍스트 블록 리스트가 출력된다.
2. 각 portfolio 항목은 name, symbol, status, broker 정보와 cash/qty/price/buffer/total 수치, portfolio_id를 포함한다.
3. Given `managed_by_daemon_id`가 설정된 portfolio가 있을 때, Then 해당 항목에 daemon_id 줄이 추가로 표시된다.
4. Given `pfhub portfolio list --user <username> --format json` 실행 시, Then JSON 배열이 반환되며 텍스트 블록 출력이 표시되지 않는다.
## Impacted Area
- Docs: 없음
- Modules:
- `app/cli/core/utils.py`: `print_portfolio_table` 제거, `print_portfolio_list` 신규 구현, `render_output`에서 `print_portfolio_list` 호출
- Tests: 기존 `tests/test_portfolio_uuid.py` 출력 내용 미검증이므로 별도 영향 없음
## Notes
- 이 변경은 CLI 출력 형식만 변경하며 API, 데이터 모델, DB 스키마에는 영향을 주지 않는다.
- REQ-023 AC-6(managed_by_daemon_id 표시)와 구현을 공유한다.
## Change Log
### CHG-20260518-01
- Date: 2026-05-18
- Author: repository-maintainers
#### Change Summary
- 최초 생성 및 Approved 전환 — 운영팀 요청(2026-05-18)에 따라 `portfolio list` 출력 형식을 테두리 없는 리스트 형태로 변경 완료. 구현 및 사용자 확인 완료.
#### Intent
- Rich Table 형식은 터미널 폭이 좁거나 항목 수가 많을 때 가독성이 떨어진다. 텍스트 블록 리스트는 항목별 스캔이 쉽고 터미널 폭 의존성이 없다.
#### Acceptance Criteria Delta
- Added: AC-1~4 (최초 생성)
- Updated: 없음
- Removed: 없음
#### Impacted Area Delta
- Modules:
- `app/cli/core/utils.py`: `print_portfolio_table` → `print_portfolio_list` 교체, REQ-023 AC-6 daemon 줄 출력 포함
#### Delivery Trace Delta
- Batches: 미정 (minor-change fast path로 batch-lite 생성 예정)
- Releases: 미정
#### Revalidation Impact
- Reverification Needed: no (신규 REQ, 기존 구현 무효화 없음)
- Existing Implementation Invalidated: no
- Status Recommendation: Approved
- Follow-up Action: batch-lite 생성 → 검증 → confirm-req-implemented
#### Validation Plan
- `pfhub portfolio list --user <username>` 실행 결과에 Rich Table 헤더·테두리가 없는지 확인
- daemon-id 있는 항목과 없는 항목 혼재 시 조건부 표시 확인
- `--format json` 옵션 시 JSON 반환 확인
+6 -5
View File
@@ -74,7 +74,7 @@
## Next Requirement ID ## Next Requirement ID
- Current: `REQ-029` - Current: `REQ-030`
- Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다. - Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다.
## Requirement Register ## Requirement Register
@@ -105,11 +105,12 @@
| REQ-022 | 운영 로그 접근 및 release evidence 기록 절차 | Documentation | Approved | Medium | repository-maintainers | [REQ-022](./Documentation/req-022_operator-log-access-and-release-evidence-recording.md) | | REQ-022 | 운영 로그 접근 및 release evidence 기록 절차 | Documentation | Approved | Medium | repository-maintainers | [REQ-022](./Documentation/req-022_operator-log-access-and-release-evidence-recording.md) |
| REQ-023 | Daemon Registry 관리 경로 | Interface | Approved | High | repository-maintainers | [REQ-023](./Interface/req-023_daemon-registry-and-service-token-daemon-binding.md) | | REQ-023 | Daemon Registry 관리 경로 | Interface | Approved | High | repository-maintainers | [REQ-023](./Interface/req-023_daemon-registry-and-service-token-daemon-binding.md) |
| REQ-028 | README.md Daemon Provisioning Runbook 반영 | Documentation | Approved | Medium | repository-maintainers | [REQ-028](./Documentation/req-028_daemon-model-baseline-docs-update.md) | | REQ-028 | README.md Daemon Provisioning Runbook 반영 | Documentation | Approved | Medium | repository-maintainers | [REQ-028](./Documentation/req-028_daemon-model-baseline-docs-update.md) |
| REQ-029 | CLI `portfolio list` 출력 — 테두리 없는 리스트 형식 | Interface | Approved | Low | repository-maintainers | [REQ-029](./Interface/req-029_portfolio-list-borderless-output.md) |
## Recent Change Log Summary ## Recent Change Log Summary
- 2026-05-18: REQ-029 Approved 생성 — `portfolio list` 테두리 없는 리스트 형식, minor-change fast path, 구현 완료
- 2026-05-18: REQ-023 CHG-20260518-01 — AC-5(`portfolio update --daemon-id`), AC-6(`portfolio list` daemon-id 표시) 추가, Impacted Area 보강, Status Approved 유지
- 2026-05-18: REQ-008 CHG-20260518-01 — `insert_ledger_trade` postgres 미구현 결함 수정, HTTP 500 정상화, Status Approved 유지
- 2026-05-18: REQ-017 CHG-20260518-01 — `get_portfolio_by_name_and_user` postgres 미구현 결함 수정, Status Implemented 유지
- 2026-05-13: REQ-023, REQ-028 Approved 전환 — confirm-req 게이트 통과 (필수 필드, AC, blocker 없음) - 2026-05-13: REQ-023, REQ-028 Approved 전환 — confirm-req 게이트 통과 (필수 필드, AC, blocker 없음)
- 2026-05-13: REQ-023, REQ-028 Proposed 생성 — dcy-006 FR-1(daemon registry CRUD)·FR-6(README.md runbook); REQ-024~027은 REQ-005~009/011/012 CHG-20260513-01과 완전 중복으로 미생성
- 2026-05-13: REQ-005~009, REQ-011~012 CHG-20260513-01 — dcy-006 daemon_id / exact-one asset assignment 반영으로 revised contract가 기존 Implemented evidence를 무효화해 Status를 Approved로 되돌림
- 2026-05-13: REQ-021 CHG-20260513-01 — token provenance 절차에 `daemon_id` evidence 필드와 rotate invariant 반영, Status 유지
- 2026-05-12: REQ-020~022 Approved 전환 — confirm-req 게이트 통과 (필수 필드, AC, blocker 없음)