Two items from the menu, fanned out:
1. time-series-quantized@v1 — last meaningful π* stub graduates.
Sample-array carrier (sensor / temporal data) joins the registry
alongside text · claim_lattice · code · arithmetic · logic.
Quantizes to (dt, dv) grid, sorts by timestamp, dedupes
collisions (last wins), serializes as integer-vector text:
dt=1;dv=0.1;n=2;t0=0:10|20
Equivalence classes preserved: timestamp jitter < Δ_t,
value jitter < Δ_v/2 (banker's rounding), out-of-order samples,
different JSON presentation. Distinct: any change to dt/dv grid,
any quantized value or timestamp difference. Projective —
canonical text is not valid JSON, so re-canonicalization raises.
- 13 unit tests in tests/test_pi_star.py (jitter, dedupe, sort,
fractional dv, error paths, idempotency-projective)
- 10 syntax + 12 semantics fixtures under bench/fixtures/5s/
(10/10 + 12/12 pass)
- bench-5s-time-series Makefile target
- time_series added to PHASE_1_CARRIERS whitelist
- tabular-pinned@v1 is now the only remaining stub
2. Substrate docs — first formal coverage of the registry, bench
harness, and v8 ForkScore at arborist.unturf.com:
- docs/_source/pi-star.rst: registry overview, cross-modality
discipline (carrier + pi_star_ref), math π* highlights
(arithmetic + logic-kernel worked examples), composition
algebra pointer, authoring checklist (8 steps).
- docs/_source/bench.rst: 5S/5T/5F/5R structure, sub-batteries,
phase-1 carriers, ForkScore integration, fixture format,
reproducibility (runtime_digest, fixture_digest).
- docs/_source/v8-fork-score.rst: formula, default weights,
verdict thresholds (ACCEPT/MARGINAL/REJECT), hard-regression +
NEG_INF_REGRESSION flags, CLI usage.
- index.rst gets a "Substrate" toctree section above the existing
module-reference autosummary.
Sphinx build clean (3 new pages, no new warnings).
Test suite: 1269 passed, 36 skipped.
134 lines
5.2 KiB
ReStructuredText
134 lines
5.2 KiB
ReStructuredText
π* domain library
|
||
=================
|
||
|
||
Arborist's canonical-projection registry — the substrate that
|
||
implements SQD whitepaper §3's invariant projection
|
||
``π*: Σ* → 𝓘 ∪ {⊥}``. Every modality the bench surface or audit
|
||
chain touches has (or reserves) a registered π* that maps surface
|
||
bytes to canonical bytes; the SHA-256 of the canonical bytes is
|
||
the equivalence-class identity.
|
||
|
||
Registry overview
|
||
-----------------
|
||
|
||
Lookup is by ``name@version`` key. Six concrete π*'s + one stub
|
||
ship today:
|
||
|
||
========================== =========== ===========================================================
|
||
Key Domain Status
|
||
========================== =========== ===========================================================
|
||
``wikitext-base@v1`` text Wikitext → plain prose (Phase 1a)
|
||
``claim-lattice@v1`` text Claim lines → JSON parsed-claim list (Phase 1a)
|
||
``code-py-ast@v1`` code Python source → canonical AST S-expression
|
||
``arithmetic@v1`` arithmetic Expression → exact rational ``num/den`` (SQD §14.1)
|
||
``logic-kernel@v1`` logic Boolean expression → canonical CNF (SQD §14.3)
|
||
``time-series-quantized@v1`` time-series JSON sample array → quantized integer vector
|
||
``tabular-pinned@v1`` tabular reserved (stub)
|
||
========================== =========== ===========================================================
|
||
|
||
Cross-modality discipline
|
||
-------------------------
|
||
|
||
Every bench fixture and audit-bound canonicalization names its
|
||
:class:`PiStar` via:
|
||
|
||
- ``carrier`` — a Phase-1 whitelist enforced by
|
||
:data:`bench.batteries.base.PHASE_1_CARRIERS`
|
||
- ``pi_star_ref`` — the registry key
|
||
|
||
Unsupported carriers fail or skip explicitly with
|
||
``reason="unsupported_carrier"`` — never silently accepted.
|
||
Hidden-channel work is defensive only (detection / flagging,
|
||
never generation or concealment).
|
||
|
||
The discipline gives every benchmark, every audit row, and every
|
||
selection score a stable answer to "what canonicalizer was used"
|
||
that survives schema migrations and is reproducible from the
|
||
canonical bytes alone.
|
||
|
||
Math π*'s — SQD §14
|
||
-------------------
|
||
|
||
Two of the most recently graduated π*'s implement the SQD
|
||
whitepaper's math substrate:
|
||
|
||
**arithmetic@v1** — closed-form rational arithmetic. Solves the
|
||
canonical SQD test exactly:
|
||
|
||
.. code-block:: python
|
||
|
||
from arborist.pi_star import get
|
||
ps = get("arithmetic@v1")
|
||
|
||
ps.canonicalize(b"0.1+0.2") # → b"3/10"
|
||
ps.canonicalize(b"0.3") # → b"3/10"
|
||
ps.canonicalize(b"1+2") # → b"3/1"
|
||
ps.canonicalize(b"6/4") # → b"3/2" (lowest terms)
|
||
|
||
No floating-point drift — ``Decimal(str(0.1))`` gives exact
|
||
``1/10``, then ``fractions.Fraction`` arithmetic stays in ℚ.
|
||
Identifiers, function calls, division by zero, and non-integer
|
||
exponents raise :class:`PiStarError`.
|
||
|
||
**logic-kernel@v1** — propositional Boolean expression →
|
||
Conjunctive Normal Form (CNF):
|
||
|
||
.. code-block:: python
|
||
|
||
ps = get("logic-kernel@v1")
|
||
|
||
ps.canonicalize(b"A AND B") # → b"A AND B"
|
||
ps.canonicalize(b"B AND A") # → b"A AND B" (commutativity)
|
||
ps.canonicalize(b"A IMPL B") # → b"(NOT A OR B)"
|
||
ps.canonicalize(b"(NOT B) IMPL (NOT A)") # → b"(NOT A OR B)" (contrapositive)
|
||
ps.canonicalize(b"NOT NOT A") # → b"A" (double negation)
|
||
ps.canonicalize(b"A OR NOT A") # → b"TRUE" (tautology)
|
||
|
||
Atom cap: 8 (CNF expansion is exponential; cap keeps
|
||
canonicalization deterministic in bounded time).
|
||
|
||
Equivalences preserved:
|
||
commutativity, associativity, IMPL/IFF/XOR rewrites, De Morgan,
|
||
double negation, distribution, idempotence, tautology collapse,
|
||
contrapositive.
|
||
|
||
Composition algebra
|
||
-------------------
|
||
|
||
Two π*'s can be composed into a third via
|
||
:func:`arborist.pi_star.compose`:
|
||
|
||
.. code-block:: python
|
||
|
||
from arborist.pi_star import compose
|
||
|
||
chain = compose("wikitext-base@v1", "claim-lattice@v1")
|
||
# Auto-registers as "wikitext-base-then-claim-lattice@v1"
|
||
chain.canonicalize(b"- The release date was July 3, 1985. [E1]")
|
||
|
||
Each composition is itself a registered π* with its own key. See
|
||
:file:`docs/pi-star-composition.md` for the algebra (type
|
||
compatibility, determinism preservation, equivalence-class
|
||
preservation, projective vs invertible compositions).
|
||
|
||
Authoring a new π*
|
||
------------------
|
||
|
||
1. Add ``arborist/pi_star/<name>.py`` with a frozen dataclass
|
||
declaring ``name``, ``version``, ``domain``, and a
|
||
``canonicalize(self, raw: bytes) -> bytes`` method.
|
||
2. Call :func:`arborist.pi_star.register` at module import time.
|
||
3. Import the new module in ``arborist/pi_star/__init__.py`` so
|
||
the registration fires at package load.
|
||
4. Write tests covering: idempotency on the canonical form (or
|
||
document projective behavior), equivalence classes preserved,
|
||
equivalence classes kept distinct, error paths (bad input
|
||
rejected explicitly).
|
||
5. Add bench fixtures under ``bench/fixtures/5s/{syntax,semantics}-<name>-v1.jsonl``
|
||
exercising the new carrier through the existing 5S Syntax and
|
||
Semantics runners.
|
||
6. Add the carrier name to
|
||
:data:`bench.batteries.base.PHASE_1_CARRIERS`.
|
||
7. Add ``make bench-5s-<name>`` Makefile target.
|
||
|
||
See :file:`docs/spec-methodology.md` for the full discipline.
|