ssookra commited on
Commit
c339d52
·
verified ·
1 Parent(s): 0a1f495

wave-48 backend deploy

Browse files
apex/instruct/__pycache__/docling_bridge.cpython-312.pyc CHANGED
Binary files a/apex/instruct/__pycache__/docling_bridge.cpython-312.pyc and b/apex/instruct/__pycache__/docling_bridge.cpython-312.pyc differ
 
apex/instruct/docling_bridge.py CHANGED
@@ -83,8 +83,14 @@ def extract_pdf_text(pdf_bytes: bytes) -> str:
83
  ) from exc
84
  import io
85
 
86
- reader = PdfReader(io.BytesIO(pdf_bytes))
87
- text = "\n".join((page.extract_text() or "") for page in reader.pages)
 
 
 
 
 
 
88
  if not text.strip():
89
  raise CoaBridgeError(
90
  "no extractable text in the PDF (likely a scanned image; needs OCR or the "
@@ -125,13 +131,24 @@ def coa_dict_from_text(text: str, generator: Callable[[str, int], str]) -> dict:
125
  malformed or fails the existing `parse_coa_payload` schema validation.
126
  """
127
  prompt = f"{_EXTRACTION_SYSTEM}\n\nDOCUMENT:\n{text[:_MAX_PROMPT_CHARS]}"
128
- raw = generator(prompt, 0)
 
 
 
 
 
129
  payload = _extract_json(raw)
130
  if not isinstance(payload, dict):
131
  raise CoaBridgeError("Granite extraction returned non-object JSON")
132
 
133
  explicit = payload.get("simultaneity_permission_flag")
134
- if explicit is None and not _has_simultaneity_approval(payload):
 
 
 
 
 
 
135
  raise CoaBridgeUndetermined(
136
  "COA simultaneity gate could not be determined from the PDF. Upload a "
137
  "structured COA or a clearer certificate; APEX will not guess a "
 
83
  ) from exc
84
  import io
85
 
86
+ try:
87
+ reader = PdfReader(io.BytesIO(pdf_bytes))
88
+ text = "\n".join((page.extract_text() or "") for page in reader.pages)
89
+ except Exception as exc: # noqa: BLE001 - pypdf raises PdfReadError/DependencyError on corrupt, encrypted, or truncated PDFs
90
+ raise CoaBridgeError(
91
+ "could not read the PDF (corrupt, encrypted, or unsupported format); "
92
+ "upload a structured COA or a clearer certificate"
93
+ ) from exc
94
  if not text.strip():
95
  raise CoaBridgeError(
96
  "no extractable text in the PDF (likely a scanned image; needs OCR or the "
 
131
  malformed or fails the existing `parse_coa_payload` schema validation.
132
  """
133
  prompt = f"{_EXTRACTION_SYSTEM}\n\nDOCUMENT:\n{text[:_MAX_PROMPT_CHARS]}"
134
+ try:
135
+ raw = generator(prompt, 0)
136
+ except Exception as exc: # noqa: BLE001 - external LLM/network boundary; re-raise generically so no upstream response text leaks
137
+ raise CoaBridgeError(
138
+ "COA extraction generator failed (upstream LLM or network error)"
139
+ ) from exc
140
  payload = _extract_json(raw)
141
  if not isinstance(payload, dict):
142
  raise CoaBridgeError("Granite extraction returned non-object JSON")
143
 
144
  explicit = payload.get("simultaneity_permission_flag")
145
+ # Never-guess gate. Treat null AND an uncorroborated non-True value (e.g.
146
+ # the model emitting `false` for an ambiguous certificate instead of the
147
+ # instructed `null`) as undetermined when no approval anchor is present, so
148
+ # a hallucinated negative cannot silently close the gate on an adaptive
149
+ # driver. An affirmative `true` (or any flag backed by the approval anchor)
150
+ # passes here and is consistency-checked by parse_coa_payload below.
151
+ if explicit is not True and not _has_simultaneity_approval(payload):
152
  raise CoaBridgeUndetermined(
153
  "COA simultaneity gate could not be determined from the PDF. Upload a "
154
  "structured COA or a clearer certificate; APEX will not guess a "
apex/orchestration/__pycache__/langgraph_runtime.cpython-312.pyc CHANGED
Binary files a/apex/orchestration/__pycache__/langgraph_runtime.cpython-312.pyc and b/apex/orchestration/__pycache__/langgraph_runtime.cpython-312.pyc differ
 
apex/orchestration/langgraph_runtime.py CHANGED
@@ -241,10 +241,14 @@ class LangGraphRuntime:
241
  )
242
  active_narrator = narrator or Narrator()
243
  narrator_out = active_narrator.narrate(narrator_inputs)
244
- narrator_engine = (
245
- "granite-4.1-8b-openrouter"
246
- if narrator is not None else "deterministic-floor"
247
- )
 
 
 
 
248
  steps.append(NodeExecutionTrace(
249
  node="instruct",
250
  status="ok",
 
241
  )
242
  active_narrator = narrator or Narrator()
243
  narrator_out = active_narrator.narrate(narrator_inputs)
244
+ # The instruct node calls Narrator.narrate(), which composes the
245
+ # coaching report deterministically (derive_corner_insights) and does
246
+ # not invoke the wired text generator. Label the prose engine honestly
247
+ # as the deterministic floor regardless of whether a generator was
248
+ # supplied; the live Granite 4.1 8B narrative is produced by the
249
+ # frontend /api/coaching/narrate route, layered over these backend
250
+ # numbers (frontend provenance "backend-granite-live").
251
+ narrator_engine = "deterministic-floor"
252
  steps.append(NodeExecutionTrace(
253
  node="instruct",
254
  status="ok",