Skip to content

feat(semantic): compositional coordinate-address algebra + 23×6 bridge - #1199

Closed
mdheller wants to merge 10 commits into
mainfrom
feat/semantic-coordinate-algebra
Closed

feat(semantic): compositional coordinate-address algebra + 23×6 bridge#1199
mdheller wants to merge 10 commits into
mainfrom
feat/semantic-coordinate-algebra

Conversation

@mdheller

@mdheller mdheller commented Aug 1, 2026

Copy link
Copy Markdown
Member

What

A graded, non-commutative semantic-address algebra so that semantic distance is computed from structure rather than learned from a corpus — plus the first contracts and the bridge that put it to work. Every primitive traces to a public-domain source (Aristotle's potentiality/actuality, Peirce's Firstness/Secondness/Thirdness); the provenance register in docs/SEMANTIC_COORDINATE_ALGEBRA.md is the warrant.

Commits

kernel (S0–S2) Term/add/mul/distance, pushout/pullback + one shared meet, bind_tiered, SemanticAddress (intension + extension + warrant), pluralistic Lexicons
S0 AgentCoordinateVector.v0.1 the eleven axes; 10 or 12 is rejected, exactly one primary, middle column = pushout/pullback/meet
S4 BoundaryTransition.v0.2 the nine actantial roles (universal linguistics) + skeleton() de-identification lever
S5 abstraction-level gate measures the intro→graduate mismatch rate; fails on a cross-tier match and fails vacuous
BOTTOM + derived verdict lattice abstention as a first-class value; VERDICT_ORDER derived from VERDICT_CLEARS, not authored
bridge the 23×6 intent grid lifted into the algebra — a metric + a layer on the flat grid; the sense gap becomes a first-class ⊥
adjunction design note lift ⊣ ground spec (code to follow)

Why it's trustworthy

  • 98 tests, every guard exercised on its refusal path. A control only ever seen to pass is not a control.
  • The abstraction gate is proven against deliberately broken binders (naive + lazy), from the outside.
  • Layer discipline makes a cross-abstraction match structurally impossible, not threshold-discouraged — the fix for the measured intro-physics → graduate-QFT failure.
  • Stdlib-only, local-first: the addressing kernel sits in the hot path of retrieval and every boundary crossing, so it takes no round-trip.

Scope / notes

  • Pure library + contracts + one bridge module. No service wiring in this PR.
  • Encodes the intent roster as data; the 23×6 canon stays in Noetica.
  • Unbuilt phases (S1, S3, S6–S8) and the lift ⊣ ground implementation are follow-ups.

🤖 Generated with Claude Code

…venance register

Graded, non-commutative addressing algebra so semantic distance is COMPUTED
from structure, not learned. Primitives trace to public-domain sources
(Aristotle POT/ACT, Peirce FST/SND/TRD); layer discipline makes cross-abstraction
matches structurally impossible. Ships Term/add/mul/distance, pushout/pullback
+ shared meet, bind_tiered, SemanticAddress (intension+extension+warrant), and
pluralistic versioned Lexicons. 44 tests, every guard exercised both ways.
Provenance register doubles as the clean-room warrant.
…h both ways

Every agent declares itself on exactly eleven named axes (ten sefirot + Da'at).
A vector with ten or twelve coordinates is REJECTED structurally, exactly one
axis is primary, and the three middle-column axes (chesed/gevurah/tiferet) must
be realised by pushout/pullback/meet respectively — so the middle column cannot
be reimplemented ad hoc. JSON Schema is the registry face; the stdlib validator
is the enforcement face for the two cross-field rules. 18 tests, all guards
exercised on their refusal path.
Adds a complete, non-redundant governed-action frame (Tesniere's actants + case
grammar: who, to what, for whom, by what and why, when, where, to what purpose,
how), additive over v0.1. root+initiator required; the inventory is closed so an
invented role is refused. skeleton() drops every role's surface text while
keeping shape — the concrete linkability (G2) / twin de-identification lever.
Universal linguistics, zero third-party IP. 14 tests, both ways.
Measures the quantity the KKO board never did: the rate at which an intro-level
query is bound to a graduate-level topic. Over >=30 cases it FAILS if the binder
crosses the abstraction anchor (mismatch_rate) AND FAILS as vacuous if it never
admits a correct match or never abstains on a trap — a binder that abstains on
everything scores a perfect zero and is worthless. bind_fn is a parameter so the
gate is proven to catch a naive (anchor-ignoring) and a lazy (always-abstain)
binder. Reproduces the intro-physics -> graduate-QFT trap explicitly.
…tice

Two algebra deltas, each closing a place the kernel flinched under its own test.

1. Abstention becomes a first-class value BOTTOM (Gödel: incompleteness makes
   abstention structural, so it is carried, not smuggled as None). bind_tiered and
   pullback return it; meet absorbs it; distance to it is undefined; an abstaining
   SemanticAddress is well-formed but never grounded (is_grounded False even with an
   iri). The abstraction gate is made BOTTOM-aware.

2. The verdict lattice is DERIVED from VERDICT_CLEARS (what each verdict clears) by
   derive_verdict_order, not hand-authored — the one authored canon in the kernel,
   now removed. It raises unless the verdicts form a chain; a nested verdict extends
   the order with no second edit. Mach's economy + our own derived-not-authored rule
   turned on our own code.

SPEC_VERSION 0.1.0 -> 0.2.0. 91 tests, both ways.
Lifts each intent row into a SemanticAddress, giving the flat grid the two things it
lacked and the kernel already had: a computed metric (same-column intents at distance
1, cross-column at 2 — nothing learned or curated per pair) and a layer (the meta row
conversation_objective is second-order, built one layer up out of an action address —
a fixed point in the grading, comparable only to its own order).

The columns are made explicit as {read:pullback, write:pushout} x {held=FST, world=SND,
store=TRD}. And the grid's headline finding goes structural: route a world:read query
with the sense intents absent and bind_tiered returns BOTTOM — the sense wiring gap
(thinnest column, 1/... on the primary grouping) surfaces as a first-class abstention,
not a silent mis-route. 7 tests. Encodes the roster as data; the canon stays in Noetica.
The #2 delta as its own spec: a coreflection L_n -> L_{n+1} with lift a full embedding,
ground its retraction (BOTTOM on a leaf), ground∘lift = id and p ⊑ lift(ground(p)).
Turns cross-layer relation from forbidden into warranted — distance_bridged is the only
legal crossing, raw cross-layer distance still raises. Subsumes bind_tiered (admit c iff
c ⊑ ground(anchor)) and makes Kant's schematism plural (many named morphisms, e.g.
taxonomic vs mereological). Ships P1-P6 proof obligations, each with a refusal-path test;
code to follow in its own change.
Copilot AI review requested due to automatic review settings August 1, 2026 19:26
from __future__ import annotations

from dataclasses import dataclass
from typing import Callable, List, Optional, Sequence

from __future__ import annotations

from typing import Dict, List, Optional
Comment thread tools/intent_address.py

from __future__ import annotations

from typing import Dict, List, Optional, Tuple
Comment thread tools/intent_address.py
Comment on lines +34 to +51
from tools.semantic_algebra import (
ACT,
BOTTOM,
FST,
NIL,
POT,
PRIMITIVES,
SND,
TRD,
SemanticAddress,
Term,
TermSet,
add,
bind_tiered,
distance,
mul,
prim,
)

from __future__ import annotations

import copy

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a stdlib-only “semantic address” kernel (tools/semantic_algebra.py) and related contracts/validators/tests, plus a bridge (tools/intent_address.py) that lifts the existing 23×6 intent grid into the algebra to gain a structural metric, explicit layering, and first-class abstention (BOTTOM).

Changes:

  • Added a graded, non-commutative term algebra with structural distance, tiered grounding, dual operators (pullback/pushout), an absorbing abstention value (BOTTOM), and a derived verdict lattice.
  • Added the 23×6 intent-grid bridge that assigns each intent row a SemanticAddress and provides structural routing/distance utilities.
  • Added contracts, examples, validators, and extensive “both ways” test suites for the algebra, deltas, intent bridge, actants frame, and abstraction-level gate.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tools/semantic_algebra.py Core semantic-address algebra (terms, distance, tiered binding, abstention, verdict lattice derivation, lexicons).
tools/intent_address.py Bridge from the 23×6 intent grid into the algebra; adds intent addresses, routing, distance, and fill metrics.
tools/boundary_transition_actants.py Validator + skeleton for BoundaryTransition v0.2 actantial frame.
tools/agent_coordinate_vector.py Validator for AgentCoordinateVector v0.1 with cross-field/operator-axis coherence.
tools/abstraction_level_gate.py Gate that measures abstraction-level mismatch rate against a pluggable binder.
tools/tests/test_semantic_algebra.py Main algebra conformance tests (construction, operators, distance, tiered binding, addresses, lexicons).
tools/tests/test_semantic_algebra_deltas.py Tests for BOTTOM-as-abstention and derived verdict lattice ordering.
tools/tests/test_intent_address.py Tests for intent-grid bridge (layering, metric, routing, sense-gap abstention, column fill).
tools/tests/test_boundary_transition_actants.py Tests for actantial frame validation + skeleton + shipped example validation.
tools/tests/test_agent_coordinate_vector.py Tests for AgentCoordinateVector v0.1 validation rules and shipped example validation.
tools/tests/test_abstraction_level_gate.py Tests demonstrating the gate passing real binder and failing naive/lazy binders.
docs/SEMANTIC_LAYER_ADJUNCTION.md Design note/spec for a future lift ⊣ ground layer-bridging adjunction (no code yet).
docs/SEMANTIC_COORDINATE_ALGEBRA.md Provenance register + conformance notes backing the kernel’s primitives and rules.
contracts/BoundaryTransition.v0.2.json JSON Schema for BoundaryTransition v0.2 including closed actants inventory.
contracts/AgentCoordinateVector.v0.1.json JSON Schema for AgentCoordinateVector v0.1 (11 axes, primary, operator metadata).
contracts/examples/boundary-transition-v0.2-ai-invocation.example.json Example instance for BoundaryTransition v0.2 (includes actants frame).
contracts/examples/agent-coordinate-vector-michael-agent.example.json Example instance for AgentCoordinateVector v0.1.
Suppressed comments (1)

tools/intent_address.py:182

  • column_fill() assumes every SemanticAddress has a non-abstaining Term. If any address has term is BOTTOM, accessing addr.term.layer/roles() will fail. Skip abstaining terms explicitly so the helper can operate on partial/abstaining address sets safely.
    for name, addr in addresses.items():
        if name == META_ROW or addr.term.layer != 2:
            continue
        ground = addr.term.roles()["ground"]
        col = anchors.get(ground.code())

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tools/intent_address.py
Comment on lines +158 to +171
def route(query_column: str, addresses: Dict[str, SemanticAddress]) -> "Term | object":
"""Ground a by-column query to an intent under that column, or abstain.

Returns the admitted intent's term, or BOTTOM when the column has no intent in
`addresses` — which is exactly what makes the `sense` wiring gap show up as an
honest abstention rather than a mis-route.
"""
topic_terms = [
addr.term for name, addr in addresses.items()
if name != META_ROW and addr.term.layer == 2 # layer-2 topic rows
]
upper = add(*[column_anchor(c) for c in COLUMNS])
lower = add(*topic_terms)
return bind_tiered(column_anchor(query_column), upper, lower)
Comment thread tools/intent_address.py
Comment on lines +74 to +77
def column_anchor(column: str) -> Term:
"""The layer-1 anchor for a column: substrate primitive x polarity marker."""
substrate, polarity = COLUMNS[column]
return mul(prim(SUBSTRATE_PRIM[substrate]), prim(POLARITY_PRIM[polarity]))
Comment thread tools/semantic_algebra.py
# --------------------------------------------------------------------------- #


def distance(a: Term, b: Term) -> int:
Implements the #2 delta from the design note. lift generalizes (t -> one layer up as
the ground of a neutral product), ground specializes (BOTTOM on a leaf). A coreflection:
ground(lift(t)) == t exactly, refines(p, lift(ground(p))) always. refines is the ⊑
relation (neutral = top). distance_bridged is the ONLY legal cross-layer comparison
(adjacent-only); raw cross-layer distance still raises. P1-P6 proof obligations, each
with its refusal path. Kant's schematism, now plural and typed.
…tive schemas

Self-review found two real defects, both fixed with teeth:

1. Clean-room LEAK: docs/SEMANTIC_COORDINATE_ALGEBRA.md named a third-party metalanguage
   twice in a tracked repo file, contradicting its own posture. Scrubbed to generic
   wording; and mechanized so it can't recur — tools/check_cleanroom.py scans the
   framework files and exits non-zero on any third-party mark (self-excluding, proven to
   bite on a synthetic leak).

2. DECORATIVE schemas: the JSON-Schema contracts were shipped but nothing loaded them.
   test_contract_schemas.py now validates each schema is well-formed, each example
   conforms, and a malformed doc is rejected AT THE SCHEMA (ten/twelve axes, missing
   actants, bad enum). Matches the estate's jsonschema convention.

114 tests total, all green; clean-room CLI verified clean over the real tree.
Copilot AI review requested due to automatic review settings August 1, 2026 19:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 21 changed files in this pull request and generated no new comments.

Suppressed comments (6)

tools/semantic_algebra.py:125

  • Term.__post_init__ enforces only the leaf-vs-product split, but does not enforce the stated product invariants (differentia/mode present and same-layer). Because Term is public, callers can construct invalid products (e.g., Term(ground=prim(POT))) that will later crash in code()/roles() or miscompute layer without a clear error. Consider validating product completeness and operand layers here so the type is internally consistent regardless of construction path.
    def __post_init__(self) -> None:
        is_leaf = self.primitive is not None
        is_product = self.ground is not None
        if is_leaf == is_product:
            raise ValueError("a Term is either a primitive or a product, not both/neither")
        if is_leaf and self.primitive not in PRIMITIVES:
            raise ValueError(f"unknown primitive {self.primitive!r}")

tools/intent_address.py:133

  • build_intent_addresses() assigns disambiguators by iterating sorted(INTENT_PRIMARY.items()). This makes term codes (and therefore semantic addresses) unstable: adding a new intent whose name sorts earlier will renumber every later intent’s disambiguator, changing existing addresses unexpectedly. If these addresses are persisted or compared across versions, that becomes a breaking change for a non-semantic edit.
    for i, (name, column) in enumerate(sorted(INTENT_PRIMARY.items())):
        ground = _META_COLUMN_ANCHOR if column == "meta" else column_anchor(column)
        term = mul(ground, _DISAMBIGUATORS[i])

tools/check_cleanroom.py:12

  • The module docstring says the guard and its test are “never scanned”, but scan_paths() only self-excludes check_cleanroom.py by filename. If tools/tests/test_check_cleanroom.py is passed explicitly (or the repo is scanned wholesale), the guard will flag its own fixtures and fail, contradicting the stated self-exclusion behavior.
Self-exclusion: this file and its test necessarily contain the forbidden tokens (the
patterns they scan for, and the fixtures that prove they bite), so they are never
scanned. A scanner that flags itself is broken — see the estate rule that a

docs/SEMANTIC_LAYER_ADJUNCTION.md:6

  • This design note still claims “Status: DESIGN (code to follow)” and that it “does not ship code”, but this PR now adds lift, ground, refines, and distance_bridged plus proof-obligation tests. The status/description is now materially outdated and could confuse readers about where the implementation lives.
Status: DESIGN (code to follow) · Scope: an addition to `tools/semantic_algebra.py`
Motivation: Kant's schematism, made plural and principled. This note is spec + proof
obligations; it deliberately does not ship code, because an adjunction earns its keep
only with a both-ways proof and that deserves its own change.

docs/SEMANTIC_COORDINATE_ALGEBRA.md:3

  • The status line says “v0.1”, but the implementation sets SPEC_VERSION = "0.2.0" in tools/semantic_algebra.py. If these versions are meant to track one another, the doc is now inconsistent with the shipped spec version.
Status: v0.1 · stdlib-only kernel in `tools/semantic_algebra.py`

tools/semantic_algebra.py:355

  • pullback() doesn’t validate that constraint keys are valid roles. If a caller passes an unknown key, cell.roles()[role] will raise a KeyError mid-comprehension, which is a leaky/unclear failure mode for a public API. Consider validating constraint keys up front and raising a ValueError with a helpful message.
def pullback(candidates: TermSet, constraint: Dict[str, Term]) -> "TermSet | Abstain":
    """LIMIT / restrict — keep only the cells agreeing with `constraint` on each role.

    The restrictive operator. Returns BOTTOM when the restriction is total: a
    first-class abstention the caller must reconcile, not an empty-but-fine result
    and not a smuggled ``None``.
    """
    kept = set()
    for cell in candidates.terms:
        if cell.is_leaf:
            continue
        if all(cell.roles()[role] == want for role, want in constraint.items()):
            kept.add(cell)
    return TermSet(frozenset(kept)) if kept else BOTTOM

…theory (proof, both ways)

Turns the two tightest doctrine claims into passing tests, not prose:
1. Edgeworth supermodularity (manuscript eq 21) IS the lattice meet condition — the
   cross-difference equals g(a∨b)+g(a∧b)−g(a)−g(b) with ∧=min, the same min-on-a-chain
   that semantic_algebra.meet implements. Shown equal for arbitrary cells.
2. The per-cell clipping projection (eq 57) IS a pullback onto the supermodular
   half-space: idempotent on feasible cells, lands infeasible cells exactly on the
   boundary by the minimal L2 move; dual projection for substitutability (eq 23).
11 tests both ways; spectral_grounding.py added to the clean-room manifest.
Copilot AI review requested due to automatic review settings August 1, 2026 19:49

from typing import Dict, Tuple

from tools.semantic_algebra import VERDICT_ORDER, meet

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated no new comments.

Suppressed comments (2)

tools/intent_address.py:162

  • route() will raise a ValueError when addresses contains no layer-2 topic rows because add(*topic_terms) is illegal for an empty list (TermSet must be non-empty). It also raises a KeyError for an unknown query_column. Since the docstring describes abstention (BOTTOM) as the outcome for an unrouteable query, it would be safer for route() to validate query_column and return BOTTOM when there are no candidate topic terms (instead of throwing). Also, the return annotation can be narrowed from Term | object to Term | Abstain to match the actual outcomes (bind_tiered/BOTTOM).
def route(query_column: str, addresses: Dict[str, SemanticAddress]) -> "Term | object":
    """Ground a by-column query to an intent under that column, or abstain.

    Returns the admitted intent's term, or BOTTOM when the column has no intent in
    `addresses` — which is exactly what makes the `sense` wiring gap show up as an

tools/semantic_algebra.py:126

  • Term.__post_init__ does not enforce the invariants implied by the class docs: a primitive term can still be constructed with differentia/mode set, and a product term can be constructed with differentia or mode missing (or at a different layer) if callers instantiate Term(...) directly. That can later crash in roles()/code()/distance() via None.code() or mixed-layer recursion. Consider validating product/leaf shape (and operand layers) here so invalid terms are rejected at construction, not at use sites.
    def __post_init__(self) -> None:
        is_leaf = self.primitive is not None
        is_product = self.ground is not None
        if is_leaf == is_product:
            raise ValueError("a Term is either a primitive or a product, not both/neither")

@mdheller

mdheller commented Aug 1, 2026

Copy link
Copy Markdown
Member Author

Closing in favor of the ProCybernetica sovereign lib. The kernel developed on this branch was extracted and MERGED into ProCybernetica (procyber/semantic/, #113), which is the kernel's canonical home per the grounding doctrine (superconscious #77): the kernel is vendored, not forked. Merging this PR would place a second copy of the same kernel in prophet-platform — exactly the duplication the framework's derived-not-authored discipline forbids.

The review findings raised here (route abstaining-address guard, column_anchor ValueError, distance signature, unused imports) were applied to the live kernel in ProCybernetica #116 — not to this soon-to-be-redundant copy.

Nothing is lost: the algebra, the S0/S4/S5 work, the BOTTOM+derived-lattice deltas, the lift⊣ground adjunction, the spectral-grounding proof, and the clean-room guard all live on ProCybernetica main. If prophet-platform's contract registry wants the BoundaryTransition.v0.2 (which extends its native v0.1), that's a small contracts-only follow-up that vendors procyber.semantic rather than duplicating it.

@mdheller mdheller closed this Aug 1, 2026
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.

2 participants