Repository navigation
ADR 0024 stub semantics
A fixed-date year with week-based periods states its week grid with an explicit stub.anchor that ends the first period, states with a required stub.absorb that the first and last periods take the partial weeks, and keeps a week pattern that sums to 52.
Last reviewed: 1 Nov 2026
Accepted on 1 Nov 2026 under the maintainer's delegation; may be revisited. The research proposal left this open ("Exact semantics of stub for fixed-date years with week-based periods, checked against Vishay's reported quarter ends"), and the maintainer asked for the open Phase 0 decisions to be completed without them (issue #11). Not built: in 0.1.0 subdivision.stub is rejected with UNSUPPORTED_FEATURE, and week_pattern inside a fixed_date year is rejected with UNSUPPORTED_COMBINATION. This decision is implemented in 0.2.
Vishay's 10-Q describes "13-week periods beginning on a Sunday and ending on a Saturday, except for the first fiscal quarter, which always begins on January 1, and the fourth fiscal quarter, which always ends on December 31". The quote matched the filing in an excerpt check; sec.gov refused a raw fetch, so it is not raw-verified (Evidence). The year is fixed (1 January to 31 December) but the quarters are built from weeks, so the first and last quarters absorb partial weeks.
The proposal's Vishay definition anchors the week grid so that Q1 ends on the Saturday nearest 31 March. The filing does not name that anchor, so the definition is illustrative. Vishay's reported Q1 ends, 1 Apr 2023 and 30 Mar 2024, match "Saturday nearest 31 March" (Evidence); two years are not proof of the rule.
-
D1 (resolved by this ADR). The proposal's block table documents
stub: first_and_last, a value saying the first and last periods absorb partial weeks. Its Vishay example instead writesstub: { "anchor": { "month": 3, "day": "last", "rule": "nearest" } }, an object that places the week grid. The two cannot both be the format. -
D4 (resolved by this ADR).
WEEKS_SUM_MISMATCHrequires aweek_patternto sum to 52 weeks only inside aweek_basedyear. What a pattern must sum to inside afixed_dateyear is unspecified. Vishay's[13, 13, 13, 13]sums to 52 weeks, but a fixed-date year has 365 or 366 days, so one or two days must go somewhere. -
Pattern length (found while deciding; not one of D1 to D12). The proposal's block table gives
periods12 or 13 entries, andspec/definition-v1.mdrejects any other length withINVALID_VALUE. The proposal's own Vishay example has four entries, one per quarter.
- Reproduce Vishay's reported quarter ends exactly.
- Express the grid anchor explicitly, not as an inferred default.
- Keep
stubmeaningful only where partial weeks exist (STUB_WITHOUT_FIXED_YEARin the proposal).
Pros:
- Simple to state.
Cons:
- Does not say where the week grid starts, so it cannot reproduce Vishay's Q1 end without another rule, which would be an implicit default.
Pros:
- States the grid anchor with the same
month,dayandrulevocabulary as week-based year anchors.
Cons:
- Leaves implicit which periods absorb the partial weeks; the example assumes Q1 and Q4.
Pros:
- Fully explicit; covers calendars that put the stub elsewhere.
Cons:
- More fields to validate; no real calendar in the research needs a non-default stub placement yet.
For D4, the options are: require the pattern to sum to 52 and let the stub periods absorb the remaining days; require it to describe only the whole-week interior periods; or drop the sum rule for fixed-date years and rely on tiling validation.
Option 3, with one allowed placement in spec version 1. For D4, the pattern sums to 52 and the two stub periods absorb the difference.
Shape. In 0.2, subdivision.stub is an object with two required fields:
-
anchor:{month, day, rule}, withmonth1–12,day1–31 or"last", andrulelast,firstornearest, the same vocabulary and meanings as aweek_basedyear's anchor. It has noedge. -
absorb:"first_and_last", the only value in spec version 1.
The proposal's Vishay example becomes valid by adding "absorb": "first_and_last":
"stub": {
"anchor": { "month": 3, "day": "last", "rule": "nearest" },
"absorb": "first_and_last"
}The anchor is still the proposal's illustrative one.
Meaning. In each fiscal year:
- The target date is the first occurrence of (
anchor.month,anchor.day) on or after the fiscal year's first day. - The anchor date is the qualifying weekday chosen from the target by
rule. The qualifying weekday is the day beforeweek.starts_on, as foredge: "end"in ADR-0028. So every period after the first starts onweek.starts_on, and the period grid lines up with the week grid. - Period 1 runs from the fiscal year's first day to the anchor date, inclusive.
- Periods 2 to n − 1 are exactly
periods[k]weeks each. - Period n runs from the next day to the fiscal year's last day.
D4. periods must sum to 52 inside a fixed_date year too, and WEEKS_SUM_MISMATCH applies there. periods[0] and periods[n − 1] are the nominal lengths of the two stub periods. Validation then checks every fiscal year in the supported range and rejects the definition if either stub period differs from its nominal length by seven days or more, or would be empty. For the illustrative Vishay anchor, a hand calculation over years 1 to 9999 gives Q1 between four days shorter and three days longer than 13 weeks, and Q4 between one day shorter and five days longer; this calculation is not yet a committed check. extra_week is not allowed in a stub year, because there is no 53rd week: the last period absorbs the extra days.
Where stub is valid. Only with subdivision.type: "week_pattern" inside a fixed_date year. Inside a week_based year it is STUB_WITHOUT_FIXED_YEAR, the proposal's code. A week_pattern inside a fixed_date year without stub is MISSING_FIELD at subdivision.stub. The proposal's code also allows stub in a table year; that combination is not decided here (ADR-0022 leaves it open), so 0.2 rejects it with UNSUPPORTED_COMBINATION.
Pattern length. In 0.2, periods may have 4 entries (one period per quarter) as well as 12 or 13, in any year type, so that the proposal's Vishay example can be written as it stands. The rule does not depend on the year type, which keeps the blocks independent (ADR-0005).
What decided it:
- Option 1 needs a hidden default. Without an anchor, the grid position would have to be inferred, which the decision drivers and AGENTS.md design rule 10 rule out.
- Option 2 alone leaves the placement implicit. Adding a placement field later as optional would create a silent default, and adding it as required would break every definition written for 0.2. A required field with one allowed value costs one line now, and a later value is an addition, not a breaking change. This is a judgement, not evidence: the research has no calendar with another placement.
-
Option 3 resolves D1 without discarding either source. The block table's
first_and_lastbecomes the value ofabsorb, and the example's object becomesanchor. -
The 52-week sum keeps a useful check (D4). Describing only the interior periods would make
quartersandextra_week.periodcount different things in different year types. Dropping the sum would stop catching a mistyped pattern such as[13, 13, 13, 12]. With the sum and the seven-day bound, the pattern's first and last entries keep a meaning that validation enforces. - The anchor shape does not depend on Vishay's real anchor. The anchor is data in each definition. Whether Vishay's own definition uses "Saturday nearest 31 March" is a separate, open question about the illustrative example.
Good:
- D1 and D4 are resolved, and a Vishay-style calendar can be written without an implicit rule once 0.2 ships.
- Every period boundary after the first falls on a week boundary.
Bad:
- Two required fields where the proposal's example has one. Definitions copied from the proposal fail validation with
MISSING_FIELDuntilabsorbis added; the hint can name it. - A fixed-date year with the stub at only one end cannot be written until a new
absorbvalue is added by a later ADR.
What 0.2 must implement:
- The shape, meaning and validation above, in
spec/definition-v1.mdand the core, with the reserved-list entry forsubdivision.stubremoved. -
STUB_WITHOUT_FIXED_YEAR, a code for a stub period outside the seven-day bound or empty, and the widened descriptions ofWEEKS_SUM_MISMATCHandINVALID_VALUEforperiods, all in the catalogue inspec/api-v1.mdin the same pull request. The new code's name is fixed in that change. - A committed check in
research/verification/that reproduces the seven-day bound for the illustrative anchor, computed independently of fiscalclock. - A cited Vishay conformance vector, which Gate C on the Roadmap requires. Its expected quarter ends must come from Vishay's filings for several years, not from the illustrative anchor and not from running fiscalclock. Until then the Vishay definition stays illustrative.
- The Definition-Format page updated to the decided shape.
Not decided here:
- Whether Vishay's real anchor is the Saturday nearest 31 March.
-
stubinside atableyear. - Any
absorbvalue other thanfirst_and_last.
fiscalclock is licensed under MIT OR Apache-2.0 (MIT, Apache-2.0). Last reviewed: 31 Oct 2026. Found an error on this page? Report it with the documentation form.