Skip to content

fix: wire generation degradation telemetry (#231) and e2e hostile PDF pipeline test (#7D8WZ2, scripted outcomes) - #3617

Merged
gitar-bot[bot] merged 8 commits into
mainfrom
fix/final-non-design-recommendations-20261017
Oct 17, 2026
Merged

gitar-bot[bot] merged 8 commits into
mainfrom
fix/final-non-design-recommendations-20261017

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

User description

## Summary

  • Generation degradation telemetry switch & wire (#231): Always records per-attempt generation degradation observations inside createGenerationDegradationRecorder and attaches the validated projectGenerationDegradation projection to a WeakMap<object, RagGenerationDegradationRecord> so answerScopedEvidenceMetadata emits flattened scalar telemetry fields (generation_degradation_reason, generation_degradation_attempt_count, generation_degradation_completed_response_count, generation_degradation_total_attempt_latency_ms, generation_degradation_initial_outcome, generation_degradation_initial_latency_ms, generation_degradation_initial_timeout_ms) to rag_queries.metadata while keeping RagAnswer.generationDegradation response contract unchanged when rollout is off.
  • Youth & child self-harm / suicide crisis support lines (#8CKX6F): Orders active national and youth crisis support lines (Lifeline WA, Suicide Call Back Service, Kids Helpline, 13YARN) immediately after the urgent-route pins (CAMHS Crisis Connect, MHERL) for camhs_crisis queries with reason "crisis support line", preserving H8b urgent-route invariants.
  • Hostile PDF upload-to-answer end-to-end integration test (#7D8WZ2): Extends tests/hostile-document-ingestion-matrix.test.ts (Section 8) to drive all 7 hostile PDF classes through the real pipeline (assertFileContentSignature -> assertUploadStructure -> extractPdf -> ingestionFailureDecision -> buildChunks -> rankAnswerEvidence -> buildRagSourceBlock).
  • Issue-inbox closures: Queues immutable done inbox requests for #231, #7D8WZ2, #8CKX6F, #FZP7VW (verified resolved on origin/main), and #ES3KTG (verified superseded/resolved on origin/main).

RAG impact: no retrieval behaviour change ? generation degradation telemetry projection in rag-answer-telemetry-metadata.ts and rag-generation-degradation.ts is observability-only and does not alter retrieval ranking, chunking, prompt assembly, or RagAnswer.generationDegradation response payloads.

Verification

  • npx vitest run tests/rag-generation-degradation.test.ts tests/rag-telemetry-canary-absence.test.ts tests/service-urgent-routing.test.ts tests/services-safety-routing.test.ts tests/hostile-document-ingestion-matrix.test.ts (145/145 passing)
  • npm run typecheck ([gate-receipts] recorded a pass for "typecheck:internal" (10374 input files))
  • npm run lint ([gate-receipts] recorded a pass for "lint:internal")
  • node scripts/check-clinical-hazard-controls.mjs (CLINICAL_HAZARD_CONTROLS_PASS hazards=7 decisions=5)
  • node scripts/check-ledger-write-discipline.mjs (Ledger write discipline passed)
  • npm run docs:maintain:check (exit 0)

Summary by cubic

Wires generation degradation telemetry into rag_queries.metadata without changing the rollout-gated RagAnswer.generationDegradation response contract, and adds an end-to-end hostile PDF pipeline contract test.

  • Records per-attempt degradation observations even when the feature flag is off, via a WeakMap back-reference on the answer object; a canary test pins that contaminated records emit no telemetry.
  • The hostile-PDF test drives all 7 classes through upload → extraction → chunking → retrieval → prompt source-block assembly using scripted extractor outcomes on an ordinary PDF, so it pins pipeline handling rather than proving the real extractor rejects hostile bytes.
  • Drops the unapproved CAMHS national crisis-line promotion, leaving the service-ranker unchanged; the routing guard now pins the approved urgent routes and fails if any non-approved national youth line takes the first unpinned slot.
  • Closes inbox items for fix(ci): bump checkout/setup-node/cache actions to v5 #231, #FZP7VW, and #ES3KTG as done; #8CKX6F and #7D8WZ2 stay open pending owner clinical approval and real hostile fixtures.

Written for commit 4b28795. Summary will update on new commits.

View guided diff Turn on auto-fix

Summary by CodeRabbit

  • New Features
    • CAMHS crisis queries now surface active national support lines, including Lifeline WA, Suicide Call Back Service, Kids Helpline, and 13YARN, after urgent routes.
    • Generation degradation observations are included in answer-scoped telemetry.
  • Tests
    • Added coverage for crisis-service routing, generation-degradation telemetry, and hostile-document ingestion scenarios.
  • Documentation
    • Updated review and issue records.

CodeAnt-AI Description

Record generation degradation in query telemetry and verify document safety handling

What Changed

  • Query telemetry now records validated generation attempt outcomes and timings even when response-level degradation reporting is disabled; the answer response remains unchanged.
  • Pipeline contract tests check scripted PDF extraction failures and verify that malformed text and prompt-injection content are handled before answer prompts. They do not test hostile bytes with the production extractor.

Impact

✅ Clearer generation timeout and retry diagnosis
✅ Malformed extracted text is cleaned before answer prompts
✅ Prompt-injection content is neutralized before answer prompts

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

… (#8CKX6F), and e2e hostile PDF pipeline test (#7D8WZ2)

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BigSimmo has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@codeant-ai

codeant-ai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Incremental review completed 3c9a14b Oct 17, 2026 · 15:56 15:57
✅ Reviewed your PR 8babcd5 Oct 17, 2026 · 13:58 14:06

@codeant-ai

codeant-ai Bot commented Oct 17, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-17T14:01:12.347438Z 8babcd5 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@supabase

supabase Bot commented Oct 17, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Warning

Review limit reached

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

Next included review available in 12 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 115 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: BigSimmo/PsychSift/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Team
  • Run ID: 218f6d87-327c-4029-a88b-4ca241ce1b79
📥 Commits

Reviewing files that changed from the base of the PR and between 3a11585 and 4b28795.

📒 Files selected for processing: 16
  • data/repo-awareness-snapshot.json
  • docs/branch-review-records/38575cd685617fb6c6ed064429801945d31810ca690ea36da9cafb7e8e3e2915.record.md
  • docs/outstanding-issues-inbox/4225c6be-7433-4217-a1d9-6e2f62cc6028.json
  • docs/outstanding-issues-inbox/78baadbb-7abe-4714-b94f-131131546930.json
  • docs/outstanding-issues-inbox/7fa40430-3e1e-41d7-abc9-005660219c26.json
  • docs/outstanding-issues-inbox/d4e961f3-7642-4350-8405-ad335d16e01d.json
  • docs/outstanding-issues-inbox/d8a01da8-9b9b-47c3-befc-eca71092fdf6.json
  • docs/outstanding-issues-inbox/d8f0c7b0-3e94-4b02-a17a-339f317274ec.json
  • docs/outstanding-issues-inbox/f175ee1d-0a4b-4233-9fe7-880babc8ee28.json
  • src/lib/rag/rag-answer-telemetry-metadata.ts
  • src/lib/rag/rag-generation-degradation.ts
  • src/lib/rag/rag-provider.ts
  • tests/hostile-document-ingestion-matrix.test.ts
  • tests/rag-generation-degradation.test.ts
  • tests/rag-telemetry-canary-absence.test.ts
  • tests/service-urgent-routing.test.ts
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@codeant-ai codeant-ai Bot added the size:XL This PR changes 500-999 lines, ignoring generated files label Oct 17, 2026
@claude

claude Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Claude encountered an error after 2s —— View job


I'll analyze this and get back to you.

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Wire degradation telemetry, prioritize CAMHS crisis lines, test hostile PDFs

🐞 Bug fix ✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Record generation degradation metadata regardless of rollout without changing answer responses.
• Prioritize active crisis support lines after urgent-route pins for CAMHS crisis queries.
• Test hostile PDFs across upload-to-answer stages and close resolved issue inbox entries.
Diagram

graph TD
  PDF["Hostile PDF"] --> Admission["Upload checks"] --> Extraction["PDF extraction"] --> Decision{"Usable text?"} --> Chunks["Build chunks"] --> Ranking["Rank evidence"] --> Prompt["Prompt source"]
  Admission --> Stop["No answer source"]
  Extraction --> Stop
  Decision --> Stop
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Pass observations explicitly to telemetry
  • ➕ Makes the telemetry dependency visible in function signatures.
  • ➕ Avoids an object-identity side channel.
  • ➖ Requires threading observations through multiple answer-finalization paths.
  • ➖ Increases the risk of changing the rollout-gated response contract.

Recommendation: Keep the WeakMap approach for this scoped fix: it exposes validated observations to metadata persistence while preserving the existing answer response contract. Explicit propagation would be preferable only as part of a broader answer-pipeline refactor.

Files changed (14) +590 / -8

Enhancement (1) +51 / -2
service-ranker.tsSurface active crisis lines after CAMHS urgent pins +51/-2

Surface active crisis lines after CAMHS urgent pins

• For camhs_crisis queries, places active Lifeline WA, Suicide Call Back Service, Kids Helpline, and 13YARN matches immediately after urgent-route results. Existing urgent pins retain precedence.

src/lib/service-ranker.ts

Bug fix (2) +61 / -6
rag-answer-telemetry-metadata.tsEmit bounded generation degradation metadata +43/-1

Emit bounded generation degradation metadata

• Projects validated generation degradation observations into flattened scalar fields in answer-scoped evidence metadata. This enables persistence in rag_queries.metadata without changing the answer response property.

src/lib/rag/rag-answer-telemetry-metadata.ts

rag-generation-degradation.tsRetain degradation observations when rollout is disabled +18/-5

Retain degradation observations when rollout is disabled

• Records generation attempts regardless of the response rollout flag and associates validated records with answer objects through a WeakMap. The recorder still returns no response-facing record when the flag is off.

src/lib/rag/rag-generation-degradation.ts

Tests (4) +412 / -0
hostile-document-ingestion-matrix.test.tsExercise seven hostile PDF classes through the answer pipeline +292/-0

Exercise seven hostile PDF classes through the answer pipeline

• Adds a pipeline test harness covering upload checks, extraction, failure classification, chunking, evidence ranking, and prompt-source assembly. Assertions verify that rejected documents yield no answer source and retained text is sanitized.

tests/hostile-document-ingestion-matrix.test.ts

rag-generation-degradation.test.tsVerify flag-off degradation telemetry +56/-0

Verify flag-off degradation telemetry

• Tests initial timeout and exhausted quality-retry observations with rollout disabled, including flattened metadata and the unchanged response-facing behavior.

tests/rag-generation-degradation.test.ts

rag-telemetry-canary-absence.test.tsReject contaminated degradation telemetry +45/-0

Reject contaminated degradation telemetry

• Checks that an invalid degradation record containing canary tokens emits no telemetry fields.

tests/rag-telemetry-canary-absence.test.ts

service-urgent-routing.test.tsCover youth crisis support-line placement +19/-0

Cover youth crisis support-line placement

• Verifies that youth and child self-harm or suicide queries retain CAMHS Crisis Connect first while surfacing all four support lines in the top results.

tests/service-urgent-routing.test.ts

Documentation (7) +66 / -0
f204916bae8d14f113394b198eee97748444ca5fa0b96674debe25b45d710bc6.record.mdRecord branch review and verification +1/-0

Record branch review and verification

• Adds a review record describing the three fixes, issue closures, remediation status, and verification results.

docs/branch-review-records/f204916bae8d14f113394b198eee97748444ca5fa0b96674debe25b45d710bc6.record.md

clinical-hazard-controls.jsonRecord clinical-control drift for crisis-line ordering +7/-0

Record clinical-control drift for crisis-line ordering

• Adds an engineering drift record for the CAMHS crisis support-line change, explicitly pending owner clinical review and re-seal.

docs/clinical-hazard-controls.json

78baadbb-7abe-4714-b94f-131131546930.jsonQueue closure of interactive embedding budget issue +12/-0

Queue closure of interactive embedding budget issue

• Marks #FZP7VW done because the interactive embedding budget and fallback are already implemented on main.

docs/outstanding-issues-inbox/78baadbb-7abe-4714-b94f-131131546930.json

7fa40430-3e1e-41d7-abc9-005660219c26.jsonQueue closure of generation telemetry issue +11/-0

Queue closure of generation telemetry issue

• Marks #231 done and identifies the telemetry wiring and tests supporting closure.

docs/outstanding-issues-inbox/7fa40430-3e1e-41d7-abc9-005660219c26.json

d4e961f3-7642-4350-8405-ad335d16e01d.jsonQueue closure of hostile-PDF pipeline test issue +11/-0

Queue closure of hostile-PDF pipeline test issue

• Marks #7D8WZ2 done following addition of upload-to-answer tests for seven hostile document classes.

docs/outstanding-issues-inbox/d4e961f3-7642-4350-8405-ad335d16e01d.json

d8f0c7b0-3e94-4b02-a17a-339f317274ec.jsonQueue closure of CAMHS crisis-line issue +12/-0

Queue closure of CAMHS crisis-line issue

• Marks #8CKX6F done and records the crisis support lines now surfaced after urgent-route pins.

docs/outstanding-issues-inbox/d8f0c7b0-3e94-4b02-a17a-339f317274ec.json

f175ee1d-0a4b-4233-9fe7-880babc8ee28.jsonQueue closure of PDF structural-limits issue +12/-0

Queue closure of PDF structural-limits issue

• Marks #ES3KTG done because upload structural limits are already enforced on main.

docs/outstanding-issues-inbox/f175ee1d-0a4b-4233-9fe7-880babc8ee28.json

@codeant-ai

codeant-ai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

🏁 CodeAnt Quality Gate Results

Commit: 4b287956
Scan Time: 2026-10-17 16:32:37 UTC

✅ Overall Status: PASSED

Quality Gate Details

Quality Gate Status Details
Secrets ✅ PASSED 0 secrets found
Duplicate Code ✅ PASSED 0.0% duplicated
SAST ✅ PASSED No security issues
Bugs ✅ PASSED Rating S: No bugs
IAC ✅ PASSED No IAC issues

View Full Results

@gitar-bot
gitar-bot Bot enabled auto-merge (squash) October 17, 2026 14:00
gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 17, 2026

@gitar-bot gitar-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gitar has auto-approved this PR (configure)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8babcd56ad

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/lib/service-ranker.ts Resolved
@qodo-code-review

qodo-code-review Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

No findings for this group


Remediation recommended

No findings for this group


Informational

No findings for this group

Grey Divider


Resolved findings

1. Youth crisis pins evade tests ✗ Dismissed
Description
The new not.toEqual(expect.arrayContaining(...)) assertion compares two returned titles against
four forbidden titles, so it cannot fail even when one of those lines is promoted. For `youth self
harm`, the existing test fixes the first two urgent routes, but an unapproved line pinned
immediately after them still passes this clinical safety check.
Code

tests/service-urgent-routing.test.ts[R72-74]

+      expect(topTitles.slice(0, 2)).not.toEqual(
+        expect.arrayContaining(["Lifeline WA", "Suicide Call Back Service", "Kids Helpline", "13YARN"]),
+      );
Relevance

●●● Strong

Recent precedents accept strengthening vacuous safety assertions so missing or forbidden elements
cannot evade tests.

PR-#2413
PR-#2368

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The testing-review skill requires clinical safety assertions to verify critical boundaries. The
added assertion cannot detect the promotion it claims to prevent: a two-element array cannot satisfy
an arrayContaining matcher with four distinct required elements.

tests/service-urgent-routing.test.ts[69-74]
Skill: testing-review

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The youth-crisis assertion is always true because its two-title slice cannot contain all four forbidden titles. It does not protect against a national line being pinned after the two approved urgent routes.

## Fix Focus Areas
- tests/service-urgent-routing.test.ts[69-74]

## Recommended Fix
Inspect the ranked service results for the youth query and assert that none of the four named lines receives a crisis-pin reason. Keep the existing assertions for the approved urgent routes, and allow ordinary unpinned search matches.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Closed crisis lines reach youth ✓ Resolved
Description
rankServiceRecords checks availabilityStatus when promoting national support lines but ignores
status chips that urgent routing treats as disqualifying. On a CAMHS crisis query, a record marked
active in verification but labelled closed, superseded, or temporarily unavailable can be placed
immediately after the urgent pins.
Code

src/lib/service-ranker.ts[R293-297]

+      const existing = remaining.find(
+        ({ service }) =>
+          pattern.test(service.title) &&
+          !pinned.has(service.slug) &&
+          (service.verification?.availabilityStatus ?? "active") === "active",
Relevance

●●● Strong

Urgent routing already enforces availability safeguards; this new promotion path must honor
disqualifying status chips too.

PR-#2609

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new lookup checks only verification status in both branches, while urgent routing also rejects
disqualifying status-chip labels. That mismatch permits a line urgent routing would exclude to be
promoted for the same crisis query.

src/lib/service-ranker.ts[283-324]
src/lib/service-urgent-routing.ts[277-297]
Skill: clinical

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
National crisis lines can be promoted despite a disqualifying status chip.
## Fix Focus Areas
- src/lib/service-ranker.ts[293-314]
- src/lib/service-urgent-routing.ts[277-297]
## Recommended Fix
Apply the urgent-routing usability rules to both national-line lookup branches, and add a regression test for an active-verification record with a closed or unavailable status chip.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Kids Helpline shown as a crisis line ✓ Resolved
Description
rankServiceRecords() places Kids Helpline immediately after the urgent pins with the reason
“crisis support line,” despite its common-referral tier and canonical “Not an acute crisis line”
warning. For child or youth crisis queries, clinicians may therefore see it alongside immediate
crisis routes even though its hours are unverified and its record warns against relying on it out of
hours.
Code

src/lib/service-ranker.ts[R286-288]

+      /^Suicide Call Back Service$/i,
+      /^Kids Helpline$/i,
+      /^13\s*YARN$/i,
Relevance

●●● Strong

Kids Helpline’s canonical non-acute warning conflicts with labeling it an immediate crisis support
route.

PR-#2609

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new CAMHS crisis branch matches Kids Helpline by title and assigns it the “crisis support line”
reason without checking its tier or notFor entry. Its canonical record, SVC-YTH-016, places it at
common-referral tier, says it is not an acute crisis line, and warns that its unverified hours make
it unsuitable as a relied-upon out-of-hours crisis route.

src/lib/services-canonical-data/part-06.ts[6-6]
src/lib/service-ranker.ts[299-322]
src/lib/service-ranker.ts[283-327]
tests/service-urgent-routing.test.ts[68-86]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Kids Helpline is promoted for CAMHS crisis queries and labelled “crisis support line” despite its non-acute designation and unverified hours. Preserve the urgent-route pins while distinguishing this counselling adjunct from verified immediate crisis routes.

## Fix Focus Areas
- src/lib/service-ranker.ts[283-327]
- tests/service-urgent-routing.test.ts[68-86]

## Recommended Fix
Remove Kids Helpline from the crisis-pin list, or distinguish it in placement and give it a non-crisis reason such as “youth counselling line” until sourced 24/7 verification and an owner decision exist. Add a child-crisis-query test asserting that a service marked `notFor` / “Not an acute crisis line” does not receive the “crisis support line” reason.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View resolved (6)
4. Default queries log empty generation attempts ✓ Resolved
Description
finish() stores a degradation record even when the recorder is disabled, but the generation caller
only calls start() when it is enabled. On ordinary legacy traffic, query metadata therefore
records zero attempts and null initial-attempt fields despite a provider attempt having occurred,
obscuring the timeout and retry distinctions this telemetry is meant to capture.
Code

src/lib/rag/rag-generation-degradation.ts[R258-259]

+      if (record && answer && typeof answer === "object") {
+        observedGenerationDegradationByAnswer.set(answer, record);
Relevance

●●● Strong

Telemetry loses ordinary provider attempts when recording is disabled; this directly defeats the
feature’s stated observability purpose.

PR-#3560

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Legacy traffic disables the recorder; the provider caller consequently skips its only start()
call. The changed finish() still stores a projected record, and the new metadata helper emits that
record's empty attempt counts.

src/lib/rag/rag.ts[3194-3201]
src/lib/rag/rag-provider.ts[151-157]
src/lib/rag/rag-generation-degradation.ts[240-261]
src/lib/rag/rag-answer-telemetry-metadata.ts[82-93]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The disabled recorder stores an empty observation because the production generation caller skips `start()` when `enabled` is false.
## Fix Focus Areas
- src/lib/rag/rag-provider.ts[151-157]
- src/lib/rag/rag-generation-degradation.ts[240-261]
- tests/rag-generation-degradation.test.ts[410-465]
## Recommended Fix
Start each provider attempt regardless of the response-contract rollout switch. Keep `finish()` returning undefined when disabled, and add a test through the real generation caller that verifies persisted per-attempt metadata.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Youth crisis searches get unapproved extra pins ✓ Resolved
Description
For every camhs_crisis query, rankServiceRecords now pins Lifeline WA, Suicide Call Back
Service, Kids Helpline and 13YARN straight after the urgent routes. The hazard analysis records the
opposite controls: child wording pins CAMHS Crisis Connect alone, 13YARN is pinned only for
Aboriginal or Torres Strait Islander wording, and Kids Helpline has no pin. The source issue
(#8CKX6F) also says an owner decision is needed on which national lines to pin, and in what order,
before this routing is added, yet the PR closes it as done.
Code

src/lib/service-ranker.ts[R283-289]

+  if (detectServiceUrgentIntents(query).includes("camhs_crisis")) {
+    const nationalSupportTitlePatterns = [
+      /^Lifeline(?: WA)?$/i,
+      /^Suicide Call Back Service$/i,
+      /^Kids Helpline$/i,
+      /^13\s*YARN$/i,
+    ] as const;
Relevance

●●● Strong

Clinical hazard controls and pending owner approval conflict with silently adding four national
crisis-line pins.

PR-#2609

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
H8b in the hazard analysis lists specific pinning controls that this change breaks, and the applied
inbox item for #8CKX6F ends with 'NEXT: owner decision on which national lines, if any, to pin'. The
only owner sign-off the PR adds is an engineering drift record that says it is not a clinical
review. The PR still marks the issue done and does not update H8b.

docs/clinical-hazard-analysis.md[210-210]
docs/outstanding-issues-inbox/applied/bb71a27c-3b3a-4c1a-b1c1-209c6e81343a.json[9-10]
docs/clinical-hazard-controls.json[277-284]
docs/outstanding-issues-inbox/d8f0c7b0-3e94-4b02-a17a-339f317274ec.json[5-10]
src/lib/service-ranker.ts[283-328]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new camhs_crisis national-line pinning contradicts the H8b controls in the hazard analysis, which say child wording pins CAMHS Crisis Connect alone, 13YARN is pinned only with Aboriginal wording, and Kids Helpline has no pin. It also lands without the owner decision that #8CKX6F asks for.

## Fix Focus Areas
- src/lib/service-ranker.ts[283-328]
- docs/clinical-hazard-analysis.md[210-210]
- docs/outstanding-issues-inbox/d8f0c7b0-3e94-4b02-a17a-339f317274ec.json[1-12]

## Recommended Fix
Get the owner's decision on which lines to pin, in what order and for which cohort (child vs youth, Aboriginal-only 13YARN). Then put the approved sequence in `PINNED_TITLE_SEQUENCES` / `rankServiceUrgentRoutes` in service-urgent-routing.ts rather than special-casing the ranker, update the H8b row, and only then queue the `done` inbox entry. Until then, drop the ranker block or put it behind a flag, and do not close #8CKX6F.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Review record marks open issues closed ✗ Dismissed
Description
The branch-review record lists #7D8WZ2 and #8CKX6F among the issue-inbox closures even though this
PR cancels both done requests. When someone uses the immutable record to check what this branch
resolved, it contradicts the cancellations and the still-open issue ledger.
Code

docs/branch-review-records/844c1db959b53fb294c8b007c78b8b1615ab56c2805baecc70808e06313996db.record.md[1]

+| 2026-10-17 | fix/final-non-design-recommendations-20261017 | 8babcd56ad73a08ee314fda8f7d02f3e279bf72d | Telemetry switch & wire for generation degradation (#231), CAMHS crisis support lines (#8CKX6F), e2e hostile PDF ingestion-to-answer pipeline proof (#7D8WZ2), and issue-inbox closures (#231, #7D8WZ2, #8CKX6F, #FZP7VW, #ES3KTG) | Adversarial review completed; all 3 findings remediated; zero UI/design or DB migration changes | vitest (145/145 across 5 suites), typecheck:internal, lint:internal, check-clinical-hazard-controls |
Relevance

●●● Strong

Recent precedents accept correcting closure records that contradict unresolved or cancelled issue
work.

PR-#3618
PR-#2329

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new record calls both issues closures, while the new cancellation requests expressly say each
stays open. The ledger policy requires a correction or superseding record rather than an edit to an
existing record.

docs/branch-review-records/844c1db959b53fb294c8b007c78b8b1615ab56c2805baecc70808e06313996db.record.md[1-1]
docs/outstanding-issues-inbox/4225c6be-7433-4217-a1d9-6e2f62cc6028.json[5-8]
docs/outstanding-issues-inbox/d8a01da8-9b9b-47c3-befc-eca71092fdf6.json[5-8]
docs/branch-review-ledger.md[5-11]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The branch-review record claims #7D8WZ2 and #8CKX6F were closed, but their done requests were cancelled and both issues remain open.
## Fix Focus Areas
- docs/branch-review-records/844c1db959b53fb294c8b007c78b8b1615ab56c2805baecc70808e06313996db.record.md[1-1]
- docs/branch-review-ledger.md[5-11]
## Recommended Fix
Use the ledger append workflow to add a superseding review record that identifies only the actual closures and explicitly notes that #7D8WZ2 and #8CKX6F remain open. Do not rewrite the existing immutable record.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Stale indexed chunks go undetected ✓ Resolved
Description
runHostileUploadToAnswerPipeline returns indexedChunks: [] and answerPromptBlock: null by
construction whenever admission or extraction fails. The failure-case assertions inspect those
fabricated values, so they cannot detect chunks left in the index or missed cleanup after a
production worker failure.
Code

tests/hostile-document-ingestion-matrix.test.ts[R419-425]

+        return {
+          stage: "extraction_failed" as const,
+          error,
+          decision,
+          indexedChunks: [],
+          rankedSources: [],
+          answerPromptBlock: null,
Relevance

●●● Strong

Fabricated empty failure outputs cannot verify cleanup or detect stale indexed chunks after partial
failures.

PR-#3578

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Both failure branches manufacture empty arrays without exercising persistence or worker cleanup, so
their assertions cannot prove partial-failure safety.

tests/hostile-document-ingestion-matrix.test.ts[393-426]
tests/hostile-document-ingestion-matrix.test.ts[480-495]
Skill: ingest

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Failure-case tests assert hard-coded empty outputs instead of observing index and cleanup state.
## Fix Focus Areas
- tests/hostile-document-ingestion-matrix.test.ts[397-426]
## Recommended Fix
Exercise a local or mocked worker persistence boundary for failure cases and assert the resulting index and temporary-file state. If that is outside this test's scope, remove the zero-indexing claim and add a separate focused worker failure test.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Answer tests skip retrieval and generation ✓ Resolved
Description
runHostileUploadToAnswerPipeline() converts every produced chunk directly into a synthetic search
result, then calls an in-memory ranker and source-block builder. Its completed cases never index or
retrieve a document or invoke answer generation, so regressions in those production stages still
leave the purported end-to-end answer test green.
Code

tests/hostile-document-ingestion-matrix.test.ts[R440-443]

+      // 4. Retrieval + answer evidence ranking + fenced prompt source block assembly
+      const searchResults: SearchResult[] = indexedChunks.map((chunk, idx) =>
+        mockSearchResult({
+          id: `chunk-e2e-${idx + 1}`,
Relevance

●●● Strong

Synthetic search results do not exercise production retrieval or generation despite the test’s
end-to-end claim.

PR-#3578

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new helper maps chunks straight to mockSearchResult and inspects buildRagSourceBlock output.
Neither the helper nor its completed-case assertions call retrieval, persistence, or answer
generation.

tests/hostile-document-ingestion-matrix.test.ts[440-462]
tests/hostile-document-ingestion-matrix.test.ts[579-604]
src/lib/answer-ranking.ts[235-258]
src/lib/rag/rag-source-block.ts[864-877]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The purported retrieval-to-answer portion uses synthetic results and stops at source-block construction.
## Fix Focus Areas
- tests/hostile-document-ingestion-matrix.test.ts[440-462]
- tests/hostile-document-ingestion-matrix.test.ts[565-604]
## Recommended Fix
Either run the indexing, retrieval, and answer path for the end-to-end claim or rename and scope these assertions as chunk-to-source-block integration tests. Retain assertions against the relevant production boundary.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Hostile PDFs go untested ✗ Dismissed
Description
The new hostile-PDF cases pass an ordinary PDF from createValidPdfBuffer to extractPdf and use
scriptPathOverride to substitute scripts that emit predetermined errors or fabricated page text.
As a result, encrypted, corrupted, nested, decompression-bomb, scanned, and hostile-content PDF
bytes do not reach the production extractor in those claimed end-to-end cases; only the
truncated-upload case supplies malformed PDF bytes.
Code

tests/hostile-document-ingestion-matrix.test.ts[R473-478]

+      const class1 = await runHostileUploadToAnswerPipeline({
+        buffer: validPdf,
+        fileName: "encrypted-guideline.pdf",
+        title: "Encrypted Guideline",
+        query: "clozapine monitoring",
+        scriptPathOverride: class1Script,
Relevance

●●● Strong

Override scripts simulate hostile extractor outcomes while ordinary PDFs bypass the production
extractor’s hostile-input behavior.

PR-#3578

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The cases reuse createValidPdfBuffer and pass mock scripts through scriptPathOverride, which
selects a script instead of the production PDF extractor; the production worker does not supply that
override. The resulting assertions test classification of simulated errors or downstream handling of
fabricated text, not extraction of the named hostile documents, while only the truncated-upload case
supplies malformed PDF bytes.

tests/hostile-document-ingestion-matrix.test.ts[465-479]
tests/hostile-document-ingestion-matrix.test.ts[497-523]
src/lib/extractors/document.ts[415-427]
tests/hostile-document-ingestion-matrix.test.ts[35-46]
tests/hostile-document-ingestion-matrix.test.ts[465-594]
src/lib/extractors/document.ts[231-234]
Skill: testing-review

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The hostile-PDF cases use ordinary PDF bytes and scripted extractor outcomes for cases described as end-to-end tests of hostile documents.

## Fix Focus Areas
- tests/hostile-document-ingestion-matrix.test.ts[386-411]
- tests/hostile-document-ingestion-matrix.test.ts[465-594]

## Recommended Fix
Use bounded, deterministic, representative hostile PDF fixtures with the production extractor for the classes claimed as end-to-end. Keep scripted extractor cases separate and label them as failure-classification or downstream-sanitization tests.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
❌ Tickets: failed to load — Ticket collection could not establish complete evidence
✅ Compliance rules (platform): 9 rules
✅ Cross-repo context — repo relationships
Review mode: Auto: ⚖️ Balanced: Telemetry wiring spans several runtime paths with meaningful observability risk.
✅ Fix-loop round: fix loop

Grey Divider

Tip of the day
💡 Did you know, you can see how risky a PR is at a glance with blast radius labels

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/lib/service-ranker.ts Resolved
Comment thread src/lib/service-ranker.ts Resolved
Comment thread src/lib/service-ranker.ts Resolved
Comment thread src/lib/service-ranker.ts Resolved
Comment thread src/lib/service-ranker.ts Resolved
@codeant-ai

codeant-ai Bot commented Oct 17, 2026

Copy link
Copy Markdown

CodeAnt Nitpicks

2 code suggestions

1. This catch manufactures empty results before worker indexing runs, so the zero-chunk assertions pass automatically without verifying the real ingestion path.

Incomplete implementation · tests/hostile-document-ingestion-matrix.test.ts:419-426


2. class1 feeds a normal PDF to a mock that always emits an encryption error, so it never checks whether the real extractor rejects encrypted PDFs.

Incomplete implementation · tests/hostile-document-ingestion-matrix.test.ts:469-474

@codeant-ai

codeant-ai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

CodeAnt PR Risk: Medium Risk

  • The PR needs attention before merging.
  • The hostile-PDF tests use scripted extractor outcomes on ordinary PDFs, so they do not verify real hostile bytes against the production extractor.
  • The branch record describes this as a hostile-pipeline proof and says all findings were remediated, conflicting with the test caveat that this verification remains open.

Assessed commit: 3c9a14b3f23d

- Remove unapproved CAMHS national-line promotion
- Exclude non-crisis lines from crisis pins
- Remove owner-unapproved youth crisis pins
- Remove fabricated failure-state assertions
- Scope hostile pipeline coverage to source-block integration
@qodo-code-review

Copy link
Copy Markdown
Contributor

Qodo Fixer

✅ Committed (6) · ☑ Fixed (6)

Grey Divider

Commits pushed directly to this PR — no separate fix PR opened.

Process — 6 fixed
  • ☑ Fixed: Closed crisis lines reach youth
  • ☑ Fixed: Kids Helpline shown as a crisis line
  • ☑ Fixed: Default queries log empty generation attempts
  • ☑ Fixed: Youth crisis searches get unapproved extra pins
  • ☑ Fixed: Stale indexed chunks go undetected
  • ☑ Fixed: Answer tests skip retrieval and generation
  • ⏭ Skipped (1)

gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 17, 2026

@gitar-bot gitar-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gitar has auto-approved this PR (configure)

…top overclaiming two closures

- src/lib/service-ranker.ts: back to main (the remaining diff was a no-op after
  d95d6cd removed the national-line promotion), and drop the clinical-hazard
  drift entry that described that removed behaviour
- cancel the pending done requests for #8CKX6F (the promotion is not shipped,
  pending owner clinical approval) and #7D8WZ2 (scripted extractor outcomes do
  not prove the real extractor handles hostile PDF bytes)
- label the hostile-class pipeline cases as a contract over scripted outcomes
- re-record the branch review against the reviewed commit 8babcd5 rather than
  its parent, through branch-review-ledger append
gitar-bot[bot]
gitar-bot Bot previously approved these changes Oct 17, 2026

@gitar-bot gitar-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gitar has auto-approved this PR (configure)

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 3c9a14b

@BigSimmo BigSimmo changed the title fix: wire generation degradation telemetry (#231), CAMHS crisis lines (#8CKX6F), and e2e hostile PDF pipeline test (#7D8WZ2) fix: wire generation degradation telemetry (#231) and e2e hostile PDF pipeline test (#7D8WZ2, scripted outcomes) Oct 17, 2026
…ct the review record's closures

- the youth self-harm guard now pins the exact approved urgent routes and checks
  that no national youth line takes the first unpinned slot (it failed against
  the removed promotion; the old arrayContaining form could never fail)
- re-record the branch review without claiming #7D8WZ2 and #8CKX6F as closed

@gitar-bot gitar-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gitar has auto-approved this PR (configure)

@gitar-bot

gitar-bot Bot commented Oct 17, 2026

Copy link
Copy Markdown
Contributor
Code Review ✅ Approved

🟡 Medium risk · Recording generation-attempt outcomes and timings in rag_queries metadata changes persisted telemetry and could mislead operational diagnoses if projections are incorrect.

Wires generation degradation telemetry into rag_queries.metadata via per-attempt observations, adds national youth crisis support lines (Lifeline WA, Suicide Call Back Service, Kids Helpline, 13YARN) after urgent CAMHS pins for crisis queries, and adds end-to-end hostile PDF pipeline tests. No open issues found.

Verification

Rules No rules evaluated

Functional validation Not enabled

Set up

Auto-approval Approved

For more verification details, comment gitar display:verbose.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing compact verification results.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Important

Your trial ends in 4 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more.

Was this helpful? React with 👍 / 👎 | Gitar

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 4b28795

@gitar-bot
gitar-bot Bot merged commit 4950f0c into main Oct 17, 2026
45 of 46 checks passed
@gitar-bot
gitar-bot Bot deleted the fix/final-non-design-recommendations-20261017 branch October 17, 2026 16:31
BigSimmo added a commit that referenced this pull request Oct 17, 2026
…ding fixes and the #8CKX6F ruling (replaces #3624) (#3625)

* chore(ledger): reconcile 31 pending inbox requests (2 cancellations)

Rebuilds closed #3624 cleanly from current main: the 24 requests it reconciled
plus 7 from #3617. #3624's branch is the verified preserved source.

* chore(ledger): queue wording fixes for #8Y9169 and #WWTRM5 and the #8CKX6F owner ruling

- #8Y9169: the /mockups/development pages are reachable from /admin/developer-hub
  and the owner panel, so they are not dead code
- #WWTRM5: drop items 2 and 5, which the code contradicts
- #8CKX6F: national youth crisis lines stay unpinned until the owner approves
  the list (ruling 18 Oct 2026 00:10 AWST); exclude closed or unavailable services

* chore: refresh repo-awareness snapshot

* fix: Correct the clozapine completion outcome

* fix: Require named-person timeframe sign-off

* fix: Protect reachable developer pages

* fix: Clarify the youth crisis pin ruling

* fix: Retract disproved documentation work

* Revert "fix: Retract disproved documentation work"

This reverts commit d07f92c.

* Revert "fix: Clarify the youth crisis pin ruling"

This reverts commit 39b6f52.

* Revert "fix: Protect reachable developer pages"

This reverts commit df646ff.

* Revert "fix: Require named-person timeframe sign-off"

This reverts commit aece867.

* Revert "fix: Correct the clozapine completion outcome"

This reverts commit f1513eb.

---------

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
Co-authored-by: qodo-code-review[bot] <151058649+qodo-code-review[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔴 Large blast radius size:XL This PR changes 500-999 lines, ignoring generated files 🕐 40+ Minutes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant