mittwald / mittwald/flow

Deprecation handling has policy but no tooling

Open
#2,893 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

post-1.0 tooling
Dominant language
TypeScript
Stars
15
Forks
3
Avg merge
1d 17h
Merged PRs (30d)
184

Description

"Deprecate, don't break" is documented in three places and enforced by none. Nothing checks that a removal was preceded by a deprecation, that a @deprecated marker comes with a runtime warning, or that a deprecation reaches the release notes. The rule is carried by review attention alone.

Post-1.0.0: nothing here is due at the cut, and the guard belongs with the branch model that starts there.

Found while working through #2883 — the extension-developer upgrade report hit the one case where the policy failed silently.

What exists

  • Policy. docs/release-workflow.md (deprecate, don't break; @deprecated is fine, removals wait for 2.0.0), ADR 0005 (same rule as the SemVer contract), ADR 0003 (deprecated derived from a component-level @deprecated, feeding the status registry and the docs callout).
  • Process. .claude/templates/release-notes.md carries a fixed ## Deprecations section. .claude/commands/review-flow.md asks the reviewer whether a breaking prop change has a useWarnDeprecation path instead.
  • Machine-readable. The generated status registry is the only structured artifact, and only the docs site reads it.

The single mechanical gate, commit-guard.yml, routes breaking changes away from main/next. It says nothing about deprecations, and it is dormant until the cut.

Gaps

1. The breaking-change guard was never built. ADR 0003 defers it to #2711 and fixes the registry shape so it is not blocked later — the consumer does not exist. Nothing checks that a symbol or prop that disappeared was deprecated in a published version first. That is the removal half of the contract, and at the 2.0.0 cut it is the half that matters.

2. @deprecated and useWarnDeprecation drift apart. ADR 0003 keeps the warning manual on purpose, so the two are independent by design — but nothing reports a mismatch. Both directions are live today:

  • Action.action warns at runtime with no @deprecated anywhere, because the type was removed while the runtime fallback stayed (packages/components/src/components/Action/Action.tsx). This is exactly what the extension developers hit: a tsc error with nothing in the IDE explaining it, and nothing to grep for.
  • The reverse — a @deprecated prop without a useWarnDeprecation — is invisible to a consumer collecting warnings through DeprecationWarningProvider, which is the discovery path #2884 documents on the versioning page.

3. No generated deprecation inventory. #2883 item 5. Collected by hand once and already incomplete the day it was written: eight entries listed, thirteen in main. packages/components/dev/status-registry/deriveComponentStatus.ts already parses @deprecated including the migration text, so the inventory is derivable from a source of truth that exists.

4. The release-notes and migration side is unenforced. The ## Deprecations section is a prompt for whoever drafts the notes, not a gate. The migration-note gate is #2883 item 4 and explicitly out of scope in #2891.

Proposed

  1. Build the guard #2711 deferred. Reads the registry, exempts beta and deprecated, fails when a public symbol or prop disappears without a preceding deprecation.
  2. Pair @deprecated with a runtime warning. A check that reports either side standing alone. Cheapest item here, and it would have caught the Action case before release.
  3. Generate the deprecation inventory as a committed artifact. Closes #2883 item 5 and gives the 2.0.0 cut a scope list that cannot go stale.
  4. Decide whether ## Deprecations becomes a gate, together with the migration-note gate from #2883.

Item 2 closes the reported failure and is a day's work. Item 1 is what the 2.0.0 promise actually rests on.

Why post-1.0.0

A deprecation is additive and may land in any minor, so none of this blocks the cut. The deadline is the 2.0.0 cut: whatever is removed there must have been deprecated in a published 1.x before it, and a warning only counts as lead time if consumers saw it across real releases. The practical rule is to deprecate when the successor lands, not when the removal is planned.

That constraint is what #2774 has to plan against, which makes the inventory (item 3) the most useful piece to have early.

Related: #2883, #2711, #2774, #2884, #2891.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read docs/release-workflow.md, docs/adr/0003-component-lifecycle-status.md, docs/adr/0005-semver-contract.md, and the existing commit-guard.yml and status-registry/deriveComponentStatus.ts. First determine which of the four proposed items is in scope and how it relates to #2711, #2883, and #2891. Done should include an agreed guard or artifact with defined inputs, failure conditions, and release integration.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend, release, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.