Commit Graph
6505 Commits
Author SHA1 Message Date
15a5fb24d3 fix(profile): use replaceOne upsert to prevent duplicate key error on save (#8455)
Regression from 286fa07 (switch profile api to new mongo driver) caused
E11000 duplicate key errors when saving an existing profile because
insertOne rejects documents whose _id already exists.

Changes:
- Replace insertOne with replaceOne({ _id }, obj, { upsert: true })
- Add try/catch for ObjectID construction to handle invalid/missing _id
- Use hasOwnProperty check for created_at to preserve explicit values

Tests added:
- save() updates existing profile by _id (from PR #8455)
- save() generates _id when none provided
- save() generates _id when invalid _id provided
- save() preserves explicit created_at without overwriting

Cherry-picked from AndyLow91/cgm-remote-monitor@55a70139 with
additional regression tests.

Closes nightscout/cgm-remote-monitor#8455

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-19 12:06:56 -07:00
Ben WestandCopilot 246e46adb3 fix: legacy UUID treatments findable via $or fallback (#6923)
updateIdQuery() and upsertQueryFor() now use
  {$or: [{identifier: UUID}, {_id: UUID}]}
instead of only {identifier: UUID}. This matches both:
- New documents (UUID in identifier field, ObjectId in _id)
- Legacy documents (UUID directly in _id, no identifier field)

Gated behind env.uuidHandling (UUID_HANDLING env var, default true).

All 30 treatment tests pass:
- 3 legacy UUID tests (issue-6923): DELETE, PUT, GET all work
- 12 gap-treat-012 tests: new data paths unaffected
- 15 uuid-handling tests: edge cases, UUID_HANDLING=false still works

Fixes #6923 (unable to edit/save/delete overrides for legacy data)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-25 15:20:51 -07:00
Ben WestandCopilot 98ee2bcb3e fix: restore debounce with concurrency guard for data-received events
Strategy C: leading-edge debounce + concurrency guard.

- First data-received fires dataloader immediately (zero delay)
- Rapid events (AAPS batch upload) coalesced by 1s debounce
- Concurrency guard prevents overlapping dataloader.update() on shared ddata
- maxWait: 5s ensures data appears within 5s under sustained load
- Pending flag guarantees one final re-run after burst completes

Without this, N uploads → N concurrent dataloader runs → N×9 MongoDB
queries racing on the same ddata object. With it: N uploads → 2-3 runs.

9 tests confirm: leading-edge, coalescing (50 events → 2 runs),
no overlapping runs, trailing edge, maxWait guarantee.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-25 14:21:30 -07:00
Ben WestandCopilot f4e686c1fb fix: cache filterForAge rejects ObjectId _id on MongoDB driver 5.x
_.isEmpty(new ObjectId()) returns true on driver 5.x because ObjectId
no longer has enumerable own properties (Object.keys returns []).
This caused filterForAge() to silently drop all entries with ObjectId
_id from the server cache.

check. This correctly accepts ObjectId instances and strings while
still rejecting null, undefined, and empty string.

16 tests confirm the fix:
- 3 root cause tests (_.isEmpty regression)
- 7 filterForAge logic tests (old vs fixed behavior)
- 6 integration tests (actual cache.js with data-update events)

Fixes AAPS backfill display bug where entries were in MongoDB but
invisible on the chart when using API V3 (mongoCachedCollection
emits data-update with raw ObjectId _id).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-25 14:05:28 -07:00
Ben WestandCopilot 95b4c5e277 test: confirm _.isEmpty(ObjectId) cache regression on driver 5.x
MongoDB driver 5.x ObjectId has no enumerable properties, so
_.isEmpty(new ObjectId()) returns true. This breaks cache.js

7 tests confirm:
- _.isEmpty(ObjectId) returns true (regression)
- filterForAge rejects ObjectId _id documents
- processRawDataForRuntime mitigates by converting to string
- Proposed fix (_id != null) works correctly

Currently mitigated in V1 paths by processRawDataForRuntime, but
unmitigated in API V3 mongoCachedCollection path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-25 13:30:58 -07:00
Ben WestandCopilot b8523430db test: add regression test proving #6923 legacy UUID data bug
Inserts a treatment directly into MongoDB with UUID as _id (no identifier
field) — the shape of overrides created before normalizeTreatmentId(). All 3
tests fail as expected:

- DELETE: responds 200 but deletedCount=0 (silent no-op)
- PUT: creates duplicate document instead of updating in place
- GET: returns 0 results (query rewrite misses legacy doc)

These tests document the legacy data gap and will pass once updateIdQuery()
is updated to use a $or fallback: {identifier: UUID} || {_id: UUID}.

Relates to: #6923, #8450

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-19 17:31:31 -07:00
Ben WestandGitHub 8cf4a1a041 Merge pull request #8460 from nightscout/wip/test-improvements
Wip/test improvements
2026-03-18 20:03:19 -07:00
Ben WestandGitHub c00fd37628 Merge branch 'dev' into wip/test-improvements 2026-03-18 20:00:56 -07:00
Ben WestandCopilot e46e8532d3 docs: improve production safety check messaging
- Change 'FAILED' to 'ACTIVATED' - this is protective, not a failure
- Explain that tests WILL DELETE data in the database
- Explain the purpose: preventing accidental production data loss
- List all override options clearly

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 19:57:40 -07:00
Ben WestandCopilot b1ffeeeacf fix: use ctx.store.db for entry count check
The ctx.entries module isn't always available depending on boot context.
Access the entries collection directly via ctx.store.db.collection().

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 19:54:40 -07:00
Ben WestandCopilot 6a681509f3 feat: add database-level production safety checks (GAP-SYNC-047)
Adds multi-layer protection against running destructive tests on production:

1. Pre-flight check (hooks.js): Verifies NODE_ENV=test before any DB connection
2. Database name check: Requires 'test' substring in database name
3. Entry count threshold: Refuses if database has >100 entries (configurable)

Environment Variables:
- TEST_SAFETY_MAX_ENTRIES: Max entries before refusing (default: 100)
- TEST_SAFETY_REQUIRE_TEST_DB: Require 'test' in DB name (default: true)
- TEST_SAFETY_SKIP: Emergency bypass for all checks (default: false)

Files:
- tests/lib/production-safety.js: Core safety check module
- tests/00_production-safety.test.js: Runs first to gate test suite
- tests/production-safety.test.js: Unit tests for safety module
- tests/hooks.js: Updated to use new module

This addresses concerns about users with 'test' in production DB names
by adding the entry count threshold as a secondary safety measure.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-18 19:49:49 -07:00
Ben WestandGitHub 7e5c345e8c Merge pull request #8456 from nightscout/wip/test-improvements
Wip/test improvements - extends same fixes for data shape across all remaining api surface areas and includes test coverage across the test matrix spectrum.
2026-03-18 18:03:53 -07:00
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