Skip to content

Documentation and modifiability pass: Severance.Phase + architecture doc - #39

Merged
KTSCode merged 6 commits into
mainfrom
todo/architecture-modifiability-pass
Jun 9, 2026
Merged

Documentation and modifiability pass: Severance.Phase + architecture doc#39
KTSCode merged 6 commits into
mainfrom
todo/architecture-modifiability-pass

Conversation

@KTSCode

@KTSCode KTSCode commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add Severance.Phase as the single source of truth for the escalating countdown phases (threshold, tick interval, notification sound, tmux color, blink). Countdown, Notifier, StatusPublisher.Tmux.Format, and Status now read phase attributes from it instead of each owning a parallel copy — adding or re-ordering a phase becomes a one-place edit, and it's the seam the roadmap's "configurable escalation phases" would replace.
  • Behavior-preserving: all public signatures unchanged. The two Countdown helpers that were only exposed for testing (phase_for_remaining/1, tick_interval_ms/1) move into Phase; their tests move with them.
  • Add docs/architecture.md — a current-state living doc (distinct from the dated docs/specs/): supervision tree, CLI-dispatch vs daemon split, countdown state machine, config resolution, RPC seam, system-adapter test seam, publishers, and the new Phase module. Linked from the README.
  • The architecture doc includes a Known rough edges section flagging coupling this pass documents but does not fix: config resolution leaking through Application env, duplicated RPC/distribution setup (daemon vs CLI), and the oversized Severance.CLI.

Test plan

  • mix quality green — format, compile (warnings-as-errors), credo, dialyzer (0 warnings), doctor, tests at 63.0% coverage
  • New test/severance/phase_test.exs covers every Phase function + doctests
  • Full suite green (355 tests) — existing countdown/notifier/format tests exercise the delegations end-to-end, confirming behavior is preserved
Implementation Plan

Full design committed at docs/specs/2026-06-08-architecture-modifiability-pass-design.md.

Deliverable 1: Severance.Phase

One ordered phase list is the single source of truth. A phase is active while minutes_remaining > min_minutes; color_index is the position in a 3-element tmux palette [waiting_or_gentle, aggressive, final_or_shutdown], preserving the existing custom-palette behavior of color_for_phase/2.

phase min_minutes interval_ms sound color_index blink?
waiting 0 false
gentle 15 5m Tink 0 false
aggressive 5 2m Funk 1 true
final 0 1m Basso 2 true
shutdown 2 false
done 2 false

Public API: name/0 (type), phase_for_remaining/1, interval_ms/1, sound/1, color/2, blink?/1, default_palette/0.

Consumer changes (delegations only): Countdown calls Phase.phase_for_remaining/1 + Phase.interval_ms/1; Notifier.phase_sound/1 keeps the mode-specific :overtime clause and delegates the rest to Phase.sound/1; Format.color_for_phase/1,2Phase.color/2, blink_for_phase/1Phase.blink?/1; Status.@type phaseSeverance.Phase.name().

Out of scope (stays in Countdown — countdown timing, not per-phase): T-30 start window, stale-pane threshold, wait/retry intervals, overtime-burst constants. Loading phases from config (the roadmap item) is also out of scope; this pass only centralizes the static data so that work has one place to land.

Deviation from spec discovered during implementation: the spec proposed keeping the two Countdown helpers as thin delegations. Delegating tick_interval_ms to Phase.interval_ms (which returns nil for non-escalation phases) would have muddied its non_neg_integer() contract, so the helpers were internalized instead — Countdown calls Phase directly at the two call sites and the two test blocks moved to phase_test. Dialyzer confirmed clean.

Deliverable 2: docs/architecture.md

Current-state architecture doc covering the process model, entry points, countdown state machine, configuration, RPC seam, system adapter, publishers, a module map, and known rough edges. Linked from the README Development section.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6c8f81137f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/severance/phase.ex
Comment on lines +72 to +73
@spec phase_for_remaining(integer()) :: :gentle | :aggressive | :final | :shutdown
def phase_for_remaining(minutes) do

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the documented Countdown helpers

Existing code that calls the documented public helpers Severance.Countdown.phase_for_remaining/1 or Severance.Countdown.tick_interval_ms/1 now gets UndefinedFunctionError, because the implementations were moved here but no forwarding wrappers were left in Countdown. This matters for any user scripts/tests compiled against the previous API, and the design note for this pass explicitly says public signatures should not change; keeping deprecated delegations to Phase would preserve compatibility.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not making this change. These were internal helpers exposed only for unit testing, not a public/library contract:

  • Severance ships as the sev binary; mix.exs has no package block, so it is not published to Hex. No external code can compile against Severance.Countdown.
  • Neither function appears in any user-facing contract — not in sev help --agent, not in docs/configuration.md. The publisher extension surface is Status + Tmux.Format + Tmux.publisher.
  • grep finds zero callers of Countdown.phase_for_remaining/1 or Countdown.tick_interval_ms/1 outside the tests that moved to phase_test.

Adding forwarders would be dead code for callers that cannot exist (YAGNI). Delegating tick_interval_ms to Phase.interval_ms would also widen its non_neg_integer() contract, since interval_ms returns nil for non-escalation phases. Phase logic now lives solely in Severance.Phase. Fixed the spec note that wrongly described these as preserved delegations (936e671).

KTSCode added 3 commits June 8, 2026 16:51
The mix todo agent prompt now tells implementers to update
docs/architecture.md in the same PR when a change alters the system.
AGENTS.md and CLAUDE.md document the living-docs vs point-in-time
distinction so architecture.md stays current as the app evolves.
…untdown phase definitions in a single Severance.Phase module
@KTSCode
KTSCode merged commit 19e71e0 into main Jun 9, 2026
@KTSCode
KTSCode deleted the todo/architecture-modifiability-pass branch June 9, 2026 00:23
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.

1 participant