Skip to content

feat(recurring): close the two cadence vocabularies and separate them - #5

Merged
lessevv merged 1 commit into
mainfrom
feat/closed-cadence-vocabularies
Jul 28, 2026
Merged

feat(recurring): close the two cadence vocabularies and separate them#5
lessevv merged 1 commit into
mainfrom
feat/closed-cadence-vocabularies

Conversation

@lessevv

@lessevv lessevv commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • C2-R20 closes the series cadence vocabulary to weekly, monthly, quarterly, yearly, irregular.
  • C8-R22 closes the digest cadence vocabulary to daily, weekly, off.
  • Both require one named type rather than free strings, and a constrained column. Both state that the two vocabularies are distinct and must not share a type.

Why

Two different closed sets are both called "cadence", both are carried as free strings, and they overlap on the value weekly. Nothing in the spec says they are different things, and nothing in the product stops a value outside either set from being written.

The series cadence is already described in C2's prose — "snaps to a named cadence — weekly, monthly, quarterly, yearly — or declares the series irregular" — but never required to be closed. The consequence is visible in the schema: in the same migration that creates recurring_series, the state column gets a CHECK constraint built from an explicit allowed list, while cadence gets a bare string(24) with a default. Two closed vocabularies on one table, governed differently, with nothing in the spec to say the second one is closed at all.

The digest cadence is referenced in C8 only as "the user's chosen cadence". What may be chosen is daily, weekly, or off, which appears nowhere except in the code that reads it.

The overlap is the part worth being explicit about. Both sets contain weekly, so a single shared type is an easy and wrong simplification: it would let a digest preference of off be assigned to a series, and a series cadence of quarterly be assigned to a digest. C8-R22 says they must not share a type for that reason.

What this enables

Implementation is a follow-up in beatrax, citing these identifiers: a backed enum per vocabulary, and a CHECK constraint on each column matching how recurring_series.state is already governed.

It also removes a cause rather than a symptom. The cadence literals appear a few hundred times across Recurring, Forecasting, Calendar, Notifications, DriftAlerts and Position, and the duplicated-literal findings that keep surfacing there are that absence of a type showing through.

Checklist

  • just integrity — spec integrity clean
  • typos clean on both changed files
  • Requirements appended, never renumbered (GOV-R10) — C2 ends at R19, C8 at R21
  • Both new rows are MUST, testable, and name the vocabulary explicitly
  • The cross-reference between C2 and C8 is bidirectional
  • Commit is signed off and carries a Spec: trailer

Two different closed sets are both called cadence, and both are carried as
free strings. A series cadence is weekly, monthly, quarterly, yearly, or
irregular. A digest cadence is daily, weekly, or off. They overlap on one
value and on the word, and nothing anywhere says they are different things.

C2 already described the five series outcomes in prose but never required
the set to be closed, so the column that stores it is a bare string while
the state column beside it carries a CHECK constraint built from its own
allowed list. C8 refers to the user's chosen digest cadence without ever
saying what may be chosen.

C2-R20 and C8-R22 close both sets, require each to be one named type
rather than free strings, require the stored column to be constrained, and
state that the two are distinct and MUST NOT share a type.

Spec: GOV-R13
Signed-off-by: Wessel Verheij <info@nightworks.io>
@lessevv
lessevv enabled auto-merge (squash) July 28, 2026 22:56
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant