The ONE shared product changelog-seq invariant (Plan 142 — all-or-none).
Purpose
-------
A ``kind=product`` changelog set is rendered verbatim in ``extensions.changelog_seq``
order when sequenced. This is the single source of truth for the all-or-none seq
rule. The render path (``render_root_changelog``) calls it now (fail-loud); the
Phase-2 regenerate-time invariant (``cross_record`` → ``SRC_PRODUCT_CHANGELOG_SEQ``)
**will** call the same helper, so the render and the validator never drift (the P6
roadmap seq rule lived in two copies; the product rule is shared by contract).
Rule: if NO record carries a seq → structured fallback (return ``None``, ok). If ANY
record carries a seq → EVERY record must carry a **unique positive int** seq;
missing-in-a-sequenced-set / non-int / ``bool`` / non-positive / duplicate is a
violation. ``bool`` is checked before ``int`` (``True``/``False`` are int subclasses).
Responsibilities
----------------
- ``extract_seq`` (read ``extensions.changelog_seq`` off a model), ``check_changelog_seq``
(return ``None`` if ok, else a human-readable problem string for the caller to raise).
Diagnostics
-----------
Domain: OC_CHAT.MAIN
Levels:
L2 - validation lifecycle
L3 - per-record seq check
L4 - seq value tracing
Contracts
---------
- Pure / read-only; the caller decides the exception type (ValueError at render,
SourceValidationError at regenerate).
Dependencies
------------
- oc_diagnostics (structured debug logging via _dbg)