Skip to content

[FEATURE] Idempotence for labels/comments/generated outputs #113

Description

@koydas

🎯 Goal

Make all write-side operations idempotent so reruns with the same inputs do not create duplicates or inconsistent state.

📍 Context

  • Repo: autonomous-dev-loop
  • Domain: Re-runnability
  • Component: scripts/lib/output_writer.mjs, scripts/manage_labels.mjs

🚀 Description

Idempotence is already partially applied in this repo but inconsistently:

  • upsert_issue_validation_comment.mjs — upserts by bot-marker ✅
  • auto_fix_pr.mjs label creation — tolerates HTTP 422 (existing label) ✅
  • output_writer.mjs — overwrites files unconditionally without checking expected state ❌
  • manage_labels.mjs — label operations need idempotence verification ❌

A re-run caused by a transient failure or manual retry must produce the same final state as the first run.

🧩 Scope

In:

  • scripts/lib/output_writer.mjs: before writing a file, check if its content is already identical; skip the write if so (use fs.readFile + strict equality).
  • scripts/manage_labels.mjs: verify each label operation is upsert-safe — add only if not already present, remove only if present; no-op otherwise.
  • Define a run-context idempotency key composed of { issueNumber, commitSha, step } to scope write guards.
  • Document the idempotency contract for each write operation (inline, one line per function).

Out:

  • Workflow trigger strategy changes.
  • Changes to read-only operations.

🧪 Acceptance criteria

  • Functional

    • Running output_writer.mjs twice with identical inputs produces exactly one file write on disk (second call is a no-op).
    • Running manage_labels.mjs twice with the same label set leaves the PR/issue in the same label state (no duplicate add, no spurious remove).
  • Edge cases

    • If a file write is interrupted mid-run and the file is partially written, the next run overwrites it correctly (partial state is not treated as "already applied").
    • Removing a label that does not exist is a silent no-op, not an error.
    • Adding a label that already exists is a silent no-op, not an error (HTTP 422 already handled in auto_fix_pr.mjs — extend same pattern).
  • Tests

    • Unit: calling writeGeneratedFiles twice with the same changes array results in fs.writeFile being called only once per file (second call skipped).
    • Unit: manage_labels add operation with a label already present does not call the GitHub API a second time.
    • Smoke: re-running a full generation flow with the same issue does not create duplicate comments or labels.
    • Non-regression: no writes occur outside the allowed output scope after the change.

⚙️ Constraints

  • Preserve current business behavior — this is hardening only, no functional changes.
  • The skip-write check must use strict byte-level equality, not semantic comparison.
  • No new runtime dependencies.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestready-for-devIssue validated and ready for automated implementation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions