Commit Graph

346 Commits

Author SHA1 Message Date
PedroHMCosme
b5512498b9 fix(simple_metrics): ignore unparseable frequency_alert and malformed adaptive_state (SIENTIAPDE-2190) 2026-10-08 08:48:24 -03:00
PedroHMCosme
7222b5d1ef feat(simple_metrics): warn when frequency_alert is below the 1m floor (SIENTIAPDE-2190) 2026-10-07 15:28:45 -03:00
PedroHMCosme
40f8d8174b feat(simple_metrics): use frequency_alert while adaptive_state is escalated (SIENTIAPDE-2190) 2026-10-07 15:17:53 -03:00
github-actions[bot]
6334be2edf chore: bump version to 0.6.7 2026-09-23 11:56:34 +00:00
b834c0b8e6 Merge pull request #44 from Aignosi/fix/SIENTIAPDE-2149
SIENTIAPDE-2149: model_ids allow-list filter for receiver groups
2026-09-23 08:56:06 -03:00
bc4e64a271 Merge branch 'main' into fix/SIENTIAPDE-2149 2026-09-23 08:41:52 -03:00
github-actions[bot]
afb71c27bf chore: bump version to 0.6.6 2026-09-23 11:39:16 +00:00
52dffeecd4 Merge branch 'main' into fix/SIENTIAPDE-2149 2026-09-23 08:39:04 -03:00
d0f204d525 Merge pull request #43 from Aignosi/fix/SIENTIAPDE-2013
Fix/sientiapde 2013
2026-09-23 08:38:46 -03:00
Eduardo Rios
c85c3440ed Merge fix/SIENTIAPDE-2013 into fix/SIENTIAPDE-2149
Brings in the review-feedback fixes (batch-size default, requirements-local,
docstring trim) from PR #43 so #44 stays consistent with its base branch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

# Conflicts:
#	CLAUDE.md
2026-09-22 16:52:30 -03:00
Eduardo Rios
d3104d66ab fix: address review feedback on batch-size default, requirements-local, docstring
- NOTIFICATION_QUEUE_BATCH_SIZE default reverted to 0 (unlimited) -- the
  existing behavior before this ticket, so deployments must opt in to the
  cap rather than having it silently applied at 5000
- requirements-local.txt: bump sientia_do pin to 1.12.3 to match requirements.txt
- Trim the load_latest_data docstring addition so it reads as documentation,
  not a changelog entry

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 16:51:51 -03:00
Eduardo Rios
0edb2b5be0 refactor: extract shared union-or-nothing helper in _compute_query_time_filter
levels and model_ids (SIENTIAPDE-2149) both computed a per-group union with
identical "union only if every active group restricts, else unrestricted"
logic. Extracting _union_when_all_restrict removes the duplicated for/if
block for each axis, addressing the SonarQube quality gate failure on this
PR (cognitive complexity).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 16:48:46 -03:00
Eduardo Rios
da8a796197 SIENTIAPDE-2149: model_ids allow-list filter for receiver groups
New, separate model_id-based filter distinct from the existing
ignore_models_id deny-list (SIENTIAPDE-2012): a group configuring
model_ids only receives notifications from those models. Both axes
apply together (AND) when a group sets both.

Design decisions made while implementing (matching the levels/
ignore_models_id split from SIENTIAPDE-2011/2012, not yet confirmed
with the team beyond what's in the ticket):
- Query-time filter: union of every active group's model_ids, applied
  only when ALL active groups set one -- mirrors levels' exact
  union-or-nothing logic in _compute_query_time_filter. Combines
  cleanly with ignore_models_id's intersection $nin on the same
  model_id field.
- Per-group filter: extended _check_levels_and_ignore_models_id (now
  _check_levels_and_model_filters) in slot_manager.py, and the inline
  condition in formatters.py's filter_notification_reports.
- Empty/missing model_ids means no restriction, same convention as
  levels and ignore_models_id.

Covered by new unit tests (slot_manager, formatters,
_compute_query_time_filter) and two new e2e tests against real
Mongo/Redis/Temporal: per-group allow-list interacting with another
unrestricted group, and the query-time union excluding a model outside
every active group's allow-list.

Not yet verified on the real cluster -- blocked on the dev cluster's
package index not auto-syncing new sientia_do releases (separate issue,
being investigated for SIENTIAPDE-2013).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 15:13:28 -03:00
Eduardo Rios
87ddd02038 fix: correct sientia_do pin to the version actually released (1.12.3)
The library's release pipeline bumped a patch version (1.12.3), not the
minor bump (1.13.0) the feat: commit prefixes would normally produce --
correcting the pin here to match what was actually published.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 14:45:56 -03:00
Eduardo Rios
8e6f2eab14 Merge branch 'fix/SIENTIAPDE-2013' of https://github.com/Aignosi/sientia-dataops-orchestrator_temporal into fix/SIENTIAPDE-2013 2026-09-17 11:52:13 -03:00
Eduardo Rios
739736b824 test(e2e): verify notification_queue_batch_size=0 means unlimited
Vitor asked whether limit=0 really means "no limit" on the Mongo side
and whether that had actually been tested. It's pymongo's own
documented convention, but nothing in the suite exercised it against a
real MongoDB with enough documents to mean anything -- the existing
tests only ever seed 2-5. Seeds 12 (more than any other test in this
file) with the batch size left at its config default (0) and asserts
all 12 come back in one run, against real testcontainers Mongo.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 11:51:49 -03:00
Eduardo Rios
4ece5cf9e3 Merge branch 'main' into fix/SIENTIAPDE-2013 2026-09-17 11:48:58 -03:00
github-actions[bot]
5cc8015fc7 chore: bump version to 0.6.5 2026-09-17 14:36:26 +00:00
Eduardo Rios
d6c103c39a Merge pull request #42 from Aignosi/fix/SIENTIAPDE-2012
SIENTIAPDE-2012: per-group levels/ignore_models_id filtering
2026-09-17 11:36:01 -03:00
Eduardo Rios
eaf0ca7863 docs: make e2e/scenarios.md a strict 1:1 mirror of actual e2e tests
Removed scenarios documented with no backing test (1.2.1, 1.3.2, 1.4.1,
A.1.3) and corrected three descriptions that claimed assertions the
tests don't actually make (1.1.1's "Redis slots written", 1.3.1's
"timestamps inserted", 1.5.1's "orphan schedules removed") to match
what's really verified. A.2.1 stays as-is here -- it's already accurate
for this branch's real per-group filtering test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 09:52:38 -03:00
Eduardo Rios
d46bd55cb4 test(e2e): add batch-size cap coverage for SIENTIAPDE-2013
Also fixes the test_activities fixture, which built mongodb_config by
hand and was missing the new required notification_queue_batch_size key
-- every e2e test would have hit a KeyError without this.

New test seeds 5 notifications with a batch size of 2 and confirms three
successive runs return them oldest-first in order (n1,n2 / n3,n4 / n5),
proving the cursor only advances to what was actually returned rather
than skipping documents a capped query didn't fetch. Verified against
real testcontainers Mongo/Redis/Temporal, not mocks.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 09:39:35 -03:00
Eduardo Rios
9c153041ad SIENTIAPDE-2013: cap load_latest_data's Mongo fetch at a configurable batch size
A cold start or notification storm had no backstop: load_latest_data
fetched the entire matching backlog in one query. Confirmed live during
SIENTIAPDE-2012's cluster verification -- an empty Redis cursor plus a
real recurring error let a single run's query exceed Temporal's 4MB
message limit and get stuck retrying forever.

Threads a new notification_queue_batch_size config (env var
NOTIFICATION_QUEUE_BATCH_SIZE, default 5000) through to the repository's
find(), hard cap per run, no drain loop -- the incremental
last_data_timestamp cursor picks up any remainder next run, per the
parent ticket's design decision. Sorts by timestamp ascending so a
capped run always returns the oldest pending documents first; without
that, a capped batch has no guarantee of hitting the oldest documents,
and the cursor would advance past whatever it skipped.

Requires sientia_do>=1.13.0 (adds limit/sort params to
MongoDBRepository.find in both the sync and async client) -- bumped the
pin here per the parent ticket's decision to do it in the same PR.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 09:33:46 -03:00
Eduardo Rios
b7325938f5 refactor: extract per-group filtering to reduce cognitive complexity
filter_notification_alerts tripped Sonar's cognitive-complexity gate
(16 > 15 allowed) from its nested loop/if structure. Split into
_filter_group_notifications (per-group notification selection) and
_determine_alert_type (Redis TTL classification), leaving the public
method as a simple loop over receiver groups. Behavior and call order
are unchanged -- verified against the existing filter_notification_alerts
unit tests by inspection (sientia_do isn't installable in this local
environment, so the real suite can't run here; CI will confirm).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 15:05:59 -03:00
Eduardo Rios
081298a883 fix: annotate already_added_keys to satisfy mypy
The parameter-level annotation on _check_keys_and_notif_id alone
wasn't enough -- mypy needs the type at the empty list's declaration
site inside filter_notification_alerts. Also reformatted the helper's
now-longer signature to satisfy ruff.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 14:51:51 -03:00
Eduardo Rios
a59cc1c691 fix: apply ruff formatting to _check_keys_and_notif_id
Fixes CI formatting failure introduced by the manual Sonar cognitive-
complexity fix (extracting the ignore-list/dedup check into its own
helper).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 14:48:45 -03:00
Eduardo Rios
6a95b8d2df fix: apply ruff formatting to _check_levels_and_ignore_models_id
Fixes CI formatting failure introduced by the manual Sonar cognitive-
complexity fix (extracting the levels/ignore_models_id check into its
own helper).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 14:39:59 -03:00
Eduardo Rios
86962c2cfc Refactorizing function to reduce its Cognitive Complexity 2026-09-15 14:35:22 -03:00
Eduardo Rios
9df151d29d SIENTIAPDE-2012: per-group levels/ignore_models_id filtering
Extends filter_notification_alerts (slot_manager.py) and
filter_notification_reports (formatters.py) to check
receiver_group.get('levels') and receiver_group.get('ignore_models_id'),
mirroring the existing contents/ignore pattern exactly. Closes the gap
SIENTIAPDE-2011 deliberately left open: the query-time union/intersection
filter widens what gets fetched for the union of all active groups, but until
now nothing narrowed each group back down to its own configured slice.

Both checks short-circuit via `not levels_list or ...` / `not
ignore_models_id_list or ...` rather than accessing notification['level']/
['model_id'] directly, so groups that don't configure either field (today's
common case, and every existing unit test fixture) never evaluate the
right-hand side and can't raise KeyError on notifications missing those keys.
ignore_models_id reads via `.get(...) or []`, defensively handling an
explicit `null` in a receiver_groups document from the start (same fix
SIENTIAPDE-2011 needed a follow-up commit for).

Tests:
- 8 new unit tests (4 per file): levels restriction, ignore_models_id
  restriction, neither-configured passthrough, explicit-None safety.
- New e2e test (test_scenario_a_2_1_per_group_levels_and_ignore_models_id)
  against real Mongo/Redis/Temporal: two active groups configured
  differently: SIENTIAPDE-2011's query-time filter widens the fetch to the
  union of both, and this subtask's per-group filter narrows each group back
  to its own levels/ignore_models_id, including the case where a model is
  ignored by only one of the active groups.
- Deduplicated the two e2e suites' identical _extract_html_body helper into
  e2e/helpers.py (extract_html_body), now shared by both.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 13:46:03 -03:00
github-actions[bot]
d250383f78 chore: bump version to 0.6.4 2026-09-15 15:26:54 +00:00
a259aeeef7 Merge pull request #41 from Aignosi/fix/SIENTIAPDE-2011
SIENTIAPDE-2011: Compute query-time levels union / ignore_models_id intersection
2026-09-15 12:26:32 -03:00
Eduardo Rios
3d2a5ecc43 test: lock in that levels union replaces default_filter's level, not AND
Manual code-review pass (code-review-python checklist) flagged that no test
exercised default_filter already restricting level (e.g. Alerts' ERROR-only
default) combined with every active group specifying its own levels. The
replace-not-AND behavior is deliberate per SIENTIAPDE-2011's design doc and
ticket text, but was previously only covered by a docstring comment. Adds
test_compute_query_time_filter_union_replaces_default_level_restriction so a
future change reintroducing AND semantics fails a test instead of passing
silently.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 11:26:06 -03:00
Eduardo Rios
6479737dfb fix: harden ignore_models_id against explicit null, document levels-union design
Code review findings on the SIENTIAPDE-2011 PR:

- [Major] _compute_query_time_filter used group.get('ignore_models_id', [])
  for the intersection, whose default only applies when the key is missing.
  receiver_groups has no schema validation, so a document with
  ignore_models_id explicitly set to null (key present, value None) made
  .get() return None, and set(None) raised TypeError, crashing the whole
  activity for every mail type. Fixed with `group.get(...) or []`. Added a
  regression test.

- [Minor] CLAUDE.md:48 described Alerts' base data filter as always
  `level: ERROR`, which this ticket's own query-time union can now widen.
  Updated the line to reflect that.

- [Blocker, not applied] A finding argued the levels union should AND with
  default_filter's own level restriction instead of replacing it, to avoid
  widening Alerts (ERROR-only real-time channel) when a receiver_group sets
  broader levels. Both SIENTIAPDE-2011's ticket text and the parent design
  doc explicitly call for the union to replace the hard-coded ERROR-only
  default ("whatever levels the active groups actually care about"), so
  applying that fix would revert the subtask's actual purpose. The
  interim gap the finding correctly identifies (no per-group level filter
  exists yet until SIENTIAPDE-2012 lands) is now documented in
  _compute_query_time_filter's docstring instead of "fixed" by narrowing
  query-time behavior the ticket asked for.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 11:13:17 -03:00
Eduardo Rios
58c0bd4f2d SIENTIAPDE-2011: normalize notification timestamp in format_log_report
notification['timestamp'] crosses at least one Temporal activity
boundary (load_latest_data -> filter_notification_reports/alerts)
before reaching format_log_report. Temporal's default data converter
serializes datetime values to plain ISO-8601 strings without
restoring them on decode, and pymongo returns naive datetimes for
BSON Date fields, so the string can carry no UTC offset at all. That
broke export_data_to_postgres's strict to_datetime(..., format=
DATETIME_FORMAT_WITH_TZ) parsing downstream with:
  ValueError: time data "2024-06-01T12:00:00" doesn't match format
  "%Y-%m-%d %H:%M:%S%z"

Same underlying issue as SIENTIAPDE-2007/2009, fixed here using the
same pattern as SlotManager.put_last_data_timestamp: normalize with
pandas.to_datetime(..., utc=True) and re-format to
DATETIME_FORMAT_WITH_TZ before the value crosses the next boundary.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 09:35:25 -03:00
Eduardo Rios
ed666c260d fix: satisfy mypy in put_last_data_timestamp after utc=True normalization
CI mypy caught what my local environment couldn't (Python 3.14 has no
compatible numpy stub for the project's python_version=3.11 mypy target,
so mypy couldn't run locally at all):

  slot_manager.py:353: error: Incompatible types in assignment
    (expression has type "str", variable has type "Timestamp")
  slot_manager.py:368: error: Incompatible return value type
    (got "Timestamp", expected "str | None")

Reassigning `last_data_timestamp` from a Timestamp to its strftime() string
trips mypy's inference (it fixes an unannotated local's type from its first
assignment). Split into a separate `last_data_timestamp_str` for the string
form instead of reusing the name.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 08:18:17 -03:00
Eduardo Rios
14b854148a SIENTIAPDE-2011: add e2e coverage for query-time filter, fix stale e2e fixtures
e2e fixtures (default_notification, seed_last_timestamp, default_receiver_group)
still assumed the pre-SIENTIAPDE-2007 string-timestamp representation and the
old ignore_models field name, so the load_notification_package e2e suite was
failing independently of this ticket's changes:

- default_notification now seeds `timestamp` as a native datetime (matches
  production since SIENTIAPDE-2007's Notification.timestamp = now()).
- seed_last_timestamp now uses DATETIME_FORMAT_MS_WITH_TZ (matches what
  put_last_data_timestamp actually writes to Redis today).
- default_receiver_group's ignore_models renamed to ignore_models_id, per
  this ticket's decision.
- test_reports_main_workflow.py's explicit timestamp= call sites updated to
  match.

Also fixes a real production bug in put_last_data_timestamp (slot_manager.py)
surfaced by running the e2e suite against a real Temporal environment: Temporal's
default data converter serializes datetime values to ISO-8601 strings across
the activity boundary, and pymongo returns naive datetimes for BSON Date
fields, so `data['timestamp'].max().strftime(...)` crashed on a plain str.
Unit tests never caught this because they mock the activity boundary and
never cross real (de)serialization. Fixed by normalizing through
`pandas.to_datetime(..., utc=True)`, which handles native datetime/Timestamp
and offset-aware/naive ISO strings uniformly.

Adds test_load_package_query_time_filter_union_and_intersection, a new e2e
test exercising the actual SIENTIAPDE-2011 behavior end-to-end: union of
active groups' levels, intersection of their ignore_models_id, and the
requirement that a model ignored by only one of several active groups must
not be excluded from the fetch.

Note: test_reports_main_workflow.py / test_alerts_main_workflow.py still have
a separate, pre-existing failure in process_notifications.py (same family of
bug: a notification's timestamp field parsed with a fixed strptime format
after crossing the same Temporal serialization boundary) — confirmed present
on the unmodified baseline too, unrelated to this ticket, tracked separately.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 12:15:23 -03:00
Eduardo Rios
1711f3b0d1 SIENTIAPDE-2011: Compute query-time levels union / ignore_models_id intersection
Push level and model-exclusion filtering down to the Mongo query instead of
fetching the full notification_queue unfiltered on every run.

- Fix await ordering in load_notification_package so sending_configs (active
  receiver_groups) resolves before load_latest_data is called, letting the
  query filter be built from group data.
- Add _compute_query_time_filter: unions active groups' `levels` (falls back
  to the workflow's default filter if any group has no restriction, since
  that group wants every level) and intersects their `ignore_models_id`
  (a model is only safe to drop from the fetch if every active group
  ignores it).
- Add unit tests covering mixed groups, a model ignored by only one group
  (must not be excluded from the fetch), and the empty active-groups case.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 11:46:19 -03:00
ff7b441140 ci(deploy): Configure env_list_path as array in deploy workflow 2026-09-11 00:25:25 -03:00
github-actions[bot]
d12c89e1c5 chore: bump version to 0.6.3 2026-09-10 13:31:42 +00:00
Bruno Domingues
b933783e59 Merge pull request #40 from Aignosi/fix/SIENTIAPDE-2068
Configure Deploy Workflow for pyproject.toml Version Updates
2026-09-10 10:31:15 -03:00
d8ece5ea3c Merge branch 'main' into fix/SIENTIAPDE-2068 2026-09-10 10:26:37 -03:00
30fe5ff69c SIENTIAPDE-2068: Configure deploy workflow to update version in pyproject.toml 2026-09-10 10:20:41 -03:00
Bruno Domingues
0c63b68cdd Merge pull request #39 from Aignosi/fix/SIENTIAPDE-2068
feat(CI/CD): Migrate Orchestrator-Worker Deployment to Flow B
2026-09-09 23:30:52 -03:00
bfbc71bbfb SIENTIAPDE-2068: feat(cicd): migrate orchestrator-worker deploy to Flow B
- Delete release.yml (tarball-only, no deploy job).
- Add deploy.yml calling reusable-deploy-dataops.yml — mirror to Gitea,
  dual-bump GITHUB_BRANCH (development + chart-ref label branch), helmfile
  deploy. workflow_dispatch has no inputs: uses the picked branch as-is.
- Add require-chart-ref-label.yml (branch-protection check, wired separately).
2026-09-09 23:18:46 -03:00
cae514ebae Merge pull request #38 from Aignosi/fix/SIENTIAPDE-2009
SIENTIAPDE-2007  SIENTIAPDE-2007: Compare native datetime in load_latest_data $gt filter and bump sientia_do pin to 1.12.2
2026-09-09 11:07:38 -03:00
Eduardo Rios
3c69b35b3f fix: use DATETIME_FORMAT_MS_WITH_TZ instead of isoformat for last_data_timestamp
Addresses review feedback: prefer sientia_do's explicit datetime format
constant over Python's isoformat()/fromisoformat() when round-tripping
last_data_timestamp through Redis, matching the convention already used
elsewhere in mongo_db.py and slot_manager.py.
2026-09-09 10:54:22 -03:00
Eduardo Rios
2467d24188 style: fix ruff formatting in test_mongo_db.py
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 11:37:13 -03:00
Eduardo Rios
70f6a5d820 chore: ignore .obsidian/ directory
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 11:31:10 -03:00
Eduardo Rios
c3cd58028c SIENTIAPDE-2007 SIENTIAPDE-2007: Compare native datetime in load_latest_data $gt filter and bump sientia_do pin to 1.12.2
Notification.timestamp is now stored as a native BSON Date instead of a
string, so load_latest_data must parse the ISO string coming from Redis
back to datetime before building the $gt filter, or the comparison
silently breaks (BSON String vs Date always evaluates False). Also fixes
put_last_data_timestamp, which would otherwise raise TypeError trying to
json.dumps a pandas Timestamp when persisting the new watermark to Redis.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 13:53:01 -03:00
7352b1c1df chore(devops): Update CI quality gate workflow and add Claude AI guidance 2026-08-05 15:52:11 -03:00
817fcb90be Merge pull request #37 from Aignosi/feature/SIENTIAPDE-1646
Enhance Orchestration with Runtime Workflow Support and System Updates
2026-07-21 14:55:49 -03:00