Commit Graph
106 Commits
Author SHA1 Message Date
james.maesandCodex bb7028a446 ci: centralize QBit source scanning
Co-Authored-By: Codex <noreply@openai.com>
2026-10-21 10:19:50 -05:00
james.maesandCodex 5e76611393 ci: adopt orb 0.7.12 and stable verification gate (#55)
* ci: qualify the shared stable verification gate

Co-Authored-By: Codex <noreply@openai.com>

* ci: adopt verified stable orb 0.7.12

Co-Authored-By: Codex <noreply@openai.com>

---------

Co-authored-by: Codex <noreply@openai.com>
2026-10-21 03:26:52 -05:00
james.maesandCodex d1939eefd5 ci: use corrected orb rc reference lookup (#54)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 02:18:17 -05:00
james.maesandCodex f4cbdae305 ci: adopt verified orb rc timeout recovery (#53)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 02:06:06 -05:00
james.maesandCodex c0acf6bbf8 ci: adopt shared orb 0.7.11 (#52)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 00:57:45 -05:00
james.maes 8846d0e514 Merge pull request #51 from QRun-IO/feature/orb-rc-worker
ci: move RC coordination into shared orb
2026-10-20 18:58:23 -05:00
james.maesandCodex 7f77969f8e ci: adopt orb-owned RC coordination
Co-Authored-By: Codex <noreply@openai.com>
2026-10-20 18:55:16 -05:00
james.maes 33f1e8dcf4 Merge pull request #50 from QRun-IO/feature/central-ci
ci: adopt verified central QQQ orb 0.7.1
2026-10-20 18:46:04 -05:00
james.maesandCodex 318f176260 ci: adopt verified central QQQ orb 0.7.2
Co-Authored-By: Codex <noreply@openai.com>
2026-10-20 18:42:46 -05:00
james.maes 3adb6dc3d6 Merge pull request #46 from QRun-IO/feature/service-principal
fix(routing): per-recipient checks via the alerts service principal
2026-10-16 13:33:27 -05:00
james.maesandClaude Opus 5.5 b89c95f749 build: QQQ 4.1.0-RC.19
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 13:19:08 -05:00
james.maesandClaude Opus 5.5 86b4ca5ff4 fix(routing): per-recipient checks run via the alerts service principal
Token-less automated sessions are rejected under OAuth2, so visibility,
follower and audience checks never worked there. With the host's alerts
principal declared they run on the recipient's behalf through it.
Recording/routing bookkeeping stays system so alerting never depends on
the IdP. Undeclared: unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 08:30:04 -05:00
james.maes a79ca3f696 Merge pull request #45 from QRun-IO/ci/release-rc-secrets-inherit
ci(release-rc): pass secrets so the shared workflow can sign the RC tag
2026-10-16 08:05:01 -05:00
james.maesandClaude Opus 5.5 c70210dee0 ci(release-rc): pass secrets to the shared workflow so it can sign the RC tag
QRun-IO/.github#2 adds a tag-and-release job that signs vX with the
QRUN_TAG_SIGNING_KEY secret after Maven Central confirms the artifact.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 16:19:32 -05:00
james.maes 56e174444a Merge pull request #44 from QRun-IO/feature/ui-api-1.6
feat(ui-api): extension for QQQ UI API 1.6.0 (operationIds, BasicErrorResponseV1, QQQ 4.1.0-RC.15)
2026-10-15 16:12:44 -05:00
james.maesandClaude Opus 5.5 90e389a55c chore: target QQQ 4.1.0-RC.15 (UI API 1.6.0)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:27:02 -05:00
james.maesandClaude Opus 5.5 489663a946 feat(ui-api): extension for QQQ UI API 1.6.0 (operationIds, BasicErrorResponseV1, QQQ 4.1.0-RC.14)
Regenerated against UI API 1.6.0: every operation has an operationId and
the standard error responses (BasicErrorResponseV1: error, code, message,
fieldErrors, traceId); the extension's own error schema is kept but
deprecated; hand-written error bodies go through QJavalinUtils so they carry
code/message/traceId. Extension MINOR bumped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 11:43:36 -05:00
james.maes fe4732e12f Merge pull request #43 from QRun-IO/feature/runtime-fields-not-audited
fix(audit): do not record-audit engine bookkeeping updates
2026-10-15 07:48:45 -05:00
james.maesandClaude Opus 5.5 b08d41da7f fix(audit): do not record-audit engine bookkeeping updates
Monitor lease claims and run results, and alert reminder/notification
timers, changed on every scheduler pass and each wrote a FIELD audit row
(~7k alerts_monitor and ~1.8k alerts_alert audits per 6h in production).
AlertsDb.update now omits the DML audit when an update touches only the
RuntimeFields of its table; any update with a configuration or state field
is audited in full.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 07:45:58 -05:00
james.maes 4a7dd2bb71 Merge pull request #42 from QRun-IO/fix/alerts-system-session-instance
fix(alerts): asSystem builds its system session with the runtime instance
2026-10-15 07:38:26 -05:00
james.maesandClaude Opus 5.5 b638741c61 fix(alerts): asSystem builds its system session with the runtime instance
The alerts-sink drain thread (and schedulers) run engine work through
AlertsRuntime.asSystem with no QContext, so new QSystemUserSession()
read a null instance and warned "QInstance was not supplied" on every
call. AlertsSecurity.systemSession(QInstance) takes the instance; the
no-arg form delegates with the context instance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 07:25:44 -05:00
james.maes 7f79f86222 Merge pull request #41 from QRun-IO/fix/producer-version-from-build
fix: qbit metadata version comes from the build
2026-10-15 01:42:57 -05:00
james.maesandClaude Opus 5.5 69b94a13f5 fix: the qbit metadata version comes from the build, not a hardcoded constant
The producer read a literal version, so released artifacts reported a stale
or -SNAPSHOT version. qbit-alerts.properties (version=${project.version}) is
Maven-filtered and the producer loads it; tests assert producer == bundle ==
artifact version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 01:23:05 -05:00
james.maes 884eab9432 Merge pull request #40 from QRun-IO/fix/help-bundle-version-test
test(help): bundle version test compares with the artifact version
2026-10-14 23:18:42 -05:00
james.maesandClaude Opus 5.5 dc04474689 test(help): compare the help bundle version with the artifact version, not a hardcoded SNAPSHOT
The bundle version is now Maven-filtered, so a literal SNAPSHOT in the test
fails every release build. Surefire passes the artifact version in
qbit.artifactVersion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 23:07:02 -05:00
james.maes 912b83c2a4 Merge pull request #39 from QRun-IO/fix/help-bundle-version
fix(help): help bundle version comes from the build, not a hardcoded SNAPSHOT
2026-10-14 22:37:20 -05:00
james.maesandClaude Opus 5.5 e5d31991eb fix(help): the help bundle carries the artifact version (Maven-filtered) instead of a hardcoded SNAPSHOT
On release branches the bundle's version and the producer's differed, so the
bundle test that asserts they match failed, and released bundles recorded
SNAPSHOT as their provenance. help/*.yaml is now filtered:
version: ${project.version}.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:02:04 -05:00
james.maes fc04d0a4fb Merge pull request #38 from QRun-IO/feature/help-bundle
feat(help): Alerts help bundle via QQQ help bundles, with coverage gate
2026-10-14 20:29:38 -05:00
james.maesandClaude Opus 5.5 50e1b52a4d feat(help): ship the Alerts help bundle through QQQ help bundles (419 entries, coverage gate)
Host-neutral text (kof22-specific facts removed), registered with
HelpBundles in the producer, gated by HelpBundleAssertions. Replaces the
temporary AlertsHelp loader.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 20:01:53 -05:00
james.maes 2dcd6cd3e4 Merge pull request #37 from QRun-IO/feature/notify-email-requested-v2
feat(notifications): email REQUESTED recipients immediately (per-job opt-in), v2
2026-10-14 18:51:03 -05:00
james.maesandClaude Opus 5.5 04104ad4aa feat(notifications): email REQUESTED recipients immediately (per-job opt-in), v2
Merges feature/notify-email-requested (#22) onto current develop and
reconciles it with the paginated emailer, user pause, quiet hours and the
notification preferences. REQUESTED email honours the category email
minimum severity, pause (SECURITY bypasses) and quiet hours. No schema
change, so no new changeset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 18:48:28 -05:00
james.maes c37d5d3f2e Merge pull request #35 from QRun-IO/feature/foreign-keys
feat(schema): foreign keys for every alerts relation (changesets 30-53, after #32)
2026-10-14 18:00:42 -05:00
james.maes 0143caf4c9 Merge pull request #32 from QRun-IO/feature/alerts-join-indexes
fix(schema): index the join child columns monitor_id, alert_type_id and group_id
2026-10-14 18:00:34 -05:00
james.maes 8a4791508c Merge pull request #33 from QRun-IO/feature/bootstrap-subscription-once
fix(preferences): create the bootstrap subscription once per user
2026-10-14 18:00:27 -05:00
james.maesandClaude Opus 5.5 adb7fd7cec Merge feature/alerts-join-indexes (now with develop) into feature/foreign-keys
develop owns qbit-alerts:29 and the join indexes are now :30, so the
foreign-key changesets move from 30-53 to 31-54. Constraint and index
names are unchanged. Changesets 32-54 use PostgreSQL-only SQL
(row_to_json), so they carry dbms:postgresql and the H2 tests skip them.
The H2 digest test and AlertsForeignKeysTest's pre-FK cut now stop
before :31.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:52:37 -05:00
james.maesandClaude Opus 5.5 28545fa126 Merge origin/develop into feature/alerts-join-indexes
develop now owns qbit-alerts:29 (in_app_min_severity), so the join-index
changeset becomes qbit-alerts:30. Index names are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:50:41 -05:00
james.maesandClaude Opus 5.5 1ff75ffcda Merge origin/develop into feature/bootstrap-subscription-once
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:49:11 -05:00
james.maes ff177bd021 Merge pull request #36 from QRun-IO/feature/tables-populated-defaults
Every Alerts table used, seeded or explained; setup card and help
2026-10-14 17:31:48 -05:00
james.maesandClaude Opus 5.5 5c545dc8e1 fix(routing): review findings on owner team, sync and default channels
- coverage is decided by scope and severity, so a subscription with fewer events
  still counts; follow-ups go to the owner team only after it was told of the raise
- the first-visit type sync is best effort and never breaks the bell
- default channels keep the bell and replace only the built-in email choice
- KIND_SETUP in AlertsHome.kinds(); help marker reworded

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:23:04 -05:00
james.maesandClaude Opus 5.5 35c3b00d6f fix(defaults): empty rollback, rollback test, include order
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:13:22 -05:00
james.maesandClaude Opus 5.5 4077e8a725 feat: starter defaults, setup card and table help so no config table starts empty
Adds alerts-defaults.changelog.sql (in-app and email channels, alerts and other
groups; insert-only, guarded, tested through real Liquibase), a help bundle for
the app and every table, a Setup card on the home, guardrail tests, and docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:52:48 -05:00
james.maesandClaude Opus 5.5 684a2157b8 fix(routing): use a group's owner team and a user's default channels
ownerTeamId on a group and defaultChannelIds on a user were stored but never
read. An alert that no subscription matches (WARNING and above) now goes to the
owner team of its group (or the nearest parent with one); default channels
decide where a user is reached when a subscription names none. Types, groups and
default monitors also sync on the first bell request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:52:47 -05:00
james.maes f82b8cfbd8 Merge pull request #18 from QRun-IO/feature/notification-preferences-section
feat(preferences): Notifications section in user Preferences
2026-10-14 16:43:56 -05:00
james.maesandClaude Opus 5.5 411a8ff604 Merge origin/develop into feature/notification-preferences-section; pin QQQ 4.1.0-RC.7
Keeps develop's per-user Slack delivery, escalation and mute work; the
in_app_min_severity changeset moves to qbit-alerts:29; the Notifications
preferences section gains Slack per category; pause also skips non-security
Slack; the summary schema carries preferencesSection (alerts extension 1.1.0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:36:00 -05:00
james.maesandClaude Opus 5.5 6e70e02623 test(schema): PostgreSQL guardrail for foreign keys on every declared relation
AlertsForeignKeysTest applies the shipped changelog with Liquibase to
PostgreSQL 17 (Testcontainers) and asserts every one-to-many join and table
possible-value field has a foreign key with the decided ON DELETE rule (or
an exemption with a reason), every FK column leads an index, orphans are
quarantined then nulled or deleted, re-runs are no-ops, and a constraint a
host already added is skipped. The H2 digest-migration test stops before
the PostgreSQL-only FK changesets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:18:31 -05:00
james.maesandClaude Opus 5.5 2e1e22cdd4 feat(schema): foreign keys for every alerts relation, orphan-safe (changesets 30-53)
Changeset 30 indexes the FK columns no earlier index leads with. Changesets
31-53 add one constraint each, fk_<child_table>_<child_column>, guarded by a
precondition on the name so a host that already added it marks it ran. Each
first records orphans in qqq_fk_quarantine, then nulls a nullable column or
deletes a row whose column is NOT NULL (full row kept in row_data).

ON DELETE: CASCADE for owned detail rows (timeline, record refs, delivery
log of an alert, team members, notification recipients, escalation steps);
SET NULL for optional pointers (group, parent group, owner/assigned team,
monitor, subscription, alert event, escalation policy); RESTRICT for config
that must not vanish under live data (alert type, a channel or team that a
subscription, delivery or escalation step uses).

The H2 test schema carries the same constraints and indexes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:18:30 -05:00
james.maes 512dc7f790 Merge pull request #34 from QRun-IO/feature/recipients-widget-json
fix(config): never serialize the alerts runtime (child lists failed to render)
2026-10-14 16:10:01 -05:00
james.maesandClaude Opus 5.5 49ebea22a1 fix(config): never serialize the alerts runtime (child lists failed to render)
Record-view child lists, such as a notification's Recipients, failed with
"Error in JSON Serialization". ChildRecordListData carries the child
QTableMetaData, whose SourceQBitAware getSourceQBitConfig() hands Jackson
the AlertsQBitConfig; its getRuntime() returns an AlertsRuntime that points
back at the config, so serialization recursed to Jackson's 1000-level
nesting limit.

getRuntime() and getAudienceResolver() are now @JsonIgnore, as in the cms,
quick-search and sql-workbench configs. ChildListWidgetsJsonTest renders
the Recipients list with rows and every child-list widget, and serializes
each one; all three tests fail without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:54:23 -05:00
james.maesandClaude Opus 5.5 c9c1efca0a fix(preferences): create the bootstrap subscription once per user
AlertsPreferences.ensure was an unlocked check-then-insert, and a page
load fires the home widgets and the bell together. On kof22 this left
two identical "alerts (bootstrap rule)" subscriptions for the owner, so
every alert notified them twice. First calls are now serialized in the
JVM. Across replicas, each first call keeps the oldest bootstrap
subscription and deletes the rest. Subscriptions a person made are never
touched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:22:24 -05:00
james.maesandClaude Opus 5.5 b54d8d103c fix(schema): index the join child columns monitor_id, alert_type_id and group_id
Changeset 29 adds alerts_alert (monitor_id, status), alerts_monitor
(alert_type_id) and alerts_type (group_id). MonitorEvaluator looks up a
per-record monitor's open alerts by monitor_id + status on every
evaluation, and the type and group record pages list children by these
columns. A new test checks that every one-to-many join's child column
leads an index in the shipped changelog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:18:11 -05:00