Spaces:
Running
Running
chore(sync): mirror backend .py + Dockerfile to Space (hf-sync-backend)
Browse filesAutomated backend sync from szl-holdings/a11oy main via hf-sync-backend.
Updated (differed from the Space): Dockerfile, serve.py, szl3d_holographic.py, szl_brainlineage.py
Deleted (gone from the repo + Dockerfile COPY set): (none)
Keeps the Space-built backend (serve.py + the Dockerfile-COPY'd .py
modules) identical to GitHub main so the Space never rebuilds from a
stale backend, new endpoints don't 404 there, and orphaned modules
removed from the repo don't linger in the Space tree.
- Dockerfile +11 -0
- serve.py +20 -0
- szl3d_holographic.py +1 -0
- szl_brainlineage.py +656 -0
Dockerfile
CHANGED
|
@@ -1546,6 +1546,17 @@ COPY szl_brainconsensus.py ./szl_brainconsensus.py
|
|
| 1546 |
# brainqueryaudit.js ships via the existing whole-tree `COPY static/3d/ ./static/3d/`
|
| 1547 |
# above. RECORDS/OBSERVES only — adds NOTHING to the locked-8; Λ = Conjecture 1; trust 0.97.
|
| 1548 |
COPY szl_brainqueryaudit.py ./szl_brainqueryaudit.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1549 |
|
| 1550 |
|
| 1551 |
# WAVE R Dev 1 — boot-resilience env/secret preflight. Per-file COPY (this
|
|
|
|
| 1546 |
# brainqueryaudit.js ships via the existing whole-tree `COPY static/3d/ ./static/3d/`
|
| 1547 |
# above. RECORDS/OBSERVES only — adds NOTHING to the locked-8; Λ = Conjecture 1; trust 0.97.
|
| 1548 |
COPY szl_brainqueryaudit.py ./szl_brainqueryaudit.py
|
| 1549 |
+
# BRAIN LINEAGE (feat/frontier-brainlineage) — NODE-ORIGIN lineage over the SAME
|
| 1550 |
+
# honest brain graph: for a node id or a query's top nodes it reports HOW each node
|
| 1551 |
+
# ENTERED the graph, read VERBATIM from the node's OWN real origin fields
|
| 1552 |
+
# (source/url → structural derivation → none) → TRACED/PARTIAL-LINEAGE/UNKNOWN-ORIGIN,
|
| 1553 |
+
# never a fabricated source; POST .../receipt mints an UNSIGNED SHA-256 digest on write.
|
| 1554 |
+
# Its only import (szl_brain_api) is already in the COPY set; its 3D surface
|
| 1555 |
+
# brainlineage.js ships via the whole-tree `COPY static/3d/ ./static/3d/` above.
|
| 1556 |
+
# Node-origin lineage — NOT per-answer provenance, NOT build/model attestation. Adds
|
| 1557 |
+
# NOTHING to the locked-8; Λ = Conjecture 1; trust 0.97.
|
| 1558 |
+
COPY szl_brainlineage.py ./szl_brainlineage.py
|
| 1559 |
+
|
| 1560 |
|
| 1561 |
|
| 1562 |
# WAVE R Dev 1 — boot-resilience env/secret preflight. Per-file COPY (this
|
serve.py
CHANGED
|
@@ -1179,6 +1179,26 @@ except Exception as _brainqueryaudit_e: # pragma: no cover
|
|
| 1179 |
print(f"[a11oy] Brain query audit NOT registered: {_brainqueryaudit_e!r}; SPA + API unaffected", file=__import__("sys").stderr)
|
| 1180 |
|
| 1181 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1182 |
# -- BRAIN COMMAND view (Wave O / Dev 5) — the founder's "Brain powering the
|
| 1183 |
# ecosystem" dashboard. Read-only command rollup over the Brain nervous-system hub:
|
| 1184 |
# GET /api/a11oy/v1/brain/command → {knowledge harvested, energy harnessed, organs/
|
|
|
|
| 1179 |
print(f"[a11oy] Brain query audit NOT registered: {_brainqueryaudit_e!r}; SPA + API unaffected", file=__import__("sys").stderr)
|
| 1180 |
|
| 1181 |
|
| 1182 |
+
# -- BRAIN LINEAGE (feat/frontier-brainlineage) — NODE-ORIGIN lineage over the SAME honest
|
| 1183 |
+
# brain graph: GET /api/a11oy/v1/brain/lineage/info (static describe + which real origin fields
|
| 1184 |
+
# it reads), GET /api/a11oy/v1/brain/lineage?id= (origin chain for one node + verdict) or ?q=
|
| 1185 |
+
# (origin chains for a query's top nodes). For each node it reports HOW it ENTERED the graph,
|
| 1186 |
+
# read VERBATIM from the node's OWN real fields (source/url → structural derivation → none) →
|
| 1187 |
+
# TRACED/PARTIAL-LINEAGE/UNKNOWN-ORIGIN. A node with no source field is UNKNOWN-ORIGIN — NEVER a
|
| 1188 |
+
# fabricated source; the aggregate is NEVER TRACED while any origin is UNKNOWN. POST .../lineage/
|
| 1189 |
+
# receipt mints an UNSIGNED SHA-256 content digest on write only (0 sign-on-GET). This is
|
| 1190 |
+
# node-origin lineage (where a fact came from) — NOT per-answer provenance, NOT build/model
|
| 1191 |
+
# attestation, NOT counter-UAS. Reuses szl_brain_api.get_index (invents no node). Adds NOTHING to
|
| 1192 |
+
# the locked-8; Λ stays Conjecture 1. Registered BEFORE the SPA /{full_path:path} catch-all.
|
| 1193 |
+
# Additive, try/except-guarded. szl_brainlineage.py is per-file COPY'd in the Dockerfile.
|
| 1194 |
+
try:
|
| 1195 |
+
import szl_brainlineage as _szl_brainlineage
|
| 1196 |
+
_brainlineage_status = _szl_brainlineage.register(app, ns="a11oy")
|
| 1197 |
+
print(f"[a11oy] Brain lineage registered: {_brainlineage_status}", file=__import__("sys").stderr)
|
| 1198 |
+
except Exception as _brainlineage_e: # pragma: no cover
|
| 1199 |
+
print(f"[a11oy] Brain lineage NOT registered: {_brainlineage_e!r}; SPA + API unaffected", file=__import__("sys").stderr)
|
| 1200 |
+
|
| 1201 |
+
|
| 1202 |
# -- BRAIN COMMAND view (Wave O / Dev 5) — the founder's "Brain powering the
|
| 1203 |
# ecosystem" dashboard. Read-only command rollup over the Brain nervous-system hub:
|
| 1204 |
# GET /api/a11oy/v1/brain/command → {knowledge harvested, energy harnessed, organs/
|
szl3d_holographic.py
CHANGED
|
@@ -146,6 +146,7 @@ SURFACES: List[Dict[str, str]] = [
|
|
| 146 |
{"id": "brainwatch", "cat": "brain", "title": "Brain Watch · knowledge-graph honesty-posture drift monitor · MEASURED label-distribution/orphan/community/salience snapshot vs a caller-supplied PRIOR → STABLE/DRIFTING/DEGRADED/BASELINE-ONLY (no fabricated trend without a real prior), unsigned SHA-256 receipt-on-write", "owner": "WaveT-Dev1"},
|
| 147 |
{"id": "brainconsensus", "cat": "brain", "title": "Brain Consensus · honest corroboration of a brain grounding · measures how MANY distinct nodes support a query and how many distinct communities they span (cross-community agreement is stronger than one clique) → CORROBORATED/WEAK-CORROBORATION/SINGLE-SOURCE, single-source-risk flag when support collapses to one node/community, never CORROBORATED while that flag is set, MODELED corroboration honesty not a truth guarantee, unsigned SHA-256 receipt-on-write", "owner": "WaveU-Dev1"},
|
| 148 |
{"id": "brainqueryaudit", "cat": "brain", "title": "Brain Query Audit · append-only hash-linked ledger of brain queries + the honest verdict each returned · POST appends {query, verdict, grounding_label} and mints an UNSIGNED SHA-256 receipt chained to the prior entry (tamper-evident); GET recomputes the whole chain → CHAIN-INTACT/CHAIN-BROKEN (never softened), ephemeral in-memory ledger labelled honestly, MODELED, receipt-on-write-not-on-read", "owner": "WaveT-Dev1"},
|
|
|
|
| 149 |
]
|
| 150 |
|
| 151 |
# Content-type by extension (the only extensions we serve from the 3d tree).
|
|
|
|
| 146 |
{"id": "brainwatch", "cat": "brain", "title": "Brain Watch · knowledge-graph honesty-posture drift monitor · MEASURED label-distribution/orphan/community/salience snapshot vs a caller-supplied PRIOR → STABLE/DRIFTING/DEGRADED/BASELINE-ONLY (no fabricated trend without a real prior), unsigned SHA-256 receipt-on-write", "owner": "WaveT-Dev1"},
|
| 147 |
{"id": "brainconsensus", "cat": "brain", "title": "Brain Consensus · honest corroboration of a brain grounding · measures how MANY distinct nodes support a query and how many distinct communities they span (cross-community agreement is stronger than one clique) → CORROBORATED/WEAK-CORROBORATION/SINGLE-SOURCE, single-source-risk flag when support collapses to one node/community, never CORROBORATED while that flag is set, MODELED corroboration honesty not a truth guarantee, unsigned SHA-256 receipt-on-write", "owner": "WaveU-Dev1"},
|
| 148 |
{"id": "brainqueryaudit", "cat": "brain", "title": "Brain Query Audit · append-only hash-linked ledger of brain queries + the honest verdict each returned · POST appends {query, verdict, grounding_label} and mints an UNSIGNED SHA-256 receipt chained to the prior entry (tamper-evident); GET recomputes the whole chain → CHAIN-INTACT/CHAIN-BROKEN (never softened), ephemeral in-memory ledger labelled honestly, MODELED, receipt-on-write-not-on-read", "owner": "WaveT-Dev1"},
|
| 149 |
+
{"id": "brainlineage", "cat": "brain", "title": "Brain Lineage · node-origin chain · how each knowledge-graph node ENTERED the graph, read VERBATIM from its OWN real origin fields (source/url → structural derivation → none) → TRACED/PARTIAL-LINEAGE/UNKNOWN-ORIGIN, a node with no source is UNKNOWN-ORIGIN never a fabricated source, aggregate never TRACED while any origin UNKNOWN, unsigned SHA-256 receipt-on-write (node-origin lineage, NOT per-answer provenance, NOT build/model attestation)", "owner": "WaveT-Dev1"},
|
| 150 |
]
|
| 151 |
|
| 152 |
# Content-type by extension (the only extensions we serve from the 3d tree).
|
szl_brainlineage.py
ADDED
|
@@ -0,0 +1,656 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 2 |
+
# © 2026 Lutar, Stephen P. — SZL Holdings · ORCID 0009-0001-0110-4173 · Doctrine v11 LOCKED
|
| 3 |
+
# Signed-off-by: Stephen Lutar <stephenlutar2@gmail.com>
|
| 4 |
+
"""szl_brainlineage.py — NODE-ORIGIN LINEAGE over the honest brain graph.
|
| 5 |
+
|
| 6 |
+
This surface answers ONE honest question about a knowledge-graph node: HOW did
|
| 7 |
+
this node ENTER the graph — what is its harvest/origin metadata chain? It reads
|
| 8 |
+
ONLY the real fields the brain builder (a11oy_brain_graph) actually attached to
|
| 9 |
+
each node and reconstructs an ordered ORIGIN CHAIN from them. When a node carries
|
| 10 |
+
NO origin/source field, it reports origin = UNKNOWN — it NEVER fabricates a source.
|
| 11 |
+
|
| 12 |
+
This is KNOWLEDGE-GRAPH PROVENANCE-OF-NODE-ORIGIN (where did this fact come from),
|
| 13 |
+
and is DISTINCT from szl_brainprovenance (which nodes supported an ANSWER). It is
|
| 14 |
+
STRICTLY knowledge-graph honesty. It is explicitly NOT:
|
| 15 |
+
* cryptographic attestation of a model, weapon, or artifact,
|
| 16 |
+
* SLSA / in-toto / Rekor BUILD provenance of an image or binary,
|
| 17 |
+
* any counter-UAS / targeting / fusion / effector capability.
|
| 18 |
+
|
| 19 |
+
WHAT IT READS (the REAL origin fields, per node, VERBATIM — never invented):
|
| 20 |
+
STRONG (explicit cited source) : source, url
|
| 21 |
+
STRUCTURAL (derivation/harvest) : derived_from, axis, src_layer, ring, org,
|
| 22 |
+
domain, path, organ, formula_id, asset
|
| 23 |
+
WEAK (classification only) : node_label / label, community, kind, layer
|
| 24 |
+
A node's origin is TRACED only from a STRONG field; a STRUCTURAL field yields a
|
| 25 |
+
partial, structural-only chain; WEAK signals alone are not an origin.
|
| 26 |
+
|
| 27 |
+
VERDICT (per node, and aggregated over a query's top nodes):
|
| 28 |
+
TRACED — an explicit cited source (source and/or url) is present;
|
| 29 |
+
the origin chain traces to a real, named source.
|
| 30 |
+
PARTIAL-LINEAGE — no explicit source, but a structural/derivation origin is
|
| 31 |
+
inferable (derived_from / harvest axis / organ / org / …).
|
| 32 |
+
UNKNOWN-ORIGIN — no origin/source field at all; origin = UNKNOWN. NEVER a
|
| 33 |
+
fabricated source.
|
| 34 |
+
|
| 35 |
+
LABEL (this surface's honest read of the origin, per node):
|
| 36 |
+
MODELED — an explicit source exists; the chain is modeled from real
|
| 37 |
+
source/url fields.
|
| 38 |
+
STRUCTURAL-ONLY — only a structural (no explicit source) origin is inferable,
|
| 39 |
+
or the origin is UNKNOWN.
|
| 40 |
+
|
| 41 |
+
RECEIPTS — RECEIPT-ON-WRITE, NOT ON-READ. The GET info/lineage reads mint NOTHING.
|
| 42 |
+
Only POST .../receipt emits an UNSIGNED SHA-256 content digest over the origin
|
| 43 |
+
chain(s) (mirrors the brainprovenance content-digest pattern) — a plain content
|
| 44 |
+
hash, never a fabricated signature, never a receipt on a GET.
|
| 45 |
+
|
| 46 |
+
DOCTRINE v11:
|
| 47 |
+
* Adds NOTHING to the locked-8 {F1,F4,F7,F11,F12,F18,F19,F22}; it only re-reads
|
| 48 |
+
the brain's OWN node fields. Touches no locked formula and no kernel.
|
| 49 |
+
* Λ stays Conjecture 1 (never a theorem); Khipu BFT stays Conjecture 2. Trust
|
| 50 |
+
ceiling 0.97, never 100%. No label is ever upgraded; UNKNOWN is never hidden.
|
| 51 |
+
* Pure stdlib + numpy (numpy import is guarded; a pure-python path is used when
|
| 52 |
+
it is absent). Additive routes, registered before the SPA catch-all. 0 runtime
|
| 53 |
+
CDN.
|
| 54 |
+
"""
|
| 55 |
+
|
| 56 |
+
import datetime
|
| 57 |
+
import hashlib
|
| 58 |
+
import json
|
| 59 |
+
|
| 60 |
+
try: # numpy is allowed; keep it optional so a missing wheel degrades honestly.
|
| 61 |
+
import numpy as _np
|
| 62 |
+
_HAVE_NUMPY = True
|
| 63 |
+
except Exception: # pragma: no cover - numpy is a core dep, but stay honest
|
| 64 |
+
_np = None
|
| 65 |
+
_HAVE_NUMPY = False
|
| 66 |
+
|
| 67 |
+
# Honest Doctrine v11 labels (verbatim — never upgraded).
|
| 68 |
+
MODELED = "MODELED" # explicit source => origin chain modeled from real fields
|
| 69 |
+
STRUCTURAL_ONLY = "STRUCTURAL-ONLY" # only structural/no-explicit-source origin inferable
|
| 70 |
+
LBL_UNAVAILABLE = "UNAVAILABLE"
|
| 71 |
+
|
| 72 |
+
# Verdicts.
|
| 73 |
+
TRACED = "TRACED"
|
| 74 |
+
PARTIAL = "PARTIAL-LINEAGE"
|
| 75 |
+
UNKNOWN = "UNKNOWN-ORIGIN"
|
| 76 |
+
|
| 77 |
+
# Origin-field taxonomy — the REAL fields a11oy_brain_graph attaches to nodes.
|
| 78 |
+
# Read VERBATIM; membership here classifies a field, it never fabricates one.
|
| 79 |
+
STRONG_FIELDS = ("source", "url") # explicit cited origin
|
| 80 |
+
STRUCTURAL_FIELDS = ("derived_from", "axis", "src_layer", "ring",
|
| 81 |
+
"org", "domain", "path", "organ", "formula_id", "asset")
|
| 82 |
+
WEAK_FIELDS = ("node_label", "label", "community", "kind", "layer")
|
| 83 |
+
|
| 84 |
+
TRUST_CEILING = 0.97
|
| 85 |
+
LOCKED_SET = ["F1", "F4", "F7", "F11", "F12", "F18", "F19", "F22"]
|
| 86 |
+
LOCKED_COUNT = 8
|
| 87 |
+
|
| 88 |
+
# This surface's own id (must match szl3d_holographic.SURFACES + holographic.html).
|
| 89 |
+
SURFACE_ID = "brainlineage"
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def _now_iso() -> str:
|
| 93 |
+
return datetime.datetime.now(datetime.timezone.utc).isoformat()
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
def _verbatim_label(node: dict) -> str | None:
|
| 97 |
+
"""The node's OWN origin-class label VERBATIM (never upgraded). None if absent."""
|
| 98 |
+
v = node.get("node_label")
|
| 99 |
+
if v is None:
|
| 100 |
+
v = node.get("label")
|
| 101 |
+
if isinstance(v, str) and v.strip():
|
| 102 |
+
return v.strip()
|
| 103 |
+
return None
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def _clean(value) -> str | None:
|
| 107 |
+
"""A present, non-empty scalar rendered as a string; else None (never faked)."""
|
| 108 |
+
if value is None:
|
| 109 |
+
return None
|
| 110 |
+
if isinstance(value, bool):
|
| 111 |
+
return str(value)
|
| 112 |
+
if isinstance(value, (int, float)):
|
| 113 |
+
return str(value)
|
| 114 |
+
if isinstance(value, str):
|
| 115 |
+
s = value.strip()
|
| 116 |
+
return s or None
|
| 117 |
+
# non-scalar (list/dict) — stringify deterministically, never drop silently
|
| 118 |
+
try:
|
| 119 |
+
return json.dumps(value, sort_keys=True, separators=(",", ":"), default=str)
|
| 120 |
+
except Exception: # pragma: no cover
|
| 121 |
+
return str(value)
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
# --------------------------------------------------------------------------- #
|
| 125 |
+
# Origin chain — ordered steps read from the node's REAL fields (verbatim).
|
| 126 |
+
# --------------------------------------------------------------------------- #
|
| 127 |
+
def build_origin_chain(node: dict) -> list[dict]:
|
| 128 |
+
"""Ordered origin steps for a node, each read VERBATIM from a real field.
|
| 129 |
+
|
| 130 |
+
Order: strong (cited source) first, then structural/derivation, then the
|
| 131 |
+
weak classification signals. A field absent from the node produces NO step —
|
| 132 |
+
a missing origin is never back-filled with a fabricated one."""
|
| 133 |
+
chain: list[dict] = []
|
| 134 |
+
|
| 135 |
+
def _step(field: str, tier: str) -> None:
|
| 136 |
+
val = _clean(node.get(field))
|
| 137 |
+
if val is not None:
|
| 138 |
+
chain.append({"field": field, "value": val, "tier": tier})
|
| 139 |
+
|
| 140 |
+
for f in STRONG_FIELDS:
|
| 141 |
+
_step(f, "STRONG")
|
| 142 |
+
for f in STRUCTURAL_FIELDS:
|
| 143 |
+
_step(f, "STRUCTURAL")
|
| 144 |
+
# weak signals: label first (it is the origin CLASS), then community/kind/layer.
|
| 145 |
+
lab = _verbatim_label(node)
|
| 146 |
+
if lab is not None:
|
| 147 |
+
chain.append({"field": "node_label", "value": lab, "tier": "WEAK"})
|
| 148 |
+
for f in ("community", "kind", "layer"):
|
| 149 |
+
val = _clean(node.get(f))
|
| 150 |
+
if val is not None:
|
| 151 |
+
chain.append({"field": f, "value": val, "tier": "WEAK"})
|
| 152 |
+
return chain
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def _tier_present(chain: list[dict], tier: str) -> bool:
|
| 156 |
+
return any(s.get("tier") == tier for s in chain)
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
def classify(chain: list[dict]) -> tuple[str, str, str]:
|
| 160 |
+
"""Honest (verdict, label, origin) for ONE node's origin chain.
|
| 161 |
+
|
| 162 |
+
NEVER TRACED without a STRONG (explicit source/url) step; a node with only
|
| 163 |
+
WEAK signals is UNKNOWN-ORIGIN with origin=UNKNOWN — never a fabricated source."""
|
| 164 |
+
has_strong = _tier_present(chain, "STRONG")
|
| 165 |
+
has_structural = _tier_present(chain, "STRUCTURAL")
|
| 166 |
+
if has_strong:
|
| 167 |
+
# the origin is the first STRONG value read verbatim (source, then url).
|
| 168 |
+
origin = next(s["value"] for s in chain if s["tier"] == "STRONG")
|
| 169 |
+
return TRACED, MODELED, origin
|
| 170 |
+
if has_structural:
|
| 171 |
+
origin = next(s["value"] for s in chain if s["tier"] == "STRUCTURAL")
|
| 172 |
+
return PARTIAL, STRUCTURAL_ONLY, origin
|
| 173 |
+
# only weak signals (or nothing): the origin is genuinely untracked.
|
| 174 |
+
return UNKNOWN, STRUCTURAL_ONLY, "UNKNOWN"
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
def lineage_for_node(node: dict) -> dict:
|
| 178 |
+
"""The full origin-lineage record for ONE real node. Pure; fabricates nothing."""
|
| 179 |
+
chain = build_origin_chain(node)
|
| 180 |
+
verdict, label, origin = classify(chain)
|
| 181 |
+
strong = [s for s in chain if s["tier"] == "STRONG"]
|
| 182 |
+
structural = [s for s in chain if s["tier"] == "STRUCTURAL"]
|
| 183 |
+
return {
|
| 184 |
+
"id": node.get("id"),
|
| 185 |
+
"title": node.get("title", node.get("id")),
|
| 186 |
+
"kind": node.get("kind"),
|
| 187 |
+
"layer": node.get("layer"),
|
| 188 |
+
"node_label": _verbatim_label(node), # VERBATIM origin class, may be None
|
| 189 |
+
"community": node.get("community"),
|
| 190 |
+
"origin": origin, # UNKNOWN when untracked, never faked
|
| 191 |
+
"verdict": verdict,
|
| 192 |
+
"label": label,
|
| 193 |
+
"origin_chain": chain,
|
| 194 |
+
"origin_field_count": len(chain),
|
| 195 |
+
"explicit_source_fields": [s["field"] for s in strong],
|
| 196 |
+
"structural_fields": [s["field"] for s in structural],
|
| 197 |
+
"has_explicit_source": bool(strong),
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
# --------------------------------------------------------------------------- #
|
| 202 |
+
# Aggregate verdict over a query's top nodes (never TRACED while any UNKNOWN).
|
| 203 |
+
# --------------------------------------------------------------------------- #
|
| 204 |
+
def _fraction(part: int, total: int) -> float:
|
| 205 |
+
if not total:
|
| 206 |
+
return 0.0
|
| 207 |
+
if _HAVE_NUMPY:
|
| 208 |
+
return round(float(_np.divide(part, total)), 8)
|
| 209 |
+
return round(part / total, 8)
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
def aggregate(records: list[dict]) -> dict:
|
| 213 |
+
"""Honest roll-up over per-node lineage records.
|
| 214 |
+
|
| 215 |
+
TRACED only if every node is TRACED; UNKNOWN-ORIGIN only if every node is
|
| 216 |
+
UNKNOWN-ORIGIN (or there are no nodes); PARTIAL-LINEAGE otherwise. The verdict
|
| 217 |
+
is NEVER TRACED while any node's origin is UNKNOWN."""
|
| 218 |
+
total = len(records)
|
| 219 |
+
traced = sum(1 for r in records if r["verdict"] == TRACED)
|
| 220 |
+
partial = sum(1 for r in records if r["verdict"] == PARTIAL)
|
| 221 |
+
unknown = sum(1 for r in records if r["verdict"] == UNKNOWN)
|
| 222 |
+
if total == 0:
|
| 223 |
+
verdict, reason = UNKNOWN, "no nodes matched; nothing to trace, no origin fabricated."
|
| 224 |
+
elif traced == total:
|
| 225 |
+
verdict = TRACED
|
| 226 |
+
reason = f"all {total} node(s) carry an explicit cited source; origin fully traced."
|
| 227 |
+
elif unknown == total:
|
| 228 |
+
verdict = UNKNOWN
|
| 229 |
+
reason = f"all {total} node(s) have no origin/source field; origin UNKNOWN (never fabricated)."
|
| 230 |
+
else:
|
| 231 |
+
verdict = PARTIAL
|
| 232 |
+
reason = (f"{traced}/{total} traced to an explicit source, {partial} structural-only, "
|
| 233 |
+
f"{unknown} UNKNOWN-ORIGIN; never TRACED while any origin is UNKNOWN.")
|
| 234 |
+
return {
|
| 235 |
+
"total_nodes": total,
|
| 236 |
+
"traced": traced,
|
| 237 |
+
"partial_lineage": partial,
|
| 238 |
+
"unknown_origin": unknown,
|
| 239 |
+
"fraction_traced": _fraction(traced, total),
|
| 240 |
+
"fraction_unknown_origin": _fraction(unknown, total),
|
| 241 |
+
"verdict": verdict,
|
| 242 |
+
"verdict_reason": reason,
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
# --------------------------------------------------------------------------- #
|
| 247 |
+
# Brain access — reuse the SAME honest index; invent no node, harvest nothing.
|
| 248 |
+
# --------------------------------------------------------------------------- #
|
| 249 |
+
def _index(ns: str):
|
| 250 |
+
import szl_brain_api as _brain_api
|
| 251 |
+
return _brain_api.get_index(ns)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
def _doctrine_block() -> dict:
|
| 255 |
+
return {
|
| 256 |
+
"label_top": MODELED,
|
| 257 |
+
"locked_proven": LOCKED_COUNT,
|
| 258 |
+
"locked_set": LOCKED_SET,
|
| 259 |
+
"adds_to_locked_8": 0,
|
| 260 |
+
"lambda": "Conjecture 1",
|
| 261 |
+
"khipu_bft": "Conjecture 2",
|
| 262 |
+
"trust_ceiling": TRUST_CEILING,
|
| 263 |
+
"trust_100_percent": False,
|
| 264 |
+
"runtime_cdn": 0,
|
| 265 |
+
"note": ("additive NODE-ORIGIN lineage over the brain's own node fields; touches no "
|
| 266 |
+
"locked formula and no kernel; GET reads sign/mint nothing; POST /receipt "
|
| 267 |
+
"emits an UNSIGNED SHA-256 content digest only; introduces no theorem; a node "
|
| 268 |
+
"with no source field reports origin UNKNOWN, never a fabricated source."),
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
def _lineage_kind() -> str:
|
| 273 |
+
return "NODE-ORIGIN-LINEAGE (knowledge-graph provenance of where a node came from)"
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
def _not_lineage() -> list:
|
| 277 |
+
return ["per-answer node provenance (that is szl_brainprovenance)",
|
| 278 |
+
"build/SLSA/in-toto/Rekor artifact attestation",
|
| 279 |
+
"cryptographic model/weapon attestation",
|
| 280 |
+
"counter-UAS/targeting/fusion/effector"]
|
| 281 |
+
|
| 282 |
+
|
| 283 |
+
# --------------------------------------------------------------------------- #
|
| 284 |
+
# Lineage assembly (pure computation — mints nothing).
|
| 285 |
+
# --------------------------------------------------------------------------- #
|
| 286 |
+
def build_lineage_by_id(ns: str, node_id: str) -> dict:
|
| 287 |
+
"""Origin chain + verdict for ONE node id. Pure read; mints nothing."""
|
| 288 |
+
node_id = (node_id or "").strip()
|
| 289 |
+
base = {
|
| 290 |
+
"label": MODELED,
|
| 291 |
+
"surface_id": SURFACE_ID,
|
| 292 |
+
"endpoint": "brain/lineage",
|
| 293 |
+
"service": "a11oy.brain.lineage",
|
| 294 |
+
"mode": "id",
|
| 295 |
+
"lineage_kind": _lineage_kind(),
|
| 296 |
+
"not_lineage_of": _not_lineage(),
|
| 297 |
+
"doctrine": _doctrine_block(),
|
| 298 |
+
"receipt_policy": "RECEIPT-ON-WRITE-NOT-ON-READ — GET mints nothing; POST /receipt digests.",
|
| 299 |
+
"timestamp_utc": _now_iso(),
|
| 300 |
+
}
|
| 301 |
+
if not node_id:
|
| 302 |
+
return dict(base, ok=False, found=False, id=node_id, verdict=UNKNOWN,
|
| 303 |
+
verdict_reason="empty id; no lookup performed, no origin fabricated.",
|
| 304 |
+
lineage=None)
|
| 305 |
+
try:
|
| 306 |
+
idx = _index(ns)
|
| 307 |
+
except Exception as exc: # never 500 — honest degraded response
|
| 308 |
+
return dict(base, ok=False, found=False, id=node_id, label=LBL_UNAVAILABLE,
|
| 309 |
+
verdict=UNKNOWN,
|
| 310 |
+
verdict_reason=f"brain index unavailable; no origin fabricated: {str(exc)[:160]}",
|
| 311 |
+
lineage=None)
|
| 312 |
+
node = idx.by_id.get(node_id)
|
| 313 |
+
if node is None:
|
| 314 |
+
return dict(base, ok=False, found=False, id=node_id, verdict=UNKNOWN,
|
| 315 |
+
verdict_reason=f"unknown node id {node_id!r}; origin UNKNOWN, never fabricated.",
|
| 316 |
+
lineage=None)
|
| 317 |
+
rec = lineage_for_node(dict(node, community=idx.community_of.get(node_id)))
|
| 318 |
+
return dict(base, ok=True, found=True, id=node_id,
|
| 319 |
+
verdict=rec["verdict"], verdict_reason=(
|
| 320 |
+
f"origin {rec['verdict']}: "
|
| 321 |
+
+ ("explicit cited source present"
|
| 322 |
+
if rec["has_explicit_source"]
|
| 323 |
+
else ("structural origin only"
|
| 324 |
+
if rec["verdict"] == PARTIAL
|
| 325 |
+
else "no origin/source field — origin UNKNOWN, never fabricated"))),
|
| 326 |
+
lineage=rec, verdict_legend=_legend())
|
| 327 |
+
|
| 328 |
+
|
| 329 |
+
def build_lineage_by_query(ns: str, q: str, k: int = 10) -> dict:
|
| 330 |
+
"""Origin chains + aggregate verdict for a query's top nodes. Pure read."""
|
| 331 |
+
q = (q or "").strip()
|
| 332 |
+
k = max(1, min(int(k) if isinstance(k, (int, float)) else 10, 50))
|
| 333 |
+
base = {
|
| 334 |
+
"label": MODELED,
|
| 335 |
+
"surface_id": SURFACE_ID,
|
| 336 |
+
"endpoint": "brain/lineage",
|
| 337 |
+
"service": "a11oy.brain.lineage",
|
| 338 |
+
"mode": "query",
|
| 339 |
+
"query": q,
|
| 340 |
+
"k": k,
|
| 341 |
+
"lineage_kind": _lineage_kind(),
|
| 342 |
+
"not_lineage_of": _not_lineage(),
|
| 343 |
+
"doctrine": _doctrine_block(),
|
| 344 |
+
"receipt_policy": "RECEIPT-ON-WRITE-NOT-ON-READ — GET mints nothing; POST /receipt digests.",
|
| 345 |
+
"verdict_legend": _legend(),
|
| 346 |
+
"timestamp_utc": _now_iso(),
|
| 347 |
+
}
|
| 348 |
+
if not q:
|
| 349 |
+
agg = aggregate([])
|
| 350 |
+
return dict(base, ok=False, lineages=[], aggregate=agg,
|
| 351 |
+
verdict=agg["verdict"],
|
| 352 |
+
verdict_reason="empty query; no retrieval performed, no origin fabricated.")
|
| 353 |
+
try:
|
| 354 |
+
idx = _index(ns)
|
| 355 |
+
seeds = idx.search(q, k=k)
|
| 356 |
+
except Exception as exc: # never 500 — honest degraded response
|
| 357 |
+
agg = aggregate([])
|
| 358 |
+
return dict(base, ok=False, label=LBL_UNAVAILABLE, lineages=[], aggregate=agg,
|
| 359 |
+
verdict=agg["verdict"],
|
| 360 |
+
verdict_reason=f"brain retrieval unavailable; no origin fabricated: {str(exc)[:160]}")
|
| 361 |
+
records = []
|
| 362 |
+
for s in seeds:
|
| 363 |
+
node = idx.by_id.get(s["id"])
|
| 364 |
+
if node is None:
|
| 365 |
+
continue
|
| 366 |
+
rec = lineage_for_node(dict(node, community=idx.community_of.get(s["id"])))
|
| 367 |
+
rec["retrieval_score"] = s.get("score")
|
| 368 |
+
records.append(rec)
|
| 369 |
+
agg = aggregate(records)
|
| 370 |
+
return dict(base, ok=True, matched_nodes=len(records), lineages=records,
|
| 371 |
+
aggregate=agg, verdict=agg["verdict"], verdict_reason=agg["verdict_reason"])
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
def _legend() -> dict:
|
| 375 |
+
return {
|
| 376 |
+
TRACED: "explicit cited source (source/url) present; origin traced to a real source",
|
| 377 |
+
PARTIAL: "no explicit source, but a structural/derivation origin is inferable",
|
| 378 |
+
UNKNOWN: "no origin/source field; origin UNKNOWN — never a fabricated source",
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
|
| 382 |
+
# --------------------------------------------------------------------------- #
|
| 383 |
+
# Receipt — UNSIGNED SHA-256 content digest. RECEIPT-ON-WRITE (POST), never a GET.
|
| 384 |
+
# --------------------------------------------------------------------------- #
|
| 385 |
+
def _canonical_core(payload: dict) -> str:
|
| 386 |
+
"""Deterministic canonical serialization of the origin content (excludes the
|
| 387 |
+
volatile timestamp), so the digest attests the ORIGIN CHAIN(S) + verdict."""
|
| 388 |
+
def _rec_core(rec: dict) -> dict:
|
| 389 |
+
return {
|
| 390 |
+
"id": rec.get("id"),
|
| 391 |
+
"verdict": rec.get("verdict"),
|
| 392 |
+
"label": rec.get("label"),
|
| 393 |
+
"origin": rec.get("origin"),
|
| 394 |
+
"origin_chain": [{"field": s.get("field"), "value": s.get("value"),
|
| 395 |
+
"tier": s.get("tier")}
|
| 396 |
+
for s in (rec.get("origin_chain") or [])],
|
| 397 |
+
}
|
| 398 |
+
if payload.get("mode") == "id":
|
| 399 |
+
lin = payload.get("lineage")
|
| 400 |
+
core = {"mode": "id", "id": payload.get("id"),
|
| 401 |
+
"verdict": payload.get("verdict"),
|
| 402 |
+
"lineage": _rec_core(lin) if lin else None}
|
| 403 |
+
else:
|
| 404 |
+
core = {"mode": "query", "query": payload.get("query"),
|
| 405 |
+
"verdict": payload.get("verdict"),
|
| 406 |
+
"aggregate": payload.get("aggregate"),
|
| 407 |
+
"lineages": [_rec_core(r) for r in (payload.get("lineages") or [])]}
|
| 408 |
+
return json.dumps(core, sort_keys=True, separators=(",", ":"), default=str)
|
| 409 |
+
|
| 410 |
+
|
| 411 |
+
def content_receipt(payload: dict) -> dict:
|
| 412 |
+
"""An UNSIGNED SHA-256 content-digest receipt over the origin lineage."""
|
| 413 |
+
canonical = _canonical_core(payload)
|
| 414 |
+
digest = hashlib.sha256(canonical.encode("utf-8")).hexdigest()
|
| 415 |
+
return {
|
| 416 |
+
"kind": "szl.brainlineage.origin",
|
| 417 |
+
"algorithm": "sha256",
|
| 418 |
+
"content_sha256": digest,
|
| 419 |
+
"signed": False,
|
| 420 |
+
"mode": "UNSIGNED-CONTENT-DIGEST",
|
| 421 |
+
"receipt_on": "write (POST /receipt)",
|
| 422 |
+
"note": ("unsigned SHA-256 content digest of the node-origin lineage; "
|
| 423 |
+
"RECEIPT-ON-WRITE, never on a GET read. No signature fabricated."),
|
| 424 |
+
"computed_at": _now_iso(),
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
|
| 428 |
+
# --------------------------------------------------------------------------- #
|
| 429 |
+
# Handlers.
|
| 430 |
+
# --------------------------------------------------------------------------- #
|
| 431 |
+
def handle_info(ns: str = "a11oy") -> dict:
|
| 432 |
+
"""GET .../lineage/info — static self-describing manifest (no compute). PURE READ."""
|
| 433 |
+
base = f"/api/{ns}/v1/brain/lineage"
|
| 434 |
+
return {
|
| 435 |
+
"ok": True,
|
| 436 |
+
"label": MODELED,
|
| 437 |
+
"surface_id": SURFACE_ID,
|
| 438 |
+
"service": "a11oy.brain.lineage",
|
| 439 |
+
"endpoint": "brain/lineage/info",
|
| 440 |
+
"title": "Brain Lineage — how a node entered the knowledge graph",
|
| 441 |
+
"what": ("for a knowledge-graph node (by id, or a query's top nodes) reconstructs the "
|
| 442 |
+
"ORIGIN CHAIN of how it entered the graph — read ONLY from the REAL fields the "
|
| 443 |
+
"brain builder attached — and honestly reports origin UNKNOWN when no source "
|
| 444 |
+
"field exists (never fabricated)."),
|
| 445 |
+
"lineage_kind": _lineage_kind(),
|
| 446 |
+
"distinct_from": ("szl_brainprovenance answers WHICH nodes supported an ANSWER; this "
|
| 447 |
+
"answers WHERE a node itself came from (its harvest/origin metadata)."),
|
| 448 |
+
"explicitly_not": ("This is NODE-ORIGIN lineage of a knowledge-graph node only. It is NOT "
|
| 449 |
+
"per-answer provenance, NOT cryptographic model/weapon attestation, NOT "
|
| 450 |
+
"SLSA/in-toto/Rekor build attestation, and NOT any counter-UAS / "
|
| 451 |
+
"targeting / fusion / effector capability."),
|
| 452 |
+
"origin_fields_read": {
|
| 453 |
+
"strong_explicit_source": list(STRONG_FIELDS),
|
| 454 |
+
"structural_derivation": list(STRUCTURAL_FIELDS),
|
| 455 |
+
"weak_classification": list(WEAK_FIELDS),
|
| 456 |
+
"note": ("read VERBATIM from each node; TRACED requires a STRONG field; a STRUCTURAL "
|
| 457 |
+
"field yields PARTIAL-LINEAGE; WEAK signals alone are UNKNOWN-ORIGIN."),
|
| 458 |
+
},
|
| 459 |
+
"endpoints": {
|
| 460 |
+
"info": f"GET {base}/info",
|
| 461 |
+
"by_id": f"GET {base}?id=",
|
| 462 |
+
"by_query": f"GET {base}?q=&k=",
|
| 463 |
+
"receipt": f"POST {base}/receipt (body: {{\"id\":..}} or {{\"q\":..,\"k\":..}})",
|
| 464 |
+
},
|
| 465 |
+
"verdicts": [TRACED, PARTIAL, UNKNOWN],
|
| 466 |
+
"verdict_legend": _legend(),
|
| 467 |
+
"honest_labels": {
|
| 468 |
+
"labels": [MODELED, STRUCTURAL_ONLY],
|
| 469 |
+
"note": ("MODELED when an explicit source exists; STRUCTURAL-ONLY when only a "
|
| 470 |
+
"structural (no explicit source) origin is inferable or origin is UNKNOWN. "
|
| 471 |
+
"Labels are never upgraded; UNKNOWN is never hidden."),
|
| 472 |
+
},
|
| 473 |
+
"receipt_policy": "RECEIPT-ON-WRITE-NOT-ON-READ — only POST /receipt emits an unsigned SHA-256 digest.",
|
| 474 |
+
"doctrine": _doctrine_block(),
|
| 475 |
+
"numpy_available": _HAVE_NUMPY,
|
| 476 |
+
"timestamp_utc": _now_iso(),
|
| 477 |
+
}
|
| 478 |
+
|
| 479 |
+
|
| 480 |
+
def handle_lineage(ns: str, id: str = "", q: str = "", k: int = 10) -> dict: # noqa: A002
|
| 481 |
+
"""GET .../lineage?id= | ?q= — origin chain(s) + verdict. PURE READ (mints nothing).
|
| 482 |
+
|
| 483 |
+
id takes precedence when both are supplied; an empty request is honestly UNKNOWN."""
|
| 484 |
+
if (id or "").strip():
|
| 485 |
+
return build_lineage_by_id(ns, id)
|
| 486 |
+
return build_lineage_by_query(ns, q, k)
|
| 487 |
+
|
| 488 |
+
|
| 489 |
+
def handle_receipt(ns: str, id: str = "", q: str = "", k: int = 10) -> dict: # noqa: A002
|
| 490 |
+
"""POST .../lineage/receipt — lineage + an UNSIGNED SHA-256 content digest
|
| 491 |
+
(RECEIPT-ON-WRITE). Never 500s: honest degraded response on error."""
|
| 492 |
+
payload = handle_lineage(ns, id=id, q=q, k=k)
|
| 493 |
+
out = dict(payload)
|
| 494 |
+
out["receipt"] = content_receipt(payload)
|
| 495 |
+
return out
|
| 496 |
+
|
| 497 |
+
|
| 498 |
+
# --------------------------------------------------------------------------- #
|
| 499 |
+
# FastAPI registration.
|
| 500 |
+
# GET info/lineage — normal FastAPI GET handlers (pure reads; mint nothing).
|
| 501 |
+
# POST receipt — raw-Request handler via app.router.add_route (Starlette
|
| 502 |
+
# passes the Request positionally, version-proof under
|
| 503 |
+
# fastapi==0.137.x), with app.add_api_route as the fallback.
|
| 504 |
+
# Registered BEFORE the SPA catch-all by serve.py.
|
| 505 |
+
# --------------------------------------------------------------------------- #
|
| 506 |
+
def register(app, ns: str = "a11oy") -> str:
|
| 507 |
+
from fastapi.responses import JSONResponse
|
| 508 |
+
|
| 509 |
+
base = f"/api/{ns}/v1/brain/lineage"
|
| 510 |
+
|
| 511 |
+
@app.get(f"{base}/info")
|
| 512 |
+
def _brainlineage_info():
|
| 513 |
+
"""Static self-describing manifest (pure read; mints nothing)."""
|
| 514 |
+
return JSONResponse(handle_info(ns))
|
| 515 |
+
|
| 516 |
+
@app.get(base)
|
| 517 |
+
def _brainlineage_get(id: str = "", q: str = "", k: int = 10): # noqa: ANN202,A002
|
| 518 |
+
"""Origin chain(s) + verdict for a node id or a query (pure read; mints nothing)."""
|
| 519 |
+
payload = handle_lineage(ns, id=id, q=q, k=k)
|
| 520 |
+
if payload.get("mode") == "id" and payload.get("found") is False and (id or "").strip():
|
| 521 |
+
return JSONResponse(payload, status_code=404)
|
| 522 |
+
return JSONResponse(payload)
|
| 523 |
+
|
| 524 |
+
async def _brainlineage_receipt(request):
|
| 525 |
+
"""POST: origin lineage + UNSIGNED SHA-256 content digest (RECEIPT-ON-WRITE)."""
|
| 526 |
+
node_id, q, k = "", "", 10
|
| 527 |
+
try:
|
| 528 |
+
body = await request.json()
|
| 529 |
+
if isinstance(body, dict):
|
| 530 |
+
node_id = str(body.get("id", "") or "")
|
| 531 |
+
q = str(body.get("q", body.get("query", "")) or "")
|
| 532 |
+
kv = body.get("k", 10)
|
| 533 |
+
k = int(kv) if isinstance(kv, (int, float, str)) and str(kv).strip() else 10
|
| 534 |
+
except Exception: # noqa: BLE001 — a bodyless/garbled POST still gets an honest answer
|
| 535 |
+
node_id, q, k = "", "", 10
|
| 536 |
+
# Query params override / supplement a missing body.
|
| 537 |
+
try:
|
| 538 |
+
qp = request.query_params
|
| 539 |
+
if not node_id and qp.get("id"):
|
| 540 |
+
node_id = str(qp.get("id"))
|
| 541 |
+
if not q and qp.get("q"):
|
| 542 |
+
q = str(qp.get("q"))
|
| 543 |
+
if qp.get("k"):
|
| 544 |
+
k = int(qp.get("k"))
|
| 545 |
+
except Exception: # noqa: BLE001
|
| 546 |
+
pass
|
| 547 |
+
return JSONResponse(handle_receipt(ns, id=node_id, q=q, k=k))
|
| 548 |
+
|
| 549 |
+
# Annotate the raw-Request handler as fastapi.Request so the add_api_route fallback
|
| 550 |
+
# path treats the param as the request object (0.137.x signature-analysis gotcha).
|
| 551 |
+
try:
|
| 552 |
+
import fastapi as _fastapi
|
| 553 |
+
_brainlineage_receipt.__annotations__["request"] = _fastapi.Request
|
| 554 |
+
except Exception: # noqa: BLE001 — annotation is best-effort only
|
| 555 |
+
pass
|
| 556 |
+
|
| 557 |
+
rcpt_path = f"{base}/receipt"
|
| 558 |
+
add_route = getattr(getattr(app, "router", None), "add_route", None)
|
| 559 |
+
add_api_route = getattr(app, "add_api_route", None)
|
| 560 |
+
try:
|
| 561 |
+
if callable(add_route):
|
| 562 |
+
app.router.add_route(rcpt_path, _brainlineage_receipt, methods=["POST"])
|
| 563 |
+
elif callable(add_api_route):
|
| 564 |
+
app.add_api_route(rcpt_path, _brainlineage_receipt, methods=["POST"])
|
| 565 |
+
else: # pragma: no cover — last-resort Starlette Route append
|
| 566 |
+
from starlette.routing import Route
|
| 567 |
+
app.router.routes.append(Route(rcpt_path, _brainlineage_receipt, methods=["POST"]))
|
| 568 |
+
except Exception as exc: # additive register must never break boot
|
| 569 |
+
print(f"[{ns}] brainlineage receipt POST route NOT wired (guarded): {exc!r}",
|
| 570 |
+
file=__import__("sys").stderr)
|
| 571 |
+
return "brainlineage-wired:2(get-only)"
|
| 572 |
+
|
| 573 |
+
return "brainlineage-wired:3"
|
| 574 |
+
|
| 575 |
+
|
| 576 |
+
# --------------------------------------------------------------------------- #
|
| 577 |
+
# Self-test — origin chain from real fields, UNKNOWN when no source (no
|
| 578 |
+
# fabrication), verdict transitions, deterministic receipt on write, labels
|
| 579 |
+
# never upgraded.
|
| 580 |
+
# --------------------------------------------------------------------------- #
|
| 581 |
+
def _selftest() -> None:
|
| 582 |
+
import sys as _sys
|
| 583 |
+
|
| 584 |
+
print("=" * 72)
|
| 585 |
+
print("szl_brainlineage — self-test (node-origin lineage)")
|
| 586 |
+
print("=" * 72)
|
| 587 |
+
|
| 588 |
+
# 1) A harvested node with an explicit cited source -> TRACED / MODELED.
|
| 589 |
+
# (Λ is Conjecture 1, never a theorem — no proof claim is made here.)
|
| 590 |
+
harvested = {"id": "field:x", "title": "harvested field node", "kind": "field",
|
| 591 |
+
"layer": -1, "label": "HARVESTED", "ring": "field",
|
| 592 |
+
"url": "https://example.org/paper", "source": "brain/harvest/pass2.jsonl",
|
| 593 |
+
"axis": "A"}
|
| 594 |
+
rec = lineage_for_node(harvested)
|
| 595 |
+
assert rec["verdict"] == TRACED, rec["verdict"]
|
| 596 |
+
assert rec["label"] == MODELED, rec["label"]
|
| 597 |
+
assert rec["origin"] == "brain/harvest/pass2.jsonl", rec["origin"]
|
| 598 |
+
assert rec["has_explicit_source"] is True
|
| 599 |
+
assert rec["origin_chain"][0]["tier"] == "STRONG"
|
| 600 |
+
print(f"[1] harvested node TRACED/MODELED, origin={rec['origin']!r} OK")
|
| 601 |
+
|
| 602 |
+
# 2) A structural node (derived_from only, no explicit source) -> PARTIAL / STRUCTURAL-ONLY.
|
| 603 |
+
topic = {"id": "topic:t", "title": "topic", "kind": "topic", "layer": 1,
|
| 604 |
+
"label": "MODELED", "derived_from": "FORMULA_META.organ"}
|
| 605 |
+
tr = lineage_for_node(topic)
|
| 606 |
+
assert tr["verdict"] == PARTIAL, tr["verdict"]
|
| 607 |
+
assert tr["label"] == STRUCTURAL_ONLY, tr["label"]
|
| 608 |
+
assert tr["origin"] == "FORMULA_META.organ"
|
| 609 |
+
assert tr["has_explicit_source"] is False
|
| 610 |
+
print(f"[2] structural node PARTIAL-LINEAGE/STRUCTURAL-ONLY, origin={tr['origin']!r} OK")
|
| 611 |
+
|
| 612 |
+
# 3) A bare node with only weak signals (label + community) -> UNKNOWN-ORIGIN.
|
| 613 |
+
# origin MUST be UNKNOWN — a missing source is NEVER fabricated.
|
| 614 |
+
bare = {"id": "bare:1", "title": "bare", "kind": "misc", "layer": 0,
|
| 615 |
+
"label": "MODELED", "community": "c3"}
|
| 616 |
+
br = lineage_for_node(bare)
|
| 617 |
+
assert br["verdict"] == UNKNOWN, br["verdict"]
|
| 618 |
+
assert br["origin"] == "UNKNOWN", br["origin"]
|
| 619 |
+
assert br["label"] == STRUCTURAL_ONLY
|
| 620 |
+
assert br["has_explicit_source"] is False
|
| 621 |
+
print(f"[3] bare node UNKNOWN-ORIGIN, origin={br['origin']!r} (never fabricated) OK")
|
| 622 |
+
|
| 623 |
+
# 4) Aggregate: never TRACED while any node is UNKNOWN-ORIGIN.
|
| 624 |
+
agg = aggregate([rec, tr, br])
|
| 625 |
+
assert agg["verdict"] == PARTIAL, agg["verdict"]
|
| 626 |
+
assert agg["traced"] == 1 and agg["unknown_origin"] == 1
|
| 627 |
+
all_traced = aggregate([rec, dict(rec, id="field:y")])
|
| 628 |
+
assert all_traced["verdict"] == TRACED
|
| 629 |
+
all_unknown = aggregate([br, dict(br, id="bare:2")])
|
| 630 |
+
assert all_unknown["verdict"] == UNKNOWN
|
| 631 |
+
assert aggregate([])["verdict"] == UNKNOWN
|
| 632 |
+
print(f"[4] aggregate downgrades honestly: mixed=PARTIAL, all-traced=TRACED, "
|
| 633 |
+
f"all-unknown/empty=UNKNOWN-ORIGIN OK")
|
| 634 |
+
|
| 635 |
+
# 5) Receipt: UNSIGNED sha256, deterministic, ignores the volatile timestamp.
|
| 636 |
+
p_id = {"mode": "id", "id": "field:x", "verdict": TRACED, "lineage": rec}
|
| 637 |
+
r1 = content_receipt(p_id)
|
| 638 |
+
r2 = content_receipt(dict(p_id, timestamp_utc="2026-01-01T00:00:00Z"))
|
| 639 |
+
assert r1["signed"] is False and len(r1["content_sha256"]) == 64
|
| 640 |
+
assert r1["content_sha256"] == r2["content_sha256"], "digest ignores timestamp"
|
| 641 |
+
print(f"[5] receipt UNSIGNED sha256={r1['content_sha256'][:16]}… deterministic OK")
|
| 642 |
+
|
| 643 |
+
# 6) doctrine block honest: locked-8 exact, +0, Λ Conjecture 1, trust 0.97 not 100%.
|
| 644 |
+
d = _doctrine_block()
|
| 645 |
+
assert d["locked_proven"] == 8 and d["adds_to_locked_8"] == 0
|
| 646 |
+
assert d["lambda"] == "Conjecture 1" and d["khipu_bft"] == "Conjecture 2"
|
| 647 |
+
assert d["trust_ceiling"] == 0.97 and d["trust_100_percent"] is False
|
| 648 |
+
assert d["runtime_cdn"] == 0
|
| 649 |
+
print("[6] doctrine: locked-8 exact, +0, Λ=Conjecture 1, trust 0.97 (not 100%) OK")
|
| 650 |
+
|
| 651 |
+
print("\nok:true checks:6")
|
| 652 |
+
_sys.exit(0)
|
| 653 |
+
|
| 654 |
+
|
| 655 |
+
if __name__ == "__main__":
|
| 656 |
+
_selftest()
|