[Social Work] Support single and multi-state license types#1597
Conversation
We need to be able to distinguish DynamoDB records associated with licenses by their license scope when querying for records, since a practitioner can have both a single and multi state license with the same jurisdiction/license type. This largely impacts investigation and adverse action records, since they are associated with license/privilege records. This commit adds the licenseScope field to those record types to make them more readily distinguishable in terms of which license they are associated with.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds required licenseScope (single-state|multi-state) and provider_pk/license_sk_suffix helpers; threads licenseScope into schemas, DynamoDB PK/SK generation, API models, handlers, event payloads, OpenSearch mapping/document IDs, mock CSV generator, docs, and extensive tests/fixtures for Social Work license types. ChangesScope-aware Social Work licensing
Sequence Diagram sequenceDiagram
participant Client
participant API_Gateway
participant Handler
participant DataClient
participant DynamoDB
participant EventBus
Client->>API_Gateway: POST/PATCH (licenseType, licenseScope, ...)
API_Gateway->>Handler: validated payload (includes licenseScope)
Handler->>DataClient: create/close/encumber(..., license_scope)
DataClient->>DynamoDB: PK via provider_pk(...)/ SK via license_sk_suffix(...)
Handler->>EventBus: publish event (detail includes licenseScope)
EventBus->>Listener: delivers event (listeners extract licenseScope)
Estimated code review effort Possibly related issues
Suggested reviewers
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
backend/social-work-app/lambdas/python/common/cc_common/event_bus_client.py (1)
306-332:⚠️ Potential issue | 🟠 Major | ⚡ Quick winRequire
license_scopefor license investigations before publishing events.At Line 331 and Line 389,
licenseScopeis optional even wheninvestigation_againstis license. That can emit ambiguous events and lose single-state vs multi-state disambiguation.Proposed fix
def publish_investigation_event( self, @@ license_scope: str | None = None, event_batch_writer: EventBatchWriter | None = None, ): + if investigation_against == InvestigationAgainstEnum.LICENSE and license_scope is None: + raise ValidationError({'licenseScope': ['Missing data for required field.']}) + event_detail = { @@ if license_scope is not None: event_detail['licenseScope'] = license_scope @@ def publish_investigation_closed_event( self, @@ license_scope: str | None = None, event_batch_writer: EventBatchWriter | None = None, ): + if investigation_against == InvestigationAgainstEnum.LICENSE and license_scope is None: + raise ValidationError({'licenseScope': ['Missing data for required field.']}) + event_detail = {Also applies to: 358-390
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/common/cc_common/event_bus_client.py` around lines 306 - 332, When publishing investigation events, require license_scope when investigation_against indicates a license: in the function that builds event_detail (the method taking parameters license_scope and investigation_against and using investigation_against.value and event_detail), add an early validation that if investigation_against == InvestigationAgainst.LICENSE (or the enum/member used in this codebase) and license_scope is None, raise a ValueError (or a DomainValidationError used in this module) rather than omitting licenseScope; then set event_detail['licenseScope'] = license_scope only after that check. Repeat the same validation for the other code path that constructs event_detail (the second occurrence that currently treats licenseScope as optional) so both publishing branches enforce license_scope for license investigations.backend/social-work-app/lambdas/python/search/opensearch_client.py (1)
246-254:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd an explicit
licenseScopemapping toadverse_action_properties(it’s already present forinvestigation_propertiesandlicenses).Nested
adverseActionsincludelicenseScope(schema field is required), so without an explicitkeywordmapping OpenSearch may infer it inconsistently via dynamic mapping. [backend/social-work-app/lambdas/python/search/opensearch_client.py]🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/search/opensearch_client.py` around lines 246 - 254, The adverse_action_properties mapping is missing an explicit licenseScope entry, causing OpenSearch to dynamically infer its type; update the adverse_action_properties dict (the variable named adverse_action_properties in opensearch_client.py) to include "licenseScope": {"type": "keyword"}—mirror the existing licenseScope mapping used in investigation_properties/licenses so the nested adverseActions field is consistently mapped as a keyword.
🧹 Nitpick comments (6)
backend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.py (1)
37-38: ⚡ Quick winAdd an explicit nested-license assertion for
licenseScope.Since
licenseScopeis now part of the fixture contract, asserting it in at least one test here would improve regression detection for provider document shaping.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.py` around lines 37 - 38, The test in test_provider.py currently asserts the nested 'licenseType' but does not assert 'licenseScope'; add an explicit assertion verifying the shaped provider document contains the nested licenseScope value (e.g., assert provider_doc['license']['licenseScope'] == 'single-state' or adjust to your actual shaped structure such as provider_doc['licenses'][0]['licenseScope']) next to the existing licenseType assertion so the fixture contract for 'licenseScope' is enforced.backend/social-work-app/lambdas/python/disaster-recovery/tests/function/test_rollback_license_upload.py (1)
622-623: ⚡ Quick winAdd rollback coverage for
multi-stateupdate-key suffixes.These assertions now lock the
single-statekey format; add amulti-staterollback case to ensure both scope-specific key variants are handled and reported correctly.Also applies to: 927-928, 940-941
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/disaster-recovery/tests/function/test_rollback_license_upload.py` around lines 622 - 623, The test currently asserts rollback keys only for the 'single-state' suffix (e.g., '.../license/oh/lcsw/single-state/...') so add equivalent assertions covering the 'multi-state' suffix to ensure both scope variants are validated; update the expected-keys lists or assertions in test_rollback_license_upload.py (the assertions near the existing 'single-state' entries around the three spots mentioned) to include corresponding '.../license/oh/lcsw/multi-state/...' entries and mirror the same checks (counts/messages) used for single-state so multi-state update-key suffixes are exercised and reported.backend/social-work-app/lambdas/python/data-events/tests/function/test_investigation_events.py (1)
32-33: ⚡ Quick winAdd a
multi-statelicense investigation path test.The generator and assertions now pin
single-state; please add a correspondingmulti-statecase (open/closed) so both supported scopes are covered.Also applies to: 50-51
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/data-events/tests/function/test_investigation_events.py` around lines 32 - 33, The test currently only covers a 'single-state' licenseScope in test_investigation_events.py (the diff pins 'licenseScope': 'single-state' and uses DEFAULT_DATE_OF_UPDATE_TIMESTAMP); add a new test case that mirrors the existing single-state case but sets 'licenseScope': 'multi-state' and asserts both open and closed outcomes as appropriate (create one event for an open multi-state investigation and one for a closed multi-state investigation), updating expected generator outputs and assertions to cover both scopes so the generator is tested for multi-state behavior as well.backend/social-work-app/lambdas/python/data-events/tests/function/test_data_events.py (1)
70-71: ⚡ Quick winAdd a
multi-statesanitization test case.This assertion only protects the
single-statepath. Please add a companion case forlicenseScope='multi-state'so both supported scopes are regression-covered.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/data-events/tests/function/test_data_events.py` around lines 70 - 71, Add a companion test in test_data_events.py that covers licenseScope='multi-state' alongside the existing 'single-state' case: locate the test that builds the input dict with keys 'licenseType' and 'licenseScope' and add another assertion/input case where 'licenseScope' is 'multi-state' and assert the expected sanitized/output behavior (mirroring the pattern used for the 'single-state' assertion) so both supported scopes are regression-tested.backend/social-work-app/lambdas/python/data-events/tests/function/test_encumbrance_events.py (1)
37-37: ⚡ Quick winCover
multi-stateencumbrance/lifting flows in this suite.These updates validate the new scope-aware contract for
single-state, but the new feature supports both scopes. Add at least one license encumbrance + one lifting test withlicenseScope='multi-state'to lock behavior.Also applies to: 426-427, 501-502, 772-773, 844-845, 928-929
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/data-events/tests/function/test_encumbrance_events.py` at line 37, Add tests to exercise the multi-state flow by duplicating the existing license-encumbrance and lifting test cases that set "licenseScope": "single-state" and changing the payload key "licenseScope" to "multi-state"; update the test functions in test_encumbrance_events.py that create encumbrance events and lifting events (the cases around the existing "licenseScope" usages) to include at least one encumbrance test and one lifting test using "multi-state" so the new scope-aware contract is covered for both flows.backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_bulk_upload.py (1)
362-377: ⚡ Quick winAdd a duplicate-SSN test that varies
licenseScope(samelicenseType).Coverage currently proves duplicates are allowed when
licenseTypediffers, but not when onlylicenseScopediffers. Given scope is now a first-class discriminator, add this case to lock intended behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_bulk_upload.py` around lines 362 - 377, Add a new test (e.g., test_bulk_upload_allows_repeated_ssns_for_different_license_scopes) that mirrors test_bulk_upload_allows_repeated_ssns_for_different_license_types but keeps licenseType identical and varies licenseScope to ensure duplicates are allowed when only scope differs; build CSV content with the same ssn and licenseType but different licenseScope, call handlers.bulk_upload.parse_bulk_upload_file and assert it returns/accepts both records (no duplicate-error or rejection), referencing the existing test function and parse_bulk_upload_file to locate where to add the case.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@backend/social-work-app/lambdas/python/common/cc_common/data_model/schema/data_event/api.py`:
- Line 21: The event detail schemas currently declare licenseScope =
LicenseScopeField(required=False, allow_none=False) (see the licenseScope field
declarations in this module) which permits omitting scope; change those
declarations to require the field by setting required=True (keep
allow_none=False) so licenseScope is mandatory for encumbrance/investigation
events — update both occurrences of licenseScope in this file to
LicenseScopeField(required=True, allow_none=False).
In
`@backend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_adverse_action.py`:
- Line 61: The invalid-type test is using a non-canonical attribute name
(adverse_action_data.license_abbreviation) which masks the real validation;
change that assignment to use the canonical field
adverse_action_data.licenseTypeAbbreviation so the test exercises the intended
type/abbreviation pairing logic (update the test that sets license_abbreviation
to instead set licenseTypeAbbreviation and keep the invalid type value
unchanged).
In
`@backend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.py`:
- Around line 359-360: The retention tests currently include licenseScope in the
test data but never assert it; update the response-field retention tests to
explicitly assert the returned/license-preserved value for "licenseScope"
(alongside the existing "licenseType" checks). Locate the tests in
test_license.py that verify field retention (the blocks using the test data
containing 'licenseType' and 'licenseScope' around the shown diff and the
similar lines at 451-452) and add an assertion that the response object's
licenseScope equals the expected value (e.g., assert response['licenseScope'] ==
'single-state' or the test framework’s equivalent).
In
`@backend/social-work-app/lambdas/python/provider-data-v1/handlers/investigation.py`:
- Around line 62-67: The code currently calls json.loads(event['body']) outside
the ValidationError try/except so a malformed body raises json.JSONDecodeError
and escapes the intended CCInvalidRequestException handling; update
_load_license_investigation_patch_body to wrap json.loads(...) and the
subsequent schema.load(...) in a try that catches both json.JSONDecodeError and
ValidationError and raises CCInvalidRequestException with a clear message
(include e.msg or e.messages as appropriate), and apply the same pattern in
handle_license_investigation where event['body'] is parsed so all JSON decode
errors are converted to CCInvalidRequestException instead of bubbling up.
In
`@backend/social-work-app/lambdas/python/search/tests/function/test_provider_update_ingest.py`:
- Line 433: The OpenSearch failure fixture uses an outdated document_id format;
update the document_id assignment in test_provider_update_ingest.py (the
document_id variable) to include the scope marker "`#single-state`" between the
provider and jurisdiction segments so the ID matches current document IDs (i.e.,
change the string from f'{MOCK_SOCW_PROVIDER_ID}`#oh`#licensed clinical social
worker' to include '`#single-state`' resulting in
f'{MOCK_SOCW_PROVIDER_ID}`#single-state`#oh#licensed clinical social worker').
In
`@backend/social-work-app/lambdas/python/search/tests/function/test_public_search_providers.py`:
- Line 631: Update the pagination test fixtures so the document IDs include the
licenseScope marker `#single-state`; specifically modify the cursor payload
strings (e.g., the last_key_payload variable and the other two fixtures
referenced in this test file) to insert `#single-state` into the ID shape (for
example change 'uuid-123#oh#licensed clinical social worker' to
'uuid-123#single-state#oh#licensed clinical social worker') so the search_after
cursors mirror the new ID format.
- Around line 790-792: The test data has mismatched values for the keys
'licenseTypeAbbreviation' and 'licenseType' (currently 'lcsw' vs 'licensed
master social worker'); update the 'licenseTypeAbbreviation' value to the
correct abbreviation 'lmsw' so it matches the 'licenseType' entry used for
type-based filtering, locating the object containing the keys
'licenseTypeAbbreviation' and 'licenseType' in the
test_public_search_providers.py tests.
In
`@backend/social-work-app/lambdas/python/search/tests/function/test_search_providers.py`:
- Line 80: The test fixture builds an outdated document_id; update the
document_id variable in test_search_providers.py (where document_id =
f'{provider_id}`#oh`#licensed clinical social worker') to include the scope suffix
so it becomes scope-aware (append "`#single-state`"), ensuring the fixture matches
current indexing identity used by the search providers tests.
---
Outside diff comments:
In `@backend/social-work-app/lambdas/python/common/cc_common/event_bus_client.py`:
- Around line 306-332: When publishing investigation events, require
license_scope when investigation_against indicates a license: in the function
that builds event_detail (the method taking parameters license_scope and
investigation_against and using investigation_against.value and event_detail),
add an early validation that if investigation_against ==
InvestigationAgainst.LICENSE (or the enum/member used in this codebase) and
license_scope is None, raise a ValueError (or a DomainValidationError used in
this module) rather than omitting licenseScope; then set
event_detail['licenseScope'] = license_scope only after that check. Repeat the
same validation for the other code path that constructs event_detail (the second
occurrence that currently treats licenseScope as optional) so both publishing
branches enforce license_scope for license investigations.
In `@backend/social-work-app/lambdas/python/search/opensearch_client.py`:
- Around line 246-254: The adverse_action_properties mapping is missing an
explicit licenseScope entry, causing OpenSearch to dynamically infer its type;
update the adverse_action_properties dict (the variable named
adverse_action_properties in opensearch_client.py) to include "licenseScope":
{"type": "keyword"}—mirror the existing licenseScope mapping used in
investigation_properties/licenses so the nested adverseActions field is
consistently mapped as a keyword.
---
Nitpick comments:
In
`@backend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.py`:
- Around line 37-38: The test in test_provider.py currently asserts the nested
'licenseType' but does not assert 'licenseScope'; add an explicit assertion
verifying the shaped provider document contains the nested licenseScope value
(e.g., assert provider_doc['license']['licenseScope'] == 'single-state' or
adjust to your actual shaped structure such as
provider_doc['licenses'][0]['licenseScope']) next to the existing licenseType
assertion so the fixture contract for 'licenseScope' is enforced.
In
`@backend/social-work-app/lambdas/python/data-events/tests/function/test_data_events.py`:
- Around line 70-71: Add a companion test in test_data_events.py that covers
licenseScope='multi-state' alongside the existing 'single-state' case: locate
the test that builds the input dict with keys 'licenseType' and 'licenseScope'
and add another assertion/input case where 'licenseScope' is 'multi-state' and
assert the expected sanitized/output behavior (mirroring the pattern used for
the 'single-state' assertion) so both supported scopes are regression-tested.
In
`@backend/social-work-app/lambdas/python/data-events/tests/function/test_encumbrance_events.py`:
- Line 37: Add tests to exercise the multi-state flow by duplicating the
existing license-encumbrance and lifting test cases that set "licenseScope":
"single-state" and changing the payload key "licenseScope" to "multi-state";
update the test functions in test_encumbrance_events.py that create encumbrance
events and lifting events (the cases around the existing "licenseScope" usages)
to include at least one encumbrance test and one lifting test using
"multi-state" so the new scope-aware contract is covered for both flows.
In
`@backend/social-work-app/lambdas/python/data-events/tests/function/test_investigation_events.py`:
- Around line 32-33: The test currently only covers a 'single-state'
licenseScope in test_investigation_events.py (the diff pins 'licenseScope':
'single-state' and uses DEFAULT_DATE_OF_UPDATE_TIMESTAMP); add a new test case
that mirrors the existing single-state case but sets 'licenseScope':
'multi-state' and asserts both open and closed outcomes as appropriate (create
one event for an open multi-state investigation and one for a closed multi-state
investigation), updating expected generator outputs and assertions to cover both
scopes so the generator is tested for multi-state behavior as well.
In
`@backend/social-work-app/lambdas/python/disaster-recovery/tests/function/test_rollback_license_upload.py`:
- Around line 622-623: The test currently asserts rollback keys only for the
'single-state' suffix (e.g., '.../license/oh/lcsw/single-state/...') so add
equivalent assertions covering the 'multi-state' suffix to ensure both scope
variants are validated; update the expected-keys lists or assertions in
test_rollback_license_upload.py (the assertions near the existing 'single-state'
entries around the three spots mentioned) to include corresponding
'.../license/oh/lcsw/multi-state/...' entries and mirror the same checks
(counts/messages) used for single-state so multi-state update-key suffixes are
exercised and reported.
In
`@backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_bulk_upload.py`:
- Around line 362-377: Add a new test (e.g.,
test_bulk_upload_allows_repeated_ssns_for_different_license_scopes) that mirrors
test_bulk_upload_allows_repeated_ssns_for_different_license_types but keeps
licenseType identical and varies licenseScope to ensure duplicates are allowed
when only scope differs; build CSV content with the same ssn and licenseType but
different licenseScope, call handlers.bulk_upload.parse_bulk_upload_file and
assert it returns/accepts both records (no duplicate-error or rejection),
referencing the existing test function and parse_bulk_upload_file to locate
where to add the case.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f3d28668-cb81-4b26-a8e3-bad122f895c5
⛔ Files ignored due to path filters (3)
backend/social-work-app/lambdas/python/common/tests/resources/licenses-invalid-records.csvis excluded by!**/*.csvbackend/social-work-app/lambdas/python/common/tests/resources/licenses.csvis excluded by!**/*.csvbackend/social-work-app/tests/smoke/cosm-al-mock-licenses.csvis excluded by!**/*.csv
📒 Files selected for processing (90)
backend/social-work-app/bin/generate_mock_license_csv_upload_file.pybackend/social-work-app/cdk.jsonbackend/social-work-app/docs/README.mdbackend/social-work-app/docs/it_staff_onboarding_instructions.mdbackend/social-work-app/lambdas/nodejs/tests/sample-records.tsbackend/social-work-app/lambdas/python/common/cc_common/config.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/data_client.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/provider_record_util.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/adverse_action/__init__.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/adverse_action/api.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/adverse_action/record.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/base_record.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/common.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/data_event/api.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/fields.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/investigation/__init__.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/investigation/api.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/investigation/record.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/__init__.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/api.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/common.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/ingest.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/record.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/provider/api.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/provider/record.pybackend/social-work-app/lambdas/python/common/cc_common/event_bus_client.pybackend/social-work-app/lambdas/python/common/common_test/test_constants.pybackend/social-work-app/lambdas/python/common/common_test/test_data_generator.pybackend/social-work-app/lambdas/python/common/tests/__init__.pybackend/social-work-app/lambdas/python/common/tests/function/test_data_client.pybackend/social-work-app/lambdas/python/common/tests/resources/api/license-post.jsonbackend/social-work-app/lambdas/python/common/tests/resources/api/provider-detail-response.jsonbackend/social-work-app/lambdas/python/common/tests/resources/dynamo/license-update.jsonbackend/social-work-app/lambdas/python/common/tests/resources/dynamo/license.jsonbackend/social-work-app/lambdas/python/common/tests/resources/ingest/event-bridge-message.jsonbackend/social-work-app/lambdas/python/common/tests/resources/ingest/preprocessor-sqs-message.jsonbackend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_adverse_action.pybackend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_investigation.pybackend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.pybackend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.pybackend/social-work-app/lambdas/python/common/tests/unit/test_email_service_client.pybackend/social-work-app/lambdas/python/common/tests/unit/test_feature_flag_client.pybackend/social-work-app/lambdas/python/common/tests/unit/test_investigation_event_bus_client.pybackend/social-work-app/lambdas/python/common/tests/unit/test_provider_record_util.pybackend/social-work-app/lambdas/python/compact-configuration/tests/__init__.pybackend/social-work-app/lambdas/python/data-events/handlers/encumbrance_events.pybackend/social-work-app/lambdas/python/data-events/handlers/investigation_events.pybackend/social-work-app/lambdas/python/data-events/tests/__init__.pybackend/social-work-app/lambdas/python/data-events/tests/function/test_data_events.pybackend/social-work-app/lambdas/python/data-events/tests/function/test_encumbrance_events.pybackend/social-work-app/lambdas/python/data-events/tests/function/test_home_state_change_events.pybackend/social-work-app/lambdas/python/data-events/tests/function/test_investigation_events.pybackend/social-work-app/lambdas/python/data-events/tests/resources/events.jsonbackend/social-work-app/lambdas/python/disaster-recovery/tests/__init__.pybackend/social-work-app/lambdas/python/disaster-recovery/tests/function/test_rollback_license_upload.pybackend/social-work-app/lambdas/python/feature-flag/tests/function/test_statsig_client.pybackend/social-work-app/lambdas/python/migration/tests/__init__.pybackend/social-work-app/lambdas/python/provider-data-v1/handlers/encumbrance.pybackend/social-work-app/lambdas/python/provider-data-v1/handlers/investigation.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/__init__.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/__init__.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_data_model/test_provider_transformations.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_bulk_upload.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_encumbrance.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_investigation.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_licenses.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/unit/test_handlers/test_bulk_upload_unit.pybackend/social-work-app/lambdas/python/search/opensearch_client.pybackend/social-work-app/lambdas/python/search/tests/__init__.pybackend/social-work-app/lambdas/python/search/tests/function/test_manage_opensearch_indices.pybackend/social-work-app/lambdas/python/search/tests/function/test_populate_provider_documents.pybackend/social-work-app/lambdas/python/search/tests/function/test_provider_update_ingest.pybackend/social-work-app/lambdas/python/search/tests/function/test_public_search_providers.pybackend/social-work-app/lambdas/python/search/tests/function/test_search_providers.pybackend/social-work-app/lambdas/python/search/utils.pybackend/social-work-app/stacks/api_stack/v1_api/api_model.pybackend/social-work-app/stacks/search_api_stack/v1_api/api_model.pybackend/social-work-app/stacks/state_api_stack/v1_api/api_model.pybackend/social-work-app/tests/resources/snapshots/GET_PROVIDER_RESPONSE_SCHEMA.jsonbackend/social-work-app/tests/resources/snapshots/LICENSE_ENCUMBRANCE_LIFTING_REQUEST_SCHEMA.jsonbackend/social-work-app/tests/resources/snapshots/LICENSE_ENCUMBRANCE_REQUEST_SCHEMA.jsonbackend/social-work-app/tests/resources/snapshots/PROVIDER_USER_RESPONSE_SCHEMA.jsonbackend/social-work-app/tests/resources/snapshots/PUBLIC_GET_PROVIDER_RESPONSE_SCHEMA.jsonbackend/social-work-app/tests/resources/snapshots/PUBLIC_QUERY_PROVIDERS_RESPONSE_SCHEMA.jsonbackend/social-work-app/tests/smoke/encumbrance_smoke_tests.pybackend/social-work-app/tests/smoke/license_upload_smoke_tests.pybackend/social-work-app/tests/smoke/rollback_license_upload_smoke_tests.pybackend/social-work-app/tests/smoke/smoke_common.py
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/social-work-app/lambdas/python/common/cc_common/event_bus_client.py`:
- Around line 329-330: When building the event payload in event_bus_client (the
code that sets 'licenseScope' and 'investigationAgainst'), don't silently
default license_scope to LicenseScopeEnum.SINGLE_STATE when investigation is
against a LICENSE; instead validate that license_scope is provided when
investigation_against == InvestigationAgainstEnum.LICENSE and raise/return an
error (fail fast). Keep the existing default behavior only when
investigation_against == InvestigationAgainstEnum.PRIVILEGE; update the logic
around the payload construction that references license_scope, LicenseScopeEnum,
and InvestigationAgainstEnum to enforce this check and prevent publishing
incorrect multi-state license events.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f7df98d4-3044-43c8-93dd-015702d39350
📒 Files selected for processing (16)
backend/social-work-app/lambdas/python/common/cc_common/data_model/schema/data_event/api.pybackend/social-work-app/lambdas/python/common/cc_common/event_bus_client.pybackend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_adverse_action.pybackend/social-work-app/lambdas/python/common/tests/unit/test_investigation_event_bus_client.pybackend/social-work-app/lambdas/python/common/tests/unit/test_provider_record_util.pybackend/social-work-app/lambdas/python/data-events/tests/function/test_encumbrance_events.pybackend/social-work-app/lambdas/python/data-events/tests/function/test_investigation_events.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_bulk_upload.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_encumbrance.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_investigation.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_licenses.pybackend/social-work-app/lambdas/python/search/tests/function/test_provider_update_ingest.pybackend/social-work-app/lambdas/python/search/tests/function/test_public_search_providers.pybackend/social-work-app/tests/resources/snapshots/GET_PROVIDER_RESPONSE_SCHEMA.jsonbackend/social-work-app/tests/resources/snapshots/PATCH_LICENSE_INVESTIGATION_REQUEST_SCHEMA.json
🚧 Files skipped from review as they are similar to previous changes (10)
- backend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_adverse_action.py
- backend/social-work-app/lambdas/python/common/tests/unit/test_investigation_event_bus_client.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_bulk_upload.py
- backend/social-work-app/lambdas/python/data-events/tests/function/test_investigation_events.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_encumbrance.py
- backend/social-work-app/lambdas/python/search/tests/function/test_provider_update_ingest.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.py
- backend/social-work-app/lambdas/python/search/tests/function/test_public_search_providers.py
- backend/social-work-app/lambdas/python/common/tests/unit/test_provider_record_util.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_licenses.py
Now that we support both single and multi-state licenses, we must specifically associate privileges with multi-state license records, and only if there is a matching single-state license record for that same license type/jurisdiction.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/social-work-app/docs/design/README.md`:
- Line 339: The wording is inconsistent about whether the pairing single-state
license must be "eligible" or "active"; update the sentence(s) so the rule is
explicit and consistent: require that the most-recent multi-state license must
have a paired single-state license in the same jurisdiction and license type
that is both active and eligible. Replace the two occurrences ("eligible
single-state" and "paired active single-state") with a single consistent phrase
like "an active and eligible single-state license in the same jurisdiction and
license type" and ensure the following sentence about privilege generation
references that same phrase.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bb4f3d7c-7f8e-48b8-92e0-24cfbeb3875e
📒 Files selected for processing (14)
backend/social-work-app/docs/design/README.mdbackend/social-work-app/lambdas/python/common/cc_common/data_model/provider_record_util.pybackend/social-work-app/lambdas/python/common/common_test/test_data_generator.pybackend/social-work-app/lambdas/python/common/tests/resources/api/provider-detail-response.jsonbackend/social-work-app/lambdas/python/common/tests/resources/dynamo/license-multi-state.jsonbackend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_adverse_action.pybackend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.pybackend/social-work-app/lambdas/python/common/tests/unit/test_provider_record_util.pybackend/social-work-app/lambdas/python/common/tests/unit/test_sanitize_provider_data.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_investigation.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_providers.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.pybackend/social-work-app/lambdas/python/search/tests/function/test_search_providers.py
🚧 Files skipped from review as they are similar to previous changes (4)
- backend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_adverse_action.py
- backend/social-work-app/lambdas/python/search/tests/function/test_search_providers.py
- backend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_investigation.py
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/social-work-app/lambdas/python/common/cc_common/event_bus_client.py (1)
136-147:⚠️ Potential issue | 🔴 CriticalPass
license_scopeto all callers of license encumbrance and LICENSE investigation event publishers.
publish_license_encumbrance_event(...)/publish_license_encumbrance_lifting_event(...)now requirelicense_scope: str(no default).backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/encumbrance.pyandbackend/compact-connect/lambdas/python/provider-data-v1/handlers/encumbrance.pycall these withoutlicense_scope=, which will raiseTypeErrorat runtime (call sites use keyword args, so it’s missing kwarg—not positional misalignment).publish_investigation_event(...)/publish_investigation_closed_event(...)call_resolve_investigation_license_scope(...), which raisesValueErrorwheninvestigation_against == InvestigationAgainstEnum.LICENSEandlicense_scopeis not provided.backend/cosmetology-app/lambdas/python/provider-data-v1/handlers/investigation.py(LICENSE calls at ~120/~155 and closed at ~211/~269) andbackend/compact-connect/lambdas/python/provider-data-v1/handlers/investigation.py(LICENSE calls at ~120/~155 and closed at ~211/~269) omitlicense_scope=.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/common/cc_common/event_bus_client.py` around lines 136 - 147, Callers must pass the new required license_scope parameter into the license-related publishers and into the investigation publishers so _resolve_investigation_license_scope won't raise; update calls to publish_license_encumbrance_event and publish_license_encumbrance_lifting_event in the encumbrance handlers to include license_scope=<value>, and update calls to publish_investigation_event and publish_investigation_closed_event in the investigation handlers to include license_scope=<value> (or compute and pass the same scope used for the investigation); ensure any code that relies on _resolve_investigation_license_scope now supplies license_scope when investigation_against == InvestigationAgainstEnum.LICENSE.
🧹 Nitpick comments (1)
backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_data_model/test_provider_transformations.py (1)
98-102: ⚡ Quick winVerify license filtering logic handles both single-state and multi-state records correctly.
The test now expects exactly 2 license records and selects the single-state variant for comparison. However, the test only validates the single-state license against the expected fixture. Consider adding assertions for the multi-state license as well to ensure both ingestion paths work correctly.
🧪 Suggested enhancement to validate both licenses
# One record for each of: provider and license (no privileges in Social Work model) license_records = [r for r in provider_user_records.provider_records if r['type'] == 'license'] self.assertEqual(2, len(license_records)) records = {item['type']: item for item in provider_user_records.provider_records if item['type'] != 'license'} records['license'] = next(r for r in license_records if r['licenseScope'] == 'single-state') + +# Also verify the multi-state license exists and has correct scope +multi_state_license = next(r for r in license_records if r['licenseScope'] == 'multi-state') +self.assertEqual('multi-state', multi_state_license['licenseScope'])🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_data_model/test_provider_transformations.py` around lines 98 - 102, The test currently finds two license_records and only asserts the single-state license; update the test in test_provider_transformations.py to also locate the multi-state license (e.g., use next(r for r in license_records if r['licenseScope'] == 'multi-state' or r['licenseScope'] != 'single-state')) and add assertions that its fields match the expected fixture for multi-state licenses (similar to how the single-state license is validated), referencing provider_user_records.provider_records, the license_records list, and the records dict to locate and validate both license variants.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/social-work-app/lambdas/python/search/handlers/public_search.py`:
- Line 264: You removed the per-license-type scoping by setting nested_must:
list[dict] = [] in public_search.py which can return multiple license variants
per provider; either restore the original nested filter (add back a clause on
"licenses.mostRecentLicenseForType": True inside the nested_must used by
build_public_search_query / the provider licensing nested query) or implement
explicit provider-level deduping after search results (collapse by provider ID
and adjust total counts/pagination), and update the associated tests expecting
single-license-per-provider cardinality and any frontend pagination/count
expectations accordingly.
---
Outside diff comments:
In `@backend/social-work-app/lambdas/python/common/cc_common/event_bus_client.py`:
- Around line 136-147: Callers must pass the new required license_scope
parameter into the license-related publishers and into the investigation
publishers so _resolve_investigation_license_scope won't raise; update calls to
publish_license_encumbrance_event and publish_license_encumbrance_lifting_event
in the encumbrance handlers to include license_scope=<value>, and update calls
to publish_investigation_event and publish_investigation_closed_event in the
investigation handlers to include license_scope=<value> (or compute and pass the
same scope used for the investigation); ensure any code that relies on
_resolve_investigation_license_scope now supplies license_scope when
investigation_against == InvestigationAgainstEnum.LICENSE.
---
Nitpick comments:
In
`@backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_data_model/test_provider_transformations.py`:
- Around line 98-102: The test currently finds two license_records and only
asserts the single-state license; update the test in
test_provider_transformations.py to also locate the multi-state license (e.g.,
use next(r for r in license_records if r['licenseScope'] == 'multi-state' or
r['licenseScope'] != 'single-state')) and add assertions that its fields match
the expected fixture for multi-state licenses (similar to how the single-state
license is validated), referencing provider_user_records.provider_records, the
license_records list, and the records dict to locate and validate both license
variants.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7b88af71-832c-49a6-9cd2-5cdbe9ada4ae
📒 Files selected for processing (22)
backend/cosmetology-app/lambdas/python/common/cc_common/feature_flag_enum.pybackend/cosmetology-app/lambdas/python/provider-data-v1/handlers/bulk_upload.pybackend/cosmetology-app/lambdas/python/provider-data-v1/handlers/licenses.pybackend/social-work-app/docs/design/README.mdbackend/social-work-app/lambdas/python/common/cc_common/data_model/provider_record_util.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/api.pybackend/social-work-app/lambdas/python/common/cc_common/event_bus_client.pybackend/social-work-app/lambdas/python/common/cc_common/feature_flag_enum.pybackend/social-work-app/lambdas/python/common/tests/resources/api/license-post-multi-state.jsonbackend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.pybackend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.pybackend/social-work-app/lambdas/python/common/tests/unit/test_investigation_event_bus_client.pybackend/social-work-app/lambdas/python/common/tests/unit/test_provider_record_util.pybackend/social-work-app/lambdas/python/provider-data-v1/handlers/bulk_upload.pybackend/social-work-app/lambdas/python/provider-data-v1/handlers/licenses.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_data_model/test_provider_transformations.pybackend/social-work-app/lambdas/python/search/handlers/public_search.pybackend/social-work-app/lambdas/python/search/opensearch_client.pybackend/social-work-app/lambdas/python/search/tests/function/test_manage_opensearch_indices.pybackend/social-work-app/lambdas/python/search/tests/function/test_populate_provider_documents.pybackend/social-work-app/lambdas/python/search/tests/function/test_provider_update_ingest.pybackend/social-work-app/lambdas/python/search/tests/function/test_public_search_providers.py
💤 Files with no reviewable changes (7)
- backend/cosmetology-app/lambdas/python/common/cc_common/feature_flag_enum.py
- backend/social-work-app/lambdas/python/search/tests/function/test_populate_provider_documents.py
- backend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_provider.py
- backend/social-work-app/lambdas/python/search/tests/function/test_provider_update_ingest.py
- backend/social-work-app/lambdas/python/common/cc_common/feature_flag_enum.py
- backend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.py
- backend/social-work-app/lambdas/python/common/cc_common/data_model/provider_record_util.py
✅ Files skipped from review due to trivial changes (2)
- backend/social-work-app/lambdas/python/common/tests/resources/api/license-post-multi-state.json
- backend/social-work-app/docs/design/README.md
🚧 Files skipped from review as they are similar to previous changes (2)
- backend/social-work-app/lambdas/python/search/tests/function/test_public_search_providers.py
- backend/social-work-app/lambdas/python/common/tests/unit/test_provider_record_util.py
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/social-work-app/lambdas/python/provider-data-v1/handlers/ingest.py (1)
141-153:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftPropagate
licenseScopeinto the update/deactivation path.This match now correctly treats
licenseScopeas part of license identity, but the follow-onlicenseUpdaterecord and deactivation event still identify the license only byjurisdiction+licenseType. If a provider has both single-state and multi-state versions of the same license in one jurisdiction, downstream consumers cannot tell which record changed.Suggested direction
def _process_license_update(*, existing_license: dict, new_license: dict, dynamo_transactions: list, data_events: list): ... license_deactivation_event = config.event_bus_client.generate_license_deactivation_event( source='org.compactconnect.provider-data', compact=existing_license['compact'], jurisdiction=existing_license['jurisdiction'], provider_id=existing_license['providerId'], license_type=existing_license['licenseType'], + license_scope=existing_license['licenseScope'], ) ... def _populate_update_record(*, existing_license: dict, updated_values: dict, removed_values: dict) -> dict: return license_update_schema.dump( { 'type': ProviderRecordType.LICENSE_UPDATE, 'updateType': update_type, 'providerId': existing_license['providerId'], 'compact': existing_license['compact'], 'jurisdiction': existing_license['jurisdiction'], 'licenseType': existing_license['licenseType'], + 'licenseScope': existing_license['licenseScope'], ... } )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/provider-data-v1/handlers/ingest.py` around lines 141 - 153, The update/deactivation path is not including licenseScope in the identity fields, so _process_license_update and subsequent licenseUpdate/deactivation events cannot distinguish same jurisdiction+licenseType with different licenseScope; update the code that builds the existing_license dict (from existing_license_data.to_dict()) and the payloads created inside _process_license_update and any deactivation event generator to include the posted_license_record['licenseScope'] (or existing_license['licenseScope']) as part of the identifying key, and ensure any functions that emit a licenseUpdate/deactivation event (references: _process_license_update, any deactivation event builder) use jurisdiction + licenseType + licenseScope when constructing the record identity and event payload so downstream consumers can disambiguate single-state vs multi-state licenses.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@backend/social-work-app/lambdas/python/provider-data-v1/handlers/ingest.py`:
- Around line 141-153: The update/deactivation path is not including
licenseScope in the identity fields, so _process_license_update and subsequent
licenseUpdate/deactivation events cannot distinguish same
jurisdiction+licenseType with different licenseScope; update the code that
builds the existing_license dict (from existing_license_data.to_dict()) and the
payloads created inside _process_license_update and any deactivation event
generator to include the posted_license_record['licenseScope'] (or
existing_license['licenseScope']) as part of the identifying key, and ensure any
functions that emit a licenseUpdate/deactivation event (references:
_process_license_update, any deactivation event builder) use jurisdiction +
licenseType + licenseScope when constructing the record identity and event
payload so downstream consumers can disambiguate single-state vs multi-state
licenses.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b9c39bd6-06b7-441d-823f-807342d07227
📒 Files selected for processing (6)
backend/social-work-app/lambdas/python/provider-data-v1/handlers/bulk_upload.pybackend/social-work-app/lambdas/python/provider-data-v1/handlers/ingest.pybackend/social-work-app/lambdas/python/provider-data-v1/handlers/licenses.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_bulk_upload.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_licenses.py
✅ Files skipped from review due to trivial changes (1)
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_licenses.py
🚧 Files skipped from review as they are similar to previous changes (2)
- backend/social-work-app/lambdas/python/provider-data-v1/handlers/licenses.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_bulk_upload.py
We will not trigger a home state change if a multi-state license is uploaded from a new jurisdiction, but there is no associated single state license uploaded from that home state. This means when generating the details for the provider to be returned from the API, the home multi-state license will be the license which was most recently issued AND has an associated single-state license on record. Any multi-state license without an associated single-state license will not be considered a home state license, regardless of how recently it was issued.
Updating the ingest flow to only change the home jurisdiction if both the single state and multi-state licenses have been uploaded for a new jurisdiction.
There was a problem hiding this comment.
Looks good to me. Well want to get those questions we spoke about earlier answered.
I believe we do actually have a bug with the rollback logic in that it can leave a provider with a different home state license than before the bad license data + rollback in this scenario and maybe a few others:
IN uploads single state expiring in 2022
OH uploads single state expiring in 2023
Home state is still IN.
OK uploads multi state and single state,
Ok gets rolled back.
Algorithm gets best license => OH 2023
So the home state would then be OH 2023 when it should be IN 2022.
The "best license" logic alone cant be applied here because its not how the home state is determined, date of upload is also relevant
|
@jlkravitz This is ready for your review. Thanks |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/social-work-app/lambdas/python/disaster-recovery/handlers/rollback_license_upload.py (1)
663-672:⚠️ Potential issue | 🟠 Major | ⚡ Quick winKeep orphan detection scope-aware too.
This loop now rolls licenses back by
(jurisdiction, licenseType, licenseScope), but_check_for_orphaned_update_records()still treats updates as unique only by(jurisdiction, licenseType). A missing multi-state top-level license can therefore be masked by an existing single-state record for the same jurisdiction/type, and rollback will proceed on inconsistent data.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/disaster-recovery/handlers/rollback_license_upload.py` around lines 663 - 672, The orphan-detection function _check_for_orphaned_update_records currently deduplicates updates by (jurisdiction, licenseType) but the rollback loop operates on (jurisdiction, licenseType, licenseScope); update _check_for_orphaned_update_records to accept license_scope (or derive it from passed records) and include licenseScope in the uniqueness key/filter so it only treats updates as unique when jurisdiction, licenseType AND licenseScope match (adjust callers such as the loop that uses provider_records.get_update_records_for_license and any other callers to pass the license_scope as needed).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/social-work-app/docs/devops/STAFF_USER_MFA_RECOVERY.md`:
- Line 49: Edit the sentence that currently reads "we use this field in the
index used to lookup the list of staff users" and replace "lookup" with the
two-word form "look up"; the change is in the STAFF_USER_MFA_RECOVERY document
and refers to the `famGiv` index field—update that sentence so it reads "...used
to look up the list of staff users" to correct the user-facing runbook text.
In
`@backend/social-work-app/lambdas/python/common/cc_common/data_model/provider_record_util.py`:
- Around line 708-711: When is_public_response is True the code currently calls
find_most_recent_licenses_for_each_license_type(LicenseScopeEnum.MULTI_STATE)
which drops license types that only have SINGLE_STATE records; change the logic
to build a per-license-type fallback: retrieve multi-state and single-state
recent maps (e.g., call find_most_recent_licenses_for_each_license_type twice
with LicenseScopeEnum.MULTI_STATE and LicenseScopeEnum.SINGLE_STATE or call once
for all and partition by scope), then for each license type select the
MULTI_STATE record if present otherwise the SINGLE_STATE record and assign that
to license_records; update the branch that sets license_records (referencing
is_public_response, find_most_recent_licenses_for_each_license_type,
LicenseScopeEnum.MULTI_STATE, LicenseScopeEnum.SINGLE_STATE) accordingly.
- Around line 540-554: The current loop filters multi-state licenses by whether
find_matching_single_state_license_for_multi_state_license(lic) returns non-None
before grouping, which lets an older paired multi-state replace a newer unpaired
one; instead, group self._license_records by lic.licenseType for records where
lic.licenseScope == LicenseScopeEnum.MULTI_STATE.value, sort each group with
_license_sort_key, pick the most_recent_multi_state for that type, then call
find_matching_single_state_license_for_multi_state_license(most_recent_multi_state)
and only append that most recent when the match exists (do not fall back to
older records); update the logic around by_type, sorted_multi_state,
most_recent_multi_state and the final append to enforce “newest-only” behavior.
In
`@backend/social-work-app/lambdas/python/disaster-recovery/handlers/rollback_license_upload.py`:
- Around line 748-788: The provider-update selection must be constrained to the
same jurisdiction(s) as the upload being rolled back: modify the loop that
builds eligible_provider_updates_in_window (which iterates over
provider_records.get_all_provider_update_records and checks
LICENSE_UPLOAD_UPDATE_CATEGORIES) to also check that the provider_update affects
the same jurisdiction as the rollback target (e.g., compare
provider_update.jurisdiction / provider_update.target_jurisdiction /
provider_update.previous.homeJurisdiction — or whichever jurisdiction field
exists on ProviderUpdate — against the jurisdiction(s) of the licenses being
removed from provider_records.get_license_records()); only then add to
eligible_provider_updates_in_window and delete its DB record and consider it for
provider_revert_target (used with
ProviderData.create_new(earliest_provider_update.previous)).
---
Outside diff comments:
In
`@backend/social-work-app/lambdas/python/disaster-recovery/handlers/rollback_license_upload.py`:
- Around line 663-672: The orphan-detection function
_check_for_orphaned_update_records currently deduplicates updates by
(jurisdiction, licenseType) but the rollback loop operates on (jurisdiction,
licenseType, licenseScope); update _check_for_orphaned_update_records to accept
license_scope (or derive it from passed records) and include licenseScope in the
uniqueness key/filter so it only treats updates as unique when jurisdiction,
licenseType AND licenseScope match (adjust callers such as the loop that uses
provider_records.get_update_records_for_license and any other callers to pass
the license_scope as needed).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4589fb28-b444-4ce7-9034-924b1133a269
📒 Files selected for processing (45)
.github/workflows/check-for-external-state-api-spec-update.yml.github/workflows/check-for-internal-api-spec-update.ymlbackend/compact-connect/lambdas/python/common/cc_common/data_model/provider_record_util.pybackend/cosmetology-app/docs/devops/STAFF_USER_MFA_RECOVERY.mdbackend/cosmetology-app/lambdas/python/common/cc_common/data_model/provider_record_util.pybackend/social-work-app/docs/api-specification/latest-oas30.jsonbackend/social-work-app/docs/devops/STAFF_USER_MFA_RECOVERY.mdbackend/social-work-app/docs/internal/api-specification/latest-oas30.jsonbackend/social-work-app/docs/internal/postman/postman-collection.jsonbackend/social-work-app/docs/postman/postman-collection.jsonbackend/social-work-app/docs/search-internal/api-specification/latest-oas30.jsonbackend/social-work-app/docs/search-internal/postman/postman-collection.jsonbackend/social-work-app/lambdas/nodejs/lib/email/ingest-event-email-service.tsbackend/social-work-app/lambdas/nodejs/lib/models/event-records.tsbackend/social-work-app/lambdas/nodejs/tests/lib/email/ingest-event-email-service.test.tsbackend/social-work-app/lambdas/nodejs/tests/sample-records.tsbackend/social-work-app/lambdas/python/common/cc_common/data_model/data_client.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/provider_record_util.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/common.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/data_event/api.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/__init__.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/api.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/record.pybackend/social-work-app/lambdas/python/common/cc_common/event_bus_client.pybackend/social-work-app/lambdas/python/common/common_test/test_data_generator.pybackend/social-work-app/lambdas/python/common/tests/function/test_data_client.pybackend/social-work-app/lambdas/python/common/tests/resources/dynamo/license-update.jsonbackend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.pybackend/social-work-app/lambdas/python/common/tests/unit/test_provider_record_util.pybackend/social-work-app/lambdas/python/data-events/tests/function/test_encumbrance_events.pybackend/social-work-app/lambdas/python/disaster-recovery/handlers/rollback_license_upload.pybackend/social-work-app/lambdas/python/disaster-recovery/tests/function/test_rollback_license_upload.pybackend/social-work-app/lambdas/python/provider-data-v1/handlers/bulk_upload.pybackend/social-work-app/lambdas/python/provider-data-v1/handlers/ingest.pybackend/social-work-app/lambdas/python/provider-data-v1/handlers/licenses.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_bulk_upload.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_investigation.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_licenses.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/unit/test_handlers/test_bulk_upload_unit.pybackend/social-work-app/tests/smoke/investigation_smoke_tests.pybackend/social-work-app/tests/smoke/license_upload_smoke_tests.pybackend/social-work-app/tests/smoke/rollback_license_upload_smoke_tests.pybackend/social-work-app/tests/smoke/smoke_common.py
💤 Files with no reviewable changes (1)
- backend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/api.py
✅ Files skipped from review due to trivial changes (3)
- backend/social-work-app/lambdas/python/common/tests/resources/dynamo/license-update.json
- backend/cosmetology-app/lambdas/python/common/cc_common/data_model/provider_record_util.py
- backend/compact-connect/lambdas/python/common/cc_common/data_model/provider_record_util.py
🚧 Files skipped from review as they are similar to previous changes (11)
- backend/social-work-app/tests/smoke/rollback_license_upload_smoke_tests.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_licenses.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_bulk_upload.py
- backend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/unit/test_handlers/test_bulk_upload_unit.py
- backend/social-work-app/lambdas/python/provider-data-v1/handlers/licenses.py
- backend/social-work-app/lambdas/python/data-events/tests/function/test_encumbrance_events.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.py
- backend/social-work-app/lambdas/python/common/cc_common/data_model/data_client.py
- backend/social-work-app/lambdas/python/common/tests/function/test_data_client.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_investigation.py
Also added check to skip rollback if any license updates occurred in other jurisdictions, as this will require manual review for any home jurisdiction changes.
jlkravitz
left a comment
There was a problem hiding this comment.
Good stuff! Few comments/questions.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/social-work-app/lambdas/python/common/cc_common/data_model/schema/data_event/api.py (1)
52-55:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd
licenseScopefield toHomeJurisdictionChangeEventDetailSchemafor audit consistency.The event schema for home jurisdiction changes includes
licenseType(line 54) but omitslicenseScope. According to the PR objectives, home jurisdiction changes are triggered when a multi-state license is the most recent across jurisdictions, making license scope a key part of the triggering logic. For audit traceability and consistency with the other four event detail schemas in this file (which all includelicenseScope), this event should capture which license scope caused the home jurisdiction change.✨ Suggested addition
class HomeJurisdictionChangeEventDetailSchema(DataEventDetailBaseSchema): providerId = UUID(required=True, allow_none=False) licenseType = String(required=True, allow_none=False) + licenseScope = LicenseScopeField(required=True, allow_none=False) formerHomeJurisdiction = Jurisdiction(required=True, allow_none=False)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/lambdas/python/common/cc_common/data_model/schema/data_event/api.py` around lines 52 - 55, HomeJurisdictionChangeEventDetailSchema is missing the licenseScope field used for audit consistency; update the class (HomeJurisdictionChangeEventDetailSchema) to include licenseScope with the same type and validation as the other event detail schemas (e.g. add licenseScope = LicenseScope(required=True, allow_none=False)) alongside providerId, licenseType and formerHomeJurisdiction, and ensure the LicenseScope symbol is imported if not already.
♻️ Duplicate comments (1)
backend/social-work-app/docs/design/README.md (1)
333-333:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winFix spacing in "theSocial WorkCompact".
Should be "the Social Work Compact" with proper spacing.
📝 Proposed fix
-Privileges are authorizations that allow licensed providers to practice their profession in jurisdictions other than their home state. The Social Work Compact follows a multi-state licensure model, where privileges are automatically granted to a licensee as a result of having a multi-state license in their home state. The list of jurisdictions where privileges are granted is determined by which states have onboarded into the CompactConnect system for theSocial WorkCompact. +Privileges are authorizations that allow licensed providers to practice their profession in jurisdictions other than their home state. The Social Work Compact follows a multi-state licensure model, where privileges are automatically granted to a licensee as a result of having a multi-state license in their home state. The list of jurisdictions where privileges are granted is determined by which states have onboarded into the CompactConnect system for the Social Work Compact.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/social-work-app/docs/design/README.md` at line 333, Replace the typographical error "theSocial WorkCompact" in the README content with the correct spaced phrase "the Social Work Compact"; locate the exact string "theSocial WorkCompact" in the documentation text and update it to "the Social Work Compact" so spacing is correct throughout the sentence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.py`:
- Around line 911-914: The assertions currently check
provider_data_after_ky_single_state which was captured before the single-state
KY upload; update the two assertions to use the response object returned by the
step-5 ingestion call (the variable that holds the latest response from the KY
single-state upload, e.g., response_after_ky_single_state or whatever variable
name you used for the step-5 result) and assert its 'licenseJurisdiction' and
'givenName' fields instead of the earlier snapshot variable.
---
Outside diff comments:
In
`@backend/social-work-app/lambdas/python/common/cc_common/data_model/schema/data_event/api.py`:
- Around line 52-55: HomeJurisdictionChangeEventDetailSchema is missing the
licenseScope field used for audit consistency; update the class
(HomeJurisdictionChangeEventDetailSchema) to include licenseScope with the same
type and validation as the other event detail schemas (e.g. add licenseScope =
LicenseScope(required=True, allow_none=False)) alongside providerId, licenseType
and formerHomeJurisdiction, and ensure the LicenseScope symbol is imported if
not already.
---
Duplicate comments:
In `@backend/social-work-app/docs/design/README.md`:
- Line 333: Replace the typographical error "theSocial WorkCompact" in the
README content with the correct spaced phrase "the Social Work Compact"; locate
the exact string "theSocial WorkCompact" in the documentation text and update it
to "the Social Work Compact" so spacing is correct throughout the sentence.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9e538a51-08f8-461f-99ee-32e859f437dd
⛔ Files ignored due to path filters (1)
backend/social-work-app/docs/design/practitioner-home-state-assignment.pdfis excluded by!**/*.pdf
📒 Files selected for processing (46)
.github/workflows/check-for-external-state-api-spec-update.yml.github/workflows/check-for-internal-api-spec-update.ymlbackend/compact-connect/lambdas/python/common/cc_common/data_model/provider_record_util.pybackend/cosmetology-app/docs/devops/STAFF_USER_MFA_RECOVERY.mdbackend/cosmetology-app/lambdas/python/common/cc_common/data_model/provider_record_util.pybackend/social-work-app/docs/api-specification/latest-oas30.jsonbackend/social-work-app/docs/design/README.mdbackend/social-work-app/docs/devops/STAFF_USER_MFA_RECOVERY.mdbackend/social-work-app/docs/internal/api-specification/latest-oas30.jsonbackend/social-work-app/docs/internal/postman/postman-collection.jsonbackend/social-work-app/docs/postman/postman-collection.jsonbackend/social-work-app/docs/search-internal/api-specification/latest-oas30.jsonbackend/social-work-app/docs/search-internal/postman/postman-collection.jsonbackend/social-work-app/lambdas/nodejs/lib/email/ingest-event-email-service.tsbackend/social-work-app/lambdas/nodejs/lib/models/event-records.tsbackend/social-work-app/lambdas/nodejs/tests/lib/email/ingest-event-email-service.test.tsbackend/social-work-app/lambdas/nodejs/tests/sample-records.tsbackend/social-work-app/lambdas/python/common/cc_common/data_model/data_client.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/provider_record_util.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/common.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/data_event/api.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/__init__.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/api.pybackend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/record.pybackend/social-work-app/lambdas/python/common/cc_common/event_bus_client.pybackend/social-work-app/lambdas/python/common/common_test/test_data_generator.pybackend/social-work-app/lambdas/python/common/tests/function/test_data_client.pybackend/social-work-app/lambdas/python/common/tests/resources/dynamo/license-update.jsonbackend/social-work-app/lambdas/python/common/tests/unit/test_data_model/test_schema/test_license.pybackend/social-work-app/lambdas/python/common/tests/unit/test_provider_record_util.pybackend/social-work-app/lambdas/python/data-events/tests/function/test_encumbrance_events.pybackend/social-work-app/lambdas/python/disaster-recovery/handlers/rollback_license_upload.pybackend/social-work-app/lambdas/python/disaster-recovery/tests/function/test_rollback_license_upload.pybackend/social-work-app/lambdas/python/provider-data-v1/handlers/bulk_upload.pybackend/social-work-app/lambdas/python/provider-data-v1/handlers/ingest.pybackend/social-work-app/lambdas/python/provider-data-v1/handlers/licenses.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_bulk_upload.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_ingest.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_investigation.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_licenses.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.pybackend/social-work-app/lambdas/python/provider-data-v1/tests/unit/test_handlers/test_bulk_upload_unit.pybackend/social-work-app/tests/smoke/investigation_smoke_tests.pybackend/social-work-app/tests/smoke/license_upload_smoke_tests.pybackend/social-work-app/tests/smoke/rollback_license_upload_smoke_tests.pybackend/social-work-app/tests/smoke/smoke_common.py
💤 Files with no reviewable changes (1)
- backend/social-work-app/lambdas/python/common/cc_common/data_model/schema/license/api.py
✅ Files skipped from review due to trivial changes (3)
- backend/compact-connect/lambdas/python/common/cc_common/data_model/provider_record_util.py
- backend/cosmetology-app/lambdas/python/common/cc_common/data_model/provider_record_util.py
- backend/social-work-app/docs/postman/postman-collection.json
🚧 Files skipped from review as they are similar to previous changes (9)
- backend/social-work-app/lambdas/python/common/tests/resources/dynamo/license-update.json
- backend/social-work-app/tests/smoke/rollback_license_upload_smoke_tests.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_licenses.py
- backend/social-work-app/lambdas/python/provider-data-v1/handlers/licenses.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_public_lookup.py
- backend/social-work-app/lambdas/python/provider-data-v1/tests/function/test_handlers/test_bulk_upload.py
- backend/social-work-app/lambdas/python/data-events/tests/function/test_encumbrance_events.py
- backend/social-work-app/lambdas/python/common/cc_common/data_model/data_client.py
- backend/social-work-app/lambdas/python/common/tests/function/test_data_client.py
The previous implementation was not taking into consideration that the best license is the most recent multi-state license that has an associated single-state license. This updates the implementation and adds test cases for each of the conditional branches.
These methods do not need to be referenced outside of the ProviderUserRecords class, as they are primarily intended to be used to generate the api response and opensearch documents. Keeping them private will help encapsulate the logic for finding home state licenses.
|
@jlkravitz This is now ready for another review. Thanks |
jlkravitz
left a comment
There was a problem hiding this comment.
@isabeleliassen This is good to merge!
The Social Work compact needs to support both single and multi-state license types. To support this, we are adding a new license field specific to their API,
licenseScope, which will have a value of eithersingle-stateormulti-state.This change includes updating all of the relevant schemas and tests to account for this new field, and inserts the relevant license types specific for Social Work throughout the codebase.
As part of this, we needed to update the sort keys for our license related DynamoDB records to include the license scope, in order to distinguish the single state versus multi state records when storing these records in the provider DynamoDB table. For adverse actions/investigations, this means the frontend client will now need to specify the license scope as part of the request body when setting/lifting encumbrances and investigations (privilege related records will always have a 'licenseScope' of single-state, since a privilege record in the system is scoped to the state it is associated with).
In addition, the ingest flow now checks for additional conditions to trigger home state changes for providers. A home state change is not triggered until both the single and multi-state licenses have been uploaded for a jurisdiction, and the multi-state license is more recent than any other jurisdiction's multi-state license.
This logic also holds for generating privileges. We only generate privileges for multi-state licenses if the multi-state license is marked as compact eligible and there is an associated single-state license for the same jurisdiction/license type that is also compact eligible. Likewise, if the single-state license is marked as compact ineligible, than the associated multi-state license will also show as compact ineligible in the api response.
Testing List
yarn test:unit:allshould run without errors or warningsyarn serveshould run without errors or warningsyarn buildshould run without errors or warningsbackend/compact-connect/tests/unit/test_api.pyrun compact-connect/bin/download_oas30.pyCloses #1585
Summary by CodeRabbit
New Features
Documentation
Bug Fixes
Tests