Compare commits

..

3 commits

Author SHA1 Message Date
Kisa
5ba31fac03 Add attorney-review legal bundle: BAA template v1, cover memo, send-ready docx set
lead-sttil drafted, ops-steward independently reviewed (6 findings fixed).
Entity name corrected to KJF Professional Services LLC dba STTIL Solutions.
Formation state left as attorney question 1. LOI/NDA v3 live in STTIL-Vault/Projects/Legal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 05:35:21 -04:00
Kisa
bd92126384 feat: patient rollup + nested patients payload (plan 02, P3)
core/rollup.py implements the locked truth table: worst gradeable line wins;
a Plan Type Needed line caps the patient at Action Needed; non-gradeable
lines are displayed but never touch the light; no-graded-lines patients carry
None (no label invented). /api/upload gains additive patients[] (one entry
per patient, nested device lines with doc checklists, citations, timing
flags, dedup display fields) and patient_stats (counts patients, not rows).
Flat records payload untouched until P6. Independent audit: SHIP; its LOW
findings fixed (date coercion on timing keys, empty-rollup guard, severity
divergence documented). 151 tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 05:20:45 -04:00
Kisa
d24340c47a feat: citation rule IDs on every documentation requirement (plan 02, P2)
core/rules.py format-tolerant readers + stable registry (R001-R004 plan-scoped,
R100-R102 universal per LCD L33822). payer_rules.json wrapped in the same
commit as both engine readers (coupling hazard closed). Every DocItem now
cites the rule that decided it; NOT_EVALUATED cites nothing. Independent
audit: SHIP (registry-drift test added per its L2 finding). 138 tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 05:10:52 -04:00
19 changed files with 1069 additions and 64 deletions

View file

@ -4,7 +4,7 @@ v:1
ACTIVE: 2026-07-07 [CC]. SIGNAL BUILD UN-PAUSED — readiness-model completion in flight per docs/build-plans/. P1 (wiring) SHIPPED + LIVE-VERIFIED (commit a3af499, deployed to Railway, false-green kill observed live). Executing P2 (citation IDs) -> P3 (rollup) -> P4 (device overrides) -> P5 (plan-type enforcement) next, one item at a time with independent audit each. P6 (frontend nesting) BLOCKED on Kisa approving the rendered mockup (built, awaiting render+review).
NEXT: (CC) P2-P5 per docs/build-plans/02-readiness-model-completion.md; (Kisa) approve/reject P6 mockup decisions A-D; (Kisa) confirm OQ1 plan_type-ingestion decision recorded 2026-07-07 (shipped per umbrella plan; two-line revert if reversed); (Kisa) attorney email bundle + Gaboro re-approach per reactivation plan 00 (unchanged). Queued behind Signal: UMSIS docs-only activation, "63% written off" Draft fix.
NEXT: (CC) P2-P5 per docs/build-plans/02-readiness-model-completion.md; (Kisa) approve/reject P6 mockup decisions A-D; (Kisa) confirm OQ1 plan_type-ingestion decision recorded 2026-07-07 (shipped per umbrella plan; two-line revert if reversed); (Kisa) attorney bundle READY TO SEND (signal/pitch/legal/attorney-bundle-2026-07-07, 5 Word docs + sendable memo): confirm recipient (Clyde Mathes vs Bittinger/Nixon), entity name + formation state, arbitration-vs-courts posture, Partner Concepts carve-out keep/drop, then email; Gaboro re-approach per reactivation plan 00 (unchanged). Queued behind Signal: UMSIS docs-only activation, "63% written off" Draft fix.
PRIOR ACTIVE: 2026-06-28. Signal paused at clean checkpoint — Insight Engine in active BUILD phase for July 4 deadline. See insight-engine/context/current-state.md and insight-engine/handoff-clock.md for full state. Key progress today: x-sight guided experience designed (Compass) and approved by Kisa, lane-lock handoff clock created, frontend finish readiness assessed (15 ranked items). Claude is building the Compass landing + B1 deploy blocker + finish items. Signal READINESS MODEL still queued at the clean checkpoint from 2026-06-27.
@ -25,6 +25,7 @@ Insight Engine (July 4 deadline = tomorrow) is the active project. Key files:
## Decisions (last
- 2026-07-07 [CC]: Attorney-review legal bundle PREPARED (lead-sttil drafted, ops-steward independently reviewed, 6 findings fixed incl. 4 HIGH counterparty-name leaks). LOI template v3 (product-agnostic body, Exhibit A pre-filled for Signal, labABLE negotiation learnings folded in), NDA template v3 (products list corrected to Signal/Vitality Med Tracker/UMSIS + catch-all), BAA template v1 (generalized from Gaboro draft, forward-looking posture block), cover memo bundling both templates + BAA + FDA CDS memo + labABLE AKS question per reactivation plan 00. Entity name corrected everywhere to KJF Professional Services LLC dba STTIL Solutions (per executed labABLE LOI; kg_add recorded); formation state left as placeholder (old docs disagree: Delaware/Florida/Pennsylvania) = attorney Q1. Templates: STTIL-Vault/Projects/Legal/ (LOI+NDA v3) + signal/pitch/legal/ (BAA, memo). Send-ready docx: signal/pitch/legal/attorney-bundle-2026-07-07/.
- 2026-07-07 [CC]: Readiness model WIRED LIVE (plan 01, commit a3af499, Railway deploy verified). Phase 2a seam confirmed: readiness AUGMENTS legacy output (byte-identical legacy proven by live diff). OQ1 executed per umbrella plan 00 ("ship plan_type ingestion with the wiring") — minimal client-mapped column, never guessed; flagged for Kisa's explicit confirmation, two-line revert if reversed. Adversarial review caught a false-green in the draft row-resolution; fixed via dedup-group-keyed ReadinessIndex, regression-locked. Grounded test count: 132 (the old "73 tests" figure corrected per plan 01 §12.5).
- 2026-07-06 [CC]: Model routing SETTLED (Kisa agreed) — strongest model in the orchestrator seat (plain claude, full MCP, skip-permissions), sonnet/haiku subagents for mechanical work, Fable-as-subagent only for cleanly separable hard problems. Docs-verified: delegation multiplies tokens on one shared pool; per-agent model override + mid-session /model GROUNDED. Config application PARKED. Discovered com.sttil.cos-model-switch: Fable-to-Opus swap fires 2026-07-07 09:00. Watcher audit: 9 agents healthy, clean exits; research watcher never built.
- 2026-07-06 [CC]: Crew Compounding Memory Phase 1 shipped + independently verified — retrieve-and-inject wired into the dispatch skill (validity-stamped "WHAT THE CREW ALREADY KNOWS" block, current==true filter, recall guard) + ~/.claude/crew-log.md; built by the memory-crew, verified PASS (2 agents flagged every planted contradiction, independent grader confirmed). Also ruled: UMSIS activates sttil/umsis docs-only (state in the repo, not the vault). Spec + build record: STTIL-Vault/Projects/STTIL Solutions/Crew Compounding Memory - Design Spec - 2026-07-05.md.
@ -58,4 +59,4 @@ Insight Engine (July 4 deadline = tomorrow) is the active project. Key files:
State protocol: read = `git pull --rebase` then read this file (warn if Updated > 24h old); write = edit ACTIVE/NEXT, append one author-stamped decision, then commit + push. Full protocol in the `state-sync` skill. Detailed ship-status (what shipped / didn't / why) = docs/ship-status-ledger.md. TriLane = searchable archive, not live state.
## Updated: 2026-07-07 (CC: Signal un-paused; P1 readiness wiring shipped+live-verified a3af499; P2-P5 executing; P6 mockup awaiting Kisa; OQ1 recorded for confirmation.)
## Updated: 2026-07-07 (CC: Signal un-paused; P1 readiness wiring shipped+live-verified a3af499; P2-P5 executing; P6 mockup awaiting Kisa; OQ1 recorded for confirmation; attorney legal bundle prepared and ready to send.)

View file

@ -0,0 +1,224 @@
# BUSINESS ASSOCIATE AGREEMENT (Template v1)
> **DRAFT, for attorney review before use. Not legal advice.**
> Prepared 2026-07-07. Generalized from the a prior supplier-specific BAA into a reusable STTIL Solutions template. This is a FORWARD-LOOKING instrument. See "Status and posture" immediately below before reading the operative terms.
---
## STATUS AND POSTURE (read first, attorney)
This BAA template is prepared as a forward-looking instrument, not a description of the current live environment. As of 2026-07-07:
- Real PHI is BLOCKED. The Product operates on mock and de-identified data today; no real protected health information is in active exposure (Signal current-state.md, 2026-07-07).
- The current pilot stack (Supabase, Railway, Vercel, Clerk) does NOT have executed subprocessor BAAs in place. The subprocessor table in Section 2.5 describes the pilot stack, not a BAA-covered chain.
- AWS is the compliant migration path. An AWS BAA was signed and became active 2026-05-27; RDS and S3 are provisioned but parked, not in active build until post-funding. If and when a Covered Entity relationship requires real PHI, the Product migrates to the AWS (or equivalent BAA-capable) environment before any PHI is processed, and the subprocessor table is updated accordingly.
Counsel should review this template as the instrument STTIL would execute at the point real PHI enters the system, and advise on the threshold question in Attorney Review Note 1 (whether a BAA is required at all given the crosswalk-stays-with-supplier architecture).
---
**Effective Date:** __________ , 20__
**Between:**
- **KJF Professional Services LLC d/b/a STTIL Solutions** ("Business Associate"), a [STATE, confirm formation state with counsel] limited liability company, Kisa Fenn, Managing Member
- **[COVERED ENTITY FULL LEGAL NAME]** ("Covered Entity"), [SIGNER NAME], [SIGNER TITLE]
Each a "Party" and together the "Parties."
---
## Recitals
Covered Entity is [a durable medical equipment supplier / a healthcare provider / other] subject to the Health Insurance Portability and Accountability Act of 1996 and its implementing regulations ("HIPAA"). Business Associate provides a documentation readiness platform (the "Service"), described in the Pilot Letter of Intent between the Parties (the "LOI") and its Exhibit A. In connection with the Service, Business Associate may receive, create, maintain, or transmit data on behalf of Covered Entity that may constitute Protected Health Information ("PHI") as defined under HIPAA. The Parties enter into this Agreement to satisfy the Business Associate Agreement requirements of 45 C.F.R. Part 164, Subpart C.
---
## 1. Definitions
Terms used in this Agreement have the meanings assigned under HIPAA and its implementing regulations, including the HITECH Act amendments, as of the Effective Date.
**"Protected Health Information" or "PHI"** means individually identifiable health information created, received, maintained, or transmitted by Business Associate on behalf of Covered Entity, in any form or medium.
**"Minimum Necessary"** means the least amount of PHI required to accomplish the intended purpose of a given use, disclosure, or request.
**"Security Incident"** means the attempted or successful unauthorized access, use, disclosure, modification, or destruction of information, or interference with system operations in an information system.
---
## 2. Obligations of Business Associate
### 2.1 Permitted Uses and Disclosures
Business Associate may use or disclose PHI only:
(a) To perform the Service described in the LOI and its Exhibit A, specifically: receiving order-management data uploaded by Covered Entity limited to the minimum-necessary fields specified in the LOI, calculating documentation readiness status per record, and returning a prioritized worklist to Covered Entity staff;
(b) As required by law; or
(c) For the proper management and administration of Business Associate's own operations, provided that any such disclosure is required by law or Business Associate obtains reasonable assurances that the information will be held in confidence and used or further disclosed only as required by law or for the purpose for which it was disclosed.
Business Associate will not use or disclose PHI in any manner that would violate HIPAA if done by Covered Entity directly.
### 2.2 Minimum Necessary
Business Associate will make reasonable efforts to use, disclose, and request only the minimum necessary PHI to accomplish the intended purpose.
### 2.3 Safeguards
Business Associate will implement and maintain appropriate administrative, physical, and technical safeguards to protect the confidentiality, integrity, and availability of PHI it creates, receives, maintains, or transmits on behalf of Covered Entity, in accordance with 45 C.F.R. Part 164, Subpart C (Security Rule).
Business Associate's safeguards include:
- HTTPS enforced on all data transmission surfaces
- SHA-256 hashing of patient_id before storage in any log or database record
- Row Level Security restricting data access by organization
- JWT authentication required on all API endpoints
- No storage of patient names, dates of birth, Social Security numbers, addresses, or contact information at any time
- The patient identity crosswalk (supplier's internal patient_id to real patient identity) is maintained solely by Covered Entity staff and is never transmitted to or stored by Business Associate
*Attorney note: this safeguards list reflects the current pilot architecture. When the Service migrates to a BAA-capable host for real PHI (see Status and posture), this list is updated to reflect the production environment, including encryption at rest.*
### 2.4 Reporting
Business Associate will report to Covered Entity, without unreasonable delay and in no event later than 30 calendar days of discovery:
(a) Any use or disclosure of PHI not permitted by this Agreement of which Business Associate becomes aware;
(b) Any Security Incident of which Business Associate becomes aware, including breaches of Unsecured PHI as required by 45 C.F.R. Part 164, Subpart D;
(c) Any attempted but unsuccessful Security Incident of which Business Associate becomes aware, to the extent practicable.
Reports will be made to Covered Entity's designated contact in writing.
### 2.5 Subcontractors
Business Associate will ensure that any subcontractor or agent to which it provides PHI on behalf of Covered Entity agrees in writing to the same restrictions, conditions, and requirements that apply to Business Associate under this Agreement, before any PHI is provided to that subcontractor.
Business Associate's current subprocessors are:
| Subprocessor | Purpose | Data Touched |
|---|---|---|
| Supabase | PostgreSQL database hosting | Hashed patient_id, device_type, shipment_date, payer, doc status fields |
| Railway | Backend API hosting | Processes upload requests in transit; does not persist PHI |
| Vercel | Frontend hosting | No PHI; serves static application only |
| Clerk | Staff authentication | No PHI; stores staff identity only |
*Attorney note: none of the subprocessors listed above currently has an executed subprocessor BAA. Real PHI is blocked today (see Status and posture). Before any real PHI is processed, Business Associate will either (a) obtain an executed BAA from each subprocessor that will touch PHI, or (b) migrate the PHI-touching functions to a BAA-capable environment (an AWS BAA is signed and active as of 2026-05-27; AWS RDS and S3 are provisioned and parked). This table is updated to reflect the production chain at that point.*
Business Associate will notify Covered Entity of any material change to subprocessors that will touch PHI, and will obtain Covered Entity's written approval before adding any new subprocessor that will receive or process PHI.
### 2.6 Access to PHI
To the extent Business Associate maintains PHI in a Designated Record Set, Business Associate will make such PHI available to Covered Entity as necessary to fulfill Covered Entity's obligations under 45 C.F.R. Section 164.524 within 15 business days of a written request.
### 2.7 Amendment
To the extent Business Associate maintains PHI in a Designated Record Set, Business Associate will make such PHI available for amendment and will incorporate any amendments requested by Covered Entity as required by 45 C.F.R. Section 164.526.
### 2.8 Accounting of Disclosures
Business Associate will maintain a record of disclosures of PHI and will make such information available to Covered Entity as necessary to respond to a request for an accounting of disclosures under 45 C.F.R. Section 164.528.
### 2.9 Government Access
Business Associate will make its internal practices, books, and records relating to the use and disclosure of PHI available to the Secretary of the U.S. Department of Health and Human Services for purposes of determining compliance with HIPAA.
---
## 3. Obligations of Covered Entity
Covered Entity agrees to:
(a) Notify Business Associate of any limitation in Covered Entity's Notice of Privacy Practices that would affect Business Associate's permitted uses or disclosures;
(b) Notify Business Associate of any changes in, or revocations of, authorization by individuals that would affect Business Associate's permitted uses or disclosures;
(c) Not request Business Associate to use or disclose PHI in any manner that would not be permissible under HIPAA if done by Covered Entity directly;
(d) Ensure that any data uploaded to the Service is limited to the minimum-necessary fields specified in the LOI: an internal patient identifier (patient_id), device type, shipment date, quantity, and payer name, plus any optional documentation-status fields the Parties agree to. Covered Entity will not upload patient names, Social Security numbers, dates of birth, addresses, or direct contact information to the Service at any time.
---
## 4. Term and Termination
### 4.1 Term
This Agreement is effective as of the Effective Date and continues until the later of: (a) the termination of the LOI or any subsequent formal agreement between the Parties; or (b) the date on which Business Associate has completed its data return and destruction obligations under Section 4.3.
### 4.2 Termination for Cause
Either Party may terminate this Agreement immediately upon written notice to the other Party if the other Party has materially breached a provision of this Agreement and has not cured the breach within 10 business days of written notice identifying the breach.
### 4.3 Return or Destruction of PHI
Upon termination of this Agreement for any reason:
(a) Business Associate will return to Covered Entity or destroy all PHI received from or created on behalf of Covered Entity, including PHI in the possession of subcontractors, within 10 business days of the effective termination date;
(b) Business Associate will certify in writing to Covered Entity that all such PHI has been returned or destroyed;
(c) If return or destruction is not feasible, Business Associate will extend the protections of this Agreement to such PHI and limit further use or disclosure to the purposes that make return or destruction infeasible, for as long as Business Associate maintains the PHI.
---
## 5. Miscellaneous
### 5.1 Regulatory References
Any reference in this Agreement to a section of HIPAA includes the most recent amendment or regulatory guidance applicable to that section.
### 5.2 Interpretation
This Agreement is intended to comply with HIPAA as amended. Where this Agreement conflicts with HIPAA, HIPAA controls. Where this Agreement is silent, HIPAA controls.
### 5.3 No Third-Party Beneficiaries
Nothing in this Agreement confers any right, remedy, or claim upon any third party, including any patient whose PHI is involved.
### 5.4 Governing Law
This Agreement is governed by the laws of the State of [STATE, confirm formation state with counsel], without regard to conflict of law principles.
### 5.5 Entire Agreement
This Agreement, together with the LOI and the mutual NDA between the Parties, constitutes the entire agreement with respect to PHI and supersedes all prior understandings on the subject.
---
## Signatures
**KJF Professional Services LLC d/b/a STTIL Solutions (Business Associate)**
By: ___________________________
Name: Kisa Fenn
Title: Managing Member
Date: _________________________
Email: [KISA EMAIL]
**[COVERED ENTITY FULL LEGAL NAME] (Covered Entity)**
By: ___________________________
Name: [SIGNER NAME]
Title: [SIGNER TITLE]
Date: _________________________
Email: ___________________________
---
## Attorney Review Notes
Each load-bearing factual claim is labeled GROUNDED (cited source) or GRAFTED (assumption for counsel to confirm). Items to confirm before this Agreement is executed with any Covered Entity:
1. **LOAD-BEARING: Is a BAA required at all? (GRAFTED as applied.)** Confirm whether Business Associate's receipt of Covered Entity's internal patient_id (a supplier account number, one of HIPAA's 18 identifiers) makes STTIL a Business Associate requiring this Agreement, or whether the Service's de-identification architecture (no names, no DOBs, no SSNs; the crosswalk stays with Covered Entity) satisfies the Safe Harbor or Expert Determination de-identification standards such that no BAA is triggered. GROUNDED that patient_id is an account number and the sole crosswalk key, and that names/DOBs/SSNs are refused at the normalizer (Signal CLAUDE.md, PHI Architecture; data-handling.md). Whether that architecture avoids Business Associate status is GRAFTED and is the single most important question in this bundle.
2. **Subprocessor agreements (GROUNDED posture, GRAFTED requirement).** GROUNDED that the current pilot stack (Supabase, Railway, Vercel, Clerk) has no executed subprocessor BAAs and that an AWS BAA is signed and active as of 2026-05-27 (Signal current-state.md; KG Signal). Confirm which of the subprocessors, in the production PHI configuration, legally requires its own BAA, and confirm the AWS migration path satisfies the subcontractor obligation in 45 C.F.R. 164.308(b) and 164.314.
3. **Accounting of disclosures scope (GRAFTED as applied).** Confirm the scope of Section 2.8 as applied to a software service that processes de-identified or minimum-necessary data only.
4. **State-specific requirements (GRAFTED).** Confirm which state's health-data statutes (beyond HIPAA) apply once formation state and Covered Entity location are known. A prior supplier-specific version governed under Pennsylvania; this template uses a placeholder. Confirm no additional state-law obligations attach.
5. **Governing law and entity alignment (GROUNDED that documents disagree).** The v1 LOI and NDA said Delaware; the a prior supplier BAA said Pennsylvania; an executed letter of intent states Florida. Entity name is now "KJF Professional Services LLC d/b/a STTIL Solutions." Confirm the correct legal name and formation state and align Section 5.4 with the LOI and NDA.
6. **Forward-looking status (GROUNDED).** Real PHI is blocked/mock today (Signal current-state.md, 2026-07-07). Confirm this template is the correct instrument to execute at the point real PHI enters the system, and advise whether any interim data-handling addendum is needed for a pilot that stays inside the de-identified minimum-necessary field set before that point.
---
*Document prepared for attorney review. Not legal advice.*
*Related: STTIL-pilot-LOI-template-v3, STTIL-NDA-template-v3*

View file

@ -0,0 +1,109 @@
> **DRAFT, for attorney review before use. Not legal advice.**
> Cover memo prepared 2026-07-07. Bundles five items for a single review pass.
**To:** [ATTORNEY NAME, CONFIRM RECIPIENT before sending. Session records dated 2026-06-05 name Clyde Mathes as attorney of record; the Signal compliance checklist rows name Bittinger Law / Nixon Law Group. These conflict. Reconcile before this memo goes out.]
**From:** Kisa Fenn, Founder and CEO, KJF Professional Services LLC d/b/a STTIL Solutions
**Date:** [DATE]
**Re:** Single-pass review of three template agreements plus two focused legal questions
---
Hello [ATTORNEY NAME],
I would like to engage you for one bundled review pass covering five items. I have grouped them deliberately so you can scope the whole thing at once rather than in pieces. An associate handling the bulk of this is completely fine with me. What I need first is a turnaround estimate and a fee estimate so I can plan around it.
Here is what is in the bundle:
1. **Pilot Letter of Intent (LOI) template (v3)**, a product-agnostic pilot LOI. Product specifics live in an Exhibit A, pre-filled for our active product, Signal.
2. **Mutual Non-Disclosure Agreement (NDA) template (v3)**, portfolio-wide.
3. **Business Associate Agreement (BAA) template (v1)**, a reusable BAA, generalized from an earlier supplier-specific draft. Please read it as a forward-looking instrument; I explain why below.
4. **U.S. Food and Drug Administration (FDA) device-status memo for Signal**, a draft I am providing for your review, not asking you to write. It argues that Signal is not an FDA-regulated medical device. It is candid about its weakest points. I need you to confirm, correct, or reject its position.
5. **Anti-Kickback Statute question** on a specific partner integration, described below. This one is time-sensitive because it gates whether we can deepen an existing partner relationship.
I have written my own focused questions under each item. Please treat these as a starting list, not a limit.
---
### Overarching question (applies to all three templates)
**Q1. Confirm our legal name, our state of formation, and align governing law across every document.** Our entity is KJF Professional Services LLC d/b/a STTIL Solutions. Our documents currently disagree on the state: two older templates say Delaware, an executed letter of intent says Florida, and an older business associate agreement says Pennsylvania. I have replaced the state with a placeholder everywhere so nothing is asserted incorrectly. Please tell me the correct legal name and formation state, and set governing law and dispute-resolution venue consistently across the LOI, NDA, and BAA.
**Q2. Standardize my signing title.** The LOI and NDA sign as "Founder and CEO" while the BAA signs as "Managing Member." Tell me which title is correct for an LLC signer and I will use it across all three.
---
### 1. Pilot LOI template (v3)
1. The BAA cross-reference in Section 5.3 turns on whether we are a Business Associate at all. That is the BAA question below; please keep the two consistent.
2. Section 8.3 (we retain all rights to any modification or enhancement made during a pilot, regardless of who requested it) and Section 8.4 (a narrow carve-out for a partner's pre-documented pre-existing concepts). Confirm both are enforceable and that 8.4 does not erode 8.3.
3. Section 12.3, a new mutual exclusion of consequential damages for a no-cost pilot. Confirm it is adequate and enforceable.
4. Section 14, a dispute-resolution path (30-day good-faith discussion, then arbitration, with the American Arbitration Association (AAA) as fallback, and a court carve-out for injunctive relief). We added this after an out-of-state counterparty objected to exclusive Delaware court jurisdiction. Tell me whether to keep arbitration here and whether to match it in the NDA, which currently uses courts.
5. Sections 6.1 and 13.3, confirming that a successful pilot does not obligate us to offer a commercial agreement. Confirm this closes any promissory-estoppel exposure.
### 2. Mutual NDA template (v3)
1. The residuals clause (Articles 1.2 and 2.3), which carves our algorithms, payer and coverage logic, and scoring formulas out of what a counterparty may reuse from memory. Confirm the carve-out is enforceable.
2. The Health Insurance Portability and Accountability Act (HIPAA) carve-out (Article 6). I softened the flat claim that the data we handle is never protected health information (PHI). Confirm the new framing is defensible.
3. The tightened third-party exclusion (Article 3.1(d)). Confirm it closes the loophole cleanly and applies equally to both sides.
4. The named-products list (Article 1.1(c)): Signal, Vitality Med Tracker, UMSIS, plus a catch-all for any current or future offering. Confirm the catch-all is sufficient to cover future products we have not named.
### 3. BAA template (v1)
1. **The single most important question in this whole bundle:** does our receipt of a supplier's internal patient_id, which is an account number and one of HIPAA's 18 identifiers, make us a Business Associate that needs this agreement, or does our architecture (we never receive names, dates of birth, or Social Security numbers, and the identity crosswalk stays with the supplier) avoid Business Associate status? Everything downstream depends on your answer.
2. Please read this as forward-looking. Real patient data is blocked today; we run on mock and de-identified data. Our current pilot vendors do not have subprocessor BAAs. Our compliant path is AWS, where we already have a signed BAA (active since 2026-05-27) with database and storage provisioned and parked until funding. I want you reviewing the instrument we would sign at the moment real data enters, and advising whether we need any interim addendum before then.
3. Whether each pilot vendor legally needs its own subprocessor BAA in the production configuration.
### 4. FDA device-status memo for Signal (for your review, not to be drafted)
The memo is at `signal/docs/compliance/fda-cds-exemption-memo-DRAFT.md`. I am not asking you to write it; I am asking you to rule on it. Its own author flagged these as the points to press on:
1. Confirm or correct the primary position: Signal is not a device under section 201(h) because its intended use is administrative and billing support, with the section 520(o)(1)(A) administrative-support exclusion as reinforcement.
2. Rule on whether a DMEPOS supplier can rely on 520(o)(1)(A) as a "health care facility," or whether the position must rest on the 201(h) intended-use analysis alone.
3. Review our live worklist status labels, reason strings, and "recommended action" strings verbatim, and tell us if any wording reads as clinical rather than documentation-focused.
4. Approve a short list of permitted marketing claim framings so our intended use stays administrative.
5. Confirm the memo's citations against FDA's Clinical Decision Support (CDS) guidance current at the time of your review (it was verified against the January 29, 2026 version).
6. Advise whether, once settled, this should be reissued as a counsel letter we can hand to supplier compliance contacts and investors.
### 5. Anti-Kickback Statute question (time-sensitive, privileged, confidential)
**Confidentiality note:** the partner named here is bound to us by a confidentiality clause that bars public mention of the relationship. I am sharing the name with you only because you are our counsel and I need the facts to get sound advice. Please keep it inside privilege.
We have an executed 180-day discovery letter of intent with Pathogens Artificial Intelligence Inc., which does business as LabABLE, a diagnostic-laboratory software platform run by Dr. Mehul Patel's team. During discovery we discussed a reciprocal integration concept, informally called "kit in kit": LabABLE could be made available as a component inside our Signal platform, and Signal could be made available as a component inside the LabABLE platform.
Both of our customer bases serve providers who bill federal healthcare programs (our suppliers bill Medicare for DMEPOS; laboratories bill Medicare Part B). My question:
1. Does this reciprocal embedding or cross-availability arrangement, where each party's product carries value into the other's platform and could influence orders or referrals of federally reimbursable items or services, implicate the federal Anti-Kickback Statute (42 U.S.C. 1320a-7b(b)), the Eliminating Kickbacks in Recovery Act, or the Stark Law?
2. If so, what structure or safe harbor would we need before executing any definitive agreement with this partner?
This must be resolved before we execute any further agreement with them, so please tell me how heavily it weighs on your timeline.
---
### What I need back
- A turnaround estimate and a fee estimate for the full bundle.
- Your answers, or corrections, to the questions above.
- A flag on anything I have framed wrong or missed.
Thank you. I am happy to get on a call to walk through any of it.
Kisa Fenn
KJF Professional Services LLC d/b/a STTIL Solutions
[KISA EMAIL] / [PHONE]
---
## ATTORNEY REVIEW NOTES (for internal use, do not send)
Load-bearing facts in this memo, labeled GROUNDED (cited source) or GRAFTED (assumption to confirm):
- Recipient is unresolved. GROUNDED that 2026-06-05 records name Clyde Mathes and the Signal compliance checklist names Bittinger/Nixon; the two conflict (Signal CLAUDE.md; FDA memo routing note). Confirm before sending. GRAFTED which is correct.
- labABLE LOI executed 2026-06-12, 180-day discovery term. GROUNDED (KG Signal; executed PDF `signal/pitch/legal/labABLE-LOI-v3-EXECUTED-2026-06-12.pdf`). Verify signer names and clause numbers against the executed PDF before any citation; the "kit-in-kit" description here is from the 2026-06-06 markup, not the final executed text.
- labABLE legal entity is Pathogens Artificial Intelligence Inc. d/b/a LabABLE. GROUNDED (labABLE LOI markup 2026-06-06).
- AWS BAA signed and active 2026-05-27, RDS and S3 provisioned and parked. GROUNDED (KG Signal; Signal current-state.md).
- Real PHI blocked/mock today. GROUNDED (Signal current-state.md 2026-07-07).
- FDA memo location and its own self-identified weak points. GROUNDED (`fda-cds-exemption-memo-DRAFT.md`).
- The AKS/EKRA/Stark characterization is a lay framing of the question, not a legal conclusion. GRAFTED, for counsel to analyze.
---
*Prepared for attorney review. Not legal advice.*

View file

@ -180,6 +180,39 @@ class ReadinessItemOut(BaseModel):
quality: str # GOOD | PENDING | BAD | NONE
value: Optional[str] = None
satisfied: bool
# Citation: the payer_rules.json rule that decided required_state.
# None when NOT_EVALUATED (no rule fired, nothing to cite).
rule_id: Optional[str] = None
class LineOut(BaseModel):
"""One coverage line (patient x device x plan type) in the nested payload."""
device_type: str
device_display: str
plan_type: Optional[str] = None # None = plan type needed (never guessed)
gradeable: bool
line_status: Optional[str] = None # LineStatus verbatim; None = ungraded
timing_flag: Optional[str] = None # CoverageFlag of the current shipment
doc_items: Optional[list[ReadinessItemOut]] = None
# Display fields per the locked dedup design (section 6)
order_numbers: list[str] = []
hcpcs_codes: list[str] = []
total_quantity: int = 0
shipment_date: Optional[str] = None # current shipment DOS
payer: Optional[str] = None
prior_shipment_count: int = 0
class PatientOut(BaseModel):
"""One patient in the nested payload; tabs count these, not rows (P6)."""
patient_id: str
rollup_status: Optional[str] = None # None = no graded gradeable lines
plan_type_needed: bool = False
cgm_line_count: int = 0
total_line_count: int = 0
lines: list[LineOut] = []
class RecordOut(BaseModel):
@ -231,6 +264,10 @@ class UploadResponse(BaseModel):
mapping_summary: dict
batch_id: str | None = None
readiness_stats: dict | None = None
# Nested patient payload (P3, additive). The flat `records` list stays
# untouched until P6 switches the UI (locked migration strategy).
patients: list[PatientOut] | None = None
patient_stats: dict | None = None
def _build_reason(
@ -330,6 +367,24 @@ class DocStatusRequest(BaseModel):
expiry_date: Optional[str] = None
def _readiness_items_out(readiness) -> Optional[list[ReadinessItemOut]]:
"""Serialize a ReadinessVerdict's doc items (shared by rows and lines)."""
if not readiness:
return None
return [
ReadinessItemOut(
doc_type=i.doc_type,
required_state=i.required_state.value,
input_state=i.input_state.value,
quality=i.quality.value,
value=i.value,
satisfied=i.satisfied,
rule_id=i.rule_id,
)
for i in readiness.doc_items
]
def _to_record_out(
r,
record=None,
@ -419,19 +474,7 @@ def _to_record_out(
else None,
plan_type=getattr(record, "plan_type", None) if record else None,
readiness_status=readiness.line_status.value if readiness else None,
readiness_items=[
ReadinessItemOut(
doc_type=i.doc_type,
required_state=i.required_state.value,
input_state=i.input_state.value,
quality=i.quality.value,
value=i.value,
satisfied=i.satisfied,
)
for i in readiness.doc_items
]
if readiness
else None,
readiness_items=_readiness_items_out(readiness),
)
@ -457,6 +500,104 @@ def _compute_stats(records: list[RecordOut]) -> dict:
}
def _build_patients_payload(index, reachable_line_keys, results):
"""Assemble the nested patients payload (P3) from the lines reachable in
THIS response, so patients/lines always reconcile with the flat records.
Rollup rules are locked in core/rollup.py (worst gradeable line; PTN caps
at Action Needed; non-gradeable lines excluded from the light)."""
from core.dedup import UNKNOWN_PLAN_TYPE
from core.rollup import rollup_patients
reachable = {
k: index.lines[k] for k in reachable_line_keys if k in index.lines
}
if not reachable:
return [], {"patients_total": 0}
from core.dedup import _as_date
# Line-level timing flag = the worst-urgency row of the line's CURRENT
# shipment group (twin rows can differ; worst wins, fail-safe).
flag_by_group: dict = {}
for r in results:
gk = (r.patient_id, r.device_type, _as_date(r.last_shipment_date))
flag_val = r.flag.value if hasattr(r.flag, "value") else str(r.flag)
prev = flag_by_group.get(gk)
if prev is None or r.priority_score > prev[1]:
flag_by_group[gk] = (flag_val, r.priority_score)
# DISPLAY ordering, intentionally different from rollup.SEVERITY: the
# worklist queues At Risk above Plan Type Needed (urgency), while the
# rollup's capping rule treats PTN as the worst LINE state. Do not unify.
severity = {
"At Risk": 4,
"Plan Type Needed": 3,
"Action Needed": 2,
"On Track": 1,
"Clear to Ship": 0,
}
patients = []
for pid, ru in rollup_patients(reachable).items():
lines_out = []
for line in sorted(
ru.lines,
key=lambda l: (
-(severity.get(l.line_status, -1)),
l.device_type,
),
):
line_key = (line.patient_id, line.device_type, line.plan_type)
verdict = index.by_line.get(line_key)
cur = line.current_shipment
timing = flag_by_group.get(
(line.patient_id, line.device_type, _as_date(cur.shipment_date))
)
lines_out.append(
LineOut(
device_type=line.device_type,
device_display=DEVICE_DISPLAY.get(
line.device_type, line.device_type
),
plan_type=None
if line.plan_type == UNKNOWN_PLAN_TYPE
else line.plan_type,
gradeable=line.gradeable,
line_status=line.line_status,
timing_flag=timing[0] if timing else None,
doc_items=_readiness_items_out(verdict),
order_numbers=cur.order_numbers,
hcpcs_codes=cur.hcpcs_codes,
total_quantity=cur.total_quantity,
shipment_date=cur.shipment_date.isoformat(),
payer=cur.payer or None,
prior_shipment_count=len(line.prior_shipments),
)
)
patients.append(
PatientOut(
patient_id=pid,
rollup_status=ru.rollup_status.value
if ru.rollup_status
else None,
plan_type_needed=ru.plan_type_needed,
cgm_line_count=ru.cgm_line_count,
total_line_count=ru.total_line_count,
lines=lines_out,
)
)
# Worklist order: worst patients first, stable by patient_id.
patients.sort(
key=lambda p: (-(severity.get(p.rollup_status, -1)), p.patient_id)
)
stats: dict = {"patients_total": len(patients)}
for p in patients:
key = p.rollup_status if p.rollup_status else "ungraded"
stats[key] = stats.get(key, 0) + 1
return patients, stats
@app.get("/health")
def health():
return {"status": "ok", "service": "signal-api", "version": "1.0.0"}
@ -547,10 +688,13 @@ async def upload_csv(
out = []
used_lines = {}
reachable_line_keys = set()
for r in results:
verdict, line_key, merged = resolve_group(
index, r.patient_id, r.device_type, r.last_shipment_date
)
if line_key is not None:
reachable_line_keys.add(line_key)
if verdict is not None and line_key is not None:
used_lines[line_key] = verdict
# Exact row match first (byte-identical legacy path). CoverageResult
@ -606,6 +750,10 @@ async def upload_csv(
clerk_org_id=clerk_org_id,
)
patients_out, patient_stats = _build_patients_payload(
index, reachable_line_keys, results
)
return UploadResponse(
records=out,
total=len(out),
@ -618,6 +766,8 @@ async def upload_csv(
# reconcile with the records beside them (a record calculate_batch
# skipped cannot leave a phantom line in the counts).
readiness_stats=readiness_stats(used_lines),
patients=patients_out,
patient_stats=patient_stats,
)

View file

@ -1,5 +1,14 @@
{
"_comment": "Wear-day rules by device type and payer. Updated 2026-06-07. Run quarterly review per compliance checklist.",
"_comment": "Wear-day rules by device type and payer. Updated 2026-07-07 (P2: plan-scoped keys wrapped with citation rule_ids). Run quarterly review per compliance checklist.",
"_rule_registry": {
"R001": "visit_renewal_days — visit renewal window in days (standard: 180)",
"R002": "refill_window_days — resupply window in days before coverage end (standard: 30; legacy code key name retained)",
"R003": "pa_required — prior authorization required for this plan type",
"R004": "pecos_required — PECOS enrollment verification required for this plan type",
"R100": "swo_required — SWO is a universal claim requirement per LCD L33822",
"R101": "visit_required — qualifying visit is a universal requirement per LCD L33822",
"R102": "diagnosis_required — diagnosis (ICD-10) is a universal requirement per LCD L33822"
},
"devices": {
"dexcom_g6": {
"display_name": "Dexcom G6",
@ -31,42 +40,42 @@
},
"payer_rules": {
"medicare": {
"visit_renewal_days": 180,
"refill_window_days": 30,
"pa_required": false,
"pecos_required": true,
"visit_renewal_days": { "value": 180, "rule_id": "R001" },
"refill_window_days": { "value": 30, "rule_id": "R002" },
"pa_required": { "value": false, "rule_id": "R003" },
"pecos_required": { "value": true, "rule_id": "R004" },
"_note": "Medicare FFS. PA not required (CGM coverage expansion 2023). Face-to-face visit required every 6 months. CMS-1828-F: suppliers at >=90% affirmation rate may qualify for PA exemption from June 1, 2026.",
"covered_devices": ["dexcom_g6", "dexcom_g7", "freestyle_libre_2", "freestyle_libre_3"]
},
"medicare_advantage": {
"visit_renewal_days": 180,
"refill_window_days": 30,
"pa_required": true,
"pecos_required": true,
"visit_renewal_days": { "value": 180, "rule_id": "R001" },
"refill_window_days": { "value": 30, "rule_id": "R002" },
"pa_required": { "value": true, "rule_id": "R003" },
"pecos_required": { "value": true, "rule_id": "R004" },
"_note": "Medicare Advantage — PA required, varies by plan. Verify plan-specific rules.",
"covered_devices": ["dexcom_g6", "dexcom_g7", "freestyle_libre_2", "freestyle_libre_3"]
},
"medicaid": {
"visit_renewal_days": 180,
"refill_window_days": 30,
"pa_required": true,
"pecos_required": false,
"visit_renewal_days": { "value": 180, "rule_id": "R001" },
"refill_window_days": { "value": 30, "rule_id": "R002" },
"pa_required": { "value": true, "rule_id": "R003" },
"pecos_required": { "value": false, "rule_id": "R004" },
"_note": "PA required — Keystone First, UPMC Health Plan, Highmark BCBS require PA. NJ FamilyCare, Horizon BCBS NJ require PA.",
"covered_devices": []
},
"commercial": {
"visit_renewal_days": 180,
"refill_window_days": 30,
"pa_required": true,
"pecos_required": false,
"visit_renewal_days": { "value": 180, "rule_id": "R001" },
"refill_window_days": { "value": 30, "rule_id": "R002" },
"pa_required": { "value": true, "rule_id": "R003" },
"pecos_required": { "value": false, "rule_id": "R004" },
"_note": "Commercial payer rules vary by plan. PA required by default — verify per plan.",
"covered_devices": []
},
"default": {
"visit_renewal_days": 180,
"refill_window_days": 30,
"pa_required": true,
"pecos_required": false,
"visit_renewal_days": { "value": 180, "rule_id": "R001" },
"refill_window_days": { "value": 30, "rule_id": "R002" },
"pa_required": { "value": true, "rule_id": "R003" },
"pecos_required": { "value": false, "rule_id": "R004" },
"covered_devices": []
}
}

View file

@ -328,8 +328,10 @@ def calculate_coverage(
rule_version=RULE_VERSION,
)
visit_renewal_days = payer_config.get("visit_renewal_days")
refill_window_days = payer_config.get("refill_window_days", 30)
from core.rules import rule_value
visit_renewal_days = rule_value(payer_config, "visit_renewal_days")
refill_window_days = rule_value(payer_config, "refill_window_days", 30)
# Resolve visit date using priority chain
visit_date, confidence = _resolve_visit_date(record, confirmed_visit_date)

View file

@ -38,6 +38,8 @@ from functools import lru_cache
from pathlib import Path
from typing import Optional
from core.rules import UNIVERSAL_RULE_IDS, rule_id_for, rule_value
logger = logging.getLogger(__name__)
PAYER_RULES_PATH = Path(__file__).parent.parent / "config" / "payer_rules.json"
@ -87,6 +89,9 @@ class DocItem:
quality: Quality
value: Optional[str]
satisfied: bool
# Names the payer_rules.json rule that decided required_state. None when
# required_state is NOT_EVALUATED: no rule fired, so nothing is cited.
rule_id: Optional[str] = None
@dataclass
@ -174,7 +179,8 @@ def _pa_quality(value: Optional[str]) -> Quality:
def _make_item(doc_type: str, required: RequiredState,
quality: Quality, value: Optional[str]) -> DocItem:
quality: Quality, value: Optional[str],
rule_id: Optional[str] = None) -> DocItem:
input_state = InputState.ABSENT if quality == Quality.NONE else InputState.SUPPLIED
if required == RequiredState.NOT_REQUIRED:
@ -191,26 +197,36 @@ def _make_item(doc_type: str, required: RequiredState,
quality=quality,
value=value,
satisfied=satisfied,
rule_id=rule_id,
)
def _required_from_config(plan_known: bool, plan_cfg: Optional[dict],
flag_key: str, plan_type: Optional[str]) -> RequiredState:
"""Required-ness for a plan-dependent item, read from config.
def _required_from_config(
plan_known: bool, plan_cfg: Optional[dict],
flag_key: str, plan_type: Optional[str],
) -> tuple[RequiredState, Optional[str]]:
"""(Required-ness, citing rule_id) for a plan-dependent item, from config.
A missing config (known plan absent from payer_rules.json, or the flag key
missing) means we CANNOT decide -> NOT_EVALUATED, which blocks green. We
never treat a config gap as 'not required' (that was the false-green hole).
When NOT_EVALUATED, rule_id is None: no rule fired, nothing is cited.
Accepts both flat and wrapped ({"value":..., "rule_id":...}) config values.
"""
if not plan_known:
return RequiredState.NOT_EVALUATED
return RequiredState.NOT_EVALUATED, None
if not plan_cfg or flag_key not in plan_cfg:
logger.warning(
"plan_type '%s' missing '%s' in payer_rules.json -> cannot grade %s",
plan_type, flag_key, flag_key,
)
return RequiredState.NOT_EVALUATED
return RequiredState.REQUIRED if bool(plan_cfg[flag_key]) else RequiredState.NOT_REQUIRED
return RequiredState.NOT_EVALUATED, None
required = (
RequiredState.REQUIRED
if bool(rule_value(plan_cfg, flag_key))
else RequiredState.NOT_REQUIRED
)
return required, rule_id_for(plan_cfg, flag_key)
def evaluate_readiness(
@ -233,19 +249,24 @@ def evaluate_readiness(
# Plan-dependent required-ness from config (single source of truth, never sets).
plan_cfg = rules.get("payer_rules", {}).get(plan_type) if plan_known else None
pecos_required = _required_from_config(plan_known, plan_cfg, "pecos_required", plan_type)
pa_required = _required_from_config(plan_known, plan_cfg, "pa_required", plan_type)
pecos_required, pecos_rule = _required_from_config(plan_known, plan_cfg, "pecos_required", plan_type)
pa_required, pa_rule = _required_from_config(plan_known, plan_cfg, "pa_required", plan_type)
visit_date = csv_visit_date or confirmed_visit_date
items = [
_make_item("swo", RequiredState.REQUIRED, _swo_quality(csv_swo_status), csv_swo_status),
_make_item("swo", RequiredState.REQUIRED, _swo_quality(csv_swo_status),
csv_swo_status, rule_id=UNIVERSAL_RULE_IDS["swo"]),
_make_item("visit", RequiredState.REQUIRED,
_visit_quality(csv_visit_date, confirmed_visit_date),
visit_date.isoformat() if visit_date else None),
visit_date.isoformat() if visit_date else None,
rule_id=UNIVERSAL_RULE_IDS["visit"]),
_make_item("diagnosis", RequiredState.REQUIRED,
_diagnosis_quality(csv_diagnosis_on_file), csv_diagnosis_on_file),
_make_item("pecos", pecos_required, _pecos_quality(csv_pecos_verified), csv_pecos_verified),
_make_item("pa", pa_required, _pa_quality(csv_pa_status), csv_pa_status),
_diagnosis_quality(csv_diagnosis_on_file), csv_diagnosis_on_file,
rule_id=UNIVERSAL_RULE_IDS["diagnosis"]),
_make_item("pecos", pecos_required, _pecos_quality(csv_pecos_verified),
csv_pecos_verified, rule_id=pecos_rule),
_make_item("pa", pa_required, _pa_quality(csv_pa_status),
csv_pa_status, rule_id=pa_rule),
]
return ReadinessVerdict(

View file

@ -0,0 +1,101 @@
"""
rollup.py
Signal STTIL Solutions
Patient-level rollup of coverage-line readiness verdicts (build plan 02, P3).
Design locked in readiness-model-brief section 4 and the phase-2 design Item 3:
- The light = worst gradeable line. Severity (worst first):
Plan Type Needed > At Risk > Action Needed > On Track > Clear to Ship.
- Any gradeable Plan Type Needed line caps the patient no greener than
Action Needed (the patient IS being served; one unmapped plan type must not
read as the whole patient being ungradeable).
- Non-gradeable lines (non-CGM) never participate in the light or the counts.
- Tabs count patients, not rows.
A patient with no graded gradeable lines has rollup_status None the UI
treatment is an open Kisa question; no label is invented here.
PHI CONTRACT: operates on patient_id only; this module logs nothing.
"""
from __future__ import annotations
from collections import defaultdict
from dataclasses import dataclass
from typing import Optional
from core.dedup import CoverageLine
from core.readiness import LineStatus
# Higher = worse. Plan Type Needed ranks worst for LINE severity ordering;
# its patient-level effect is the capping rule below, not raw worstness.
SEVERITY = {
LineStatus.CLEAR_TO_SHIP: 0,
LineStatus.ON_TRACK: 1,
LineStatus.ACTION_NEEDED: 2,
LineStatus.AT_RISK: 3,
LineStatus.PLAN_TYPE_NEEDED: 4,
}
@dataclass
class PatientRollup:
patient_id: str
lines: list[CoverageLine] # all lines, incl. non-gradeable
rollup_status: Optional[LineStatus] # None = no graded gradeable lines
cgm_line_count: int # gradeable lines
total_line_count: int # all lines
plan_type_needed: bool # any gradeable line in PTN
def rollup_patient(lines: list[CoverageLine]) -> PatientRollup:
"""Roll one patient's coverage lines into a single verdict, per the
locked truth table (plan 02 P3):
| gradeable statuses present | rollup_status |
| none | None |
| all Plan Type Needed | Plan Type Needed |
| some PTN + others | worse of (Action Needed, worst other)|
| no PTN | worst by severity |
"""
if not lines:
raise ValueError("rollup_patient requires at least one CoverageLine")
graded = [
l for l in lines if l.gradeable and l.line_status is not None
]
statuses = [LineStatus(l.line_status) for l in graded]
ptn = [s for s in statuses if s == LineStatus.PLAN_TYPE_NEEDED]
if not statuses:
status: Optional[LineStatus] = None
elif len(ptn) == len(statuses):
status = LineStatus.PLAN_TYPE_NEEDED
elif ptn:
worst_other = max(
(s for s in statuses if s != LineStatus.PLAN_TYPE_NEEDED),
key=SEVERITY.get,
)
status = max(worst_other, LineStatus.ACTION_NEEDED, key=SEVERITY.get)
else:
status = max(statuses, key=SEVERITY.get)
return PatientRollup(
patient_id=lines[0].patient_id,
lines=lines,
rollup_status=status,
cgm_line_count=sum(1 for l in lines if l.gradeable),
total_line_count=len(lines),
plan_type_needed=bool(ptn),
)
def rollup_patients(lines: dict) -> dict[str, PatientRollup]:
"""Group CoverageLines (any keying) by patient and roll each up."""
by_patient: dict[str, list[CoverageLine]] = defaultdict(list)
for line in lines.values():
by_patient[line.patient_id].append(line)
return {
patient_id: rollup_patient(patient_lines)
for patient_id, patient_lines in by_patient.items()
}

View file

@ -0,0 +1,52 @@
"""
rules.py
Signal STTIL Solutions
Format-tolerant readers for payer_rules.json plus the stable rule-ID registry
(build plan 02, item P2; design: readiness-model-design-phase2 section 3.1).
A rule value may be FLAT (legacy: `"visit_renewal_days": 180`) or WRAPPED with
its citation (`"visit_renewal_days": {"value": 180, "rule_id": "R001"}`).
Both engines read through these helpers so the JSON format can carry citation
IDs without breaking either reader.
RULE IDS ARE STABLE never change an ID after shipping. The ID names the rule
KIND; the plan type plus the value together are the citation.
"""
from __future__ import annotations
from typing import Optional
# Universal claim/coverage requirements per LCD L33822, independent of plan
# type. They live in code (no plan-type dependency) but carry rule IDs for
# citation consistency.
UNIVERSAL_RULE_IDS = {"swo": "R100", "visit": "R101", "diagnosis": "R102"}
# Plan-scoped keys in payer_rules.json and their registry IDs.
PLAN_KEY_RULE_IDS = {
"visit_renewal_days": "R001",
"refill_window_days": "R002",
"pa_required": "R003",
"pecos_required": "R004",
}
def rule_value(cfg: Optional[dict], key: str, default=None):
"""Read a rule value, accepting flat (180) and wrapped
({'value': 180, 'rule_id': 'R001'}) formats."""
if not cfg:
return default
raw = cfg.get(key, default)
if isinstance(raw, dict) and "value" in raw:
return raw["value"]
return raw
def rule_id_for(cfg: Optional[dict], key: str) -> Optional[str]:
"""The citation ID for a plan-scoped rule: from the wrapped config when
present, else the registry default for that key."""
raw = cfg.get(key) if cfg else None
if isinstance(raw, dict) and "rule_id" in raw:
return raw["rule_id"]
return PLAN_KEY_RULE_IDS.get(key)

View file

@ -36,6 +36,7 @@ from typing import Optional
from core.coverage_calculator import ShipmentRecord
from core.dedup import (
UNKNOWN_PLAN_TYPE,
CoverageLine,
MergedShipment,
_as_date,
assign_to_coverage_lines,
@ -54,11 +55,13 @@ class ReadinessIndex:
"""Dedup-derived resolution index for one upload batch.
by_line: verdicts per gradeable coverage line
lines: every CoverageLine (graded ones carry line_status)
line_by_group: dedup group -> the line that group's shipment belongs to
merged_by_group: dedup group -> its MergedShipment (display-field truth)
"""
by_line: dict[LineKey, ReadinessVerdict] = field(default_factory=dict)
lines: dict[LineKey, "CoverageLine"] = field(default_factory=dict)
line_by_group: dict[GroupKey, LineKey] = field(default_factory=dict)
merged_by_group: dict[GroupKey, MergedShipment] = field(default_factory=dict)
@ -93,22 +96,26 @@ def build_readiness_index(
index = ReadinessIndex()
for key, line in lines.items():
line_key = (key.patient_id, key.device_type, key.plan_type_id)
index.lines[line_key] = line
if not line.gradeable:
continue
cur = line.current_shipment
index.by_line[(key.patient_id, key.device_type, key.plan_type_id)] = (
evaluate_readiness(
line.plan_type if line.plan_type != UNKNOWN_PLAN_TYPE else None,
csv_swo_status=cur.csv_swo_status,
csv_visit_date=cur.csv_visit_date,
confirmed_visit_date=_confirmed_for(
key.patient_id, confirmed_visits
),
csv_pecos_verified=cur.csv_pecos_verified,
csv_pa_status=cur.csv_pa_status,
csv_diagnosis_on_file=cur.csv_diagnosis_on_file,
)
verdict = evaluate_readiness(
line.plan_type if line.plan_type != UNKNOWN_PLAN_TYPE else None,
csv_swo_status=cur.csv_swo_status,
csv_visit_date=cur.csv_visit_date,
confirmed_visit_date=_confirmed_for(
key.patient_id, confirmed_visits
),
csv_pecos_verified=cur.csv_pecos_verified,
csv_pa_status=cur.csv_pa_status,
csv_diagnosis_on_file=cur.csv_diagnosis_on_file,
)
index.by_line[line_key] = verdict
# The grading step owns line_status (dedup leaves it None) — the
# rollup (P3) reads it from the line.
line.line_status = verdict.line_status.value
for m in merged:
gkey: GroupKey = (m.patient_id, m.device_type, m.shipment_date)

View file

@ -101,3 +101,12 @@ def test_priority_sort_order():
assert results[0].flag == CoverageFlag.SUPPLY_LAPSED
assert results[1].flag == CoverageFlag.RENEWAL_CRITICAL
assert results[2].flag == CoverageFlag.ACTIVE
def test_wrapped_config_drives_timing_rules():
"""P2: with the wrapped citation format on disk, the timing calculator
still resolves visit_renewal_days correctly (R001 = 180 days)."""
visit = TODAY - timedelta(days=30)
r = make_record(csv_visit_date=visit)
result = calculate_coverage(r)
assert result.next_visit_due_date == visit + timedelta(days=180)

View file

@ -255,3 +255,70 @@ def test_known_plan_types_match_payer_rules_config():
configured = set(json.loads(rules_path.read_text())["payer_rules"].keys()) - {"default"}
from core.readiness import KNOWN_PLAN_TYPES
assert set(KNOWN_PLAN_TYPES) == configured
# ---------------------------------------------------------------------------
# P2: citation rule IDs (build plan 02, readiness-model-design-phase2 §3.1)
# ---------------------------------------------------------------------------
def test_doc_items_carry_rule_ids():
v = evaluate_readiness(
"medicare",
csv_swo_status="On File",
csv_visit_date=VISIT,
csv_pecos_verified="Yes",
csv_diagnosis_on_file="Yes",
)
items = items_by_type(v)
assert items["swo"].rule_id == "R100"
assert items["visit"].rule_id == "R101"
assert items["diagnosis"].rule_id == "R102"
assert items["pecos"].rule_id == "R004"
assert items["pa"].rule_id == "R003"
def test_flat_and_wrapped_config_produce_identical_verdicts():
flat = {"payer_rules": {"medicare": {
"pa_required": False, "pecos_required": True,
}}}
wrapped = {"payer_rules": {"medicare": {
"pa_required": {"value": False, "rule_id": "R003"},
"pecos_required": {"value": True, "rule_id": "R004"},
}}}
kwargs = dict(
csv_swo_status="On File", csv_visit_date=VISIT,
csv_pecos_verified="Yes", csv_diagnosis_on_file="Yes",
)
v_flat = evaluate_readiness("medicare", rules=flat, **kwargs)
v_wrapped = evaluate_readiness("medicare", rules=wrapped, **kwargs)
assert v_flat.line_status == v_wrapped.line_status
for a, b in zip(v_flat.doc_items, v_wrapped.doc_items):
assert (a.doc_type, a.required_state, a.satisfied) == (
b.doc_type, b.required_state, b.satisfied
)
def test_not_evaluated_items_have_no_rule_id():
v = evaluate_readiness(None)
items = items_by_type(v)
assert items["pecos"].required_state == RequiredState.NOT_EVALUATED
assert items["pecos"].rule_id is None
assert items["pa"].rule_id is None
def test_on_disk_rule_ids_match_registry():
"""Guards citation drift: every wrapped rule_id in payer_rules.json must
equal the registry ID for its key (auditor finding L2, 2026-07-07)."""
import json
from pathlib import Path as _P
from core.rules import PLAN_KEY_RULE_IDS
cfg = json.loads(
(_P(__file__).parent.parent / "python-backend" / "config" / "payer_rules.json").read_text()
)
for plan, entry in cfg["payer_rules"].items():
for key, expected_id in PLAN_KEY_RULE_IDS.items():
raw = entry.get(key)
assert isinstance(raw, dict) and raw.get("rule_id") == expected_id, (
f"{plan}.{key} must be wrapped with rule_id {expected_id}"
)

238
tests/test_rollup.py Normal file
View file

@ -0,0 +1,238 @@
"""
Tests for the patient rollup (build plan 02, P3).
Rollup rules locked in readiness-model-brief section 4 / phase-2 design Item 3:
worst gradeable line; any gradeable Plan Type Needed line caps the patient no
greener than Action Needed; non-gradeable lines never touch the light; a
patient with no graded gradeable lines has rollup_status None (no label
invented).
PHI CONTRACT: synthetic patient_ids only.
"""
import io
import sys
from datetime import date, timedelta
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).parent.parent / "python-backend"))
from core.dedup import CoverageLine, MergedShipment # noqa: E402
from core.readiness import LineStatus # noqa: E402
from core.rollup import rollup_patient, rollup_patients # noqa: E402
TODAY = date.today()
def make_line(patient_id="PT-1", device="dexcom_g7", plan="medicare",
status=None, gradeable=True):
shipment = MergedShipment(
patient_id=patient_id,
device_type=device,
shipment_date=TODAY - timedelta(days=5),
total_quantity=3,
components=["sensor"],
order_numbers=[],
hcpcs_codes=[],
payer="Medicare Part B",
plan_type=None if plan == "unknown" else plan,
)
return CoverageLine(
patient_id=patient_id,
device_type=device,
plan_type=plan,
gradeable=gradeable,
current_shipment=shipment,
prior_shipments=[],
line_status=status,
timing_flag=None,
)
def test_patient_rollup_single_line():
ru = rollup_patient([make_line(status="On Track")])
assert ru.rollup_status == LineStatus.ON_TRACK
assert ru.cgm_line_count == 1
assert ru.total_line_count == 1
def test_patient_rollup_mixed_statuses():
ru = rollup_patient([
make_line(device="dexcom_g7", status="Clear to Ship"),
make_line(device="freestyle_libre_2", status="At Risk"),
])
assert ru.rollup_status == LineStatus.AT_RISK
def test_patient_rollup_plan_type_needed_capping():
# PTN + Clear to Ship = Action Needed (capped, not PTN)
ru = rollup_patient([
make_line(device="dexcom_g7", status="Clear to Ship"),
make_line(device="freestyle_libre_2", plan="unknown",
status="Plan Type Needed"),
])
assert ru.rollup_status == LineStatus.ACTION_NEEDED
assert ru.plan_type_needed is True
# PTN + At Risk = At Risk (the worse of the two)
ru2 = rollup_patient([
make_line(device="dexcom_g7", status="At Risk"),
make_line(device="freestyle_libre_2", plan="unknown",
status="Plan Type Needed"),
])
assert ru2.rollup_status == LineStatus.AT_RISK
def test_patient_rollup_all_lines_plan_type_needed():
ru = rollup_patient([
make_line(device="dexcom_g7", plan="unknown", status="Plan Type Needed"),
make_line(device="freestyle_libre_2", plan="unknown",
status="Plan Type Needed"),
])
assert ru.rollup_status == LineStatus.PLAN_TYPE_NEEDED
def test_patient_rollup_non_cgm_excluded():
ru = rollup_patient([
make_line(device="dexcom_g7", status="Clear to Ship"),
make_line(device="omnipod_5", gradeable=False, status=None),
])
assert ru.rollup_status == LineStatus.CLEAR_TO_SHIP # pod changes nothing
assert ru.cgm_line_count == 1
assert ru.total_line_count == 2
def test_patient_rollup_no_gradeable_lines():
ru = rollup_patient([make_line(device="omnipod_5", gradeable=False)])
assert ru.rollup_status is None
assert ru.total_line_count == 1
assert ru.cgm_line_count == 0
def test_rollup_patients_groups_by_patient():
lines = {
("A", "dexcom_g7", "medicare"): make_line("A", status="Clear to Ship"),
("A", "freestyle_libre_2", "medicare"): make_line(
"A", device="freestyle_libre_2", status="Action Needed"),
("B", "dexcom_g7", "unknown"): make_line(
"B", plan="unknown", status="Plan Type Needed"),
}
rollups = rollup_patients(lines)
assert set(rollups) == {"A", "B"}
assert rollups["A"].rollup_status == LineStatus.ACTION_NEEDED
assert rollups["B"].rollup_status == LineStatus.PLAN_TYPE_NEEDED
# --- API level ---------------------------------------------------------------
httpx = pytest.importorskip("httpx", reason="httpx required for TestClient")
from fastapi.testclient import TestClient # noqa: E402
import api.main as api_main # noqa: E402
client = TestClient(api_main.app)
SHIP = (TODAY - timedelta(days=5)).isoformat()
VISIT = (TODAY - timedelta(days=30)).isoformat()
HEADER = (
"patient_id,device_type,shipment_date,quantity,payer,plan_type,"
"swo_status,visit_date,pecos_verified,pa_status,diagnosis_on_file"
)
def _upload(csv_text: str):
return client.post(
"/api/upload",
files={"file": ("fixture.csv", io.BytesIO(csv_text.encode()), "text/csv")},
)
def test_upload_response_contains_patients_nested():
csv_text = (
HEADER
+ f"\nPT-N-1,Dexcom G7,{SHIP},3,Medicare Part B,medicare,"
+ f"On File,{VISIT},Yes,,Yes"
+ f"\nPT-N-1,Libre 2,{SHIP},1,Medicare Part B,medicare,"
+ "On File,,Yes,,Yes"
)
resp = _upload(csv_text)
assert resp.status_code == 200
body = resp.json()
patients = body["patients"]
assert len(patients) == 1
p = patients[0]
assert p["patient_id"] == "PT-N-1"
assert p["rollup_status"] == "Action Needed" # worst line (Libre 2 no visit)
assert len(p["lines"]) == 2
by_dev = {l["device_type"]: l for l in p["lines"]}
assert by_dev["dexcom_g7"]["line_status"] == "Clear to Ship"
assert by_dev["freestyle_libre_2"]["line_status"] == "Action Needed"
items = {i["doc_type"]: i for i in by_dev["freestyle_libre_2"]["doc_items"]}
assert items["visit"]["satisfied"] is False
assert items["visit"]["rule_id"] == "R101"
# Worst line renders first
assert p["lines"][0]["device_type"] == "freestyle_libre_2"
def test_patient_stats_count_patients_not_rows():
csv_text = (
HEADER
+ f"\nPT-S-1,Dexcom G7,{SHIP},3,Medicare Part B,medicare,"
+ f"On File,{VISIT},Yes,,Yes"
+ f"\nPT-S-1,Libre 2,{SHIP},1,Medicare Part B,medicare,"
+ f"On File,{VISIT},Yes,,Yes"
+ f"\nPT-S-2,Dexcom G6,{SHIP},3,Medicaid - GA,,"
+ f"On File,{VISIT},,,Yes"
)
resp = _upload(csv_text)
assert resp.status_code == 200
stats = resp.json()["patient_stats"]
assert stats["patients_total"] == 2 # 2-device patient counts once
assert stats["Clear to Ship"] == 1
assert stats["Plan Type Needed"] == 1
def test_flat_records_untouched_by_nested_payload():
csv_text = (
HEADER
+ f"\nPT-F-1,Dexcom G7,{SHIP},3,Medicare Part B,medicare,"
+ f"On File,{VISIT},Yes,,Yes"
)
resp = _upload(csv_text)
body = resp.json()
assert body["total"] == 1
assert len(body["records"]) == 1 # flat path byte-identical (P6 switches UI)
assert body["records"][0]["readiness_status"] == "Clear to Ship"
def test_non_gradeable_only_patient_has_null_rollup():
csv_text = (
HEADER
+ f"\nPT-P-1,Omnipod 5,{SHIP},1,Highmark BCBS,commercial,"
+ f"On File,{VISIT},Yes,Approved,Yes"
)
resp = _upload(csv_text)
body = resp.json()
p = body["patients"][0]
assert p["rollup_status"] is None
assert p["cgm_line_count"] == 0
assert p["lines"][0]["gradeable"] is False
assert p["lines"][0]["line_status"] is None
assert body["patient_stats"]["ungraded"] == 1
def test_rollup_patient_empty_raises():
with pytest.raises(ValueError):
rollup_patient([])
def test_line_timing_flag_populated():
csv_text = (
HEADER
+ f"\nPT-T-1,Dexcom G7,{SHIP},3,Medicare Part B,medicare,"
+ f"On File,{VISIT},Yes,,Yes"
)
resp = _upload(csv_text)
line = resp.json()["patients"][0]["lines"][0]
assert line["timing_flag"] == "RESUPPLY_READY"

View file

@ -594,3 +594,18 @@ def test_confirm_visit_normalizes_plan_type(monkeypatch):
rec = resp.json()
assert rec["plan_type"] == "medicare"
assert rec["readiness_status"] == "Clear to Ship"
def test_upload_readiness_items_carry_rule_ids():
"""P2 contract W2: the serialized doc_items cite their rules."""
csv_text = (
HEADER
+ f"\nPT-RID-1,Dexcom G7,{SHIP},3,Medicare Part B,medicare,"
+ f"On File,{VISIT},Yes,,Yes"
)
resp = _upload(csv_text)
assert resp.status_code == 200
items = {i["doc_type"]: i for i in resp.json()["records"][0]["readiness_items"]}
assert items["pecos"]["rule_id"] == "R004"
assert items["pa"]["rule_id"] == "R003"
assert items["swo"]["rule_id"] == "R100"