Skip to content

feat(idd-close): Step 6.5 distribution sync chain detection (#45)#67

Merged
kiki830621 merged 6 commits intomainfrom
idd/45-feature-idd-close-should-chain-to-plugin
May 10, 2026
Merged

feat(idd-close): Step 6.5 distribution sync chain detection (#45)#67
kiki830621 merged 6 commits intomainfrom
idd/45-feature-idd-close-should-chain-to-plugin

Conversation

@kiki830621
Copy link
Copy Markdown
Contributor

Refs #45

Summary

/idd-close Step 6.5 — distribution-aware close-tier checkpoint that surfaces user-facing channel sync (plugin marketplace / MCP binary / CLI binary) at the moment the issue closes. Closes the gap where fixes land in main but marketplace.json doesn't bump, leaving users with stale binary on /plugin update.

Per Plan tier issue body Step 4.7 scope clarification: this PR is single-repo (PsychQuant/issue-driven-development). Cross-repo --source-issue flag in plugin-update / mcp-deploy / cli-deploy is deferred to a sister issue in psychquant-claude-plugins.

Changes (2 commits)

Files Changed

  • NEW plugins/issue-driven-dev/references/distribution-detection.md (+189) — canonical contract for is_plugin_marketplace_member / has_binary_wrapper / infer_distribution_type helpers + D3 superset rule + extension protocol + smoke fixture matrix
  • plugins/issue-driven-dev/skills/idd-close/SKILL.md (+128) — insert Step 6.5 between Step 6 and Step 7;Step 0.5 Bootstrap Task List adds distribution_sync_chain_detection entry

Plan tier highlights

Decision Resolution
D1 walk-up $REPO_ROOT$HOME (find_idd_config convention)
D2 keywords gh release download + curl.*github.com.*releases (extension hook in ref doc)
D3 mixed-type Chain plugin-update only — superset cascade per common-plugins.md (audit filed as #66)
D4 caller flag v1 no --source-issue flag (graceful;sister issue tracks caller-side)
D5 escape hatch env var IDD_DISTRIBUTION_SYNC_PROMPT=false silently skips prompt

Tangential filed

Checklist

  • Diagnose
  • Plan (Plan tier with EnterPlanMode approval gate)
  • Implement (2 commits)
  • Verify (run /idd-verify --pr <N>)
  • Pending: human review of this PR + /idd-close #45 after merge

🤖 Generated by /idd-implement on PR path. Do NOT add Closes #45 — IDD discipline requires manual /idd-close after merge to enforce checklist gate + closing summary.

… detection (Refs #45)

NEW reference doc covering:
- Detection helpers (is_plugin_marketplace_member, has_binary_wrapper, infer_distribution_type)
- D3 mixed-type superset rule (chain plugin-update only, contingent on #66 audit)
- Skill resolution table
- Escape hatch (IDD_DISTRIBUTION_SYNC_PROMPT=false env var)
- Extension protocol for unlisted distribution patterns
- Smoke matrix fixtures (manual until #62 test infra)

Per Plan tier #45 D1-D5 decisions. SKILL.md Step 6.5 in next commit will delegate to this contract.
…45)

Inserts Step 6.5 between Step 6 (auto-update phase=closed) and Step 7 (batch close):
- Detection delegated to references/distribution-detection.md canonical contract
- Silent skip path for non-distribution repos + IDD_DISTRIBUTION_SYNC_PROMPT=false env var
- AskUserQuestion 3-option as prose (per #47 P1 finding 2 — agent-level tool, not bash function)
- D3 superset table: plugin+mcp/cli → chain plugin-update only (Phase 1.5 cascade)
- Audit trail PATCH appends ### Distribution Sync section to closing comment regardless of choice
- Failure-mode summary covers gh api / parse / network failures

Step 0.5 Bootstrap Task List adds distribution_sync_chain_detection entry between
auto_update_body and report_result (per skill bootstrap rule: every step listed
in skill body MUST have a TaskCreate entry).

Per Plan tier #45 D1-D5 decisions:
- D1 walk-up to $HOME (find_idd_config convention)
- D2 keywords: gh release download / curl github releases (extension hook in ref doc)
- D3 mixed-type → plugin-update only (contingent on #66 audit)
- D4 v1 no --source-issue flag (graceful, sister issue tracks caller-side)
- D5 IDD_DISTRIBUTION_SYNC_PROMPT=false rollback hatch
…(Refs #45)

In-scope dependency caught during Step 5.7 sister bug sweep:
Step 6.5 PATCH references $CLOSING_COMMENT_ID expected to be set in Step 4,
but Step 4 was a fire-and-forget gh issue comment without URL capture.
Without this fix, Step 6.5 audit trail PATCH would fail with empty ID.

3-line addition: capture URL via tail -1 + extract numeric ID via sed regex.
No behavior change for non-distribution repos (Step 6.5 silent-skips before
PATCH path is reached).
@kiki830621
Copy link
Copy Markdown
Contributor Author

Verify Report — PR #67 (Round 1)

Engine

Codex CLI (gpt-5.5 xhigh) + Agent Team (regression + devil's advocate completed; requirements/logic/security hit Anthropic API usage limit reset 7:20pm Taipei — degraded mode but 3 independent sources converge)

Aggregate

FAIL — 5 P1 blocking findings, 4 P3 follow-up

The 3 reviewers (Codex / regression / devil's advocate) independently converge on the same critical finding: is_plugin_marketplace_member jq query targets a schema (.source.git object) that does not exist in any real marketplace.json — all 37 inspected plugins use "source": "./plugins/<name>" string form. Detection is silently dead.

Scope coverage

PR refs: #45, #66
Verified scope: #45 (primary), #66 (intentionally not addressed by this PR — confirmed correct)

Blocking findings (P1) — must fix before merge

# Severity Finding Source File
1 P1 is_plugin_marketplace_member jq query .plugins[]?.source.git targets non-existent schema. Real marketplace.json uses "source": "./plugins/<name>" string. jq error suppressed by 2>/dev/null → silent false return → detection dead-on-arrival for 100% of real plugin repos codex + regression + devils-advocate (P0/P1) references/distribution-detection.md:42-58 + idd-close/SKILL.md
2 P1 has_binary_wrapper regex gh release download|curl.*github\.com.*releases is line-anchored but real wrappers (e.g. che-apple-mail-mcp-wrapper.sh, agent-cacher) put GitHub URLs in API_URL= / asset_url= variable assignments and call curl "$VAR" on a separate line → regex misses entire dogfood ecosystem codex + devils-advocate references/distribution-detection.md:73
3 P1 infer_distribution_type and patch_closing_comment_append are referenced in SKILL.md Step 6.5 bash without being defined (only defined in references/distribution-detection.md as algorithm spec). Skill markdown calls them as if they exist — silent skip path fails first codex + devils-advocate (empirically confirmed: bash 127 error) idd-close/SKILL.md:485-516
4 P1 Step 4 closing comment ID capture gh issue comment ... 2>&1 | tail -1 mixes stderr into stdout — gh deprecation warnings interleave; sed regex without anchor returns input unchanged on no-match → CLOSING_COMMENT_ID becomes garbage URL → Step 6.5 PATCH 404s; pipeline exit status loss means failed gh issue comment doesn't abort codex + regression + devils-advocate idd-close/SKILL.md:407-411
5 P1 D3 superset rule (chain plugin-update only) ships without #66 audit verification. Plan explicitly stated audit must precede or accompany implementation, otherwise fall back to "chain both with explicit ordering". Risk: if common-plugins.md cascade claim is stale, mixed plugin+MCP repos see plugin shell sync without binary sync — exact anti-pattern #45 was designed to prevent codex + devils-advocate references/distribution-detection.md:122

P3 follow-up advisories (post-fix)

# Severity Finding Source Action
6 P3 exit 0 # proceed to Step 7 literal in markdown skill — bash exit terminates shell, not "proceed to Step 7". Replace with agent-level prose branching or wrap in helper that returns codex + devils-advocate + regression Refactor when re-implementing Step 6.5
7 P3 Audit heading inconsistency: option text says ### Distribution Sync Pending / ### Distribution Sync — Not Applicable, actual PATCH always uses ### Distribution Sync — reduces archaeology scannability codex Align option labels to actual heading
8 P3 Smoke matrix has 8 cases but none actually executed. Case 4 (this very repo → n/a) is verifiable now; current "n/a" pass-through is wrong reason (jq error, not legitimate non-distribution) devils-advocate (#1.d) Run smoke after F1 fix to confirm
9 P3 $REPO_ROOT == $HOME edge case: walk-up loop never enters → false negative for repos cloned directly to $HOME; endswith($repo) no slash boundary → false-positive risk on org names with substring devils-advocate (#1.a, #1.b) Add / boundary; check $HOME itself

Devil's Advocate WITHSTOOD

  • MCP-vs-CLI heuristic regex (-mcp-wrapper\.sh$|/[^/]*mcp[^/]*\.sh$): all 13 real PsychQuant MCP wrappers correctly classified as MCP ✓ (one false-positive: test-wrapper-pid.sh → cli, expected for non-MCP test fixture)

Scope check

Engine degradation note

3 of 5 Claude reviewers (requirements / logic / security) hit Anthropic API usage limit (resets 7:20pm Taipei) and produced empty findings files. This verify ran with 3 independent sources instead of 6 (Codex + regression + devil's advocate). The 3 sources nonetheless converge strongly on the same P1 findings — verify discipline preserved despite degraded ensemble. Re-running full 6-AI ensemble after fixes ship is recommended for full Plan tier coverage.

Next: in-scope fixes + re-verify

The 5 P1 findings are all in-scope (correctness fixes for #45's own deliverable, not separate concerns). Fix path:

  1. Fix F1: rewrite is_plugin_marketplace_member to handle source string form
  2. Fix F2: extend has_binary_wrapper to match URL patterns anywhere in file (not line-anchored grep)
  3. Fix F3: define helpers inline in SKILL.md Step 6.5 (or have skill explicitly source the contract)
  4. Fix F4: replace Step 4 capture with set -e-friendly form, validate ID with sed -n + p (no fallback to garbage)
  5. Address F5: change D3 default to "chain both with explicit ordering" UNTIL [bug] Verify common-plugins.md plugin-update Phase 1.5 cascade claim (mid-plan tangential from #45) #66 audit completes (safer fallback; D3 superset becomes v2 when audit confirms)

Re-verify with full 6-AI when usage limit resets.

Round 1 verify (3-source convergence: Codex + regression + devil's advocate)
flagged 5 P1 blocking findings. All 5 fixed in this round:

F1 — marketplace.json schema mismatch (P0/P1):
  Real schema is "source": "./plugins/X" string, not {"git": "..."} object.
  Updated is_plugin_marketplace_member to:
  - parse plugins[].source as string (with select(type=="string") guard)
  - resolve relative to manifest dir + canonicalize via pwd -P
  - match if plugin_dir == repo_root OR plugin_dir is inside repo_root tree
  Empirically validated 5/5 cases including dogfood (this very repo → plugin).

F2 — wrapper regex misses real-world wrappers (P0/P1):
  Real wrappers (che-apple-mail-mcp, agent-cacher) construct GitHub URLs in
  variables (API_URL=, asset_url=) and call curl/gh api on a separate line.
  Old regex was line-anchored. New pattern matches anywhere in bin/*.sh:
    gh release download | gh api .* /releases | api.github.com/.*/releases
    | github.com/.*/releases/(download|tags|latest)
  Validated against 13 PsychQuant MCP wrappers + agent-cacher CLI wrapper.

F3 — helpers undefined when called (P1):
  Step 6.5 SKILL.md called infer_distribution_type and patch_closing_comment_append
  but defs lived only in references/distribution-detection.md. Inlined helpers
  inside Step 6.5 detection block, BEFORE first call. Removed duplicate def
  in audit trail section (now references the inlined version).

F4 — Step 4 closing comment ID capture brittle (P1):
  Old: `gh issue comment ... 2>&1 | tail -1` mixed stderr into stdout;
       sed without -n returned input unchanged on no-match → silent corruption.
  New: capture stdout-only with || abort on gh failure;
       use sed -nE '...p' to print only on match;
       explicit empty-check with abort.

F5 — D3 superset rule unverified (P1):
  Plan/contract claimed "chain plugin-update only" relying on Phase 1.5 cascade
  per common-plugins.md (filed #66 to audit empirically). Until #66 confirms,
  v1 default is "chain both with explicit ordering" (binary-deploy first, then
  plugin-update). Idempotent regardless of cascade behavior. v2 superset rule
  pending #66.

Bonus fixes:
- F6 (P3): replaced `exit 0  # proceed to Step 7` literal bash exit (which
  would terminate close skill) with agent-level branching prose comment.
-  == /Users/che edge case fixed via do-while-style loop.
- Symlink resolution via `pwd -P` for /Users vs /private/var on macOS.
…oc consistency (Refs #45)

Round 2 verify caught 2 NEW P1 introduced by round-2 + 2 PARTIAL doc inconsistencies:

NEW-P1-1: REPO_ROOT undefined causing infinite loop / false positive on legacy repos
  - idd-close didn't define REPO_ROOT before Step 6.5 detection invocation
  - Empty string triggered: cd "" succeeds → resolved_root='', dirname '.' loops forever
  - Fix: Step 6.5 prelude resolves via 'git rev-parse --show-toplevel' (fallback pwd)
  - If unresolvable (not in git tree), audit-skip with explicit reason + advance to Step 7

NEW-P1-2: SKILL_NAME / plugin name not mechanically resolved → audit refs undefined var
  - Old code referenced $SKILL_NAME but never set it from helper output
  - is_plugin_marketplace_member returned only boolean — no name extraction
  - Fix: NEW resolve_plugin_name() helper returns matched plugin's .name field
  - Detection invocation now sets PLUGIN_NAME for plugin/plugin+* types
  - Composes $CHAIN_DESC table-driven from (DISTRIBUTION_TYPE, PLUGIN_NAME) before AskUserQuestion
  - If type=plugin* but PLUGIN_NAME unresolvable → demote to n/a (avoid malformed chain)
  - Replaces $SKILL_NAME with $CHAIN_DESC throughout audit/AskUserQuestion blocks

PARTIAL-1: Top-level summary table still said "plugins[].source.git" (object schema)
  - Fix: row 17 now says "plugins[].source (string \"./plugins/<name>\")"
  - row 18 'mcp' detection signal updated to enumerate broadened pattern
  - Mixed types now show explicit ordering chain (D3 v1) instead of plugin-update only

PARTIAL-2: Failure-mode summary claimed marketplace.json malformed → audit error
  - jq 2>/dev/null swallowed parse errors → no error audit fired
  - Fix: clarify behavior is "demote to n/a + WARN to stderr";simpler audit schema

Smoke validated round-3:
- resolve_plugin_name correctly returns 'issue-driven-dev' for this repo, 'che-apple-mail-mcp'
  for plugin dir, empty for che-claude-config (not a plugin), first match for monorepo host
- REPO_ROOT git rev-parse works in-tree;pwd fallback for non-git contexts
@kiki830621
Copy link
Copy Markdown
Contributor Author

Verify Report — PR #67 (Round 3)

Engine

Codex CLI (gpt-5.5 xhigh) standalone — Anthropic Claude reviewers continue to be limit-blocked (resets 7:20pm Taipei). Convergent multi-round trace:

  • Round 1: 3 sources (Codex + regression + devil's advocate) → 5 P1 blocking
  • Round 2: 1 source (Codex) → 3/5 fixed + 2 PARTIAL + 2 NEW P1 introduced
  • Round 3: 1 source (Codex) → all NEW P1 + PARTIAL fixed → PASS

Aggregate

PASS — 0 P1 blocking, 3 minor doc-drift advisories

Round-3 commit 3ba6ad1 resolved all P1 findings. Empirical smoke validated detection (5/5 cases) + plugin name resolution (4/4 cases).

Per-fix verdict (round-3)

Round-2 NEW finding Verdict Evidence
NEW-P1-1 REPO_ROOT undefined → infinite loop PASS Step 6.5 prelude resolves via git rev-parse --show-toplevel || pwd + audit-skip if unresolvable
NEW-P1-2 SKILL_NAME unresolved → undefined var refs PASS NEW resolve_plugin_name helper + PLUGIN_NAME set in Detection invocation + CHAIN_DESC composed table-driven from (DISTRIBUTION_TYPE, PLUGIN_NAME)
PARTIAL-1 schema header drift PASS Top summary table line 17 now says plugins[].source string form
PARTIAL-2 D3 summary mixed types PASS All locations consistent: binary-deploy first → plugin-update second
PARTIAL-3 failure-mode summary PASS w/ minor drift Aligned with implementation (REPO_ROOT row example slightly imprecise — see advisory below)

Round-3 new advisories (non-blocking, P3)

# Severity Finding Action
A1 P3 doc drift Failure-mode row "REPO_ROOT cannot be resolved (e.g. not in git work tree)" — actually pwd fallback covers non-git case;the unresolvable branch fires only when pwd itself fails (rare) Tighten example phrasing in failure-mode table
A2 P3 known limit Monorepo host (e.g. psychquant-claude-plugins with 37 plugins) returns FIRST plugin in marketplace.json order — not user-disambiguated v1 acceptable;v2 improvement: detect multi-match and AskUserQuestion or use git diff changed-files heuristic
A3 P3 doc internal Reference doc "Extension protocol" section contradicts itself: says "Don't edit SKILL.md" then "edit inline implementation in SKILL.md" Reconcile text

Empirical smoke validation (round-3)

=== Detection cases (5/5 PASS) ===
issue-driven-development        → plugin       ✓
che-apple-mail-mcp plugin dir   → plugin+mcp   ✓
psychquant-claude-plugins host  → plugin       ✓
agent-cacher plugin dir         → plugin+mcp   ✓
che-claude-config (non-plugin)  → n/a          ✓

=== Plugin name resolution (4/4 PASS) ===
issue-driven-development        → "issue-driven-dev"   ✓
che-apple-mail-mcp              → "che-apple-mail-mcp" ✓
psychquant-claude-plugins host  → "mcp-tools" (first)  ✓ (v1 known limit, A2 advisory)
che-claude-config               → "" (empty)           ✓

=== REPO_ROOT init (2/2 PASS) ===
in git tree                     → /Users/che/Developer/issue-driven-development ✓
outside git (e.g. /tmp)         → /tmp (pwd fallback)                            ✓

Engine note (degraded mode)

Anthropic API limit blocked 5-Claude-reviewer team across all 3 verify rounds. Codex CLI (gpt-5.5 xhigh, independent OpenAI infra) carried all 3 rounds. Round 1 also had regression + devil's advocate complete before limit triggered (3 sources convergent on initial findings). Plan tier ideal would re-run full 6-AI after limit resets — but Codex's track record across 3 iterations (caught 5 P1 + 2 NEW P1 + verified all fixes) demonstrates the verification discipline survives degraded engine.

Scope check

  • ✅ All commits use Refs #45
  • ✅ No Closes trailer (per IDD discipline)
  • ✅ 4 commits total: 0c7431a (docs) + 4765092 (Step 6.5 v1) + 023748c (Step 4 capture) + 133354c (round-2 fix) + 3ba6ad1 (round-3 fix)
  • ✅ No scope creep observed across all 3 rounds
  • ✅ Cross-skill ripple clean

Next: triage 3 P3 advisories + merge decision

Per Step 5b (mandatory triage):

  • A1 doc-drift: cosmetic, can fix in this PR or follow-up
  • A2 monorepo limit: v2 improvement, should file follow-up
  • A3 reference doc contradiction: cosmetic, can fix here

After triage: PR ready for human review + merge + /idd-close #45.

A1 — failure-mode REPO_ROOT row: clarify pwd fallback covers non-git case;
     unresolvable branch fires only when both git rev-parse AND pwd fail.
A3 — Extension protocol: removed contradiction ("Don't edit SKILL.md" vs
     "edit inline implementation in SKILL.md"). Now correctly states
     two-location update is required since skills don't source reference
     markdown at runtime.

A2 monorepo host disambiguation filed as #68 follow-up (out-of-scope here).
@kiki830621 kiki830621 merged commit 566741c into main May 10, 2026
@kiki830621 kiki830621 deleted the idd/45-feature-idd-close-should-chain-to-plugin branch May 10, 2026 12:02
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