fix: egress empty-body guard + edit-comment verb — surgery channel enters the nets#281
Merged
Merged
Conversation
…t 15)
Every existing net inspects what the body CONTAINS; none checked whether it
EXISTS. An empty/whitespace-only body sailed through all nets and, on edit
(overwrite semantics), wiped the target issue body — live incident 2026-07-22
(bestOCR#1: upstream python composition failed silently, '$(cat empty)' went
out at scrub-attested warn, 40s restore only because a local copy existed).
New guard after arg parse: body channel PROVIDED + stripped-empty -> refuse
for all three verbs; edit additionally floors at 10 stripped chars ('done' is
a legit short comment, a 3-char body OVERWRITE almost never is; byte-length
on multibyte only relaxes the floor — safe direction). Wrapper-origin code 15
(band >=10 per #227 — the issue's suggested exit 5 would break the rc<10-is-gh
invariant). Explicit-intent escape --allow-empty-body (consumed, never
forwarded; same pending-value malformed-shape guard as the attestation
flags). Label-only edits with no body channel are untouched. Suite +8
fixtures (RED 6 -> GREEN 75/0).
Refs #275
…the nets, batch consumes the band Root cause ran deeper than the filed symptom: idd-edit's Step-6 PATCH went through raw 'gh api', a channel the #226 rollout explicitly whitelisted as 'tracked separately' — so it bypassed EVERY net (privacy / mention / attestation / tier-floor / #275 empty-body), and classifying wrapper exit codes in the batch loop without wiring the channel first would have been a placebo (diagnosis correction on the issue). Two-part fix: (1) wrapper: new edit-comment verb — 'edit-comment <id> --repo o/r --body-file <f>' dispatches the comment PATCH ('gh api .../comments/:id -X PATCH -F body=@file'); the body-file content rides the existing scan pipeline so all nets apply automatically, and the #275 near-empty floor covers it (overwrite semantics). --body-file is mandatory (14 otherwise). (2) idd-edit batch: Step 6 dispatches via the verb; rc>=10 lands in the new EGRESS_REFUSED bucket (warn-continue, #158 semantics), 0<rc<10 stays honest gh-failure (skipped, not counted as refusal); Step 7.5 reports both buckets with source tags; final exit stays 4 for any refusal — per-comment classification CONSUMES the band, the aggregate exit does not adopt it (which is exactly what the #227 band exists for). Disaster-recovery restore recipe deliberately stays raw (re-publishing already-published content must not be blockable) with the rationale annotated. Suites: gh-egress +6 (84/84), idd-edit f14 needles synced + f15 x6 (37/37), rollout whitelist retired + raw-line refuted + idd-edit joins the privacy-scrubbing cite loop (28/28). Full sweep 42 suites 0 fail. Refs #273
This was referenced Jul 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #275
Refs #273
Cluster: egress 資料安全 + 觀測性(同 gh-egress 家族,per-issue commit)
Commit 1 — empty-body guard(
fe224f5系列,Refs #275)edit覆寫語意 = 整個 issue body 清空(2026-07-22 實際事故)。edit(含新 verb)加 <10 chars 覆寫地板(done類短 comment 合法不受影響)。--allow-empty-body(wrapper 消費不轉發,split-token guard 同 attestation flags)。Commit 2 — edit-comment verb + batch band 消費(
d5e7a3f,Refs #273)gh api,是 [followup] gh-egress wider rollout — idd-comment 等 7 skill 的 comment/edit egress 接線 (follow-up finding from #117) #226 rollout 明文白名單的「tracked separately」通道 — 繞過全部網,不只觀測不到 13;不先接線就給迴圈加分類 = placebo。edit-comment <id> --repo o/r --body-file <f>→ 派送 comment PATCH;body-file 內容走既有掃描管線,全網自動套用(含 bug: gh-egress.sh edit 接受空 body → 靜默清空 issue body(資料遺失) #275 的覆寫地板)。rc≥10→EGRESS_REFUSED桶(warn-continue,[design] /idd-edit batch mode + R5 refuse interaction — semantic decision needed (tangential from #154 plan) #158 語意同款)、0<rc<10誠實分流為 gh-failure;Step 7.5 雙桶報表帶來源標記;final exit 維持 4(任一 refusal)—「per-comment 分類消費 band、聚合碼不套 band」分層明文。過程紀錄(dogfood 亮點)
commit 2 的首次 sweep 被 #163 剛上線的 contract layer 當場抓到新 code 的
$SCRUB_LEVEL無 provenance(正是它為之而生的 class)— 已改為 block 內顯式解析賦值。該層上線同 session 即立功。Verification
gh-egress 84/84、idd-edit 37/37、rollout 28/28、idd-edit-contract 17/17;全 sweep 41 suites 0 fail。issue 結案不由本 PR 觸發。