[{"data":1,"prerenderedAt":423},["ShallowReactive",2],{"navigation_docs":3,"-design-adrs-003-overflow-policy":101,"-design-adrs-003-overflow-policy-surround":420},[4,23,66],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":22},"Guide","i-lucide-book-open","\u002Fguide","1.guide",[10,14,18],{"title":11,"path":12,"stem":13},"Introduction","\u002Fguide\u002Fintroduction","1.guide\u002F1.introduction",{"title":15,"path":16,"stem":17},"Getting started","\u002Fguide\u002Fgetting-started","1.guide\u002F2.getting-started",{"title":19,"path":20,"stem":21},"Pieces and sets","\u002Fguide\u002Fpieces-and-sets","1.guide\u002F3.pieces-and-sets",false,{"title":24,"icon":25,"path":26,"stem":27,"children":28},"Design (ADRs)","i-lucide-drafting-compass","\u002Fdesign","2.design",[29,32],{"title":30,"path":26,"stem":31},"Design decisions (ADRs)","2.design\u002Findex",{"title":33,"icon":34,"path":35,"stem":36,"children":37,"page":22},"Decision records","i-lucide-scroll-text","\u002Fdesign\u002Fadrs","2.design\u002Fadrs",[38,42,46,50,54,58,62],{"title":39,"path":40,"stem":41},"ADR-001: The refinement-chain model for calendar points","\u002Fdesign\u002Fadrs\u002F001-refinement-chain","2.design\u002Fadrs\u002F001-refinement-chain",{"title":43,"path":44,"stem":45},"ADR-002: Sets first — the Span algebra","\u002Fdesign\u002Fadrs\u002F002-set-primary-spans","2.design\u002Fadrs\u002F002-set-primary-spans",{"title":47,"path":48,"stem":49},"ADR-003: Overflow policy — clamp by default, skip on request","\u002Fdesign\u002Fadrs\u002F003-overflow-policy","2.design\u002Fadrs\u002F003-overflow-policy",{"title":51,"path":52,"stem":53},"ADR-004: Fortnights as every-k scopes","\u002Fdesign\u002Fadrs\u002F004-fortnight-scopes","2.design\u002Fadrs\u002F004-fortnight-scopes",{"title":55,"path":56,"stem":57},"ADR-005: One denotation function, and what DST does to it","\u002Fdesign\u002Fadrs\u002F005-shared-denotation","2.design\u002Fadrs\u002F005-shared-denotation",{"title":59,"path":60,"stem":61},"ADR-006: Zocam is a standalone, released library","\u002Fdesign\u002Fadrs\u002F006-standalone-library","2.design\u002Fadrs\u002F006-standalone-library",{"title":63,"path":64,"stem":65},"ADR-007: A set is one value — struct answers, enumerable shapes","\u002Fdesign\u002Fadrs\u002F007-one-value-sets","2.design\u002Fadrs\u002F007-one-value-sets",{"title":67,"path":68,"stem":69,"children":70,"icon":100},"API Reference","\u002Fapi","3.api\u002Findex",[71,72,76,80,84,88,92,96],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75},"Zocam","\u002Fapi\u002Fzocam","3.api\u002Fzocam",{"title":77,"path":78,"stem":79},"Zocam.Intervals","\u002Fapi\u002Fzocam-intervals","3.api\u002Fzocam-intervals",{"title":81,"path":82,"stem":83},"Zocam.ISO","\u002Fapi\u002Fzocam-iso","3.api\u002Fzocam-iso",{"title":85,"path":86,"stem":87},"Zocam.Point","\u002Fapi\u002Fzocam-point","3.api\u002Fzocam-point",{"title":89,"path":90,"stem":91},"Zocam.Point.ComposeError","\u002Fapi\u002Fzocam-point-composeerror","3.api\u002Fzocam-point-composeerror",{"title":93,"path":94,"stem":95},"Zocam.Span","\u002Fapi\u002Fzocam-span","3.api\u002Fzocam-span",{"title":97,"path":98,"stem":99},"Zocam.Span.Arc","\u002Fapi\u002Fzocam-span-arc","3.api\u002Fzocam-span-arc","i-lucide-braces",{"id":102,"title":47,"body":103,"description":131,"extension":414,"links":415,"meta":416,"navigation":417,"path":48,"seo":418,"stem":49,"__hash__":419},"docs\u002F2.design\u002Fadrs\u002F003-overflow-policy.md",{"type":104,"value":105,"toc":403},"minimark",[106,124,129,132,136,139,142,155,159,164,171,175,178,182,189,193,196,280,332,337,341,344,365,368,387,393,399],[107,108,109,115,116,123],"p",{},[110,111,114],"span",{"className":112},[113],"ai-slop","AI SLOP"," an AI agent wrote this page. ",[117,118,122],"a",{"href":119,"rel":120},"https:\u002F\u002Fgithub.com\u002Fyuri4n",[121],"nofollow","yuri4n",", a senior engineer, gave the direction and did the review. The review is human, thus errors can stay.",[125,126,128],"h2",{"id":127},"status","Status",[107,130,131],{},"Accepted, 2026-08-04, decided by the project owner.",[125,133,135],{"id":134},"context","Context",[107,137,138],{},"Some day numbers do not exist in some months. \"The 31st\" names nothing in February. \"The 30th of every month\" must still mean something, because users write such recurrences often.",[107,140,141],{},"The forces:",[143,144,145,149,152],"ul",{},[146,147,148],"li",{},"A recurrence is written once and runs forever. A rule that fails later harms the user at the worst moment.",[146,150,151],{},"Users who write \"the 31st\" often mean \"the end of the month\". Users who write \"Feb 29\" often mean the literal date.",[146,153,154],{},"One symbol cannot serve both intents. The library must pick a default and give an override.",[125,156,158],{"id":157},"options","Options",[160,161,163],"h3",{"id":162},"option-1-error-at-ground-time","Option 1: error at ground time",[107,165,166,170],{},[167,168,169],"code",{},"Span.ground\u002F3"," raises when an instance does not exist. Caveat: this makes valid recurrences unusable. \"The 31st of every month\" is a reasonable rule, and it would crash eleven months after it worked in January. Failure is not acceptable as a default meaning.",[160,172,174],{"id":173},"option-2-always-skip-the-missing-instance","Option 2: always skip the missing instance",[107,176,177],{},"February simply has no 31st. This is honest, but it surprises users who expect month-end behavior. Their monthly bill silently disappears in February. Silent data loss is worse than an adjusted date.",[160,179,181],{"id":180},"option-3-chosen-clamp-by-default-skip-per-point","Option 3 (chosen): clamp by default, skip per point",[107,183,184,185,188],{},"Clamp moves the overflow day to the month end: the 31st becomes Feb 28 (Feb 29 in a leap year). A per-point ",[167,186,187],{},"overflow: :skip"," field overrides this for literal dates. This is the strategy pattern: the point carries a small policy value, and one denotation function reads it.",[125,190,192],{"id":191},"decision","Decision",[107,194,195],{},"Option 3 is the chosen one. The precise rules:",[143,197,198,220,226,234,244,260,266],{},[146,199,200,201,203,204,207,208,211,212,215,216,219],{},"Every ",[167,202,85],{}," has an ",[167,205,206],{},"overflow"," field: ",[167,209,210],{},":clamp"," (the default) or ",[167,213,214],{},":skip",". ",[167,217,218],{},"Point.new!\u002F1"," validates it.",[146,221,222,223,225],{},"Under ",[167,224,210],{},", a day number that a short month cannot hold moves to the last day of that month.",[146,227,222,228,230,231,233],{},[167,229,214],{},", the instance does not exist in that month. \"Feb 29\" with ",[167,232,214],{}," fires only in leap years.",[146,235,236,239,240,243],{},[167,237,238],{},"{:day, -1}"," means the last day of the month. Negative indices count from the end. This is the honest spelling of \"month end\", distinct from ",[167,241,242],{},"day(31)"," plus clamping.",[146,245,246,247,250,251,255,256,259],{},"An ",[167,248,249],{},"{:nth, n, weekday}"," selector that finds no match always skips. A four-Wednesday month has no 5th Wednesday, and it never falls back to the 4th. This follows RFC 5545 (iCalendar). The rule stays deliberately, for least surprise. The rule splits by kind: a day number ",[252,253,254],"em",{},"measures"," into the month, so it clamps. An ordinal ",[252,257,258],{},"selects"," from what exists, so it skips.",[146,261,262,265],{},[167,263,264],{},"Point.compose\u002F2"," keeps the overflow policy of the operand whose chain holds the day segment, because the policy only acts there.",[146,267,268,269,272,273,275,276,279],{},"The clamp lives in one shared denotation function, used by both ",[167,270,271],{},"Span.member?\u002F2"," and ",[167,274,169],{}," (see ",[117,277,278],{"href":56},"ADR-005","). Otherwise \"the 31st\" would disagree between the two in February.",[281,282,287],"pre",{"className":283,"code":284,"language":285,"meta":286,"style":286},"language-mermaid shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","flowchart TD\n    A[\"day segment in month M\"] --> B{\"day exists in M?\"}\n    B -- yes --> C[\"use that day\"]\n    B -- no --> D{\"segment kind\"}\n    D -- \"number, :clamp\" --> E[\"last day of M\"]\n    D -- \"number, :skip\" --> F[\"no instance\"]\n    D -- \"{:nth, ...}\" --> F\n","mermaid","",[167,288,289,296,302,308,314,320,326],{"__ignoreMap":286},[110,290,293],{"class":291,"line":292},"line",1,[110,294,295],{},"flowchart TD\n",[110,297,299],{"class":291,"line":298},2,[110,300,301],{},"    A[\"day segment in month M\"] --> B{\"day exists in M?\"}\n",[110,303,305],{"class":291,"line":304},3,[110,306,307],{},"    B -- yes --> C[\"use that day\"]\n",[110,309,311],{"class":291,"line":310},4,[110,312,313],{},"    B -- no --> D{\"segment kind\"}\n",[110,315,317],{"class":291,"line":316},5,[110,318,319],{},"    D -- \"number, :clamp\" --> E[\"last day of M\"]\n",[110,321,323],{"class":291,"line":322},6,[110,324,325],{},"    D -- \"number, :skip\" --> F[\"no instance\"]\n",[110,327,329],{"class":291,"line":328},7,[110,330,331],{},"    D -- \"{:nth, ...}\" --> F\n",[107,333,334],{},[252,335,336],{},"Figure 1 — How a day segment resolves in a month that is too short: clamp, skip, or ordinal skip. AI generated, human reviewed.",[125,338,340],{"id":339},"consequences","Consequences",[107,342,343],{},"Easy now:",[143,345,346,349,352],{},[146,347,348],{},"Common recurrences work with no extra options. \"The 31st, monthly\" fires twelve times a year.",[146,350,351],{},"Literal dates stay expressible: one option flips the meaning per point.",[146,353,354,272,357,360,361,364],{},[167,355,356],{},"member?\u002F2",[167,358,359],{},"ground\u002F3"," cannot drift, because both call the same denotation function. The tests in ",[167,362,363],{},"test\u002Fzocam\u002Fspan_test.exs"," pin this.",[107,366,367],{},"Hard now:",[143,369,370,381],{},[146,371,372,374,375,272,377,380],{},[167,373,242],{}," under ",[167,376,210],{},[167,378,379],{},"day(-1)"," denote the same set. Two spellings for one meaning is a cost. Both spellings stay, because they state different intents.",[146,382,383,384,386],{},"The ",[167,385,206],{}," field is present on every point but acts only on day numbers. Elsewhere it is inert.",[107,388,389,390,392],{},"Open items: none. The rules are implemented, and the tests in ",[167,391,363],{}," pin them.",[394,395,396],"blockquote",{},[107,397,398],{},"Clamping applies only to day numbers in months. Weeks, weekdays, and times cannot overflow, because their vocabularies are fixed.",[400,401,402],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":286,"searchDepth":298,"depth":298,"links":404},[405,406,407,412,413],{"id":127,"depth":298,"text":128},{"id":134,"depth":298,"text":135},{"id":157,"depth":298,"text":158,"children":408},[409,410,411],{"id":162,"depth":304,"text":163},{"id":173,"depth":304,"text":174},{"id":180,"depth":304,"text":181},{"id":191,"depth":298,"text":192},{"id":339,"depth":298,"text":340},"md",null,{},true,{"title":47,"description":131},"n3Ov3F1pWzeXvsUeOBT2RMdXkrkKV04jy7dMR3VJFVU",[421,422],{"title":43,"path":44,"stem":45,"description":131,"children":-1},{"title":51,"path":52,"stem":53,"description":131,"children":-1},1786065169396]