| name | append-vs-modify |
|---|---|
| description | Action-scoped discipline for IDD modify-actions — every modify SHALL declare scope category, undeclared SHALL refuse |
Every modify-action SHALL declare an explicit scope category. Undeclared modify-actions SHALL be refused.
This rule supersedes IDD's previously implicit hybrid append+modify discipline. It applies uniformly to AI invocations and human user invocations — actor identity is NOT a discipline boundary.
IDD plugin v2.72.0 development hit ≥ 6 supersession workaround instances in a single session — each new feature ran into "AI-authored stale state" and re-invented its own bridge:
#515supersession bridge (idd-closeStep 0 gate fork for Strategy/Plan pre-impl checkbox staleness)#148retroactive## Implementation Completepost (configured to trigger #515)#149retroactive## Closing Summarypost (after commit-body auto-close trap)- IC_R011 audit blocks (
### Sister Concerns Filed/### Closing Follow-ups Filed/### Distribution Sync/### Residue Acknowledgement) appending to one comment without convergence - Canonical reference docs growing freely (
ic-r011-checkpoint.md301→397 lines) #150body wiped by badsedsubstitution + silentgh issue editaccept
Pattern: no first-class principle governs "how a modify-action should exist". Each new IDD feature ran into the same shape of pain and shipped its own ad-hoc workaround. This rule codifies the discipline so future contributors classify their modify-actions on day one instead of inventing a 7th supersession workaround.
User pivot during /spectra-discuss (2026-05-25): actor-based exemption ("AI restricted / user free") was structurally weak — /idd-edit blanket user-modify entry was a black hole, structurally same shape as raw bash sed (both lack scope declaration). Discipline shifted to action-scoped: every action declares what it modifies, regardless of who invokes.
Every modify-action SHALL declare exactly one scope category from the canonical 7-category enumeration. Actions without a declared category SHALL be treated as
(undeclared)and SHALL be refused at runtime (by skill spec gate) or at review time (by analyzer, future tooling).
Scope declaration takes the form of an inline note in the action's SKILL.md description:
(category: <name>)
(category: <name>, scope: "<identifier>")
The scope qualifier names the targeted section / field / artifact when relevant (e.g. scope: "## Current Status").
Definition: Changes a machine-readable state field — phase, timestamp, status enum value, checkbox boolean. Does NOT modify prose.
Scope boundary: Only the named field. Surrounding text immutable.
Examples:
/idd-updateCurrent Status**Phase**:field change (created→diagnosed)/idd-clarify --status resolved=N,<reason>flips Clarity Surface row status enumspectra task doneflips- [ ]to- [x]- Step 0.5 dismiss row sets
deferred→dismissedwith reason
Definition: Whole named section REPLACE — section boundary explicitly declared (section identifier is part of invocation contract). Does NOT overflow.
Scope boundary: The named section's heading-to-next-heading range only.
Examples:
/idd-updateREPLACE## Current Statusentire section below---separator/idd-edit --section "## Foo"REPLACE the named section's content (heading preserved)
Definition: APPEND a new audit block to a named comment under a named section heading. Does NOT modify existing content within or outside the target.
Scope boundary: The target section's end position (insert before next heading or EOF). Existing text immutable.
Examples:
- IC_R011 sister sweep PATCHes
### Sister Concerns Filedblock into a Diagnosis comment /idd-diagnoseStep 3.4 Layer V Vagueness Pre-check PATCHes### Vagueness Pre-checkblock/idd-issueStep 4.6 emits### Clarity Surfaceblock into a new issue body
Definition: Modify occurs in the draft phase before publish. Once published (committed to GitHub or written to disk as final artifact), the content falls under append-only discipline.
Scope boundary: Time-bounded — only during draft assembly. Post-publish the same content is immutable.
Examples:
/idd-closeStep 3.5 inline replace「follow up later」→「(see #NEW)」in closing summary body assembly beforegh issue commentpublishes the comment
Definition: Absolute immutability. Once written, never modified by any action (AI or user). This is the IC_R007 zone.
Scope boundary: User-authored prose, verbatim quotes, frozen spec contracts. Identified by structural markers (issue body above --- separator) or content type (blockquote citing original text).
Examples:
- Issue body above the
---separator (Problem / Type / Expected / Actual / Impact sections — user's original framing) - Blockquote-wrapped verbatim quotes from external sources (per IC_R007)
- Spec files in
openspec/specs/<name>/spec.mdonce a change is archived
Definition: Only add new entries; never modify or remove existing entries.
Scope boundary: Whole artifact is append-target. Existing entries immutable; new entries inserted at top or bottom per artifact convention.
Examples:
- GitHub comments after publish (the GitHub mechanism enforces this; PATCH is reserved for
audit-block-appenddiscipline) CHANGELOG.md— new version entries prepended on top, old entries never modifiedtasks.mdhistory rows (the rows themselves are append-only; the checkbox state field isstate-field-update)- Spectra archive snapshot directories (
openspec/changes/archive/<date>-<name>/)
Definition: Documentation / source code artifacts — the artifact IS the work product, not audit history. Free rewriting allowed (git provides history).
Scope boundary: Whole artifact. No internal structural protection.
Examples:
- SKILL.md files
- Canonical reference docs (
plugins/issue-driven-dev/references/*.md) - Source code files (
.rs/.py/.swift/.ts/ etc.) - Plugin manifesto, README, contributor guides
When introducing a new IDD action that modifies an existing artifact, walk this tree to assign a category:
Does the action publish to a permanent place (GitHub comment, archived spec)?
├─ Yes → Does it happen in draft phase (before publish call)?
│ ├─ Yes → category: inline-replace-before-publish
│ └─ No → Continue ↓
│
Is the target a user-authored / IC_R007-verbatim zone?
├─ Yes → REFUSE the action entirely (this zone is verbatim-preserve)
│
Is the target a machine-readable state field (phase, timestamp, status enum, checkbox boolean)?
├─ Yes → category: state-field-update
│
Is the target a whole named section (with explicit identifier in the invocation)?
├─ Yes → category: bounded-section-replace
│
Does the action APPEND to a named section without modifying existing content?
├─ Yes → category: audit-block-append
│
Is the target a doc / source code file (artifact IS the work product)?
├─ Yes → category: free-rewrite
│
Is the action purely additive (new entries only, existing entries immutable)?
├─ Yes → category: append-only
│
None of the above → REFUSE; the action lacks a defined scope and SHALL NOT proceed
This rule does NOT replace existing IDD principles — it codifies the modify-action axis that the IC principles each touch from their own angle.
| IC principle | Concern | Boundary with this rule |
|---|---|---|
| IC_R007 (verbatim source preservation) | "Don't modify user-authored prose or external verbatim quotes" | IC_R007 zones map to verbatim-preserve category in this rule. IC_R007 remains the authoritative source for what counts as verbatim; this rule says how the discipline is structurally enforced (refuse modification via category gate). |
| IC_R010 (confidence-tagged routing) | "Tag confidence on automated decisions; defer low-confidence to review" | Orthogonal axis. IC_R010 governs whether an action should proceed; this rule governs what scope it operates on once proceeding. An IC_R010-confident action still SHALL declare its scope. |
| IC_R011 (follow-up filing checkpoint) | "Surface tangential concerns at deliberation moments; file by default" | IC_R011 audit blocks (### Sister Concerns Filed / ### Closing Follow-ups Filed / ### Linked-Context Siblings Filed / ### Distribution Sync / ### Residue Acknowledgement) are all instances of audit-block-append category under this rule. IC_R011 governs when and why to surface; this rule governs how the surface is structurally written (named-section append, not free modification). |
When an IC principle and this rule both apply to an action, both SHALL be satisfied. They do not conflict in observed cases — IC principles operate on different axes (content selection, surfacing eligibility) while this rule operates on the modify-action axis (scope discipline).
#515 introduced supersession bridge logic in idd-close Step 0: when ## Implementation Complete > ### Checklist exists with all items [x], the gate ignores pre-impl Strategy/Plan checkboxes (they are superseded snapshots).
This rule generalizes that pattern across all 4 gate sites (idd-close Step 0 / idd-verify checklist scan / idd-update body sync gate / idd-implement Step 5 Checklist Sync). Each gate SHALL resolve an authoritative_source via the following priority order:
authoritative_source = first_exists([
"## Implementation Complete > ### Checklist",
"## Current Status > ### Tasks",
"## Todo" | "## Tasks" | "## Checklist" # top-level headings
])
When a source resolves, the gate evaluates only items in that source. Earlier sources (Strategy, Implementation Plan) are treated as superseded snapshots — not subject to gate evaluation, retained for historical reference.
When no authoritative_source resolves (legacy issues created before this rule shipped, or pre-Implementation issues that genuinely have only Strategy), the gate SHALL fall back to scanning all checklist-bearing sections (Strategy, Implementation Plan, Implementation Complete, Todo, Tasks, Checklist, Current Status > Tasks) — the pre-discipline behavior.
This fallback preserves backward compatibility:
- Existing closed issues remain inspectable / verifiable under the same behavior they were closed under
- Legacy in-flight issues (still using Strategy-only pattern) continue to gate correctly
- The supersession bridge for
#515remains a no-op (the new generalized logic subsumes it)
Fallback is non-permanent: once an issue acquires an authoritative_source via normal /idd-implement flow, the gate transitions to authoritative-source-only evaluation for that issue.
This rule defines the discipline; tooling-level enforcement is reserved for follow-up work:
- Skill spec gate (in scope of this rule): each modify-action's SKILL.md description SHALL contain
(category: <name>)inline note. Skill author's responsibility; reviewable manually. - Future analyzer (out of scope): static analyzer that scans SKILL.md for modify-action descriptions missing
(category: ...)notes and flags as Critical. Follow-up issue when needed. - CLI parser + bash enforcement (out of scope): native
--section/--scopeflag handling for/idd-editat CLI parser layer + verbatim-preserve guard. Three R1/R2/R3 attempts at bash-level enforcement in SKILL.md introduced new bugs each iteration (infinite loop, flag-eat, multi-line awk-v BREAK). Deferred to follow-up issue #154 for proper standalone proposal with multi-line body handling + parser pattern guards + errata flow integration designed upfront. Phase 1 (this change) is spec-discipline-only: the normative--scope/--sectionrequirements + verbatim-preserve guard live inopenspec/specs/append-vs-modify-discipline/spec.mdRequirements 4-5 + this rule's "Spec discipline" section below + CHANGELOG[2.73.0].idd-edit/SKILL.mdwas reverted to pre-#150 baseline as part of the R4 / Path (c) decision — SKILL.md surface (argument-hint, mode table, usage examples) does NOT currently describe the discipline. AI / user invocation reads spec + rule + CHANGELOG + applies discipline manually until #154 ships both the runtime gate AND the SKILL.md surface updates.
≥ 8 existing IDD actions are retroactively labeled by the change that introduced this rule (add-action-scoped-modify-discipline). New actions added after this rule ships SHALL declare category at SKILL.md authoring time. The (undeclared) → REFUSE rule applies to both new and retroactively-introduced actions; legacy actions without inline notes are caught at next maintainer review.
/idd-edit is the IDD plugin's existing comment-edit primitive. Per this rule's action-scoped discipline, the skill's invocation surface SHALL declare scope:
--append/--prepend-notemodes:audit-block-appendcategory (scope inherent in mode semantics — trailing block / leading errata marker). No additional flag required.--replacemode:bounded-section-replacecategory. Invocations SHALL include--scope whole-comment(full-comment overwrite acknowledgment) OR--section <heading-within-comment>(named subsection scope).
This rule additionally declares a verbatim-preserve guard at the comment layer: comments where author_association ≠ OWNER (and author is not in known-bot allowlist) SHALL NOT be modified without explicit --override-user-content --reason="..." invocation discipline.
Enforcement status: spec-discipline + AI / user invocation guideline. Three implementation attempts (verify R1/R2/R3 on PR #153) showed bash-level enforcement in SKILL.md introduces new bugs incrementally. Runtime enforcement deferred to follow-up issue #154 requiring proper standalone proposal with multi-line body handling + parser pattern guards + /idd-comment errata flow integration designed upfront.
Recommended invocation patterns (per discipline):
/idd-edit comment:NNN --replace --scope whole-comment --body "..."/idd-edit comment:NNN --replace --section "### Sister Concerns Filed" --body "..."/idd-edit comment:<external-user-id> --append --body "..." --override-user-content --reason="..."
CHANGELOG.md [2.73.0] declares the spec discipline + cites this rule + tracks runtime-enforcement deferral via #154.
Some state-field-update operations carry a reason field that downstream gates must regex-match for behavior dispatch (e.g. /idd-diagnose Step 0.5 gate proceeds-with-warn only on specific reasons). To prevent typo drift across multiple SKILL.md sites that cite the same literal, all gate-recognized reason literals SHALL be registered here as the single source of truth. SKILL.md sites SHALL cite by reference (with cross-link to this section), not by inline duplication.
| Reason literal | Originating action | Recognized by | Behavior |
|---|---|---|---|
unattended-auto-Step-4.6-deferred |
/idd-clarify Step 4.8.A — auto-defer in unattended mode (#137, v2.74.0+) |
/idd-diagnose Step 0.5 gate |
Proceed-with-warn (instead of REFUSE the deferred row) |
Adding a new reason literal:
- Choose strict literal (no abbreviation, no version suffix, no underscore variants — kebab-case with clear semantic anchor)
- Add row to this table — name the originating action, recognizing gate(s), behavior
- Update the originating SKILL.md to write the literal; update the recognizing gate SKILL.md to match
- Both SKILL.md sites cite this registry rather than embed the literal inline
- Add corresponding scenario to
openspec/specs/append-vs-modify-discipline/spec.mdif discipline-level recognition is required
Why centralized: 3+ SKILL.md sites citing the same literal is a typo-drift HIGH risk surface. One source eliminates drift; sites that drift their citation are caught by spectra analyze or manual grep (grep -c "<literal>" plugins/issue-driven-dev/rules/append-vs-modify.md = 1 SHALL hold).
Regex matching convention: when gates match these literals via regex, dot characters in the literal MUST be escaped (Step-4\.6-deferred, not Step-4.6-deferred) to prevent over-broad match. Case-sensitive, anchored (^...$) match preferred.
openspec/specs/append-vs-modify-discipline/spec.md— normative specplugins/issue-driven-dev/references/ic-r011-checkpoint.md— audit-block-append category authority#515— Path C precedent (supersession bridge)#150— the META issue codifying this rule#137— first reason literal registered (see Reason pattern registry section)