https://gitlab.synchro.net/main/sbbs/-/work_items/326#note_10853
Design notes from reviewing the current code.
## Current behavior
The parsers accept partial input, but it is not stored as partial. The missing parts are filled in as 01: `1970` is stored as `19700101` and `1970/06` as `19700601` (`exec/tests/user/birthdate.js` expects this). As a result:
- **Age is overstated by up to a year.** Someone born in Dec 2008 was 17 on 2026-11-09, but a year-only `20080101` makes `getage()` return 18, which passes `AGE 18` in ARS.
- **Birthdays are invented.** Year-only users would get the logon birthday greeting on Jan 1 and be listed by `birthdays.js` and shown by `@BIRTH@` as if that date were real.
- **The information is lost.** A placeholder cannot be distinguished from a real Jan 1.
## Proposed storage
Store unknown parts as `00`: `CCYY0000` and `CCYYMM00`. These fit `LEN_BIRTH` (8) and existing records keep their meaning. An unpadded `CCYYMM` will not work: `split_birthdate()` reads `197006` as year 19, month 70.
## What has to change
| Code | Change |
|---|---|
| `birthdate_is_valid()` | Accept `00` parts. It rejects them now, so `getage()` would return 0 |
| `parse_birthdate()` | Stop clamping missing parts to 1, and update the test expectations |
| `getage()` | Treat unknown parts as Dec 31 or end of month, so age is never overstated |
| Birthday greeting in `logon.cpp`, `birthdays.js` | Skip unknown parts |
| `format_birthdate()`, `@BIRTH@` | Show only the known parts |
| `js_user.cpp` `birthyear`/`birthmonth`/`birthday` setters | They rewrite the other parts through clamped getters, which would turn `00` into `01` |
| Door drop files | Keep writing 01 placeholders, since doors expect a full date |
| Terminal prompts, sysop user edit | A format and template per precision; `useredit.cpp` requires exactly 10 characters |
| Web registration forms | Accept the configured precision |
`birthdays.js` already counts users with a blank birthdate as January, because `birthmonth` clamps to 1 (same cause as #1041).
## Configuration and policy
- A sysop setting for birthdate precision: Full / Year+Month / Year. This pairs with the Optional state proposed in #1331.
- Suggested: ask for exactly the configured precision rather than treating it as a minimum the user may exceed. That keeps it to one prompt and the sysop's privacy choice holds.
- Suggested: age gates use the youngest possible age for a partial date. This can delay access by up to a year but never admits an underage user. A sysop enforcing a minimum age can still require a full date.
-- *Authored by Claude (Claude Code), on behalf of @rswindell*
--- SBBSecho 3.38-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)