Add os-sdlc-implementation-abandon to abandon one implementation by id #899

Closed
opened 2026-10-02 13:04:54 +00:00 by jared · 2 comments
Owner

Problem

os-sdlc has no operator command to abandon an implementation. Implementation#abandon! (model/implementation/lifecycle.rb) and Implementation.abandon_unfinished! (model/implementation.rb) exist, but the only caller is Implementation.open, which abandons the unfinished runs of one session. plugins/os-sdlc/skills/pipeline-state-investigate/SKILL.md says "there is no operator-initiated abandon path". Implementation 14 (#880, status needs-orchestrator, escalation 6) must be abandoned so that the schema bump in #895 is allowed, because Db refuses a replacement while any implementation has no terminal stamp. Today the only way is to edit the database by hand. #895 is blocked by this ticket.

Approach

Add bin/os-sdlc-implementation-abandon <id> --reason <text>. It abandons one implementation by id, requires a reason, refuses an implementation that already has a terminal stamp, and reports what it stamped. The abandoned_at column has no reason column beside it, so the reason is echoed in the report and not stored; do not add a column (schema work belongs to #895).

Required work:

  1. Add the executable that boots the new command — check: present implementation-abandon in plugins/os-sdlc/bin/os-sdlc-implementation-abandon
  2. Register the command in the Boot table — check: present "implementation-abandon" in plugins/os-sdlc/lib/os_sdlc/controller/boot/commands.rb
  3. Parse the id and the required --reason in the Boot inputs — check: present implementation_abandon in plugins/os-sdlc/lib/os_sdlc/controller/boot/inputs.rb
  4. Add the controller that routes the call to one command — check: present class Abandoning in plugins/os-sdlc/lib/os_sdlc/controller/implementation/abandoning.rb
  5. Add the command that refuses a terminal implementation, stamps abandoned_at, and builds the report — check: present class Abandon in plugins/os-sdlc/lib/os_sdlc/command/implementation/abandon.rb
  6. Raise the existing Implementation::NotActive for an implementation that is not active — check: present NotActive in plugins/os-sdlc/lib/os_sdlc/command/implementation/abandon.rb
  7. Replace the "no operator-initiated abandon path" sentence in the skill with the new command — check: absent there is no operator-initiated abandon path in plugins/os-sdlc/skills/pipeline-state-investigate/SKILL.md
  8. Name the new command in the skill; lines 40 and 132 of that file also describe implementation-open as the only recovery and must be updated — check: present os-sdlc-implementation-abandon in plugins/os-sdlc/skills/pipeline-state-investigate/SKILL.md
  9. Add the --reason input to Boot::Inputs and the implementation-abandon entry to Boot::Commands (controller/boot/) — check: present implementation-abandon in plugins/os-sdlc/lib/os_sdlc/controller/boot/commands.rb
  10. Name the new operator path in plugins/os-sdlc/references/escalation-procedure.md (line 12 says only a fresh implementation-open abandons a waiting run) — check: present os-sdlc-implementation-abandon in plugins/os-sdlc/references/escalation-procedure.md
  11. Name the new operator path in plugins/os-sdlc/skills/implement/SKILL.md — check: present os-sdlc-implementation-abandon in plugins/os-sdlc/skills/implement/SKILL.md

Scope: abandon means stamp only, the same as Implementation.open (abandon_unfinished! updates abandoned_at and updated_at). Escalation rows stay as history (ADR-0165 derives state from implementation stamps). Handoffs and dispatches are not settled. Test patterns to copy: tests/model/implementation_report_cli_test.rb and tests/pipeline/cli_implementation_open_test.rb; check tests/cops/bin_script_load_in_test_test.rb. Add one History row to docs/implementation-status/os-sdlc.md and run bin/refresh-plugins.

Acceptance criteria

  1. Given an active implementation, when os-sdlc-implementation-abandon <id> --reason "<text>" runs, then abandoned_at is stamped, completed_at and failed_at stay NULL, and the command exits 0.
  2. Given an implementation that waits at needs-orchestrator with no terminal stamp, when the command runs, then it is abandoned like any active implementation.
  3. Given an implementation with completed_at, failed_at, or abandoned_at set, when the command runs, then it exits non-zero, names the existing terminal stamp on stderr, and changes no row.
  4. Given an id that matches no implementation, when the command runs, then it exits non-zero and names the id.
  5. Given no --reason or an empty one, when the command runs, then it exits non-zero with a usage message and changes no row.
  6. Given a successful abandon, when the command finishes, then its output names the implementation id, the ticket, the stamp written, its timestamp, and the reason.
  7. Given an abandoned implementation, when Db checks for a replacement, then that implementation no longer blocks it.

Owner sketch

class OsSdlc::Implementation::Abandoning # controller/implementation/abandoning.rb
  def abandon(root, id, reason)
end

class OsSdlc::Implementation::Abandon # command/implementation/abandon.rb
  def self.call(id, reason:)
end

Abandon finds the row, raises the existing Implementation::NotActive unless Implementation#active?, calls the existing Implementation#abandon!, and returns the report. abandon! and abandon_unfinished! stay as they are.

Origin

  • Trigger: #880 (implementation 14) blocks the schema bump in #895 and cannot be abandoned by an operator, 2026-10-02
  • Improvised this session: none
  • Root candidate: #859
  • Session: 616e6f92-69d9-4a00-bf30-33a77404deb3
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/616e6f92-69d9-4a00-bf30-33a77404deb3.jsonl
  • Chain: Db refuses replacement while a run is unfinished ← no operator command abandons a run ← DESIGN (abandon exists only inside Implementation.open)
  • Where: plugins/os-sdlc/lib/os_sdlc/model/implementation/lifecycle.rb

Parent: #859
Blocked by: none

VERDICT: CREATE (ticket-skeptic 2026-10-02: user-directed; unblocks #895 schema bump)

## Problem os-sdlc has no operator command to abandon an implementation. `Implementation#abandon!` (model/implementation/lifecycle.rb) and `Implementation.abandon_unfinished!` (model/implementation.rb) exist, but the only caller is `Implementation.open`, which abandons the unfinished runs of one session. `plugins/os-sdlc/skills/pipeline-state-investigate/SKILL.md` says "there is no operator-initiated abandon path". Implementation 14 (#880, status needs-orchestrator, escalation 6) must be abandoned so that the schema bump in #895 is allowed, because `Db` refuses a replacement while any implementation has no terminal stamp. Today the only way is to edit the database by hand. #895 is blocked by this ticket. ## Approach Add `bin/os-sdlc-implementation-abandon <id> --reason <text>`. It abandons one implementation by id, requires a reason, refuses an implementation that already has a terminal stamp, and reports what it stamped. The `abandoned_at` column has no reason column beside it, so the reason is echoed in the report and not stored; do not add a column (schema work belongs to #895). Required work: 1. Add the executable that boots the new command — check: present `implementation-abandon` in `plugins/os-sdlc/bin/os-sdlc-implementation-abandon` 2. Register the command in the Boot table — check: present `"implementation-abandon"` in `plugins/os-sdlc/lib/os_sdlc/controller/boot/commands.rb` 3. Parse the id and the required `--reason` in the Boot inputs — check: present `implementation_abandon` in `plugins/os-sdlc/lib/os_sdlc/controller/boot/inputs.rb` 4. Add the controller that routes the call to one command — check: present `class Abandoning` in `plugins/os-sdlc/lib/os_sdlc/controller/implementation/abandoning.rb` 5. Add the command that refuses a terminal implementation, stamps `abandoned_at`, and builds the report — check: present `class Abandon` in `plugins/os-sdlc/lib/os_sdlc/command/implementation/abandon.rb` 6. Raise the existing `Implementation::NotActive` for an implementation that is not active — check: present `NotActive` in `plugins/os-sdlc/lib/os_sdlc/command/implementation/abandon.rb` 7. Replace the "no operator-initiated abandon path" sentence in the skill with the new command — check: absent `there is no operator-initiated abandon path` in `plugins/os-sdlc/skills/pipeline-state-investigate/SKILL.md` 8. Name the new command in the skill; lines 40 and 132 of that file also describe implementation-open as the only recovery and must be updated — check: present `os-sdlc-implementation-abandon` in `plugins/os-sdlc/skills/pipeline-state-investigate/SKILL.md` 9. Add the `--reason` input to `Boot::Inputs` and the `implementation-abandon` entry to `Boot::Commands` (controller/boot/) — check: present `implementation-abandon` in `plugins/os-sdlc/lib/os_sdlc/controller/boot/commands.rb` 10. Name the new operator path in `plugins/os-sdlc/references/escalation-procedure.md` (line 12 says only a fresh implementation-open abandons a waiting run) — check: present `os-sdlc-implementation-abandon` in `plugins/os-sdlc/references/escalation-procedure.md` 11. Name the new operator path in `plugins/os-sdlc/skills/implement/SKILL.md` — check: present `os-sdlc-implementation-abandon` in `plugins/os-sdlc/skills/implement/SKILL.md` Scope: abandon means stamp only, the same as `Implementation.open` (`abandon_unfinished!` updates `abandoned_at` and `updated_at`). Escalation rows stay as history (ADR-0165 derives state from implementation stamps). Handoffs and dispatches are not settled. Test patterns to copy: tests/model/implementation_report_cli_test.rb and tests/pipeline/cli_implementation_open_test.rb; check tests/cops/bin_script_load_in_test_test.rb. Add one History row to docs/implementation-status/os-sdlc.md and run bin/refresh-plugins. ## Acceptance criteria 1. Given an active implementation, when `os-sdlc-implementation-abandon <id> --reason "<text>"` runs, then `abandoned_at` is stamped, `completed_at` and `failed_at` stay NULL, and the command exits 0. 2. Given an implementation that waits at needs-orchestrator with no terminal stamp, when the command runs, then it is abandoned like any active implementation. 3. Given an implementation with `completed_at`, `failed_at`, or `abandoned_at` set, when the command runs, then it exits non-zero, names the existing terminal stamp on stderr, and changes no row. 4. Given an id that matches no implementation, when the command runs, then it exits non-zero and names the id. 5. Given no `--reason` or an empty one, when the command runs, then it exits non-zero with a usage message and changes no row. 6. Given a successful abandon, when the command finishes, then its output names the implementation id, the ticket, the stamp written, its timestamp, and the reason. 7. Given an abandoned implementation, when `Db` checks for a replacement, then that implementation no longer blocks it. ## Owner sketch ```ruby class OsSdlc::Implementation::Abandoning # controller/implementation/abandoning.rb def abandon(root, id, reason) end class OsSdlc::Implementation::Abandon # command/implementation/abandon.rb def self.call(id, reason:) end ``` `Abandon` finds the row, raises the existing `Implementation::NotActive` unless `Implementation#active?`, calls the existing `Implementation#abandon!`, and returns the report. `abandon!` and `abandon_unfinished!` stay as they are. ## Origin - Trigger: #880 (implementation 14) blocks the schema bump in #895 and cannot be abandoned by an operator, 2026-10-02 - Improvised this session: none - Root candidate: #859 - Session: 616e6f92-69d9-4a00-bf30-33a77404deb3 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/616e6f92-69d9-4a00-bf30-33a77404deb3.jsonl - Chain: Db refuses replacement while a run is unfinished ← no operator command abandons a run ← DESIGN (abandon exists only inside Implementation.open) - Where: plugins/os-sdlc/lib/os_sdlc/model/implementation/lifecycle.rb Parent: #859 Blocked by: none VERDICT: CREATE (ticket-skeptic 2026-10-02: user-directed; unblocks #895 schema bump)
Author
Owner

Work started: /os-sdlc:implement on branch ticket-899 (worktree .claude/worktrees/ticket-899).

Work started: /os-sdlc:implement on branch ticket-899 (worktree .claude/worktrees/ticket-899).
Author
Owner

Resolution

Done: Added bin/os-sdlc-implementation-abandon --reason : Boot key implementation-abandon, controller Implementation::Abandoning, command Implementation::Abandon raising the existing Implementation::NotActive; it stamps abandoned_at only. Skill and escalation-procedure prose name the new operator path.

Evidence: Commit 7d985405 on ticket-899 (implementation 15 complete, 14 dispatches, contract-auditor pass after 2 refactor rounds); suite-check green 3 times; new tests in plugins/os-sdlc/tests/pipeline/cli_implementation_abandon_test.rb.

Follow-ups: History row in docs/implementation-status/os-sdlc.md added by the orchestrator after merge. Abandon reason is echoed, not stored: dropped, per ticket scope (no schema change).

## Resolution **Done:** Added bin/os-sdlc-implementation-abandon <id> --reason <text>: Boot key implementation-abandon, controller Implementation::Abandoning, command Implementation::Abandon raising the existing Implementation::NotActive; it stamps abandoned_at only. Skill and escalation-procedure prose name the new operator path. **Evidence:** Commit 7d985405 on ticket-899 (implementation 15 complete, 14 dispatches, contract-auditor pass after 2 refactor rounds); suite-check green 3 times; new tests in plugins/os-sdlc/tests/pipeline/cli_implementation_abandon_test.rb. **Follow-ups:** History row in docs/implementation-status/os-sdlc.md added by the orchestrator after merge. Abandon reason is echoed, not stored: dropped, per ticket scope (no schema change).
jared closed this issue 2026-10-02 13:24:15 +00:00
jared referenced this issue from a commit 2026-10-02 17:43:17 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#899
No description provided.