Add typed OpenAPI, MELT, and runtime contracts

#3
Dockerfile CHANGED
@@ -112,6 +112,7 @@ COPY cathedral.html knowledge.json operator_shell_v4.py serve.py szl_evidence_re
112
  # falls back and /spaces + /api/<ns>/v1/spaces/health 404. Byte-identical a11oy+killinchu.
113
  COPY szl_spaces_proxy.py szl_spaces_surface.py ./
114
  COPY szl_live_wires.py live_wires.html live_wires_3d.js szl_rosie_companion.py killinchu_szl_pqc_sign.py szl_rekor.py killinchu_osint.py szl_be_hardening.py szl_unay.py szl_khipu_lmdb.py szl_khipu_replicate.py szl_unay_routes.py szl_warhacker_aliases.py killinchu_genius.py killinchu_warhacker_demos.py killinchu_v3.py szl_brain.py szl_rag.py szl_formulas.py szl_understudy.py ./
 
115
  COPY szl_killinchu_cookbook.py szl_uds_hardening.py killinchu_fusion.py szl_v4_fleet.py szl_ken.py killinchu_frontier_patch.py killinchu_drone_routes.py killinchu_parity.py killinchu_cannonico.py killinchu_elite_console.py killinchu_experience.py _vendor_blobs.py killinchu_fleet_vessels.py killinchu_maritime_risk.py killinchu_maritime_intel.py killinchu_maritime_view.py killinchu_live_feeds.py killinchu_feeds_realdata.py killinchu_asw.py killinchu_anatomy.py killinchu_health_twin.py fleet_vessels_data.json killinchu_beyond.py szl_khipu_consensus.py killinchu_mesh.py killinchu_mesh_view.py killinchu_formula_endpoints.py killinchu_edge_formulas.py killinchu_active_flux.py killinchu_platform_dynamics.py ./
116
  COPY killinchu_edge_console.py szl_agentic_loop.py szl_anatomy_routes.py szl_formula_wiring.py a11oy_code_engine.py killinchu_ops_control.py szl_llm_registry.py szl_alloy_models.py a11oy_agent_loop.py a11oy_org_rag.py a11oy_mcp_client.py killinchu_mined_ops.py killinchu_resweep_ops.py killinchu_wave910.py killinchu_posture_topology.py szl_connectors_serve.py szl_connector_mcp.py szl_scaling.py szl_allodial.py szl_entanglement.py szl_neuroplasticity.py szl_chain_of_title.py ./
117
  # Wave 15 frontier organs (Dynamic Linear Attention, Context-Ready Transformer, OPERA perplexity-reward).
@@ -701,4 +702,3 @@ CMD ["python", "serve.py"]
701
 
702
  # Build cache-bust 2026-06-07T05:00Z (MINED ops squad): COPY killinchu_mined_ops.py
703
  # into /app so serve.py can import+register the 4 mined operational/efficiency surfaces.
704
-
 
112
  # falls back and /spaces + /api/<ns>/v1/spaces/health 404. Byte-identical a11oy+killinchu.
113
  COPY szl_spaces_proxy.py szl_spaces_surface.py ./
114
  COPY szl_live_wires.py live_wires.html live_wires_3d.js szl_rosie_companion.py killinchu_szl_pqc_sign.py szl_rekor.py killinchu_osint.py szl_be_hardening.py szl_unay.py szl_khipu_lmdb.py szl_khipu_replicate.py szl_unay_routes.py szl_warhacker_aliases.py killinchu_genius.py killinchu_warhacker_demos.py killinchu_v3.py szl_brain.py szl_rag.py szl_formulas.py szl_understudy.py ./
115
+ COPY killinchu_public_contracts.py ./
116
  COPY szl_killinchu_cookbook.py szl_uds_hardening.py killinchu_fusion.py szl_v4_fleet.py szl_ken.py killinchu_frontier_patch.py killinchu_drone_routes.py killinchu_parity.py killinchu_cannonico.py killinchu_elite_console.py killinchu_experience.py _vendor_blobs.py killinchu_fleet_vessels.py killinchu_maritime_risk.py killinchu_maritime_intel.py killinchu_maritime_view.py killinchu_live_feeds.py killinchu_feeds_realdata.py killinchu_asw.py killinchu_anatomy.py killinchu_health_twin.py fleet_vessels_data.json killinchu_beyond.py szl_khipu_consensus.py killinchu_mesh.py killinchu_mesh_view.py killinchu_formula_endpoints.py killinchu_edge_formulas.py killinchu_active_flux.py killinchu_platform_dynamics.py ./
117
  COPY killinchu_edge_console.py szl_agentic_loop.py szl_anatomy_routes.py szl_formula_wiring.py a11oy_code_engine.py killinchu_ops_control.py szl_llm_registry.py szl_alloy_models.py a11oy_agent_loop.py a11oy_org_rag.py a11oy_mcp_client.py killinchu_mined_ops.py killinchu_resweep_ops.py killinchu_wave910.py killinchu_posture_topology.py szl_connectors_serve.py szl_connector_mcp.py szl_scaling.py szl_allodial.py szl_entanglement.py szl_neuroplasticity.py szl_chain_of_title.py ./
118
  # Wave 15 frontier organs (Dynamic Linear Attention, Context-Ready Transformer, OPERA perplexity-reward).
 
702
 
703
  # Build cache-bust 2026-06-07T05:00Z (MINED ops squad): COPY killinchu_mined_ops.py
704
  # into /app so serve.py can import+register the 4 mined operational/efficiency surfaces.
 
README.md CHANGED
@@ -467,4 +467,15 @@ One sovereign substrate, many organs — every decision carries a signed, checka
467
 
468
  <sub>Doctrine v11 · Λ = Conjecture 1, never green · honest by design · public data only.</sub>
469
 
 
 
 
 
 
 
 
 
 
 
 
470
  Signed-off-by: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
 
467
 
468
  <sub>Doctrine v11 · Λ = Conjecture 1, never green · honest by design · public data only.</sub>
469
 
470
+ ## Public evidence contracts
471
+
472
+ - `GET /health` - typed read-only health contract; reachability is not readiness.
473
+ - `GET /api/killinchu/v1/status` - runtime, doctrine, and contract discovery.
474
+ - `GET /api/killinchu/v1/melt/summary` - measured in-process MELT summary with explicit external-trace limits.
475
+ - `GET /openapi.json`, `/api/killinchu/openapi.json`, or `/api/killinchu/v1/openapi.json` - the same generated API description, with bad legacy annotations omitted rather than crashing discovery.
476
+
477
+ The MELT contract exposes aggregate metric family and sample counts, not private
478
+ log content. It does not claim an external collector, complete distributed
479
+ traces, model quality, mission readiness, or actuator authority.
480
+
481
  Signed-off-by: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
killinchu_public_contracts.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Read-only public contracts for Killinchu runtime and MELT observability.
2
+
3
+ These endpoints expose measured in-process telemetry and route presence. They
4
+ do not imply model quality, external collector export, operational readiness,
5
+ or authority to actuate a defense system.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ from datetime import datetime, timezone
11
+ from typing import Any
12
+
13
+
14
+ def _now() -> str:
15
+ return datetime.now(timezone.utc).isoformat()
16
+
17
+
18
+ def _has_route(app: Any, path: str, method: str = "GET") -> bool:
19
+ for route in getattr(getattr(app, "router", None), "routes", []):
20
+ methods = getattr(route, "methods", set()) or set()
21
+ if getattr(route, "path", None) == path and method in methods:
22
+ return True
23
+ return False
24
+
25
+
26
+ def _metrics_snapshot(app: Any) -> dict[str, Any]:
27
+ try:
28
+ import szl_metrics_prom
29
+
30
+ text = szl_metrics_prom.render(app)
31
+ families = sorted(
32
+ {
33
+ line.split()[2]
34
+ for line in text.splitlines()
35
+ if line.startswith("# HELP ") and len(line.split()) >= 3
36
+ }
37
+ )
38
+ samples = [
39
+ line
40
+ for line in text.splitlines()
41
+ if line and not line.startswith("#")
42
+ ]
43
+ return {
44
+ "state": "LIVE_IN_PROCESS",
45
+ "metric_family_count": len(families),
46
+ "sample_count": len(samples),
47
+ "metric_families": families,
48
+ "source": "/metrics",
49
+ }
50
+ except Exception as exc:
51
+ return {
52
+ "state": "UNAVAILABLE",
53
+ "metric_family_count": 0,
54
+ "sample_count": 0,
55
+ "metric_families": [],
56
+ "source": "/metrics",
57
+ "error_type": type(exc).__name__,
58
+ }
59
+
60
+
61
+ def melt_summary(app: Any, ns: str = "killinchu") -> dict[str, Any]:
62
+ metrics = _metrics_snapshot(app)
63
+ metrics_route = _has_route(app, "/metrics")
64
+ mesh_route = _has_route(app, f"/api/{ns}/v1/mesh/state")
65
+ live = metrics_route and metrics["state"] == "LIVE_IN_PROCESS"
66
+ return {
67
+ "schema": "szl.killinchu.melt-summary/v1",
68
+ "observed_at": _now(),
69
+ "transport_state": "REACHABLE",
70
+ "evidence_state": "LIVE" if live else "UNAVAILABLE",
71
+ "authority_state": "READ_ONLY",
72
+ "scope": "MELT runtime observability",
73
+ "signals": {
74
+ "metrics": metrics,
75
+ "events": {
76
+ "state": "IN_PROCESS",
77
+ "basis": "request and receipt events remain within the running process unless a durable subsystem records them",
78
+ },
79
+ "logs": {
80
+ "state": "IN_PROCESS",
81
+ "basis": "structured application logs are emitted by the runtime; no public log corpus is exposed here",
82
+ },
83
+ "traces": {
84
+ "state": "EXPORT_UNAVAILABLE",
85
+ "basis": "OTLP export is not enabled in this public Space build",
86
+ },
87
+ },
88
+ "contracts": {
89
+ "metrics_route_registered": metrics_route,
90
+ "mesh_state_route_registered": mesh_route,
91
+ "metrics_endpoint": "/metrics",
92
+ "mesh_endpoint": f"/api/{ns}/v1/mesh/state",
93
+ },
94
+ "limits": [
95
+ "LIVE means measured in this process, not an uptime SLA.",
96
+ "No external collector, distributed trace completeness, model quality, or business outcome is claimed.",
97
+ "This endpoint is read-only and performs no effector action.",
98
+ ],
99
+ }
100
+
101
+
102
+ def runtime_status(app: Any, ns: str = "killinchu") -> dict[str, Any]:
103
+ route_count = len(getattr(getattr(app, "router", None), "routes", []))
104
+ return {
105
+ "schema": "szl.killinchu.runtime-status/v1",
106
+ "observed_at": _now(),
107
+ "service": ns,
108
+ "transport_state": "REACHABLE",
109
+ "evidence_state": "COMPUTED",
110
+ "verification_state": "STRUCTURAL_ONLY",
111
+ "authority_state": "READ_ONLY",
112
+ "doctrine": {
113
+ "version": "v11",
114
+ "locked_core": "749/14/163 @ c7c0ba17",
115
+ "lambda": "Conjecture 1",
116
+ },
117
+ "runtime": {
118
+ "route_count": route_count,
119
+ "git_sha": os.getenv("SZL_GIT_SHA", "unknown"),
120
+ "build_time": os.getenv("SZL_BUILD_TIME", "unknown"),
121
+ },
122
+ "contracts": {
123
+ "experience_manifest": f"/api/{ns}/v1/experience/manifest",
124
+ "openapi": f"/api/{ns}/v1/openapi.json",
125
+ "melt": f"/api/{ns}/v1/melt/summary",
126
+ "metrics": "/metrics",
127
+ "readiness": f"/api/{ns}/readyz",
128
+ },
129
+ "limits": [
130
+ "Reachability and registered routes do not establish data freshness, model quality, or mission readiness.",
131
+ "Defense effectors remain simulated and human-controlled.",
132
+ ],
133
+ }
134
+
135
+
136
+ def register(app: Any, ns: str = "killinchu") -> dict[str, Any]:
137
+ from starlette.responses import JSONResponse
138
+ from starlette.routing import Route
139
+
140
+ async def _health(_request):
141
+ payload = runtime_status(app, ns)
142
+ payload["schema"] = "szl.killinchu.health/v1"
143
+ return JSONResponse(payload, headers={"Cache-Control": "no-store"})
144
+
145
+ async def _status(_request):
146
+ return JSONResponse(runtime_status(app, ns), headers={"Cache-Control": "no-store"})
147
+
148
+ async def _melt(_request):
149
+ return JSONResponse(melt_summary(app, ns), headers={"Cache-Control": "no-store"})
150
+
151
+ routes = [
152
+ Route("/health", _health, methods=["GET"], name="killinchu_public_health"),
153
+ Route(
154
+ f"/api/{ns}/v1/status",
155
+ _status,
156
+ methods=["GET"],
157
+ name="killinchu_public_status",
158
+ ),
159
+ Route(
160
+ f"/api/{ns}/v1/melt/summary",
161
+ _melt,
162
+ methods=["GET"],
163
+ name="killinchu_melt_summary",
164
+ ),
165
+ ]
166
+ existing = {getattr(route, "name", None) for route in app.router.routes}
167
+ new = [route for route in routes if route.name not in existing]
168
+ app.router.routes[0:0] = new
169
+ return {
170
+ "schema": "szl.killinchu.public-contract-registration/v1",
171
+ "routes": [route.path for route in new],
172
+ }
173
+
174
+
175
+ if __name__ == "__main__":
176
+ from fastapi import FastAPI
177
+
178
+ candidate = FastAPI()
179
+ candidate.add_api_route("/metrics", lambda: "", methods=["GET"])
180
+ candidate.add_api_route(
181
+ "/api/killinchu/v1/mesh/state", lambda: {}, methods=["GET"]
182
+ )
183
+ result = register(candidate)
184
+ assert len(result["routes"]) == 3
185
+ assert runtime_status(candidate)["transport_state"] == "REACHABLE"
186
+ print("SELFTEST OK")
serve.py CHANGED
@@ -5583,6 +5583,26 @@ except Exception as _kc_wave_e: # pragma: no cover — never break SPA/other or
5583
  # ============================================================================
5584
 
5585
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5586
  if __name__ == "__main__":
5587
  import uvicorn
5588
  port = int(os.environ.get("PORT", "7860"))
 
5583
  # ============================================================================
5584
 
5585
 
5586
+ # Public discovery and MELT contracts. Registered last and front-inserted so
5587
+ # they cannot be shadowed by the SPA history route. All endpoints are GET-only.
5588
+ try:
5589
+ import killinchu_public_contracts as _killinchu_public_contracts
5590
+
5591
+ _killinchu_public_contracts_status = _killinchu_public_contracts.register(
5592
+ app, ns="killinchu"
5593
+ )
5594
+ print(
5595
+ f"[killinchu] public contracts registered: {_killinchu_public_contracts_status}",
5596
+ file=sys.stderr,
5597
+ )
5598
+ except Exception as _killinchu_public_contracts_e: # pragma: no cover
5599
+ print(
5600
+ f"[killinchu] public contracts NOT registered: {_killinchu_public_contracts_e!r}; "
5601
+ "SPA + existing API unaffected",
5602
+ file=sys.stderr,
5603
+ )
5604
+
5605
+
5606
  if __name__ == "__main__":
5607
  import uvicorn
5608
  port = int(os.environ.get("PORT", "7860"))
szl_be_hardening.py CHANGED
@@ -640,6 +640,33 @@ def harden(app: Any, organ: str, ns: Optional[str] = None,
640
  status_code=500,
641
  )
642
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
643
  report["registered"].append(f"openapi:/api/{organ}/openapi.json")
644
 
645
  # ---- 9: honest footer -------------------------------------------------
 
640
  status_code=500,
641
  )
642
 
643
+ # FastAPI's default /openapi.json can fail when one legacy route carries an
644
+ # annotation that Pydantic cannot resolve. The organ endpoint above already
645
+ # has a bounded, route-by-route fallback. Front-insert aliases so all public
646
+ # discovery paths use that generator instead of exposing a known 500.
647
+ try:
648
+ from starlette.routing import Route
649
+
650
+ async def _openapi_alias(_request):
651
+ value = await _organ_openapi()
652
+ return JSONResponse(value) if isinstance(value, dict) else value
653
+
654
+ aliases = [
655
+ Route("/openapi.json", _openapi_alias, methods=["GET"], name=f"{organ}_root_openapi"),
656
+ Route(
657
+ f"/api/{organ}/v1/openapi.json",
658
+ _openapi_alias,
659
+ methods=["GET"],
660
+ name=f"{organ}_v1_openapi",
661
+ ),
662
+ ]
663
+ app.router.routes[0:0] = aliases
664
+ report["registered"].extend(
665
+ ["openapi:/openapi.json", f"openapi:/api/{organ}/v1/openapi.json"]
666
+ )
667
+ except Exception as exc:
668
+ logger.error(f"openapi_aliases_unavailable: {exc!r}")
669
+
670
  report["registered"].append(f"openapi:/api/{organ}/openapi.json")
671
 
672
  # ---- 9: honest footer -------------------------------------------------
tests/test_public_contracts.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import unittest
2
+
3
+ from fastapi import FastAPI
4
+ from fastapi.testclient import TestClient
5
+
6
+ import killinchu_public_contracts
7
+ import szl_be_hardening
8
+ import szl_metrics_prom
9
+
10
+
11
+ class PublicContractTests(unittest.TestCase):
12
+ def build_app(self):
13
+ app = FastAPI(title="contract-test", version="1")
14
+ szl_metrics_prom.register(app, ns="killinchu")
15
+
16
+ @app.get("/api/killinchu/v1/mesh/state")
17
+ async def mesh_state():
18
+ return {"state": "test"}
19
+
20
+ szl_be_hardening.harden(app, organ="killinchu", khipu_path=":memory:")
21
+ killinchu_public_contracts.register(app, ns="killinchu")
22
+ return app
23
+
24
+ def test_health_status_and_melt_are_typed(self):
25
+ client = TestClient(self.build_app())
26
+ health = client.get("/health")
27
+ self.assertEqual(health.status_code, 200)
28
+ self.assertEqual(health.json()["transport_state"], "REACHABLE")
29
+ self.assertEqual(health.json()["authority_state"], "READ_ONLY")
30
+
31
+ status = client.get("/api/killinchu/v1/status")
32
+ self.assertEqual(status.status_code, 200)
33
+ self.assertEqual(status.json()["schema"], "szl.killinchu.runtime-status/v1")
34
+
35
+ melt = client.get("/api/killinchu/v1/melt/summary")
36
+ self.assertEqual(melt.status_code, 200)
37
+ self.assertEqual(melt.json()["evidence_state"], "LIVE")
38
+ self.assertTrue(melt.json()["contracts"]["metrics_route_registered"])
39
+ self.assertTrue(melt.json()["contracts"]["mesh_state_route_registered"])
40
+ self.assertEqual(melt.json()["signals"]["traces"]["state"], "EXPORT_UNAVAILABLE")
41
+
42
+ def test_all_openapi_discovery_paths_avoid_legacy_500(self):
43
+ client = TestClient(self.build_app())
44
+ for path in (
45
+ "/openapi.json",
46
+ "/api/killinchu/openapi.json",
47
+ "/api/killinchu/v1/openapi.json",
48
+ ):
49
+ with self.subTest(path=path):
50
+ response = client.get(path)
51
+ self.assertEqual(response.status_code, 200)
52
+ self.assertEqual(response.json()["openapi"], "3.1.0")
53
+
54
+
55
+ if __name__ == "__main__":
56
+ unittest.main()