Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). Thi
## [Unreleased]

### Added
- Vocab-currency loop — draft-term emission (closes the currency→proposal lifecycle): each remediation step now emits a conformant status:**draft** `GlossaryTerm` artifact (`result.proposedTerms`) for the token it connects — the loop PROPOSES drafts for ontogenesis's 3-method alignment pass and never self-approves (`partOfSpeech`/`alignment` are left for downstream; status stays `draft`). The CI harness now REFUSES any proposed term that doesn't conform to `GlossaryTerm.json` or that isn't status:draft, so the loop can't push malformed or self-approved vocab into the glossary. 6 teeth total.
- Vocab-currency loop v0.1 — the vocabulary-currency GovernedLoop made LIVE (task #13): `tools/vocab_currency_loop.py` instantiates the merged `GovernedLoop` contract and is governed BY it (reads bound + tolerance + `onNonConvergence` + admission from the document). The approved glossary is the FIXED set (LSA), the corpus token distribution is the OPEN set (LDA), and uncovered probability mass is the currency signal (the LSI drive: new fields that became vocab but aren't connected). Remediation connects the highest-mass uncovered term (a proposed `GlossaryTerm`), strictly decreasing divergence. Fail-closed: runs at most `maxIterations` (never spins); escalates-human (non-zero exit) if it can't reach tolerance within the bound rather than declaring currency; refuses to run unadmitted (no `superconsciousRef`). `validate-vocab-currency-loop` asserts all three teeth (converges / escalates / refuses). Emits `candidateNewVocab` for routing into ontogenesis/prophet-ontology. Dependency-free.
- DataClass v0.1 (OntoDT/OntoDQ data-side governance, task #14; AMG 2.0 deck): a `DataClass` binds a datatype-ontology class (OntoDT), the business `GlossaryTerm` (biz↔data), and a `ValidValues` domain (enum/range/regex), with an optional **TF-Lattice wide-and-deep** classifier that is a first-class CATALOGED model — `modelRef`→`ModelManifest`, `runRef`→`RunRecord`, `compute` on **Ray/TritFabric**, `monotonicFeatures` lattice constraint, and `labels` that are `GlossaryTerm` URNs (assigned in the glossary). `EntityField` gains an optional `dataClassRef`; the drift-guard enforces field↔class domain conformance + classifier integrity (labels are glossary terms, model is cataloged, compute is ray/tritfabric) + ontological typing. 4 negative vectors, teeth-verified. Backward-compatible. Two-level classifier: per-class LOGISTIC head (`DataClass.classifier`, one-vs-rest, required `evalRunRef` — individually testable per class/glossary term) + a per-table SOFTMAX `TableClassifier` aligning an LSA bag-of-words embedding AND a doc2vec sentence-encoder (the n-ary logit→class assignment), a cataloged model on Ray/TritFabric assigning N DataClasses. Drift-guard enforces both.
- Table keys/indexes as set-identifiers (v0.1): `SchemaDefinition.keys` (primary/unique/foreign/index) with recomputed rank (arity) + primitive (single-attribute). `tools/validate_key_bipartite.py` is a LIVE fail-closed tool that recomputes rank/primitive, checks key attributes are real fields, requires exactly one primary (for tables that declare keys), resolves every foreign key to a real key in the referenced entity (a Biperpedia bipartite entity↔entity line), and emits the entity↔attribute bipartite graph (`--emit`). Wired into `make validate`. Teeth-verified.
Expand Down
4 changes: 4 additions & 0 deletions specs/vocab-currency-loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ rather than declaring the vocab current; and a loop with no `admission.supercons

Next: feed the estate's real corpus + glossary, and route the emitted `candidateNewVocab` into
ontogenesis / the prophet-ontology as draft terms for the 3-method alignment pass.

## Remediation artifacts

Each connected token is emitted as a conformant status:`draft` `GlossaryTerm` in `result.proposedTerms` — the loop's output is directly ingestible by ontogenesis for the 3-method alignment pass. The loop only proposes: `partOfSpeech`, `alignment`, and approval are downstream. `make validate-vocab-currency-loop` refuses any proposed term that fails `GlossaryTerm.json` or that is not `draft` (the loop may not self-approve).
17 changes: 17 additions & 0 deletions tools/validate_vocab_currency_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
FIX = ROOT / "fixtures" / "vocab-currency"
LOOP = ROOT / "examples" / "governed_loop.vocab_currency.json"
LOOP_SCHEMA = ROOT / "schemas" / "GovernedLoop.json"
GLOSSARY_SCHEMA = ROOT / "schemas" / "GlossaryTerm.json"

FAILURES: list[str] = []
CHECKS: dict[str, bool] = {}
Expand Down Expand Up @@ -51,6 +52,22 @@ def main() -> int:
else:
CHECKS["convergent:reaches-currency"] = True

# 1b. Every proposed remediation artifact MUST conform to GlossaryTerm.json and be status:draft
# — the loop proposes drafts for ontogenesis, it must never emit a malformed or self-approved
# term. (Uses the divergent run too, which proposes the most terms.)
gt = jsonschema.Draft202012Validator(vcl.load(GLOSSARY_SCHEMA))
proposals = r.get("proposedTerms", []) + run("corpus_divergent.json").get("proposedTerms", [])
bad = [(t.get("id"), e.message) for t in proposals for e in gt.iter_errors(t)]
self_approved = [t.get("id") for t in proposals if t.get("status") != "draft"]
if bad:
FAILURES.append(f"proposed term(s) do not conform to GlossaryTerm.json: {bad[:3]}")
elif self_approved:
FAILURES.append(f"proposed term(s) not status:draft — the loop must not self-approve: {self_approved[:3]}")
elif not proposals:
FAILURES.append("expected the loop to emit proposed draft terms, got none")
else:
CHECKS["proposed-terms:conform-and-draft"] = True

# 2. Divergent corpus — a domain the vocab cannot name within the bound MUST escalate,
# never silently succeed, never spin past maxIterations.
r = run("corpus_divergent.json")
Expand Down
27 changes: 25 additions & 2 deletions tools/vocab_currency_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
D = uncovered probability mass = Σ Q(t) for corpus tokens t the approved vocab does NOT name,
where Q is the corpus token distribution (what the current state actually discusses). Remediation
= connect the single highest-Q uncovered token (propose it as a new GlossaryTerm), which lowers D
by exactly Q(t) — strictly monotone-decreasing, so `monotone-decrease` convergence is real.
by exactly Q(t) — strictly monotone-decreasing, so `monotone-decrease` convergence is real. Each
remediation emits a conformant status:draft `GlossaryTerm` ARTIFACT (`result.proposedTerms`) for
ingestion by ontogenesis — the loop proposes drafts, never self-approves (alignment happens
downstream). A proposed term that does not conform to GlossaryTerm.json is a bug the CI harness
refuses.

Fail-closed teeth:
* a loop with no `admission.superconsciousRef` is REFUSED (loops don't self-authorize);
Expand Down Expand Up @@ -86,6 +90,23 @@ def uncovered_mass(Q: dict[str, float], covered: set[str]) -> float:
return sum(q for t, q in Q.items() if t not in covered)


def proposed_term(loop_id: str, token: str, mass: float) -> dict:
"""The loop's remediation ARTIFACT: a conformant status:draft GlossaryTerm for a token the
corpus uses but the approved vocab doesn't name. `partOfSpeech`/`alignment` are deliberately
OMITTED — those are assigned by the downstream 3-method alignment pass in ontogenesis; the
loop only proposes, it does not self-approve (status stays `draft`)."""
return {
"id": f"urn:srcos:glossary:{token}",
"type": "GlossaryTerm",
"specVersion": "2.0.0",
"name": token,
"definition": (f"Proposed by vocab-currency loop {loop_id}: appears in the current corpus "
f"(mass {mass:.4f}) but is named by no approved glossary term. Awaiting "
f"3-method alignment before approval."),
"status": "draft",
}


# Convergence measures this runner actually implements: it drives divergence strictly down each
# step (monotone-decrease) until it is below tolerance (error-below-tolerance). It does NOT
# implement `fixpoint`, so a contract declaring that measure is REFUSED rather than run with
Expand Down Expand Up @@ -130,7 +151,8 @@ def run_loop(loop: dict, glossary: dict, corpus: dict) -> dict:
return {"ok": False, "escalated": "non-monotone",
"handler": on_nonconv, "detail": f"divergence did not decrease at step {i}",
"trace": trace}
connected.append({"term": tok, "massConnected": round(q, 6)})
connected.append({"term": tok, "massConnected": round(q, 6),
"proposedTerm": proposed_term(loop["id"], tok, q)})
trace.append({"iteration": i, "divergence": round(D, 6), "connected": tok})

converged = D <= tolerance
Expand All @@ -144,6 +166,7 @@ def run_loop(loop: dict, glossary: dict, corpus: dict) -> dict:
"finalDivergence": round(D, 6),
"converged": converged,
"connectedVocab": connected,
"proposedTerms": [c["proposedTerm"] for c in connected], # conformant draft GlossaryTerms
"candidateNewVocab": [{"term": t, "mass": q} for q, t in remaining[:10]],
"trace": trace,
}
Expand Down
Loading