Commit Graph
6493 Commits
Author SHA1 Message Date
Ben WestandCopilot 729a6f5234 Add single object and empty array tests for entries API
- Add test for single entry returns array with one item
- Add test for empty array returns empty result
- Validates response format consistency for entries API

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 16:01:35 -07:00
Ben WestandCopilot eacb6fca91 Add single object and array tests for activity API
- Add test for single activity returns array with one item
- Add test for activity array returns array
- Add test for empty array returns empty array
- Rename test file to follow *.test.js convention

Validates array normalization behavior for activity API.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 16:00:18 -07:00
Ben WestandCopilot c6c60af906 Add array input tests for food API
- Add tests for POST with array of foods
- Add tests for PUT with array of foods
- Add test for empty array returning empty array
- Fix PUT endpoint to normalize array input like POST
- Fix food.save() storage to handle arrays with bulkWrite
- Rename test file to follow *.test.js convention

Validates fix from ef7bff3d for complete array handling.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 15:58:50 -07:00
Ben WestandCopilot 67d2099331 perf: optimize activity and food storage with bulkWrite
Replace sequential replaceOne calls with bulkWrite for batch upserts.
This improves performance when inserting multiple documents at once.

- activity.js: Use bulkWrite with replaceOne ops instead of forEach loop
- food.js: Same optimization for consistency

Both maintain exact same upsert behavior (query by _id+created_at or doc).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 14:49:25 -07:00
Ben WestandCopilot ef7bff3d53 fix(food): add array support to food API POST
Add array normalization to food API POST endpoint:
- API layer: normalize single object to array (like activity/profile)
- Storage layer: use replaceOne loop with upsert (same as activity pattern)
- Storage layer: accept both single object and array for backward compat

Previously POST /api/food/ with array input would crash:
  insertOne([{...}]) → MongoDB error

Now supports both single object and array input consistently.
Response format is now array (matching treatments pattern).

Fixes #8447

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 14:06:16 -07:00
Ben WestandCopilot 808b923e8e feat(api): add _id validation to activity and food APIs
Add validation for _id field in activity and food APIs:
- activity: POST, PUT, DELETE now validate _id format
- food: POST, PUT, DELETE now validate _id format

Accepts: undefined, null, or 24-character hex string
Rejects: UUIDs, short strings, numbers, objects with 400 Bad Request

Previously:
- activity: 500 crash on invalid _id in save/remove
- food: silently replaced invalid _id with new ObjectId (data loss)

Tests added covering all validation cases.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 11:05:40 -07:00
Ben WestandCopilot 8d44a04304 feat(devicestatus): return 400 for invalid _id format
Add validation for _id field in devicestatus API:
- POST: validates each document's _id before storage
- DELETE: validates _id parameter (allows wildcard '*')

Accepts: undefined, null, or 24-character hex string
Rejects: UUIDs, short strings, numbers, objects with 400 Bad Request

Previously, invalid _id values were silently stored as strings instead
of ObjectIds, causing inconsistent data and query issues.

Tests added for all validation cases.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 11:02:31 -07:00
Ben WestandCopilot 32b1d70074 feat(profile): return 400 for invalid _id format
Add validation for _id field in profile API:
- POST: validates each document's _id before storage
- PUT: validates _id format before update
- DELETE: validates _id parameter before removal

Accepts: undefined, null, or 24-character hex string
Rejects: UUIDs, short strings, numbers, objects with 400 Bad Request

This prevents 500 errors from BSONError when clients send
UUID-style _ids (e.g., NightscoutKit).

Tests added for all validation cases.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 10:57:20 -07:00
Ben WestandCopilot 5f5bf224a6 Add API array handling test matrix with NightscoutKit fixtures
Extends api.shape-handling.test.js with:

Profile API tests:
- Single profile object POST
- Single-element array POST (NightscoutKit format)
- Multi-element array POST (batch upload)
- Response count equals input count validation
- Empty array handling
- Response shape consistency (always returns array)

NightscoutKit Fixtures Integration tests:
- Bolus treatments with syncIdentifier
- Carb entries with absorption time
- Temp basal treatments
- Mixed batch arrays
- Loop devicestatus with IOB/COB
- Batch devicestatus arrays
- Loop profile with loopSettings
- Historical profile batch sync

Test matrix coverage per spec in profile-api-array-regression.md:
| API | Single | Array | Batch | Empty | Response=Array | _id present |
|-----|--------|-------|-------|-------|----------------|-------------|
| Treatments |  |  |  |  |  |  |
| DeviceStatus |  |  |  |  |  |  |
| Entries |  |  |  |  |  |  |
| Profile |  |  |  |  |  |  |

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 10:38:34 -07:00
Ben WestandCopilot 83248e7f1d Add NightscoutKit treatment fixtures for API testing
Extract treatment fixture patterns from NightscoutKit Swift source:
- BolusNightscoutTreatment (Correction Bolus)
- CarbCorrectionNightscoutTreatment (Carb Correction)
- TempBasalNightscoutTreatment (Temp Basal)
- OverrideTreatment (Temporary Override)
- MealBolusNightscoutTreatment (Meal Bolus)
- BGCheckNightscoutTreatment (BG Check)
- NoteNightscoutTreatment (Note)
- Site Change, Sensor Start

Includes:
- Individual treatment objects for each type
- Array-wrapped formats (what NightscoutKit actually sends)
- Batch upload arrays for testing
- Helper functions for generating unique fixtures
- syncIdentifier field handling (client-provided dedup ID)

Source files:
- externals/NightscoutKit/Sources/NightscoutKit/Models/Treatments/*.swift
- externals/NightscoutKit/Sources/NightscoutKit/NightscoutClient.swift

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 10:34:57 -07:00
Ben WestandCopilot 269170b970 fixtures: add NightscoutKit devicestatus fixtures for array testing
Extract devicestatus structure from NightscoutKit Swift source:
- DeviceStatus.swift: top-level structure with device, created_at, identifier
- LoopStatus.swift: name, version, iob, cob, predicted, enacted, failureReason
- PumpStatus.swift: pumpID, manufacturer, model, reservoir, battery
- IOBStatus.swift: iob, basaliob with timestamp
- COBStatus.swift: cob with timestamp
- PredictedBG.swift: startDate, values array, optional COB/IOB curves
- LoopEnacted.swift: rate, duration (minutes), received, bolusVolume
- UploaderStatus.swift: name, battery percentage
- BatteryStatus.swift: percent, voltage, status

Fixtures include:
- minimal: Just device and timestamp
- loopWithIOBCOB: Loop status with IOB/COB
- fullLoop: Complete status with pump, predictions, enacted
- withEnacted: Status with active temp basal
- withFailure: Status with failureReason
- withAutoBolus: Status with automatic dose recommendation
- withMultiplePredictions: COB and IOB prediction curves
- singleArray: Single status in array format
- batchArray: 3 statuses for batch upload testing
- helpers: Factory functions for building custom fixtures

NightscoutKit sends devicestatus as arrays (NightscoutClient.swift:646-647).

Sources:
  externals/NightscoutKit/Sources/NightscoutKit/Models/DeviceStatus.swift
  externals/NightscoutKit/Sources/NightscoutKit/Models/LoopStatus.swift
  externals/NightscoutKit/Sources/NightscoutKit/Models/PumpStatus.swift
  externals/NightscoutKit/Sources/NightscoutKit/Models/IOBStatus.swift
  externals/NightscoutKit/Sources/NightscoutKit/Models/COBStatus.swift
  externals/NightscoutKit/Sources/NightscoutKit/Models/PredictedBG.swift
  externals/NightscoutKit/Sources/NightscoutKit/Models/LoopEnacted.swift

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 10:32:03 -07:00
Ben WestandCopilot 9fd53e324a fixtures: add NightscoutKit profile fixtures for array testing
Extract profile structure from NightscoutKit Swift source:
- ProfileSet.swift: dictionaryRepresentation structure
- LoopSettings.swift: loopSettings with overrides, dosing params
- TemporaryScheduleOverride.swift: override presets format

Fixtures include:
- minimal: Minimal valid profile
- fullLoop: Full profile with loopSettings and schedules
- withActiveOverride: Profile with active schedule override
- mmol: mmol/L units variant
- singleArray: Single profile in array (most common case)
- batchArray: 3 profiles for batch upload testing
- generateUniqueProfile(): Helper for dedup testing

NightscoutKit always sends profiles as arrays (NightscoutClient.swift:404).

Sources:
  externals/NightscoutKit/Sources/NightscoutKit/Models/ProfileSet.swift
  externals/NightscoutKit/Sources/NightscoutKit/Models/LoopSettings.swift
  externals/NightscoutKit/Sources/NightscoutKit/Models/TemporaryScheduleOverride.swift

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 10:29:15 -07:00
Ben WestandCopilot 2e81ce07e5 fix(devicestatus): purify each item in array input
The API layer was calling purifyObject() on the raw req.body without
handling arrays. When NightscoutKit sends [status], only the outer
array would be purified (no-op), not the individual status objects.

Now normalizes to array and purifies each devicestatus object,
matching the treatments pattern.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 10:26:16 -07:00
Ben WestandCopilot cbb6d06107 fix(profile): restore array handling for profile POST API
NightscoutKit (Loop) sends profiles wrapped in arrays: [profile].
The MongoDB driver migration changed insert() to insertOne(), breaking
array support.

Changes:
- API layer: normalize input to array, purify each item
- Storage layer: use insertMany() instead of insertOne()
- Tests: verify single, array, and empty array handling

This matches the proven pattern from treatments API.

Fixes array handling regression introduced in d46c5b41.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 10:24:48 -07:00
Ben WestandCopilot 22f325c132 fix(tests): add missing closing brace in uuid-handling.test.js
First describe block was missing its closing });

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 17:17:33 -07:00
Ben WestandGitHub 18c10565bc Merge pull request #8457 from nightscout/copilot/sub-pr-8456
fix: gate UUID_HANDLING on both write and read paths; fix doc accuracy
2026-03-17 17:11:40 -07:00
copilot-swe-agent[bot]andbewest 002f34fcda fix: gate UUID write-path normalization on UUID_HANDLING flag and fix docs accuracy
Co-authored-by: bewest <394179+bewest@users.noreply.github.com>
2026-03-17 23:44:47 +00:00
copilot-swe-agent[bot] d1c9f185ac Initial plan 2026-03-17 23:32:08 +00:00
Ben WestandCopilot 095c9d0454 fix: remove scope creep from UUID handling (syncIdentifier/uuid dedup)
UUID_HANDLING should ONLY affect UUID values in the _id field.
Previous commit incorrectly added server-side dedup for syncIdentifier
and uuid fields, which was never part of the original behavior.

Changes:
- upsertQueryFor(): Remove syncIdentifier/uuid as dedup keys
- Batch POST: Only fetch existing IDs by identifier, not by
  syncIdentifier/uuid
- tests: Update TEST-CACHE-003/004 to document actual behavior
  (duplicates occur without ObjectIdCache - this is by design)
- docs: Correct treatments-schema.md (syncIdentifier/uuid preserved,
  not copied to identifier)
- docs: Remove external link from entries-schema.md

Loop carbs/doses rely on ObjectIdCache for dedup, not server-side logic.
This matches the original (pre-change) server behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 16:00:03 -07:00
Ben WestandCopilot a432b5cf8c docs(changelog): correct UUID handling scope description
syncIdentifier and uuid fields are used for dedup, not copied to
identifier. Only UUID values in _id field are extracted to identifier.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 15:37:00 -07:00
Ben WestandCopilot 8fc155aa48 fix(treatments): correct UUID handling scope (only _id field)
REQ-SYNC-072 scope correction: normalizeTreatmentId() should ONLY
handle UUID values in the _id field, not copy syncIdentifier or uuid
fields to identifier.

Changes:
- normalizeTreatmentId(): Only extract UUID from _id to identifier
- normalizeEntryId(): Same fix for entries collection
- upsertQueryFor(): Add syncIdentifier and uuid as dedup fallbacks
  (fields are preserved, not copied to identifier)
- Batch POST: Fetch _id for docs deduped by syncIdentifier/uuid

Test updates:
- TEST-ID-003, TEST-V1-ID-004: Updated to expect identifier NOT copied
  from syncIdentifier (scope fix)

Affected clients:
- Loop overrides (UUID _id → identifier): Still works
- Loop carbs/doses (syncIdentifier): Dedup works, no identifier copy
- xDrip+ (uuid): Dedup works, no identifier copy
- AAPS (identifier): Unchanged

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 15:21:25 -07:00
Ben WestandCopilot 013e7b6efd fix(tests): update UUID_HANDLING test for new default
UUID_HANDLING default changed to true in 15.0.7. Test now explicitly
sets UUID_HANDLING=false rather than deleting the env var.

742 passing, 1 pending.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 14:59:05 -07:00
Ben WestandCopilot c1bece1386 docs: clarify write vs read path in schema docs
- Write normalization (syncIdentifier/uuid → identifier) is ALWAYS on
- UUID_HANDLING flag only controls READ path (GET/DELETE by UUID)
- Fix default: UUID_HANDLING=true (not false)
- Remove incorrect xDrip+ mention from entries (doesn't use UUID _id)
- Clarify that flag only affects API calls with UUID as _id parameter

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 14:45:52 -07:00
Ben WestandCopilot 86e0564694 docs: clarify UUID_HANDLING only affects _id field, not all UUIDs
The feature only handles the specific case where a UUID is sent as
the _id field itself. It does NOT affect:
- AAPS (uses 'identifier' field)
- xDrip+ (uses 'uuid' field)
- Loop carbs/doses (uses 'syncIdentifier' field)

Only affects:
- Loop overrides (_id: syncIdentifier.uuidString)
- Trio CGM entries (_id: UUID)

See docs/10-domain/client-id-handling-deep-dive.md for full analysis.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 14:40:37 -07:00
Ben WestandCopilot ca22e8d930 docs: fix MongoDB pool default values to match code
Actual defaults in lib/storage/mongo-storage.js:
- MONGO_POOL_SIZE: 5 (not 10)
- MONGO_MIN_POOL_SIZE: 0 (not 1)
- MONGO_MAX_IDLE_TIME_MS: 30000 (not 10000)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 14:36:34 -07:00
Ben WestandCopilot a2c6ce1e5a docs: use neutral wording for UUID handling description
Avoid implying all AID clients use the same pattern or that any
specific implementation is incorrect. Different clients have
divergent sync patterns - the feature accommodates this variety.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 14:32:05 -07:00
Ben WestandCopilot abb505b256 docs: add MongoDB pool settings and advanced test scripts
README.md:
- Add MONGO_POOL_SIZE, MONGO_MIN_POOL_SIZE, MONGO_MAX_IDLE_TIME_MS
  to Core section for production tuning

CONTRIBUTING.md:
- Add 'Advanced Test Scripts' section documenting:
  - test:stress for concurrent write testing
  - test:flaky variants for detecting flaky tests
  - test:timing for finding slow tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 14:28:02 -07:00
Ben WestandCopilot 3bb100836b fix: change UUID_HANDLING default to true
Update default from false to true to enable AID client compatibility
out of the box:

- lib/server/env.js: readENVTruthy('UUID_HANDLING', true)
- README.md: Document UUID_HANDLING in Features section
- docs/example-template.env: Update comments, show true as default

Rationale:
- Loop, Trio, AAPS, xDrip+ use UUID sync patterns by default
- Before MongoDB 5.x, UUID _id didn't crash (just didn't CRUD properly)
- ObjectID users completely unaffected (quirk only triggers on UUID)
- Can set UUID_HANDLING=false for strict mode if needed

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 14:17:48 -07:00
Ben WestandCopilot 942263c4d3 docs: fix _id format in entries example (string, not Extended JSON)
API returns _id as plain string "507f1f77bcf86cd799439011", not
MongoDB Extended JSON format {"$oid": "..."}.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 14:11:47 -07:00
Ben WestandCopilot 113d27cc7e docs: add entries schema documentation with UUID handling
Document entries collection fields, sysTime+type dedup behavior,
and identifier normalization for Trio/xDrip+ UUID _id uploads.

Refs: DOC-API-002, REQ-SYNC-072, GAP-SYNC-045

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 13:44:31 -07:00
Ben WestandCopilot 551f6dfac6 docs: add test environment variables section to CONTRIBUTING.md
Document MongoDB pool settings and AUTH_FAIL_DELAY for test tuning.
Useful for CI or resource-constrained environments.

Refs: DOC-ENV-002

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 13:42:59 -07:00
Ben WestandCopilot f37f44e8c8 test: add UUID edge case tests
Add 7 edge case tests for UUID_HANDLING:
- UUID-EDGE-001: 23-char hex (invalid ObjectId)
- UUID-EDGE-002: 25-char hex (too long)
- UUID-EDGE-003: UUID without hyphens not recognized
- UUID-EDGE-004: Empty _id query
- UUID-EDGE-005: Same identifier upsert behavior
- UUID-EDGE-006: Uppercase UUID matching
- UUID-EDGE-007: Valid ObjectId still works

Refs: uuid-test-edge, REQ-SYNC-072

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 13:40:59 -07:00
Ben WestandCopilot f91837f874 test: add UUID_HANDLING feature flag tests
Add 6 tests verifying UUID_HANDLING env var behavior:
- UUID-OFF-001: GET by UUID returns empty (no crash)
- UUID-OFF-002: DELETE by UUID deletes nothing (no crash)
- UUID-ON-001: GET by UUID finds treatment via identifier
- UUID-ON-002: DELETE by UUID removes treatment via identifier
- UUID-ON-003: ObjectId still works normally
- UUID-ON-004: Non-matching UUID returns empty

Tests use clearModuleCache() to reload env.js with different flag values.

Refs: uuid-test-flag-off, uuid-test-flag-on, REQ-SYNC-072

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 13:39:03 -07:00
Ben WestandCopilot 358941bba2 fix(tests): use fixed timestamp in BWP test for determinism
Replace Date.now() with the pre-captured 'now' variable in the
'set a pill to BWP with infos' test. This prevents timing drift
between when test data timestamps are set and when the sandbox
is initialized, eliminating flaky failures in CI environments.

Refs: BWP-TIME-001, GAP-TEST-001

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 13:28:12 -07:00
Ben WestandCopilot d987e55cb1 docs: add UUID_HANDLING to example-template.env
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 13:21:29 -07:00
Ben WestandCopilot bf6cfb7730 feat: add UUID_HANDLING feature flag for GET/DELETE by identifier
- env.js: Add UUID_HANDLING env var (default: false)
- query.js: Add UUID detection in normalizeIdValue()
  - When UUID_HANDLING=true and _id is UUID, search by identifier field
  - Returns searchByIdentifier flag to redirect query
- treatments.js: Move queryOpts inside query_for() for env access
- entries.js: Same pattern for entries collection

When UUID_HANDLING=true:
- GET /treatments/{uuid} searches by identifier field
- DELETE /treatments/{uuid} deletes by identifier field
- Same behavior for entries collection

When UUID_HANDLING=false (default):
- UUID _id values return empty results (safe, no crash)
- Maintains backwards compatibility

Refs: uuid-feature-flag, uuid-query-impl from uuid-identifier-lookup.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 13:21:14 -07:00
Ben WestandCopilot 4e79654d9f docs: add identifier field documentation and CHANGELOG for 15.0.7
- docs/data-schemas/treatments-schema.md: Document REQ-SYNC-072 identifier normalization
  - Describe how Loop/AAPS/xDrip+ sync fields are unified into identifier
  - Add example showing UUID _id → identifier promotion
  - Update sync/reconciliation fields table
- CHANGELOG.md: Create changelog for 15.0.7 release
  - Document UUID/identifier handling (REQ-SYNC-072)
  - Document test infrastructure improvements (GAP-SYNC-046)
  - Document Node.js/MongoDB requirement changes
  - Document bug fixes and documentation updates

Addresses DOC-API-001 and DOC-CHANGELOG from release-15.0.7-documentation.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 13:04:13 -07:00
Ben WestandCopilot 81393a4c1f docs: update Node.js requirements and add test documentation
- README.md: Update from Node 14/16 to Node 20+ (v22, v24 supported)
- README.md: Update MongoDB from 4.2/4.4 to 4.4+ (5.0, 6.0 supported)
- CONTRIBUTING.md: Add 'Running Tests Locally' section
- Document NODE_ENV=test requirement for safety
- Document npm scripts: test:unit, test:integration

Addresses DOC-NODE-001 and DOC-ENV-001 from release-15.0.7-documentation.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-17 13:02:12 -07:00
Andy LowandGitHub cdef1e7c2c Merge pull request #8421 from bewest/wip/bewest/mongodb-5x
Wip/bewest/mongodb 5x
2026-03-16 19:37:34 +00:00
Ben WestandCopilot 96f9697866 test: add retry to AAPS entry dedup test for CI flakiness
This test passes locally in ~50ms but occasionally times out at 30s
in constrained GitHub runners. Adding retries(2) allows it to recover
from transient CI resource contention.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-12 14:16:21 -07:00
Ben WestandCopilot b76fb3e18a test: remove completed MongoDB 5.x array investigation tests
The 'WebSocket dbAdd Array Handling Investigation' block was R&D to
understand insertOne behavior with arrays. The investigation concluded:
- MongoDB's insertOne([a,b]) creates single doc (not multiple)
- Fix: sequential processing via processNextItem() in websocket.js

Production tests now cover this behavior:
- 'dbAdd with array input for treatments - current behavior test'
- 'dbAdd with array input for devicestatus - current behavior test'
- 'dbAdd with array input for entries - current behavior test'

Removes 2 flaky investigative tests, keeps 729 production tests passing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-12 14:09:36 -07:00
Ben WestandCopilot ee3e6af76e ci: temporarily allow Node 20 for branch protection compliance
GitHub deprecated Node 20 on runners (2025-09-19), but branch protection
rules still require Node 20 tests to pass. Set ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true
only for the test job, not publish.

Reverts node-version matrix to [20, 22] to match master.

Ref: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-12 12:49:43 -07:00
Ben WestandCopilot e12cf3d2e2 fix(tests): make NODE_ENV=test check a hard failure (GAP-SYNC-046)
Change from warning to process.exit(1) to prevent any possibility of
running destructive test operations against a production database.

Tests now fail immediately if NODE_ENV !== 'test', with clear instructions
on how to fix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-12 12:39:01 -07:00
Ben WestandCopilot 61501cac3a feat(tests): add NODE_ENV=test safety check (GAP-SYNC-046)
SAFETY-001: Fix tests/ci.test.env to use NODE_ENV=test instead of production
SAFETY-002: Add NODE_ENV check to tests/hooks.js with warning
SAFETY-003: Create tests/fixtures/test-guard.js with guarded deleteMany/drop helpers

This prevents deleteMany({}) from accidentally running against production
databases if test environment is misconfigured.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-12 12:24:15 -07:00
Ben WestandCopilot b88155057c fix(entries): handle UUID _id in CGM entries (GAP-SYNC-045)
Trio/Loop upload CGM entries with UUID strings as _id field.
This caused MongoDB errors when re-uploading with different UUID
at same timestamp: "immutable field '_id'" error.

Fix:
- Add normalizeEntryId() to extract UUID from _id to identifier field
- Add upsertQueryFor() to strip non-ObjectId _id before $set
- Maintain sysTime+type as primary dedup key for CGM data integrity
- Add identifier to indexed fields

Tests:
- 3 baseline tests document current sysTime+type dedup behavior
- 6 UUID handling tests including the previously-failing scenario

Refs: GAP-SYNC-045, REQ-SYNC-072

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-11 14:36:23 -07:00
Ben West 3758b6e339 github deprecates node 20 on runners 2026-03-10 16:35:16 -07:00
Ben WestandCopilot abd89f7935 test: add v3 API identifier generation tests (REQ-SYNC-072)
TEST-V3-ID-001: Null identifier generates ObjectId, copies to identifier
TEST-V3-ID-002: ObjectId string as identifier uses it directly
TEST-V3-ID-003: UUID string identifier preserved as-is

Validates Option G behavior extends to v3 API endpoints.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-10 16:13:51 -07:00
Ben WestandCopilot 02eec1b5a7 test: add identifier field tests for AAPS pattern (REQ-SYNC-072)
Add 3 new tests for explicit identifier field handling:
- supports identifier field for AAPS-style treatments
- deduplicates by identifier on re-upload
- supports batch upload with identifiers

These complement existing UUID _id tests (Loop pattern) to cover
both AID client sync patterns.

Refs: REQ-SYNC-072, GAP-TREAT-012

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-10 15:26:39 -07:00
Ben WestandCopilot 595219f9c4 Add Loop SGV entry and DeviceStatus upload tests
SGV Entry Tests (TEST-SGV-001 to 005):
- Single SGV with required fields
- All direction values
- Loop device identifier preserved
- Dexcom device with filtered/unfiltered/noise
- SGV deduplication by date+device
- Different devices create separate entries
- MBG (manual BG check) entries

DeviceStatus Tests (TEST-DS-001 to 005):
- Loop status with IOB/COB
- Loop predicted values array
- Loop enacted temp basal
- Pump reservoir and battery
- Omnipod specific fields
- Override in deviceStatus
- Override with insulinNeedsScaleFactor
- Complete Loop deviceStatus

17 new tests, all passing (716 total).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-10 15:03:48 -07:00
Ben WestandCopilot 16191f9c99 Add Loop carb and dose upload tests
Carb Tests (TEST-CARB-001 to 004):
- Create carb with syncIdentifier and absorptionTime
- Create carb with fat/protein (Warsaw FPU method)
- Create carb with cached _id
- Update carb via cached _id
- Delete carb via cached _id

Dose Tests (TEST-DOSE-001 to 005):
- Bolus with syncIdentifier
- Meal bolus with carbs and insulin
- Temp basal with rate and duration
- Suspend (zero rate) temp basal
- Update dose via cached _id
- Hex string syncIdentifier (pump events)
- Mixed dose batch maintains order

13 new tests, all passing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-10 15:00:16 -07:00