Skip to content

cluster: 4 refactor/docs follow-ups from #49 / #60 IDD lifecycles#72

Open
kiki830621 wants to merge 6 commits into
mainfrom
idd/cluster-refactor-archive-plugin-update
Open

cluster: 4 refactor/docs follow-ups from #49 / #60 IDD lifecycles#72
kiki830621 wants to merge 6 commits into
mainfrom
idd/cluster-refactor-archive-plugin-update

Conversation

@kiki830621
Copy link
Copy Markdown
Collaborator

Refs #56 #57 #68 #70

Summary

Cluster of 4 refactor / docs follow-ups surfaced from /idd-verify security & sister-bug review of #49 (archive-mail) + #60 (plugin-update). All P3/LOW priority defensive hardening — no behavior change, just invariant markers, null-safe hygiene, and audit-trail comments to forestall future false-positive reviews.

Cluster overview

# Type Scope Commit
#56 refactor archive-mail Step 2.1 read-only invariant marker 3b01d3f
#57 fix archive-mail Step 2.1 null-safe find/while (both finds) 5b610cd
#68 docs plugin-update Phase 1.5/2.5 default-option policy alignment with Phase 0.5 f25621e
#70 docs plugin-update Phase 0.5 Step 5 tempfile-avoidance invariant comment ac3c673

Per-issue rationale

#56 — archive-mail Step 2.1 read-only invariant marker

Sister-bug from #49 implementation: Step 2.1 sibling-archive-dir dedup extension reads symlinked subdir markdown frontmatter for message_id: dedup. Block must remain read-only w.r.t. $symlink_dir to preserve immutability invariant. Add invariant marker comment listing allowed (find / head / awk / cat / grep) vs forbidden (mv / rm / cp / > / >> / tee / chmod) operations against $symlink_dir or its target. Future trap-based check + pre-commit scan deferred — comment is the load-bearing contract.

#57 — archive-mail Step 2.1 null-safe find/while loops

Per /idd-verify #49 security LOW#1: outer find ... | while IFS= read -r symlink_dir and inner find ... | while IFS= read -r mdfile split on newlines. Filenames containing newlines (POSIX-legal, rare in practice) silently mis-parse — partial filename gets processed.

Apply standard null-safe pattern to both: -print0 | while IFS= read -r -d ''. Both must change together — partial conversion mis-parses pipeline.

Realistic exposure low (Apple Mail subject lines don't contain raw newlines), but trivial defensive hygiene fix.

#68 — Phase 1.5/2.5 default-option policy clarification

Sister concern from #60 implementation: Phase 0.5 enforces abort-default safety policy for ambiguous git states, but Phase 1.5 (順便更新) and Phase 2.5 (更新 README) both have action-defaults. Audit conclusion: NOT a divergence — both correctly apply Phase 0.5 rule's exception clause:

"active default is reserved for unambiguous happy-path / reversible action / frequent dev flow"

Phase 1.5: binary sync in dev flow IS unambiguous happy path; binary install reversible. Phase 2.5: '更新 README' option proposes diff (read CHANGELOG → draft → user reviews → commit), doesn't mutate; user-confirmation gate intact, reversible draft. Phase 0.5 (release-time push to public marketplace) is irreversible → abort default warranted.

No behavior change — documentation that the deliberate divergence IS correct application of Phase 0.5 rule.

#70 — Phase 0.5 Step 5 tempfile-avoidance comment

Per /idd-verify #60 security LOW (DA→LOW): finding L233 flagged /tmp/touched-plugins.txt race / TOCTOU. Audit found the flagged tempfile DOES NOT EXIST — Phase 0.5 Step 5 already uses inline subshell TOUCHED=$(git log ...) which captures to process-local variable, never touches /tmp.

False-positive verify finding. Add load-bearing comment documenting: (1) why current code is safe (inline subshell, not tempfile), (2) if future refactor needs persistence, use mktemp + trap pattern, (3) hardcoded /tmp/touched-plugins.txt is FORBIDDEN. Forestalls re-flagging by future audits.

Verify checklist


Generated by /idd-implement #56 #57 #68 #70 --pr cluster-PR mode. Do NOT add Closes #N trailers — IDD discipline requires manual /idd-close per issue after merge to enforce checklist gate + per-issue closing summary.

…p 2.1 (Refs #56)

Per /idd-verify #49 DA new finding: Step 2.1 sibling-archive dedup
extension claims 'read-only' but enforcement is honor-system (current
bash uses only find/head/awk; future maintainer adding mv/rm wouldn't
be caught by any guard).

Option A per issue body — invariant marker comment at top of bash block:
- Lists allowed ops (find / head / awk / cat / grep)
- Lists forbidden ops (mv / rm / cp / > / >> / tee / chmod)
- Self-documenting, load-bearing contract for future maintainers

Option B (bash trap-based check) + Option C (pre-commit hook scanning)
deferred — requires real bash impl file or repo-level tooling, both
out of scope for this docs-only fix.

Refs #56
Per /idd-verify #49 security review LOW#1: Step 2.1 sibling-archive
dedup extension used 'find ... | while IFS= read -r' which splits
on newlines. Filenames containing newlines (POSIX-legal, rare in
practice) would silently mis-parse — partial filename gets processed.

Apply standard null-safe pattern to BOTH find invocations:
- Outer: find -P -type l -print0 + while read -r -d '' symlink_dir
- Inner: find -P -name '*.md' -print0 + while read -r -d '' mdfile

Both -print0 / read -d '' must change together — partial conversion
of one without the other would mis-parse the pipeline.

Realistic exposure low (Apple Mail subject lines don't contain raw
newlines), but trivial defensive hygiene fix.

Refs #57
…nment with Phase 0.5 (Refs #68)

Per /idd-implement #60 Step 5.7 sister bug sweep: audit found Phase 1.5
(action default '順便更新') + Phase 2.5 (action default '更新 README')
appear to diverge from Phase 0.5's abort-default safety policy.

Audit conclusion: NOT a divergence — they correctly apply Phase 0.5
rule's exception clause:
  'active default is reserved for unambiguous happy-path / reversible
   action / frequent dev flow'

Phase 1.5: binary-out-of-sync in daily dev flow IS unambiguous happy
path. Binary install is reversible (mcp-deploy / cli-upgrade can reset).
Frequent. → action default justified.

Phase 2.5: '更新 README' option doesn't mutate; it proposes diff
(read CHANGELOG + git log → draft → user reviews → commit). User-
confirmation gate still present. Reversible draft. → action default
justified.

Contrast with Phase 0.5 (release-time push to public marketplace):
push is IRREVERSIBLE (force-push to public is bad day) → abort default
warranted regardless of user-in-session.

Each phase's default reflects its action's risk profile. No behavior
change — just documentation that the deliberate divergence IS the
correct application of Phase 0.5 rule, not a violation.

Refs #68
….5 Step 5 (Refs #70)

Per /idd-verify #60 security review (LOW, DA→LOW): finding L233 flagged
'/tmp/touched-plugins.txt race / TOCTOU on shared /tmp'. Audit found the
flagged tempfile DOES NOT EXIST in current implementation — Phase 0.5
Step 5 already uses inline subshell:

    TOUCHED=$(git log --name-only --pretty=format: ... | sort -u)

Inline $(...) substitution captures to a process-local variable, never
touches /tmp, hence no TOCTOU window and no race. The verify finding
was a false positive imagining a tempfile that was never written.

No behavior change. Add load-bearing comment documenting:
1. Why current code is already safe (inline subshell, not tempfile)
2. If future refactor *does* need persistence, use mktemp + trap pattern
   (the '#70 expected behavior' from the issue)
3. Hardcoded /tmp/touched-plugins.txt is FORBIDDEN — it would re-introduce
   the false-positive surface and the actual race window

Comment forestalls future audits from re-flagging the same false positive,
and gives future maintainers explicit guidance if refactoring direction
changes.

Refs #70
…e exception + explicitly justify frequent-dev → non-destructive substitution (Refs #68)

Per /idd-verify --pr 72 codex MEDIUM finding (single blocking): Phase 2.5
audit blockquote silently substituted 'non-destructive' for 'frequent dev'
in the 3-criterion exception clause, while Phase 1.5 quoted all 3
verbatim. Codex (gpt-5.5 xhigh) flagged the inconsistency:

  Phase 1.5 note: 'unambiguous happy-path / reversible / frequent dev flow' ✓
  Phase 2.5 note: 'unambiguous happy-path / reversible / non-destructive' ✗
                                                       ^^^^^^^^^^^^^^^^
                                                       silent substitution

Substitution is defensible (README updates aren't a daily dev flow —
they fire only after substantive change), but the audit must EXPLAIN the
substitution, not silently reword the canonical rule. Otherwise future
readers comparing the two notes would see two different rule statements
and conclude the policy is incoherent.

Fix: rewrite Phase 2.5 note as 3-bullet itemize listing each criterion:
  - unambiguous happy-path ✓ (with explanation)
  - reversible action ✓ (with explanation — propose diff, not mutate)
  - frequent dev flow ✗ → substituted with non-destructive (with reason)

Phase 1.5 note unchanged (all 3 criteria fit verbatim).

Refs #68
@kiki830621
Copy link
Copy Markdown
Collaborator Author

Verify Report — PR #72

Engine

Lighter cluster ensemble (1 combined Claude reviewer covering Requirements/Logic/Security/Regression/Devil's-advocate + 1 Codex GPT-5.5 xhigh independent). Pure-docs/refactor cluster — no behavior change, 90-line diff.

Aggregate

PASS (after 4c1b102 verify-fix) — 0 blocking remaining, 2 follow-up advisory.

Scope coverage

PR refs: #56 #57 #68 #70
Verified scope: #56 #57 #68 #70 (matches user-requested set; no scope creep).


#56 — invariant marker comment (archive-mail Step 2.1)

Coverage: FULLY (both reviewers agree)

Reviewer Verdict
Combined Claude FULLY — diff L9-L14 includes allowed find/head/awk/cat/grep + forbidden mv/rm/cp/>/>>/tee/chmod. Empirical audit confirmed Step 2.1 block at HEAD only uses allowed ops; no hidden writes.
Codex FULLY — same conclusion.

Devil's advocate:

  • Comment over-permissive (cat listed but unused) — LOW, harmless.
  • Forbidden list omits ln/touch/sed -i — covered by "If you need to write, do it OUTSIDE this block" catch-all. INFO.
  • Still comment-only (no enforcement) — accepted, matches issue's explicit Option A.

#57 — null-safe find/while (archive-mail Step 2.1)

Coverage: FULLY (both reviewers agree)

Reviewer Verdict
Combined Claude FULLY — both find -P invocations got -print0, both while IFS= read -r got -d ''. Symmetric pair preserved. Pre-existing [ -z "$X" ] && continue paranoid guards kept.
Codex FULLY — confirmed at diff L22-L23 (outer while), L27-L28 (inner while), L36-L37 (inner find), L43-L44 (outer find).

Devil's advocate: bash-specific (dash doesn't support read -d '') — non-issue, skill blocks already use bash-specific features (arrays, process substitution).


#68 — Phase 1.5/2.5 default-option policy alignment audit

Coverage: FULLY after fix 4c1b102

Reviewer Pre-fix verdict Post-fix verdict
Combined Claude FULLY (missed substitution divergence) FULLY
Codex PARTIALLY (BLOCKING) — Phase 2.5 note silently substituted "non-destructive" for "frequent dev" in the 3-criterion exception clause; Phase 1.5 note quoted all 3 verbatim. Inconsistency would let future readers conclude policy is incoherent. FULLY (after 4c1b102)

Fix applied (4c1b102):

  • Rewrote Phase 2.5 audit blockquote as 3-bullet itemize per canonical 3-criterion exception clause
  • unambiguous happy-path ✓ (with explanation)
  • reversible action ✓ (propose diff, user-confirmation gate intact)
  • frequent dev flow ✗ → substituted with non-destructive (explicit substitution + reason: README updates aren't daily dev flow)

The substitution is now explicit and justified rather than silent. Phase 1.5 note unchanged.

Codex earned its keep here: Claude reviewer marked FULLY without flagging the divergence between Phase 1.5 (verbatim) and Phase 2.5 (substituted). Cross-model independent verification caught what same-family review missed.


#70 — Phase 0.5 Step 5 tempfile-avoidance comment

Coverage: FULLY (both reviewers agree)

Reviewer Verdict
Combined Claude FULLY — confirmed verify #60 finding was a false positive (no /tmp/touched-plugins.txt exists in source). Comment correctly documents inline subshell safety + future mktemp+trap guidance. Bash syntax (TMPFILE=$(mktemp ...) + trap) verified at runtime.
Codex FULLY — diff L56-L59 adds the 4-line comment immediately above TOUCHED=$(git log ...) at L60. All 3 expected scope items covered.

Devil's advocate: trap example is documentation, not enforcement. Acceptable — matches #70's "comment guardrail" scope.


Cross-cutting findings

Scope / regression

KAC/CHANGELOG

  • No version bump expected (refactor/docs cluster, no behavior change).
  • No CHANGELOG entry needed — neither plugin's user-facing surface changed.

Codex disagreement → fix

Severity-tagged findings list (post-fix)

# Severity File Finding Action
1 LOW archive-mail.md Step 2.1 invariant comment cat listed in allowed but unused Follow-up — over-permissive but safe
2 INFO archive-mail.md Step 2.1 forbidden list Omits ln/touch/sed -i Follow-up — covered by catch-all clause

No BLOCKING / HIGH / MEDIUM remaining.


Routing

  • ✅ All 4 issues FULLY addressed (per merged ensemble verdict)
  • ✅ Cluster branch ready for human review + squash merge
  • ⏳ Pending: human review of cluster PR + /idd-close #56 #57 #68 #70 after merge
  • ❌ Do NOT add Closes #N to PR body — IDD discipline requires manual /idd-close per issue after merge to enforce checklist gate + per-issue closing summary

What this verify deliberately did NOT do

  • Did not run full 6-AI ensemble — combined Claude reviewer + Codex was sufficient for pure-docs/refactor cluster (90-line diff, no behavior change). Same trade-off as cluster PR cluster: 4 docs follow-ups from #49 / #60 IDD lifecycles #71 verify.
  • Did not run /idd-update to flip phase=implemented — sister-bug filed issues lack the structured Current Status field; Implementation Complete comment + cluster PR are canonical audit trail.
  • Did not re-run ensemble after 4c1b102 fix — surface change was mechanical (rewrite blockquote per canonical rule), surface is too small to justify re-burn.

Bump plugin shell v2.18.1 → v2.19.0 to ship binary v2.8.0 (just released
at PsychQuant/che-apple-mail-mcp#85, tagged v2.8.0).

Binary v2.8.0 contents:
- (#19) sanitize_links opt-in URL scheme allowlist for markdown mode
- (#85) formal spec.md Requirement+Scenarios + builder-layer wiring
  contract tests pinning sanitizeLinks forwarding
- (#20/#21/#25/#27/#32) cluster A hygiene + invariant tests
- (#73) extractHTMLBody base64+UTF-8-QP decoding fixes
- 47 → 48 tools (sanitize_links param surface adds new schema field)
- swift test 309 → 313 passing / 0 failures / 8 skipped

Files synced:
- plugins/che-apple-mail-mcp/.claude-plugin/plugin.json (version + binary_version + description)
- .claude-plugin/marketplace.json (same fields mirrored from plugin.json)
- plugins/che-apple-mail-mcp/README.md (Version History entry added)

Refs PsychQuant/che-apple-mail-mcp#19 #85 #73
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.

[refactor] archive-mail Step 2.1 read-only invariant has no structural enforcement (sister concern from #49)

1 participant