Skip to content

feat(commons): scaffold commons/ with canonical type specs#43

Merged
koolamusic merged 1 commit into
mainfrom
feat/commons
May 8, 2026
Merged

feat(commons): scaffold commons/ with canonical type specs#43
koolamusic merged 1 commit into
mainfrom
feat/commons

Conversation

@koolamusic

Copy link
Copy Markdown
Contributor

Summary

Establishes the in-repo candy commons discussed in PR #42's review
thread. Six canonical type specs that today every example
re-declares with byte-identical bodies, written once.

Layout

```
commons/
README.md
types/
Email.candy — RFC 5322 email; max 320; case-insensitive compare
Money.candy — integer minor units; pinned currency parameter
Hash.candy — one-way hash; constant-time verify; argon2 default
Token.candy — opaque bearer; max 256; never logged
Password.candy — transient plaintext; never persisted
Phone.candy — E.164 normalised at construction
```

One file per type. Each contains exactly one `spec` block with the
`policy`-style prose (`intent:` + meta fields + `examples:`).

Status — provisional syntax

The `spec` block, the `use spec` line, and the `refines` extension
are not yet in `GRAMMAR.md`. A grammar ratification PR follows
separately; once it lands the linter will recognise these blocks and
projects can adopt them via `use spec Email, Hash, Token` (and pin
parameters via `use spec Money(currency: USD)`).

Until ratification, `candy lint` silently ignores `spec` blocks
(unknown top-level keyword falls through the parser's recovery
path). `candy lint commons/` exits 0; nothing about this PR breaks
lint or CI.

Deliberate omissions

  • `Key` — per session feedback, the idempotency-key parameter
    type is project-defined. Projects that prefer `IdempotencyKey`
    shouldn't have to fight a commons spec named `Key`.
  • `Role` — every project's roles differ (admin/manager/user vs
    guest/host/admin vs customer/admin). No commons candidate.
  • `Id`, `Timestamp` — already language built-ins
    (`GRAMMAR.md` §type "Built-in named types"). They never needed a
    spec.

Future structure

When the grammar ratification PR lands, follow-ups for
`commons/policies/`, `commons/events/`, `commons/externals/` open up.
Out of scope here.

Test plan

  • `candy lint commons/` exits 0 (linter ignores `spec` as
    unknown keyword).
  • `candy lint examples/` continues to exit 0 (unchanged).
  • Once the grammar ratification PR lands, the linter parses
    `spec` blocks and `candy lint commons/` reports zero violations
    in this corpus.
  • One example migrates to `use spec Email, Hash, Token, ...`
    as the proof-point for the resolution mechanic. Separate PR.

Refs

Establishes the in-repo proof of concept for the candy commons
discussed in PR #42's review thread. Each shipped example currently
re-declares the same `Email`, `Money`, `Hash`, `Token`, `Password`,
`Phone` blocks with byte-identical bodies. This directory hosts
the canonical version once.

Layout: one file per type at `commons/types/<TypeName>.candy`. Each
file contains exactly one top-level `spec` block with prose-rich
intent + examples (the same shape `policy` already uses).

Status — provisional syntax. The `spec` block, the `use spec` line,
and the `refines` extension are not yet in `GRAMMAR.md`. A grammar
ratification PR will follow; once it lands, the linter will
recognise these blocks and projects can adopt them via
`use spec Email, Hash, Token` etc. Until then `candy lint` silently
ignores `spec` (unknown top-level keyword), so the directory is
safe to ship without breaking lint.

Six types shipped: Email, Money, Hash, Token, Password, Phone.
Money carries one consumer-pinned parameter (`currency`); the rest
take their canonical shape unparameterized. Deliberately omitted:
`Key` (project-defined identifier per session feedback), `Role`
(every project's roles differ), `Id` and `Timestamp` (already
language built-ins per `GRAMMAR.md` §type "Built-in named types").

Refs #42 (built-in types discussion).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant