Skip to content

feat: spec_archive lets a code repository without a remote pass the spec archive gate on its local branch (#547) - #555

Merged
kiki830621 merged 13 commits into
mainfrom
idd/547-idd-close-spec-archive-gate-spec-archive
Nov 14, 2026
Merged

kiki830621 merged 13 commits into
mainfrom
idd/547-idd-close-spec-archive-gate-spec-archive

Conversation

@kiki830621

Copy link
Copy Markdown
Member

Refs #547
Refs #546

Summary

程式 repo 刻意沒有任何 remote、issue 開在另一個有 remote 的 repo 時,宣告了 Spectra change 的 issue 都卡在 /idd-close Step 1.57(它一律 fetch 遠端的預設 branch)。這個 PR 加一個明確打開的設定,不做自動判斷。

  • IDD 設定的 spec_archive 欄位:以程式 repo 主工作樹相對於設定檔目錄的路徑為 key,值為 {"ref": "local", "branch": "<name>"}。只在程式 repo 沒有任何 remote(url、pushurl、vcs、舊式 remotes/branches 檔)時接受;有 remote 卻設了是 error。沒設欄位的 repo 行為不變。
  • spec-change.py 新增 archive-ref(這個 repo 讀哪個 branch)與 link-base(本機模式的連結檢查起點:baseline tag,否則第一個引用 #N 或 issue repo 的 owner/repo#N 的 commit 的父 commit)。
  • idd-close Step 1.57 在本機模式讀 refs/heads/<branch>,印出 local ref <branch>@<commit>;Step 1.5 帶 check-existing-work.sh --skip-branches,open PR 照樣在 issue repo 查。references/spec-wrapper.md 第 5 步的起點改由 link-base 給。
  • 沒有 remote 又沒有條目的 repo 改成停下、不 fetch(原本 git 會把名為 origin 的本機路徑當成 remote)。
  • 順帶修正:spec-change.py 讀 top level 時會去掉結尾的空白,讀到同名的兄弟目錄(idd-close spec archive gate:加 spec_archive 設定,讓刻意沒有 remote 的程式 repo 以本機預設 branch 判定封存 #547 之前就有)。
  • 規格:spec-on-every-issue、idd-existing-work-lookup;四個 Spectra change 已封存(idd-547-spec-archive-local、-fix1、-fix2、-fix3)。文件:config-protocol.md 新增 spec_archive 一節,CHANGELOG 的 Unreleased。

verify 跑了三輪,每輪都 FAIL,修正見 issue 上的三則 Implementation Complete;範圍外的改進合成 #552。

Test plan

  • run-all-tests.sh:75 個 suite 全過(本機)
  • 新測試先在舊程式上確認失敗(spec-archive-local、spec-close-gate、check-existing-work、step 5 的區塊)
  • spec-change.py links --base <merge-base>:ok;archived --ref HEAD:pass
  • 在實際的「issue repo 底下放一個沒有 remote 的程式 repo」佈局上,唯讀執行 Step 1.5 與 1.57:讀本機 branch、沒有 fetch
  • CI
  • 第 4 輪 verify

🤖 Generated with Claude Code

kiki830621 and others added 12 commits November 14, 2026 09:52
…cal branch (#547)

The IDD configuration takes spec_archive, mapping a code repository's path to
{"ref": "local", "branch": "<name>"}. idd-close Step 1.57 then checks the archive on
that branch instead of fetching, Step 1.5 skips the branch lookup
(check-existing-work.sh --skip-branches), and the link check of spec-wrapper.md
step 5 starts at the issue's baseline. Accepted only while the repository has no
remote. New spec-change.py subcommands archive-ref and link-base.

Refs #547

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #547

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #547

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nch names only, link-base reads the config first (#547)

archive-ref: a configuration that cannot be read as a JSON object counts as having no
entry (remote, with the reason), so a repository that never set spec_archive is not
blocked; a UTF-8 BOM is read; two keys naming one path are an error; the branch must be
a branch name; a remote means a remote URL; a linked worktree uses its main working
tree's key; the walk-up does not read /. link-base resolves the configuration before
reading --issue, uses the pr-issue-matching guards, auto_tag.baseline_format and NUL
separated log records. check-existing-work refuses a repeated --cwd. idd-close Step 1.57
carries archive-ref's reason into a failed fetch and no longer prints the config path;
spec-wrapper step 5 takes NUMBER or N. Tests pin the configured branch over HEAD and the
--skip-branches hand-off.

Refs #547

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #547

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ory, no fallback to ., signature-proof log (#547)

link-base also counts the issue repository's own owner/repo#N (github_repo of the
configuration): a separate code repository names its issues that way, and the
pr-issue-matching left guard alone never found a base for this layout. git log runs
with --no-show-signature and "--", and every id it reads must be hexadecimal. A
baseline tag on HEAD itself is skipped. archive-ref no longer falls back to "." when the
repository's path cannot be a key, counts pushurl-only and legacy remotes, keys a
--separate-git-dir repository by its top level, keeps a trailing space in a path, refuses
a key written twice, and names the configuration relative to the repository. idd-close
and spec-wrapper read JSON with python3 -I and label archive-ref's reasons as such.
Tests run the step-5 block, log the git calls behind --skip-branches, and check the
reasons.

Refs #547

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #547

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tes found while parsing, no guessed key for a separate-git-dir worktree (#547)

- archive-ref: every remote answer carries has_remote; idd-close Step 1.57 and spec-wrapper step 5
  fetch only when it is true (git would read a local path named origin as the remote)
- duplicate keys recorded on the parsed objects (top-level spec_archive, its keys, the matching
  entry's keys), so no key in the file can imitate one; "spec_archive": null is no field
- a remote counts when it has a url, a pushurl or a vcs
- main working tree from git worktree list; a linked worktree of a --separate-git-dir repository,
  whose main working tree git does not record, gets no entry instead of a guessed key
- link-base reads git log in UTF-8 whatever i18n.logOutputEncoding says
- check-existing-work --skip-branches no longer looks up the default branch (no origin/HEAD read)
- step 5 error label link-base:; docstring, config-protocol, CHANGELOG
- tests: Example rows for each, detail assertions for three earlier rows, a top level ending in a space

Refs #547

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s line ending goes, step 5 remote path tested (#547)

- remotes_of: a url, pushurl or vcs counts when the key is set, whatever its value (blank or empty url)
- one_line(): paths git prints lose only the one line ending git appends (a name may end in a newline)
- main_tree reason names both cases git does not record (separate git dir not named .git, a submodule);
  spec and config-protocol state the .git-named and bare cases as they behave
- spec: fetch only when has_remote is exactly true, in both requirements; step 5 adds link-base's reason
  when the fetch fails
- tests: blank and empty url, a top level ending in a newline, bare main, .git-named separate git dir,
  detail assertions for the rows that checked status only, step 5's remote path run as written
  (fails on a never-fetch mutation)
- link-base docstring, config-protocol, CHANGELOG

Refs #547

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kiki830621
kiki830621 merged commit d42cf15 into main Nov 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant