Skip to content

feat(spp_dci_demo): add DCI birth verification demo module and Conditional Child Grant#40

Open
jeremi wants to merge 10 commits intofeat/dci-client-improvementsfrom
feat/dci-demo-module
Open

feat(spp_dci_demo): add DCI birth verification demo module and Conditional Child Grant#40
jeremi wants to merge 10 commits intofeat/dci-client-improvementsfrom
feat/dci-demo-module

Conversation

@jeremi
Copy link
Member

@jeremi jeremi commented Feb 17, 2026

Summary

  • Add spp_dci_demo module: DCI-powered birth verification via SPDCI/OpenCRVS for the Add Child Member change request flow
  • CR detail form with inline birth verification (verify BRN, match name/DOB/gender, auto-approve on match)
  • Consolidate auto-approval logic in _after_submit (removed separate wizard)
  • Add _onchange_invalidate_verification to reset verification when verified fields are edited
  • Add demo household data and system parameters for the demo
  • Add Conditional Child Grant program to spp_mis_demo_v2 with event types for child-related life events
  • Utility module (dci_verification.py) for extracting and matching person data from DCI responses
  • Comprehensive tests: birth verification flow, BRN creation on apply, DCI verification utils

Dependencies

Test plan

  • Run test_single_module.sh spp_dci_demo
  • Run test_single_module.sh spp_mis_demo_v2
  • Verify Add Child Member CR form shows birth verification fields
  • Verify DCI verification triggers and auto-approves on match
  • Verify Conditional Child Grant program is created in demo data

Note

Medium Risk
Touches core change-request and program demo flows and adds new verification/enrollment behaviors plus OpenCRVS-specific request formatting, which could affect integrations and downstream data creation if misconfigured.

Overview
Adds a new spp_dci_demo module that extends the Add Member change request flow with DCI/OpenCRVS birth verification (BRN entry, verify/re-verify action, verification invalidation on edits), surfaces verification status on the parent CR form, and ships demo data plus system parameters and a post-init hook for auto-enrollment configuration.

Updates the DCI client and schemas to be SPDCI-spec compliant by switching RegistryType values to namespaced strings, adding OpenCRVS-specific search/envelope building (search_by_id_opencrvs, optional OpenCRVS expression wrapping, and corrected OpenCRVS envelope fields), and expands tests to cover the new OpenCRVS formats.

Enhances registry IDs by adding verification metadata (verification_method, is_verified, etc.) and UI support (form view + list columns), and extends MIS demo content with a new Conditional Child Grant program (new demo constant, event type, and generator support for compliance manager CEL configuration).

Written by Cursor Bugbot for commit a9a731d. This will update automatically on new commits. Configure here.

@gemini-code-assist
Copy link

Summary of Changes

Hello @jeremi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly advances the DCI integration capabilities by introducing a comprehensive demo module for birth verification. It enhances the DCI client to support specific external registry formats like OpenCRVS, making the system more adaptable. Crucially, it integrates verification directly into the change request workflow, enabling automated processing of new member additions and their enrollment into relevant programs based on verified data. This work also lays a stronger foundation for identity verification within the registry by adding dedicated fields to track how IDs are verified.

Highlights

  • DCI Birth Verification Demo Module: Introduced a new module, spp_dci_demo, to showcase DCI-powered birth verification for the 'Add Child Member' change request flow. This includes a CR detail form with inline verification, auto-approval logic, and demo data.
  • OpenCRVS DCI Client Compatibility: Enhanced the DCI client (spp_dci_client) to support OpenCRVS's non-standard DCI query formats. This includes a new search_by_id_opencrvs method and a use_opencrvs_format flag for expression searches, ensuring broader interoperability.
  • Registry ID Verification Fields: Added comprehensive verification fields to the core spp.registry.id model, including verification_method, is_verified (computed), verification_date, verification_source, and verification_response. This provides a standardized way to track ID verification status.
  • Automated BRN Creation and Program Enrollment: Implemented logic within the 'Add Member' change request application process to automatically create a verified Birth Registration Number (BRN) identity document for new individuals if birth verification is successful. Additionally, new members are auto-enrolled into configured programs.
  • Conditional Child Grant Program: Added a new 'Conditional Child Grant' program to the spp_mis_demo_v2 module, targeting children aged 0-2 years with compliance requirements for health checkups and immunizations. This program is used in the DCI demo for auto-enrollment.
  • DCI Registry Type Standardization: Updated the RegistryType enum in spp_dci/schemas/constants.py to use SPDCI spec-compliant namespaced formats, improving consistency with DCI API standards.
Changelog
  • spp_dci/schemas/constants.py
    • Updated RegistryType enum values to SPDCI spec-compliant namespaced format.
  • spp_dci_client/services/client.py
    • Added registry_event_type parameter to search_by_id method.
    • Introduced search_by_id_opencrvs method for OpenCRVS-specific ID searches.
    • Modified search_by_expression to support an use_opencrvs_format flag for OpenCRVS query structures.
    • Refactored _search_by_date_range_opencrvs and _build_search_envelope_opencrvs for improved OpenCRVS envelope construction.
  • spp_dci_client/tests/test_client_service.py
    • Updated test data sources and assertions to reflect new RegistryType values.
    • Added new test cases for TestOpenCRVSEnvelopeFormat to validate OpenCRVS-specific envelope structures and behaviors.
    • Included tests for search_by_expression with and without the OpenCRVS format flag.
  • spp_dci_demo/init.py
    • Added module initialization.
  • spp_dci_demo/manifest.py
    • Added new module manifest for 'OpenSPP DCI Demo', detailing its purpose and dependencies.
  • spp_dci_demo/data/demo_household.xml
    • Added demo household data including 'Adam Masters' and 'Mary Masters' as individuals and a 'Masters Household' group.
  • spp_dci_demo/data/system_parameters.xml
    • Added system parameters for spp_dci_demo.auto_approve_on_match and spp_dci_demo.enrollment_program_id.
  • spp_dci_demo/data/vocabulary_data.xml
    • Added a vocabulary code for 'Birth Registration Number (BRN)'.
  • spp_dci_demo/hooks.py
    • Added a post_init_hook to automatically configure the spp_dci_demo.enrollment_program_id system parameter based on available programs.
  • spp_dci_demo/models/init.py
    • Added model initialization for cr_detail_add_member, cr_apply_add_member, and change_request.
  • spp_dci_demo/models/change_request.py
    • Extended spp.change.request model with computed fields (dci_verification_status, dci_verification_html, dci_data_match) to display DCI birth verification summary on the main CR form.
  • spp_dci_demo/models/cr_apply_add_member.py
    • Extended spp.cr.apply.add_member to create verified BRN registry IDs and auto-enroll new individuals into household programs upon successful birth verification.
  • spp_dci_demo/models/cr_detail_add_member.py
    • Extended spp.cr.detail.add_member with fields for birth_registration_number, birth_verification_status, dci_data_match, birth_verification_date, birth_verification_response, and dci_data_source_id.
    • Added _onchange_invalidate_verification to reset verification status if verified fields are edited.
    • Implemented action_verify_birth method to perform DCI birth verification against a CRVS registry.
    • Added utility methods _parse_dci_response, _extract_person_from_dci_response, and _check_data_matches_dci_response.
  • spp_dci_demo/security/ir.model.access.csv
    • Added security access file (empty).
  • spp_dci_demo/tests/init.py
    • Added test initialization for test_birth_verification, test_apply_creates_brn, and test_dci_verification_utils.
  • spp_dci_demo/tests/test_apply_creates_brn.py
    • Added test cases to verify that applying an 'Add Member' CR creates a verified BRN registry ID when birth is verified.
    • Included tests for scenarios where BRN is not created (unverified, not found, missing BRN number).
    • Added tests for updating existing BRN registry IDs.
    • Added TestRegistryIdVerification class to test is_verified computation on spp.registry.id.
  • spp_dci_demo/tests/test_birth_verification.py
    • Added test cases for the birth verification flow in spp.cr.detail.add_member, covering field existence, default status, required BRN/data source, successful verification (OpenCRVS and standard DCI formats), 'not found' scenarios, and API errors.
  • spp_dci_demo/tests/test_dci_verification_utils.py
    • Added comprehensive test cases for parse_dci_response, extract_person_from_dci_response, and check_data_matches utility functions, covering various DCI response formats and matching logic.
  • spp_dci_demo/utils/init.py
    • Added utility initialization for dci_verification.
  • spp_dci_demo/utils/dci_verification.py
    • Added standalone utility functions: parse_dci_response to determine verification status, extract_person_from_dci_response to normalize person data from DCI responses, and check_data_matches to compare DCI data with CR fields.
  • spp_dci_demo/views/change_request_view.xml
    • Extended the spp.change.request form view to display a DCI birth verification banner with status and summary for reviewers.
  • spp_dci_demo/views/cr_detail_add_member_view.xml
    • Extended the 'Add Member' CR detail form to include a 'Birth Verification' section with fields for BRN, verification status, and 'Verify Birth'/'Re-verify' buttons.
    • Hid 'Contact Information' and 'Relationship to Head' sections for demo purposes.
  • spp_mis_demo_v2/data/event_types.xml
    • Added a new Health Visit event type.
    • Updated descriptions for existing event types to wrap text for better readability.
  • spp_mis_demo_v2/models/demo_programs.py
    • Updated program catalog count from 6 to 7.
    • Added a new Conditional Child Grant program definition, including CEL expressions for eligibility and compliance.
    • Updated entitlement_formula and cel_expression for elderly_social_pension to improve readability.
  • spp_mis_demo_v2/models/demo_variables.py
    • Added first_1000_days_grant to demo variables.
  • spp_mis_demo_v2/models/mis_demo_generator.py
    • Modified _create_demo_programs to configure compliance managers based on compliance_cel_expression in program definitions.
    • Added _configure_compliance_manager method to set compliance CEL expressions for programs.
  • spp_registry/models/reg_id.py
    • Added new fields for ID verification: verification_method, is_verified (computed), verification_date, verification_source, and verification_response.
    • Implemented _compute_is_verified to determine verification status based on the method.
  • spp_registry/views/reg_id_view.xml
    • Added a new form view for spp.registry.id to display all ID information and new verification fields.
    • Updated the tree view for spp.registry.id to include is_verified and verification_method fields.
Activity
  • jeremi created the pull request with a detailed summary of the new spp_dci_demo module and its features, including DCI-powered birth verification and Conditional Child Grant.
  • The initial commit introduced the core functionality for DCI client compatibility with OpenCRVS, new verification fields in spp.registry.id, and the spp_dci_demo module with its models, data, and views.
  • Subsequent commits refined the DCI client's OpenCRVS integration, added comprehensive test coverage for verification flows and utility functions, and configured the demo programs and data.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a DCI-powered birth verification demo, a new Conditional Child Grant program, and refactors the DCI client for better OpenCRVS compatibility. While the changes are generally well-structured, a critical security vulnerability exists: Personally Identifiable Information (PII), such as names, birth dates, and registration numbers from DCI request/response data, is logged to an audit model and included in exception messages. This PII must be sanitized or masked to comply with data protection principles. Furthermore, a high-severity bug in the auto-enrollment logic prevents new child enrollment, and a medium-severity issue involves a missing system parameter definition. Addressing these points will make this an excellent addition.

Comment on lines +174 to +177
if hasattr(household, "group_membership_ids"):
for membership in household.group_membership_ids:
if membership.individual:
self._enroll_partner_in_program(membership.individual, program)

Choose a reason for hiding this comment

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

high

The auto-enrollment logic for the new child is likely to fail. The household record's cache for group_membership_ids is probably stale after the super().apply() call and won't include the newly created member. As a result, the loop over group_membership_ids will skip the new child.

To fix this, you should invalidate the cache for this field on the household record before iterating over the members. This ensures the new child is included in the enrollment process.

Suggested change
if hasattr(household, "group_membership_ids"):
for membership in household.group_membership_ids:
if membership.individual:
self._enroll_partner_in_program(membership.individual, program)
# Enroll all household members including the new child
household.invalidate_recordset(["group_membership_ids"])
if hasattr(household, "group_membership_ids"):
for membership in household.group_membership_ids:
if membership.individual:
self._enroll_partner_in_program(membership.individual, program)

# Re-raise UserError as-is
raise
except Exception as e:
_logger.exception("Birth verification failed for BRN %s", self.birth_registration_number)

Choose a reason for hiding this comment

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

security-medium medium

The action_verify_birth method logs the Birth Registration Number (BRN) in an exception message using _logger.exception. BRN is considered Personally Identifiable Information (PII). Logging PII in system logs is generally discouraged as it may lead to unauthorized data exposure if log files are not properly secured or are aggregated into less secure logging systems.

Choose a reason for hiding this comment

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

medium

The code attempts to read the system parameter spp_dci_demo.default_crvs_data_source, but this parameter is not defined in any of the module's data files (e.g., data/system_parameters.xml). While the code correctly falls back to searching for a data source, this makes the configuration via system parameter non-functional out of the box. Consider adding this parameter to your data files for completeness and to make the feature fully configurable.

<record id="param_auto_approve_on_match" model="ir.config_parameter">
<field name="key">spp_dci_demo.auto_approve_on_match</field>
<field name="value">True</field>
</record>
Copy link

Choose a reason for hiding this comment

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

Auto-approval on match feature is not implemented

High Severity

The spp_dci_demo.auto_approve_on_match system parameter is defined and set to True, and the module description explicitly states "CR auto-approved if verification matched", but no code ever reads this parameter or implements the auto-approval logic. The _after_submit hook (mentioned in the PR description as the consolidation point for auto-approval) is never overridden in spp_dci_demo. After a successful birth verification with matching data, submitting the CR will not auto-approve it — it will follow the normal manual approval flow, contradicting the documented behavior and the purpose of the parameter.

Additional Locations (1)

Fix in Cursor Fix in Web

Returns:
Dict with normalized person data or None if not found
"""
return extract_person_from_dci_response(response)
Copy link

Choose a reason for hiding this comment

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

Model method _extract_person_from_dci_response is unused dead code

Low Severity

The _extract_person_from_dci_response method is defined on the model but never called anywhere in the codebase. The only caller of the extraction logic, _check_data_matches_dci_response, directly invokes the standalone utility function extract_person_from_dci_response instead of going through this wrapper method. This is dead code that adds confusion about which extraction path is actually used.

Fix in Cursor Fix in Web

CRVS = "ns:org:RegistryType:Civil"
IBR = "ns:org:RegistryType:IBR"
DISABILITY_REGISTRY = "ns:org:RegistryType:DR"
FUNCTIONAL_REGISTRY = "ns:org:RegistryType:FR"
Copy link

Choose a reason for hiding this comment

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

RegistryType enum value change lacks data migration

Medium Severity

The RegistryType enum values changed from short strings (e.g., "CRVS", "SOCIAL_REGISTRY") to namespaced strings (e.g., "ns:org:RegistryType:Civil", "ns:org:RegistryType:Social"), but there is no data migration for existing spp.dci.data.source records. Existing records still store the old values in the registry_type Selection field, which no longer match any valid option. This causes _get_registry_type() to silently fall back to SOCIAL_REGISTRY for CRVS sources, and crvs_service.py to reject them outright with a ValidationError.

Additional Locations (1)

Fix in Cursor Fix in Web

@jeremi jeremi force-pushed the feat/dci-client-improvements branch from db3b9a4 to 3ea418e Compare February 18, 2026 14:50
Features:
- Birth verification via OpenCRVS DCI integration
- Auto-approval when DCI data matches CR detail fields
- Auto-enrollment of household in configured program on CR apply
- Add Child wizard for streamlined UX
- Verified BRN registry ID created on apply

Technical:
- Add search_by_id_opencrvs method for OpenCRVS-specific format
- Extract DCI verification logic to utils module
- Add system parameters for configuration
- Add post_init_hook for auto-configuration

Note: DCI data source credentials must be configured manually
via Settings > Technical > System Parameters or UI.
…exists

Add computed single_dci_data_source field to auto-hide the DCI data
source dropdown when there is zero or one active Civil registry,
removing an unnecessary selection step from the UI.
…after_submit

The DCI demo wizard adds no value over the standard CR flow now that
detail forms have Submit buttons. Remove the wizard and its tests, and
remove the duplicated _try_auto_approve() from the detail model. Auto-
approval now only happens via the _after_submit() hook on the CR model.
…emo household

- Add Masters household (Adam + Mary) as demo data for DCI CR flow
- Hide Contact Information and Relationship fields in add-member form
- Target Conditional Child Grant program in post_init_hook
- Add Conditional Child Grant program with first-1,000-days eligibility
- Add Health Visit event type for compliance tracking
- Configure compliance manager with CEL expression support
…add system parameter

Invalidate household group_membership_ids cache before iterating so the
newly created child membership is included in auto-enrollment.

Add missing spp_dci_demo.default_crvs_data_source system parameter with
an empty default to system_parameters.xml so the parameter is defined on
module install.
@jeremi jeremi force-pushed the feat/dci-demo-module branch from eb68e0d to 76e158e Compare February 18, 2026 14:55
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

if "sex" in person_data:
normalized["sex"] = person_data["sex"].lower()
elif "gender" in person_data:
normalized["sex"] = person_data["gender"].lower()
Copy link

Choose a reason for hiding this comment

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

Null API values cause AttributeError in extraction

Medium Severity

extract_person_from_dci_response calls .lower() on person_data["sex"] and person_data["gender"] without guarding against None. If the API returns {"sex": null}, None.lower() raises AttributeError. The same issue exists at lines 106–107 where name.get("given_name", "") returns None (not "") when the key exists with a null value, causing .strip() to fail. The outer exception handler catches this but incorrectly reports an "error" verification status.

Additional Locations (1)

Fix in Cursor Fix in Web

"cycle_duration": 30, # Monthly
# CEL: Households with children under 2 (first 1,000 days)
# Pattern: Member age check via members.exists()
"cel_expression": "r.is_group == true and members.exists(m, age_years(m.birthdate) < 2)",
Copy link

Choose a reason for hiding this comment

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

Eligibility CEL expression contradicts program description

Low Severity

The Conditional Child Grant cel_expression uses age_years(m.birthdate) < 2 (targeting children aged 0–1 only), but the description says "children aged 0-2" and the demo_points say "0-2 years." The compliance_cel_expression correctly uses <= 2 (ages 0–2). Since age_years returns a floored integer, < 2 excludes 2-year-olds from eligibility despite the description including them. The eligibility expression likely needs <= 2 to match the stated intent.

Additional Locations (2)

Fix in Cursor Fix in Web

Copy link
Contributor

@emjay0921 emjay0921 left a comment

Choose a reason for hiding this comment

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

Code review complete. Well-structured demo module with clean separation of concerns. No blockers found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments