tickets: consider rejecting outside-repository operands in StoreCommitter
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 49/100
Hướng nghiên cứu
Read src/bmad_loop/ticketstore.py, especially StoreCommitter.commit and _foreign, alongside verify.commit_paths to understand the existing path handling. Check the engine’s use of the commit result in tickets_engine.py and the tests covering store commits. Done means outside-repository operands raise a typed error while an unchanged plan can still return sha=None.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary
StoreCommitter currently inherits verify.commit_paths' documented behavior of ignoring outside-repository operands. A direct call with only such an operand returns StoreCommit(sha=None, foreign=()), while a modified plan elsewhere in the store stays dirty. Consider rejecting these operands at the store-commit boundary as defensive validation. An operator-visible lost store commit has not been reproduced.
What was measured
- Observed: at the symbol level,
StoreCommitter.commitreturnsStoreCommit(sha=None, foreign=())with no error when the path it is given lies outside the store repository, and the store's plan stays modified (3/3 runs). The control (the same change, with the path inside the store) commits (3/3). - Source-derived, not observed: if an outside operand reaches
TicketsEngine._store_commit, itsStoreCommit(sha=None, foreign=())result is journaled asstore-committedand treated as settled. The caller then clears pending fields. No supported run reaching that condition has been demonstrated. - No supported operator trigger is established. Moving an external store and changing its configuration is expected to hit the documented changed-topology refusal before replay (
cli.py:4976-4985;ticketstore.py:279-314). A live move/resume scenario was not run. - A
sha=Noneresult is also the legitimate answer for an unchanged plan (measured: the same committer called again on an already-committed plan returnssha=Noneand the store stays clean), soNonealone cannot be treated as a failure.
Environment
bmad-loop a5a8f097, Windows 11 10.0.26200, PowerShell 7.6.6 (SHELL unset), Python 3.13.2, git 2.49.0.windows.1; pure call, no session; Linux: not measured.
Steps to reproduce (symbol level)
From a bmad-loop checkout at a5a8f097 after uv sync --all-extras, in PowerShell 7 with SHELL removed: Remove-Item Env:SHELL -ErrorAction SilentlyContinue; $env:PYTHONUTF8 = '1', save the script as repro_store_outside.py, then run uv run python repro_store_outside.py outside and uv run python repro_store_outside.py inside (control).
import os, subprocess, sys, tempfile
from pathlib import Path
from bmad_loop import ticketstore
mode = sys.argv[1]
root = Path(tempfile.mkdtemp(prefix="store-outside-"))
git = lambda cwd, *a: subprocess.run(["git", "-C", str(cwd), *a], capture_output=True, text=True, check=True).stdout.strip()
store = root / "store"
store.mkdir()
git(store, "init", "-q", "-b", "main"); git(store, "config", "user.email", "t@t"); git(store, "config", "user.name", "t")
(store / "plan.md").write_text("---\nstatus: built\n---\n", encoding="utf-8")
git(store, "add", "-A"); git(store, "commit", "-q", "-m", "init")
inside = store / "plan.md"
inside.write_text("---\nstatus: done\n---\n", encoding="utf-8") # the mark the run owes a commit for
outside = root / "old-store-location" / "plan.md" # a recorded path no longer inside the store
outside.parent.mkdir(); outside.write_text("---\nstatus: done\n---\n", encoding="utf-8")
res = ticketstore.StoreCommitter(store, root).commit("1.1", [outside if mode == "outside" else inside], "chore(tickets): 1.1 done")
print(f"{mode} -> {res}")
print("store HEAD:", git(store, "log", "--oneline", "-1"), "| store status:", git(store, "status", "--porcelain") or "(clean)")
Observed (Windows, 3 of 3 runs, hashes elided):
outside -> StoreCommit(sha=None, foreign=())
store HEAD: <sha> init | store status: M plan.md
inside -> StoreCommit(sha='<sha>', foreign=())
store HEAD: <sha> chore(tickets): 1.1 done | store status: (clean)
Expected vs actual
| actual | proposed (contract change, not an established requirement) | |
|---|---|---|
StoreCommitter.commit given a path outside the store repo |
sha=None, no error; if this reached the engine, it would journal store-committed commit=None and clear the owed latch (source-derived, conditional) |
a typed failure (StoreCommitError), so a caller's commit would stay owed |
Source
At a5a8f097. src/bmad_loop/ticketstore.py:688-695 (StoreCommitter._foreign) skips the path: except ValueError: continue # outside the store: commit_paths ignores it too. :684 returns StoreCommit(verify.commit_paths(repo, body, paths)), and verify.commit_paths (verify.py:11020-11025) documents "Returns … None when the given paths had no changes to commit. Paths outside the repo are ignored"; verify.py:11084-11096 implements that containment check, so the outside path is filtered before git receives its pathspec. The engine (tickets_engine.py:1801-1813, source-derived): self.journal.append("store-committed", story_key=key, commit=result.sha); return True, and tickets_engine.py:1746-1751 then clears the pending fields and saves. The resume path refuses a changed store topology (ticketstore.py:279-314, called from cli.py:4976-4985), and runs.py:4522-4535 leaves a T4 store outside the recorded project unchanged when rebasing.
Suggested fix
Not validated: in StoreCommitter.commit, refuse (raise StoreCommitError) when any path does not resolve inside store_repo, instead of letting commit_paths drop it. Keep the legitimate sha=None answer for an unchanged plan.
- Ngôn ngữ chính
- Python
- Star
- 160
- Fork
- 68
- Merge trung bình
- 1 ngày 6 giờ
- Pull request đã merge (30 ngày)
- 90
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của bmad-code-org/bmad-loop
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 69/100
bmad-code-org/bmad-loop#973 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
bmad-code-org/bmad-loop#965 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
bmad-code-org/bmad-loop#835 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area:adapters area:psmux bug P4
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
bmad-code-org/bmad-loop#673 · 8 bình luận · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
tickets: an injected plan_halt result for a built plan escalates with stopped-attempt wordingĐang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 36/100
bmad-code-org/bmad-loop#972 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của bmad-code-org/bmad-loop
Issue tương tự
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
anchore/grype-db#1149 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[Bug]: `hermes plugins update` clones an entire monorepo twice - `subdir` is resolved but dropped at both catalog-update call sitesCó thể đã có người làm @HootRock đã nhận hôm nay. Đang mởcomp/cli P2 type/perf
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
NousResearch/hermes-agent#142417 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
SMC SPEC
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
tenstorrent/tt-oca-harness#3287 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug enhancement python
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
DewaldOosthuizen/tech-cheat-sheets-and-notes#392 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Critical advisories on mainĐang mởsecurity
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
fabriziosalmi/wildbox#801 ·
Maintainer thường phản hồi trong vòng 1 ngày