File size: 13,944 Bytes
d9ba8d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17aa715
 
6cd4ac6
 
06fda08
 
 
d9ba8d6
 
 
 
 
e2a8312
 
 
 
d9ba8d6
 
e2a8312
 
 
 
aeea8ca
e2a8312
 
 
aeea8ca
 
 
 
 
e2a8312
 
 
f09cd88
 
 
 
 
 
e2a8312
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aeea8ca
e2a8312
 
aeea8ca
e2a8312
 
 
 
f09cd88
 
aeea8ca
 
f09cd88
 
 
 
 
 
 
 
 
 
aeea8ca
 
 
 
 
 
e2a8312
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d9ba8d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17aa715
e2a8312
 
d9ba8d6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17aa715
 
 
 
 
 
 
 
 
 
 
 
6cd4ac6
 
 
 
 
 
 
 
 
 
 
 
06fda08
 
 
 
 
 
 
 
 
 
 
 
17aa715
 
 
 
 
6cd4ac6
06fda08
17aa715
 
 
 
 
6cd4ac6
 
 
06fda08
 
 
17aa715
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
"""routers/frontier_reads.py — frontier read endpoints (moved verbatim from serve.py).

Wave-K Dev4 refactor-only extraction. Route group (all GET, read-only):
    GET /api/a11oy/v1/forecast-baseline      (+ /v1/forecast-baseline)
    GET /api/a11oy/v1/vertical-packs         (+ /v1/vertical-packs)
    GET /api/a11oy/v1/observability/business (+ /v1/observability/business)

Shared serve.py module-scope state referenced (unchanged, via `import serve`):
    serve._A11OY_FORECAST      — forecast-baseline payload
    serve._a11oy_build_chain   — receipt-chain builder
    serve._A11OY_CAPS          — capability list (for the observability count)

`_A11OY_VERTICALS` was defined inline in the moved block and is genuinely local to
this group, so it moves here with the routes. Registered BEFORE the /api/a11oy/
{path:path} Node proxy + SPA catch-all, identical to the pre-refactor inline block.

The additive Series-A controller is registered at this same pre-catch-all seam. It
keeps GET/HEAD read-only, uses explicit POSTs for refresh/evaluate/execute, and
fails one surface closed without taking down the existing frontier reads. Frontier
Now is a read-only projection over that controller: no second store, signer,
credential, scheduler, passport authority, or effector. Atelier Frontier shares
this pre-catch-all seam as a clean-room, GET/HEAD-only reference registry and
MODELED evaluator; it has no provider write authority or effectors.

Signed-off-by: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
"""
from __future__ import annotations

import json
from datetime import datetime, timezone
from typing import Any, AsyncIterator

from fastapi.responses import JSONResponse

PHASE_B_OBSERVATION_PATHS = frozenset(
    {
        "/api/a11oy/provenance",
        "/api/a11oy/v1/energy/sci",
        "/api/a11oy/v1/ledger",
        "/api/a11oy/v1/observability/summary",
        "/api/a11oy/v1/observability/business",
        "/api/a11oy/v1/mesh/state",
        "/api/a11oy/v1/sec/cve",
        "/api/a11oy/v1/sec/attack",
        "/api/a11oy/v1/sec/threats",
        "/api/a11oy/v1/sec/threatgraph",
        "/api/a11oy/v1/sec/kevgate",
    }
)
PHASE_B_OBSERVATION_ALIASES = frozenset({"/v1/observability/business"})
KEVGATE_PATHS = frozenset(
    {
        "/api/a11oy/v1/sec/kev",
        "/api/a11oy/v1/sec/kevgate",
    }
)
_PHASE_B_MUTATED_PATHS = (
    PHASE_B_OBSERVATION_PATHS
    | PHASE_B_OBSERVATION_ALIASES
    | KEVGATE_PATHS
)


def utc_observation_clock() -> str:
    """Return one genuine request-time UTC observation clock."""
    return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")


def normalize_phase_b_payload(
    path: str,
    payload: Any,
    *,
    observed_at: str | None = None,
    status_code: int = 200,
) -> Any:
    """Apply the closed Phase-B vocabulary to one decoded JSON value.

    Supplying ``observed_at`` makes the function deterministic for regression
    tests. Unknown paths and non-object values are returned without semantic
    changes. Error responses are never rewritten into cached KEV evidence.
    """
    if not isinstance(payload, dict):
        return payload

    normalized = dict(payload)
    if 200 <= int(status_code) < 300 and (
        path in PHASE_B_OBSERVATION_PATHS
        or path in PHASE_B_OBSERVATION_ALIASES
        or path in KEVGATE_PATHS
    ):
        normalized["observed_at"] = observed_at or utc_observation_clock()

    if path in KEVGATE_PATHS and 200 <= int(status_code) < 300:
        raw_kind_text = str(normalized.get("data_kind") or "").strip()
        raw_kind = raw_kind_text.casefold()
        if raw_kind == "live":
            canonical_kind = "live"
        elif (
            raw_kind.startswith("live ")
            and "kev" in raw_kind
            and not any(
                blocked in raw_kind
                for blocked in ("mock", "fabricated", "placeholder")
            )
        ):
            canonical_kind = "live"
            normalized["data_kind_detail"] = raw_kind_text
        elif raw_kind in {"cached", "sample", "snapshot"}:
            # Bundled/in-image CISA rows are cached source material, not a
            # fabricated SAMPLE feed. Unknown kinds stay fail-closed.
            canonical_kind = "cached"
        else:
            return normalized
        normalized["data_kind"] = canonical_kind

        detail = normalized.get("detail")
        if not isinstance(detail, str) or not detail.strip():
            note = normalized.get("note")
            if isinstance(note, str) and note.strip():
                detail = note
            elif canonical_kind == "live":
                detail = (
                    "The KEV source identified this response as live during "
                    "the current request; reachability is not independent "
                    "validation."
                )
            else:
                detail = (
                    "Bundled CISA KEV snapshot served from the current image; "
                    "this is cached source material, not a live catalog fetch."
                )
        normalized["detail"] = detail

    return normalized


async def _phase_b_single_body(body: bytes) -> AsyncIterator[bytes]:
    yield body


def install_phase_b_response_contract(app: Any) -> None:
    """Install the exact-path JSON normalizer once."""
    state = getattr(app, "state", None)
    marker = "_readiness_phase_b_response_contract_installed"
    if state is not None and getattr(state, marker, False):
        return
    if state is not None:
        setattr(state, marker, True)

    @app.middleware("http")
    async def _phase_b_response_contract(
        request: Any,
        call_next: Any,
    ) -> Any:
        response = await call_next(request)
        path = request.url.path
        if path not in _PHASE_B_MUTATED_PATHS:
            return response

        content_type = response.headers.get("content-type", "").casefold()
        if "json" not in content_type:
            return response
        content_encoding = response.headers.get(
            "content-encoding",
            "identity",
        ).casefold()
        if content_encoding not in {"", "identity"}:
            return response

        iterator = getattr(response, "body_iterator", None)
        if iterator is None:
            return response

        chunks: list[bytes] = []
        async for chunk in iterator:
            if isinstance(chunk, bytes):
                chunks.append(chunk)
            elif isinstance(chunk, str):
                chunks.append(chunk.encode("utf-8"))
            else:
                chunks.append(bytes(chunk))
        raw = b"".join(chunks)

        try:
            payload = json.loads(raw.decode("utf-8"))
        except (UnicodeDecodeError, json.JSONDecodeError):
            response.body_iterator = _phase_b_single_body(raw)
            response.headers["content-length"] = str(len(raw))
            return response

        normalized = normalize_phase_b_payload(
            path,
            payload,
            status_code=int(getattr(response, "status_code", 200)),
        )
        encoded = json.dumps(
            normalized,
            ensure_ascii=False,
            separators=(",", ":"),
        ).encode("utf-8")
        response.body_iterator = _phase_b_single_body(encoded)
        response.headers["content-length"] = str(len(encoded))
        for stale_validator in ("etag", "content-md5"):
            if stale_validator in response.headers:
                del response.headers[stale_validator]
        return response


# ---- Vertical-pack registry (GAP-5): 13 verticals, live/stub. "Cyber Resilience"
# label avoids the literal forbidden string. NO amaru/sentra/rosie. ----
_A11OY_VERTICALS = [
    {"id": "platform", "title": "Platform / AgentOps", "purpose": "Release Gate Intelligence", "status": "live", "owner": "eng-vp@szl"},
    {"id": "pulse", "title": "Pulse", "purpose": "Founder Operating Channel", "status": "live", "owner": "ceo@szl"},
    {"id": "finance", "title": "Finance / Capital Weather", "purpose": "Capital Weather", "status": "live", "owner": "cfo@szl"},
    {"id": "decision_ledger", "title": "Decision Debt Ledger", "purpose": "Decision Debt Ledger", "status": "live", "owner": "cpo@szl"},
    {"id": "terra", "title": "Acquisition Time Machine", "purpose": "Acquisition Time Machine", "status": "live", "owner": "ceo@szl"},
    {"id": "voyage", "title": "Voyage Risk Exchange", "purpose": "Voyage Risk Exchange", "status": "live", "owner": "coo@szl"},
    {"id": "counsel", "title": "Matter Flight Recorder", "purpose": "Matter Flight Recorder", "status": "live", "owner": "general-counsel@szl"},
    {"id": "growth", "title": "Marketing / Growth", "purpose": "Proof-To-Pipeline Engine", "status": "live", "owner": "cmo@szl"},
    {"id": "cyber", "title": "Cyber Resilience", "purpose": "Cyber Resilience Command", "status": "live", "owner": "ciso@szl"},
    {"id": "firestorm", "title": "Firestorm Ops", "purpose": "Crisis Operations Command", "status": "stub", "owner": "coo@szl"},
    {"id": "nuroforge", "title": "NuroForge", "purpose": "AI Agent Forge", "status": "stub", "owner": "cto@szl"},
    {"id": "infra", "title": "Meridian Infra", "purpose": "Infrastructure Intelligence", "status": "stub", "owner": "eng-vp@szl"},
    {"id": "graph", "title": "Constellation Graph", "purpose": "Cross-Domain Intelligence Graph", "status": "stub", "owner": "cto@szl"},
]


def register(app) -> dict:
    """Attach frontier reads and the additive Series-A control plane."""
    install_phase_b_response_contract(app)

    import serve  # shared module-scope state lives at serve module scope

    @app.get("/api/a11oy/v1/forecast-baseline")
    @app.get("/v1/forecast-baseline")
    async def a11oy_forecast_baseline_v2() -> JSONResponse:
        return JSONResponse(serve._A11OY_FORECAST)

    @app.get("/api/a11oy/v1/vertical-packs")
    @app.get("/v1/vertical-packs")
    async def a11oy_vertical_packs_v2() -> JSONResponse:
        live = sum(1 for v in _A11OY_VERTICALS if v["status"] == "live")
        return JSONResponse({"total": len(_A11OY_VERTICALS), "live": live,
                             "stub": len(_A11OY_VERTICALS) - live,
                             "verticals": _A11OY_VERTICALS,
                             "honesty": "Live = shipping pack; stub = scaffolded, roadmap."})

    @app.get("/api/a11oy/v1/observability/business")
    @app.get("/v1/observability/business")
    async def a11oy_business_observability_v2() -> JSONResponse:
        ch = serve._a11oy_build_chain(24)
        domains = [
            {"id": "coverage", "name": "Coverage",
             "measure": "knowledge ontology + vertical policies",
             "value": "10 policies · axioms→theorems→formulas graph", "status": "real"},
            {"id": "connectivity", "name": "Connectivity",
             "measure": "in-image capability mesh + MCP tools",
             "value": "%d capabilities · 4 MCP tools" % len(serve._A11OY_CAPS), "status": "real"},
            {"id": "cognitive", "name": "Cognitive",
             "measure": "reasoning + orchestration + Λ scoring",
             "value": "13-axis trust vector · Λ=0.919 (Conjecture 1)", "status": "real"},
            {"id": "executive", "name": "Executive Interfaces",
             "measure": "operator tabs + Ask & Act",
             "value": "command tabs + grounded operator", "status": "real"},
            {"id": "impact", "name": "Impact",
             "measure": "signed decision receipts (hash-chained)",
             "value": "%d signed spans · chain verified" % ch["depth"], "status": "real"},
        ]
        return JSONResponse({
            "domains": domains,
            "honesty": ("Capability domains on real in-image data. We do NOT reproduce "
                        "any third-party marketing percentages as our own."),
            "lambda_status": "Conjecture 1 (advisory)",
        })

    try:
        from routers import series_a_control_plane as _series_a_control_plane

        series_a = _series_a_control_plane.register(app, ns="a11oy")
    except Exception as exc:  # one additive surface must never take down A11oy
        series_a = {
            "ok": False,
            "state": "UNAVAILABLE",
            "reason": type(exc).__name__,
            "effectors": [],
        }

    try:
        from routers import frontier_now_control_plane as _frontier_now

        frontier_now = _frontier_now.register(app, ns="a11oy")
    except Exception as exc:  # one read projection must never take down A11oy
        frontier_now = {
            "ok": False,
            "state": "UNAVAILABLE",
            "reason": type(exc).__name__,
            "effectors": [],
        }

    try:
        from routers import atelier_frontier as _atelier_frontier

        atelier_frontier = _atelier_frontier.register(app, ns="a11oy")
    except Exception as exc:  # reference intake must never take down A11oy
        atelier_frontier = {
            "ok": False,
            "state": "UNAVAILABLE",
            "reason": type(exc).__name__,
            "effectors": [],
        }

    return {
        "ok": True,
        "ns": "a11oy",
        "group": "frontier-reads",
        "series_a": series_a,
        "frontier_now": frontier_now,
        "atelier_frontier": atelier_frontier,
        "routes": [
            "/api/a11oy/v1/forecast-baseline", "/v1/forecast-baseline",
            "/api/a11oy/v1/vertical-packs", "/v1/vertical-packs",
            "/api/a11oy/v1/observability/business", "/v1/observability/business",
            "/series-a", "/api/a11oy/v1/series-a/status",
            "/frontier-now", "/now",
            "/api/a11oy/v1/frontier-now/summary",
            "/api/a11oy/v1/frontier-now/inventory",
            "/atelier/frontier",
            "/api/a11oy/v1/atelier/frontier/registry",
            "/api/a11oy/v1/atelier/frontier/evaluate",
        ],
    }