ADR-159: Remove ways tune-curves and the legacy curve: cadence field¶
Context¶
ways tune-curves (ADR-123 Phase E) reads fire telemetry, computes the median
token-distance between a way's firings, and — with --apply — rewrites each
way's frontmatter to a curve: block carrying an absolute half_life.
That output is now broken. ADR-126 replaced the curve: block with
refire: (a fraction of the context window, resolved per fire against the
model's actual window). The migration moved every way to refire:, curve: was
dropped from the frontmatter schema, and ways lint flags a written curve:
block as an UNKNOWN field. So ways tune-curves --apply produces frontmatter
that the project's own linter rejects — a command that corrupts way files.
The command is not worth repairing:
- Its model is superseded. It suggests an absolute
half_lifein tokens.refire:is deliberately a fraction, so way files stay portable across model window sizes (ADR-126). Translating an observed token cadence into a fraction requires dividing by the window it was observed under — reintroducing exactly the model-specific coupling ADR-126 removed. A "portable" fraction derived from one model's window is a fiction. - Its successor is a different, deferred design. Telemetry-driven cadence
tuning is ADR-134 (empirical auto-tuning from fire/near-miss streams), which is
deferred.
tune-curvesis a half-built manual precursor to it, not a standalone capability worth carrying. - Nothing uses the legacy path. No shipped way carries a
curve:block; the schema rejects it. Thecurve:frontmatter field and its read-fallback are dead code kept alive only for a command that produces lint-failing output.
Decision¶
Remove ways tune-curves and retire the legacy curve: frontmatter field
entirely.
- Delete the
tune_curvescommand, its module, and its CLI wiring. - Remove the
Frontmatter.curvefield and its read-fallback inresolved_curve— resolution now comes solely fromrefire:. - Remove the now-dead
curve:readers (show,listdoc comments) and the lint special-case that warned aboutrefire:+curve:coexistence; a straycurve:block falls through to the generic UNKNOWN-field warning, which is the correct treatment for a retired field. - Update the docs that presented
tune-curvesas a workflow (stats.md,reference/ways-cli.md) and anycurve:-as-current references.
Kept: the runtime Curve type and RefireSpec::to_curve. Curve is the
concrete decay representation that refire: resolves into at fire time
(fraction × window → Curve::Exponential); it is the engine's internal shape,
not the retired authoring field. Retiring curve: the frontmatter field does
not touch Curve the runtime type.
Consequences¶
Positive¶
- No command can emit lint-failing frontmatter; the footgun is gone.
- One cadence model, not two:
refire:is the sole authored cadence field, with no dead legacy path shadowing it in the parser,show,list, and lint. - Less code to carry toward the eventual ADR-134 auto-tuner, which will target
refire:directly rather than inheritingtune-curves'half_lifemodel.
Negative¶
- Users lose the observed-cadence suggestion helper. In practice
refire:is a small, human-judged knob (theonce/rare/normal/frequentpresets), and the telemetry that fedtune-curvesstill exists for the future ADR-134 work. - Removing a shipped subcommand is a visible CLI surface change (documented here and in the release notes).
Neutral¶
- The frontmatter schema already excludes
curve:; this change makes the code match the schema. Any hypothetical old file still carryingcurve:now simply gets the UNKNOWN-field lint warning and falls back to the missing-cadence default, rather than being silently honored.
Alternatives Considered¶
- Fix
tune-curvesto writerefire:(translatehalf_life→ window fraction). Rejected: the translation reintroduces the model-window coupling ADR-126 removed, and it invests in a manual precursor to the deferred ADR-134 auto-tuner rather than retiring it. - Leave the command, only silence the lint. Rejected: that legitimizes a
retired field and keeps two cadence models alive; the lint is correct to reject
curve:. - Delete the command but keep the
curve:read-fallback. Rejected: with no way usingcurve:and the schema rejecting it, the fallback is pure dead code — the kind of drift the project retires on sight.