Skip to content

feat: Last known status default for Manual monitors - #748

Closed
rajnandan1 wants to merge 11 commits into
mainfrom
fix/721
Closed

feat: Last known status default for Manual monitors#748
rajnandan1 wants to merge 11 commits into
mainfrom
fix/721

Conversation

@rajnandan1

@rajnandan1 rajnandan1 commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes #721 — push-driven (Manual/NONE-type) monitors lost their status between pushes in v4: one red minute, then gray forever.

  • New Default Status choice LAST_KNOWN (Manual monitors only): every scheduler tick without new data writes a CARRIED sample repeating the most recent alert-visible sample — status and latency alike — so a pushed status sticks until the next push.
  • Carry-source rule: the newest alert-visible sample (REALTIME/ERROR/TIMEOUT/MANUAL/DEFAULT/CARRIED). Incident/maintenance overlays and heartbeat SIGNAL receipts can never become sticky; backdated corrections don't change the present. CARRIED joins the alert-visible set, keeping ADR 0005's invariant (carried minutes count toward alert thresholds; alerts resolve only on a pushed recovery).
  • Closed default_status value set (NONE|UP|DOWN|DEGRADED|LAST_KNOWN) enforced by a single NormalizeDefaultStatus chokepoint across all three write paths (manage UI, v4 POST, v4 PATCH). LAST_KNOWN on a non-Manual type silently resets to UP — including when a monitor's type is changed away from Manual.
  • Migration normalizes legacy values (MAINTENANCE/unknown/NULLNONE) — behavior-preserving, since the fill engine never honored them. The dead MAINTENANCE dropdown option is removed.
  • Manage UI: rebuilt Default Status dropdown (adds None + conditional Last known status) with a full-contract warning callout; live auto-reset with toast on type change.
  • Docs: new Default Status section in the v4 monitor docs; ADR 0006 records the decision; ADR 0005 amended; CONTEXT.md glossary updated.

Test Plan

  • npm run check — 0 errors
  • Repository carry-source query verified against in-memory sqlite (skips INCIDENT/SIGNAL, returns latest alert-visible row)
  • NormalizeDefaultStatus verified: LAST_KNOWN passes on NONE type, resets to UP on others, null→NONE, MAINTENANCE rejected
  • Live E2E on dev server: create NONE+LAST_KNOWN monitor → no fill before first push → push DOWN → CARRIED DOWN rows each tick (latency carried) → push UP → CARRIED UP rows → type change to API auto-resets default to UP → PATCH MAINTENANCE returns 400
  • Migration ran against dev Postgres — 0 invalid rows remain
  • Manage UI verified in browser: dropdown options, conditional LAST_KNOWN, callout rendering
  • Docs page rendering verified (anchors, warning admonition, table)

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Last Known Status" default status option for NONE-type monitors, automatically carrying forward the most recent alert-visible status and latency metrics when no new monitoring samples arrive during scheduled ticks.
  • Documentation

    • Updated monitor documentation and architecture records to explain default status behavior, including the new "Last Known Status" feature constraints, mechanisms, and operational impact.

rajnandan1 and others added 11 commits June 7, 2026 22:18
ADR 0006, glossary terms, and implementation plan from the grilling session.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…arry source

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-data queries

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ixes #721

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… dropdown

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 7, 2026 17:53
@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements Last Known Status, a feature that allows NONE-type monitors to repeat their most recent alert-visible status across minutes without new data by writing CARRIED sample rows, addressing the gap-filling issue reported in #721.

Changes

Last Known Status: Carry-Forward Fill for NONE Monitors

Layer / File(s) Summary
Specification, Constants, and ADRs
docs/adr/0006-last-known-status-fill.md, CONTEXT.md, docs/adr/0005-alerts-evaluate-alert-visible-samples.md, docs/superpowers/plans/2026-06-07-last-known-status.md, src/lib/global-constants.ts
ADR 0006 defines LAST_KNOWN behavior for NONE monitors, CARRIED row semantics, alerting consequences, and rejected alternatives; context and ADR 0005 are updated to reflect CARRIED in alert-visible set; implementation plan breaks down 8 tasks; constants define CARRIED and LAST_KNOWN strings.
Repository: Fetch Latest Alert-Visible Sample
src/lib/server/db/repositories/monitoring.ts, src/lib/server/db/dbimpl.ts
ALERT_VISIBLE_TYPES now includes CARRIED; new getLatestAlertVisibleData() method fetches newest alert-visible sample for a monitor; DbImpl exposes method via binding.
API Validation: NormalizeDefaultStatus Helper
src/lib/server/controllers/monitorsController.ts, src/routes/(api)/api/v4/monitors/+server.ts, src/routes/(api)/api/v4/monitors/[monitor_tag]/+server.ts
NormalizeDefaultStatus validates against closed set and enforces LAST_KNOWN only for NONE type; integrated into CreateUpdateMonitor and both POST/PATCH endpoints with 400 error handling.
Worker: Emit CARRIED Samples
src/lib/server/queues/monitorExecuteQueue.ts
When default_status is LAST_KNOWN and no realtime data, fetch latest alert-visible sample and fill with CARRIED type; NO_DATA merge preserves fill type instead of forcing DEFAULT_STATUS.
Database Migration
migrations/20260607150000_normalize_default_status.ts
One-way migration normalizes NULL and invalid default_status values to NONE; down is irreversible no-op.
UI: Default Status Management
src/routes/(manage)/manage/app/monitors/[tag]/components/GeneralSettingsCard.svelte
Restrict default status options to NONE/UP/DOWN/DEGRADED with LAST_KNOWN only for NONE monitors; auto-reset LAST_KNOWN to UP on type change; add explanatory warning callout; remove MAINTENANCE option.
User Documentation
src/routes/(docs)/docs/content/v4/monitors/overview.md
Document all default status values, NONE-only scoping, carry mechanism, persistence, example flow, and warning that carried minutes can indefinitely mask stopped integrations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A carried tail of status kept,
When push-based monitors fall to sleep,
The NONE type monitors now won't weep,
Their latest state, they still shall reap!
No data gaps where status sleeps,
Just CARRIED rows in history's keep. 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main feature: adding a new 'Last known status' default option specifically for Manual (NONE-type) monitors, which is the core change in this PR.
Linked Issues check ✅ Passed The PR comprehensively addresses issue #721 by implementing last-known status persistence for NONE-type monitors via CARRIED samples, scheduler tick logic, API enforcement, migration, and UI updates.
Out of Scope Changes check ✅ Passed All changes are in-scope and directly support the last-known status feature: constants, DB queries, scheduler logic, API validation, migration, UI updates, and documentation are all necessary and cohesive.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/721

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds a new “Last known status” default for Manual (NONE-type) monitors so push-driven monitors keep their last status (and latency) between pushes by writing per-minute CARRIED samples sourced from the latest alert-visible sample. It also centralizes default_status validation/normalization (closed set + LAST_KNOWN scope rule), updates the manage UI/docs, and migrates legacy/invalid default_status values.

Changes:

  • Implement LAST_KNOWN default status and CARRIED sample type, including carry-source query restricted to alert-visible samples.
  • Enforce a closed default_status value set via a shared NormalizeDefaultStatus across manage writes and v4 POST/PATCH.
  • Update manage UI + docs/ADRs/glossary; migrate legacy/invalid/NULL default_status values to NONE.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/routes/(manage)/manage/app/monitors/[tag]/components/GeneralSettingsCard.svelte Adds LAST_KNOWN option for Manual monitors, plus explanatory warning callout and auto-reset behavior when monitor type changes.
src/routes/(docs)/docs/content/v4/monitors/overview.md Documents “Default Status” and the new LAST_KNOWN behavior and warnings.
src/routes/(api)/api/v4/monitors/+server.ts Applies NormalizeDefaultStatus on v4 monitor creation.
src/routes/(api)/api/v4/monitors/[monitor_tag]/+server.ts Applies NormalizeDefaultStatus on v4 monitor updates (including type-change auto-reset).
src/lib/server/queues/monitorExecuteQueue.ts Implements scheduler fill logic that writes CARRIED samples for LAST_KNOWN and preserves fill types through NO_DATA merge.
src/lib/server/db/repositories/monitoring.ts Adds CARRIED to alert-visible types and introduces getLatestAlertVisibleData() for carry-source selection.
src/lib/server/db/dbimpl.ts Exposes getLatestAlertVisibleData() via the db singleton.
src/lib/server/controllers/monitorsController.ts Introduces NormalizeDefaultStatus() and enforces it in the manage create/update path.
src/lib/global-constants.ts Adds CARRIED (sample type) and LAST_KNOWN (default_status value).
migrations/20260607150000_normalize_default_status.ts Normalizes NULL/unknown legacy default_status values to NONE.
docs/superpowers/plans/2026-06-07-last-known-status.md Adds an implementation plan reference for the feature work.
docs/adr/0006-last-known-status-fill.md Records the architectural decision and invariants for last-known-status fill.
docs/adr/0005-alerts-evaluate-alert-visible-samples.md Updates ADR 0005 to note CARRIED joining the alert-visible set.
CONTEXT.md Updates glossary definitions to include CARRIED and last-known status semantics.

Comment on lines +104 to +107
let defaultStatus: string;
try {
defaultStatus = NormalizeDefaultStatus(body.monitor_type ?? "API", body.default_status ?? "UP");
} catch (e) {
# Alerts evaluate alert-visible samples, not just REALTIME ones

The consecutive-sample checks behind alert evaluation (`consecutivelyStatusFor`, `consecutivelyLatencyGreaterThan`, `consecutivelyLatencyLessThan` in `src/lib/server/db/repositories/monitoring.ts`) consider samples whose type is `REALTIME`, `ERROR`, `TIMEOUT`, `MANUAL`, or `DEFAULT_STATUS` — the "alert-visible" set — instead of `REALTIME` only. Both data-API PATCH endpoints (single timestamp and range) enqueue one alert evaluation after writing `MANUAL` rows. `SIGNAL` rows and `INCIDENT`/`MAINTENANCE` overlay rows remain invisible to alerting.
The consecutive-sample checks behind alert evaluation (`consecutivelyStatusFor`, `consecutivelyLatencyGreaterThan`, `consecutivelyLatencyLessThan` in `src/lib/server/db/repositories/monitoring.ts`) consider samples whose type is `REALTIME`, `ERROR`, `TIMEOUT`, `MANUAL`, or `DEFAULT_STATUS` — the "alert-visible" set — instead of `REALTIME` only. Both data-API PATCH endpoints (single timestamp and range) enqueue one alert evaluation after writing `MANUAL` rows. `SIGNAL` rows and `INCIDENT`/`MAINTENANCE` overlay rows remain invisible to alerting. Amended by ADR 0006: last-known-status fill (`CARRIED`) later joined the alert-visible set under the same invariant.
Comment thread CONTEXT.md
Comment on lines 45 to +47
**Synthetic Sample**:
A Monitoring Sample written by the system or an admin rather than by a check: a raw heartbeat receipt (`SIGNAL`), a status pushed through the data API (`MANUAL`), a default-status fill (`DEFAULT_STATUS`), or an incident/maintenance overlay (`INCIDENT`, `MAINTENANCE`).
A Monitoring Sample written by the system or an admin rather than by a check: a raw heartbeat receipt (`SIGNAL`), a status pushed through the data API (`MANUAL`), a default-status fill (`DEFAULT_STATUS`), a last-known-status fill (`CARRIED`), or an incident/maintenance overlay (`INCIDENT`, `MAINTENANCE`).

Comment thread CONTEXT.md
Comment on lines 73 to 75
**Alert-Visible Sample**:
A Monitoring Sample that alert evaluation can see: every Observed Sample, plus data-API pushes (`MANUAL`) and default-status fill (`DEFAULT_STATUS`). Raw heartbeat receipts (`SIGNAL`) and incident/maintenance overlays are never alert-visible — while an overlay is active the alert window freezes (alerts neither trigger nor resolve). All alert conditions (status and latency alike) evaluate the same alert-visible timeline.
A Monitoring Sample that alert evaluation can see: every Observed Sample, plus data-API pushes (`MANUAL`), default-status fill (`DEFAULT_STATUS`), and last-known-status fill (`CARRIED`). Raw heartbeat receipts (`SIGNAL`) and incident/maintenance overlays are never alert-visible — while an overlay is active the alert window freezes (alerts neither trigger nor resolve). All alert conditions (status and latency alike) evaluate the same alert-visible timeline.

@greptile-apps

greptile-apps Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces a LAST_KNOWN default status for Manual (NONE-type) monitors, fixing the problem where push-driven monitors showed gaps between pushes. Each scheduler tick without new data now writes a CARRIED sample repeating the most recent alert-visible status and latency, keeping the status sticky until the next push.

  • Carry fill engine: monitorExecuteQueue gains a LAST_KNOWN branch that queries getLatestAlertVisibleData (excludes SIGNAL/INCIDENT/MAINTENANCE overlays so they can never become sticky) and writes a CARRIED row; CARRIED rows join the alert-visible set so they self-chain across ticks.
  • Validation chokepoint: NormalizeDefaultStatus enforces the closed {NONE, UP, DOWN, DEGRADED, LAST_KNOWN} set across all three write paths (manage UI via CreateUpdateMonitor, v4 POST, v4 PATCH); LAST_KNOWN on a non-NONE type silently resets to UP.
  • Migration + UI cleanup: 20260607150000_normalize_default_status rewrites legacy/null values to NONE; the manage UI dropdown removes the dead MAINTENANCE option, adds None and conditional LAST_KNOWN, and uses a $effect to mirror the server-side auto-reset live.

Confidence Score: 4/5

The carry fill logic is correct for NONE-type monitors; NoneCall.execute() returns null so realtimeData is always empty and the CARRIED row wins the merge cleanly. The main rough edge is that POST creates silently accept LAST_KNOWN for non-NONE types and store UP instead, which could surprise API consumers.

The core carry mechanism is well-reasoned and the latency preservation works correctly because NoneCall returns null. The normalization chokepoint covers all three write paths. The outstanding issue is a UX/contract gap in the create endpoint: passing LAST_KNOWN for a non-NONE type returns 200 with a silently different stored value, which contrasts with the 400 returned for other invalid values.

src/routes/(api)/api/v4/monitors/+server.ts — the POST create path silently coerces LAST_KNOWN to UP for non-NONE types; src/lib/server/queues/monitorExecuteQueue.ts — the LAST_KNOWN carry branch should guard against carrying a NO_DATA status from a REALTIME row.

Important Files Changed

Filename Overview
src/lib/server/queues/monitorExecuteQueue.ts Adds LAST_KNOWN/CARRIED fill branch and preserves fill type through the merge. The latency carry is correct because NoneCall.execute() returns null, so realtimeData is empty and defaultData wins the merge. No regression on fixed-fill path.
src/lib/server/controllers/monitorsController.ts Adds NormalizeDefaultStatus as a single enforcement chokepoint, wired into CreateUpdateMonitor (manage UI path). The silent UP coercion for LAST_KNOWN on non-NONE types is intentional for type-change PATCHes but surprising for POST creates.
src/routes/(api)/api/v4/monitors/+server.ts Validates default_status on POST creation. Silent coercion of LAST_KNOWN → UP for non-NONE types gives a 200 with a different stored value than requested.
src/routes/(api)/api/v4/monitors/[monitor_tag]/+server.ts NormalizeDefaultStatus correctly runs after monitor_type is resolved so a type change away from NONE auto-resets LAST_KNOWN to UP — this path is correct.
src/lib/server/db/repositories/monitoring.ts Adds getLatestAlertVisibleData querying the existing ALERT_VISIBLE_TYPES set (now includes CARRIED). Query is straightforward and correct.
migrations/20260607150000_normalize_default_status.ts Normalizes legacy/null default_status values to NONE. Intentionally irreversible since MAINTENANCE and unknown values were never honored by the fill engine. LAST_KNOWN is included in VALID to avoid wiping fresh rows.
src/routes/(manage)/manage/app/monitors/[tag]/components/GeneralSettingsCard.svelte Adds LAST_KNOWN option (conditionally on NONE-type monitors), removes MAINTENANCE option, adds warning callout, and adds a $effect to live-reset LAST_KNOWN on type changes. UI logic mirrors the server-side normalization.
src/lib/global-constants.ts Adds CARRIED and LAST_KNOWN constants cleanly.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Scheduler tick for NONE-type monitor] --> B{default_status?}
    B -- UP/DOWN/DEGRADED --> C[Write DEFAULT_STATUS row]
    B -- LAST_KNOWN --> D[getLatestAlertVisibleData]
    B -- NONE --> E[No fill — gap stays as no data]
    D -- found row --> F{status is NO_DATA?}
    F -- no --> G[Write CARRIED row\nstatus + latency from last known]
    F -- yes --> E
    D -- not found --> E
    G --> H[mergedData wins in spread:\ndefaultData beats empty realtimeData]
    C --> H
    H --> I[incidentData / maintenanceData\ncan still override]
    I --> J[monitorResponseQueue.push]
Loading

Reviews (1): Last reviewed commit: "style: prettify files touched by Last Kn..." | Re-trigger Greptile


let defaultStatus: string;
try {
defaultStatus = NormalizeDefaultStatus(body.monitor_type ?? "API", body.default_status ?? "UP");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Silent LAST_KNOWN coercion masks invalid requests on creation

NormalizeDefaultStatus silently returns "UP" when default_status: "LAST_KNOWN" is sent with a non-NONE monitor_type. For a PATCH where monitor_type is changing away from NONE, this auto-reset is intentional and desirable. For a POST (create), a caller that explicitly sets default_status: "LAST_KNOWN" with e.g. monitor_type: "API" gets a 201 response but the stored default_status is "UP" — a silent data change that is inconsistent with the 400 returned for every other invalid value (e.g. "MAINTENANCE"). Consider throwing inside NormalizeDefaultStatus when the combination is invalid on creation, or having the POST endpoint validate the combination before calling the normalizer.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +138 to +142
} else if (monitor.default_status === GC.LAST_KNOWN) {
// Last Known Status fill (docs/adr/0006): repeat the most recent alert-visible
// sample — status and latency alike. No sample yet → nothing to carry → no fill.
const lastKnown = await db.getLatestAlertVisibleData(monitor.tag);
if (lastKnown && lastKnown.status) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Defensive guard: avoid carrying a NO_DATA status

getLatestAlertVisibleData includes REALTIME rows in its result set. It is theoretically possible for a REALTIME row to carry status: "NO_DATA" (e.g. if a monitor type is changed after data is already written). If such a row is the most recent alert-visible sample, defaultData[ts].status would be "NO_DATA" and that value would be written into a CARRIED row and persist indefinitely. Adding an explicit lastKnown.status !== GC.NO_DATA guard closes this edge case.

Suggested change
} else if (monitor.default_status === GC.LAST_KNOWN) {
// Last Known Status fill (docs/adr/0006): repeat the most recent alert-visible
// sample — status and latency alike. No sample yet → nothing to carry → no fill.
const lastKnown = await db.getLatestAlertVisibleData(monitor.tag);
if (lastKnown && lastKnown.status) {
} else if (monitor.default_status === GC.LAST_KNOWN) {
// Last Known Status fill (docs/adr/0006): repeat the most recent alert-visible
// sample — status and latency alike. No sample yet → nothing to carry → no fill.
const lastKnown = await db.getLatestAlertVisibleData(monitor.tag);
if (lastKnown && lastKnown.status && lastKnown.status !== GC.NO_DATA) {

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/superpowers/plans/2026-06-07-last-known-status.md`:
- Around line 689-691: The fenced code block containing "Amended by ADR 0006:
last-known-status fill (`CARRIED`) later joined the alert-visible set under the
same invariant." should include a language identifier (e.g., ```text) or be
converted to normal paragraph text to satisfy MD040; update the existing
triple-backtick block around that sentence to ```text ... ``` or replace the
fenced block with a plain paragraph containing that sentence.
- Line 17: Several task section headings use H3 (e.g., "### Task 1: Constants +
alert-visible whitelist") which causes markdown-lint MD001; update those
headings to H2 by changing the leading "###" to "##". Search for the pattern
"### Task" across the document (including the instances around the provided
comment) and promote each to "## Task ..." so all task sections are H2 and lint
compliant.

In `@migrations/20260607150000_normalize_default_status.ts`:
- Around line 8-11: The migration's up function should guard against missing
table/column to be idempotent: inside up(), first call await
knex.schema.hasTable("monitors") and if false return early; then call await
knex.schema.hasColumn("monitors", "default_status") and return early if false;
only after both exist run the two update statements (the existing await
knex("monitors").whereNull... and await
knex("monitors").whereNotIn("default_status", VALID)...). Keep the VALID symbol
as-is and ensure the early returns prevent running updates on partial schemas.

In `@src/routes/`(docs)/docs/content/v4/monitors/overview.md:
- Around line 57-62: Update the curl example to clarify the timestamp
placeholder: replace {current_unix_minute} with a clearer placeholder like
{unix_timestamp} and add a short inline comment above the command stating
"Replace {unix_timestamp} with the Unix timestamp of the current minute (e.g.,
1686139200)". Ensure the example PATCH request line in the docs content (the
curl invocation) uses the new placeholder {unix_timestamp} so readers know to
substitute a numeric Unix timestamp representing the current minute.
- Around line 32-68: The example curl uses the unclear placeholder
{current_unix_minute}; update the explanatory text (near the "Example push flow"
curl block) to state succinctly that {current_unix_minute} must be the Unix
timestamp in seconds representing the start of the target minute (the API will
round to the UTC minute boundary using its minute-start helpers), keep the
existing > [!WARNING] callout syntax as-is, and ensure the curl command and
surrounding prose mention this replacement so readers know to substitute the
timestamp seconds value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d50f96a6-ff10-4466-ba5e-f6010e8227d2

📥 Commits

Reviewing files that changed from the base of the PR and between 6042105 and 74b6311.

📒 Files selected for processing (14)
  • CONTEXT.md
  • docs/adr/0005-alerts-evaluate-alert-visible-samples.md
  • docs/adr/0006-last-known-status-fill.md
  • docs/superpowers/plans/2026-06-07-last-known-status.md
  • migrations/20260607150000_normalize_default_status.ts
  • src/lib/global-constants.ts
  • src/lib/server/controllers/monitorsController.ts
  • src/lib/server/db/dbimpl.ts
  • src/lib/server/db/repositories/monitoring.ts
  • src/lib/server/queues/monitorExecuteQueue.ts
  • src/routes/(api)/api/v4/monitors/+server.ts
  • src/routes/(api)/api/v4/monitors/[monitor_tag]/+server.ts
  • src/routes/(docs)/docs/content/v4/monitors/overview.md
  • src/routes/(manage)/manage/app/monitors/[tag]/components/GeneralSettingsCard.svelte


---

### Task 1: Constants + alert-visible whitelist

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix heading-level jumps to satisfy markdown lint.

Task sections jump from H1 to H3. Promote these task headings to H2 to avoid MD001 violations.

Suggested diff
-### Task 1: Constants + alert-visible whitelist
+## Task 1: Constants + alert-visible whitelist
...
-### Task 2: Repository — latest alert-visible sample query
+## Task 2: Repository — latest alert-visible sample query
...
-### Task 8: End-to-end verification against the dev server
+## Task 8: End-to-end verification against the dev server

Also applies to: 86-86, 187-187, 308-308, 490-490, 541-541, 676-676, 720-720

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 17-17: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/superpowers/plans/2026-06-07-last-known-status.md` at line 17, Several
task section headings use H3 (e.g., "### Task 1: Constants + alert-visible
whitelist") which causes markdown-lint MD001; update those headings to H2 by
changing the leading "###" to "##". Search for the pattern "### Task" across the
document (including the instances around the provided comment) and promote each
to "## Task ..." so all task sections are H2 and lint compliant.

Source: Linters/SAST tools

Comment on lines +689 to +691
```
Amended by ADR 0006: last-known-status fill (`CARRIED`) later joined the alert-visible set under the same invariant.
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language identifier to the fenced code block.

The fenced block triggers MD040; add a language tag (e.g., text) or convert it to plain paragraph text.

Suggested diff
-```
+```text
 Amended by ADR 0006: last-known-status fill (`CARRIED`) later joined the alert-visible set under the same invariant.
</details>

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.22.1)</summary>

[warning] 689-689: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs/superpowers/plans/2026-06-07-last-known-status.md around lines 689 -
691, The fenced code block containing "Amended by ADR 0006: last-known-status
fill (CARRIED) later joined the alert-visible set under the same invariant."
should include a language identifier (e.g., text) or be converted to normal paragraph text to satisfy MD040; update the existing triple-backtick block around that sentence to text ... ``` or replace the fenced block with a plain
paragraph containing that sentence.


</details>

<!-- fingerprinting:phantom:poseidon:hawk -->

<!-- cr-comment:v1:0b63b68c908a8f63fb1f33cc -->

_Source: Linters/SAST tools_

<!-- This is an auto-generated comment by CodeRabbit -->

Comment on lines +8 to +11
export async function up(knex: Knex): Promise<void> {
await knex("monitors").whereNull("default_status").update({ default_status: "NONE" });
await knex("monitors").whereNotIn("default_status", VALID).update({ default_status: "NONE" });
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add schema guards before data updates in this migration.

This migration should guard monitors/default_status existence before running updates, otherwise it can fail on partial/non-standard schema states.

Suggested fix
 export async function up(knex: Knex): Promise<void> {
-  await knex("monitors").whereNull("default_status").update({ default_status: "NONE" });
-  await knex("monitors").whereNotIn("default_status", VALID).update({ default_status: "NONE" });
+  const hasMonitors = await knex.schema.hasTable("monitors");
+  if (!hasMonitors) return;
+
+  const hasDefaultStatus = await knex.schema.hasColumn("monitors", "default_status");
+  if (!hasDefaultStatus) return;
+
+  await knex("monitors").whereNull("default_status").update({ default_status: "NONE" });
+  await knex("monitors").whereNotIn("default_status", VALID).update({ default_status: "NONE" });
 }

Based on learnings: “Use knex.schema.hasColumn and knex.schema.hasTable guards for migration idempotency.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function up(knex: Knex): Promise<void> {
await knex("monitors").whereNull("default_status").update({ default_status: "NONE" });
await knex("monitors").whereNotIn("default_status", VALID).update({ default_status: "NONE" });
}
export async function up(knex: Knex): Promise<void> {
const hasMonitors = await knex.schema.hasTable("monitors");
if (!hasMonitors) return;
const hasDefaultStatus = await knex.schema.hasColumn("monitors", "default_status");
if (!hasDefaultStatus) return;
await knex("monitors").whereNull("default_status").update({ default_status: "NONE" });
await knex("monitors").whereNotIn("default_status", VALID).update({ default_status: "NONE" });
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@migrations/20260607150000_normalize_default_status.ts` around lines 8 - 11,
The migration's up function should guard against missing table/column to be
idempotent: inside up(), first call await knex.schema.hasTable("monitors") and
if false return early; then call await knex.schema.hasColumn("monitors",
"default_status") and return early if false; only after both exist run the two
update statements (the existing await knex("monitors").whereNull... and await
knex("monitors").whereNotIn("default_status", VALID)...). Keep the VALID symbol
as-is and ensure the early returns prevent running updates on partial schemas.

Source: Learnings

Comment on lines +32 to +68
## Default Status {#default-status}

Default Status is the monitor's answer to the question: **what does a minute with no monitoring sample mean?**

| Value | Behavior |
| ------------ | ------------------------------------------------------------------------------------------------------------------------- |
| `NONE` | Gap minutes show as no data (gray) |
| `UP` | A `DEFAULT` sample is written each minute marking the service UP |
| `DOWN` | A `DEFAULT` sample is written each minute marking the service DOWN |
| `DEGRADED` | A `DEFAULT` sample is written each minute marking the service DEGRADED |
| `LAST_KNOWN` | Each minute without a new sample, Kener writes a `CARRIED` row repeating the most recent alert-visible status and latency |

### Last known status {#last-known-status}

`LAST_KNOWN` is only available on **Manual (`NONE`-type) monitors**. If you select it on any other monitor type, the API resets it to `UP`. Changing a monitor's type away from Manual also resets it to `UP`.

How it works:

- Every scheduler tick with no new data, Kener writes a `CARRIED` sample copying the status and latency of the most recent alert-visible sample.
- Carry is tick-forward only — it starts at the next scheduler tick after you save the setting, with no backfill of past gaps.
- Carried rows persist in history even if you later change the setting.

Example push flow:

```bash
curl -X PATCH 'https://status.example.com/api/v4/monitors/my-service/data/{current_unix_minute}' \
-H 'Authorization: Bearer <api-key>' \
-H 'Content-Type: application/json' \
--data '{"status": "DOWN", "latency": 100}'
# With Default Status = Last known status, the monitor stays DOWN until you push UP.
```

> [!WARNING]
>
> - If your integration stops sending, the page keeps showing the last status indefinitely — Kener cannot tell "still up" from "stopped reporting". Use a [Heartbeat monitor](/docs/v4/monitors/heartbeat) to catch a silent integration.
> - Carried minutes count toward alert thresholds: a single DOWN push will trigger alerts after your failure threshold, and they stay triggered until you push a recovery.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if other docs use the [!WARNING] callout syntax

# Search for similar markdown callout usage in docs
rg -n '>\s*\[!(WARNING|NOTE|TIP|IMPORTANT)' --type=md --glob 'src/routes/(docs)/**'

Repository: rajnandan1/kener

Length of output: 3796


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Read the documentation-writer guidelines skill file
if [ -f .claude/skills/documentation-writer/SKILL.md ]; then
  echo "=== .claude/skills/documentation-writer/SKILL.md (head) ==="
  sed -n '1,200p' .claude/skills/documentation-writer/SKILL.md
else
  echo "SKILL.md not found at .claude/skills/documentation-writer/SKILL.md"
fi

# 2) Check whether {current_unix_minute} is used elsewhere in docs
echo
echo "=== Usage of {current_unix_minute} ==="
rg -n '\{current_unix_minute\}' --type=md --glob 'src/routes/(docs)/**' || true

# 3) Check whether other docs use a similar PATCH URL placeholder for "minute" endpoints
echo
echo "=== Usage of /data/{current_*_minute} patterns ==="
rg -n '/data/\{current_.*_minute\}' --type=md --glob 'src/routes/(docs)/**' || true

Repository: rajnandan1/kener

Length of output: 3819


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect the relevant section in the target file
echo "=== monitors/overview.md lines 40-90 ==="
nl -ba src/routes/(docs)/docs/content/v4/monitors/overview.md | sed -n '40,95p'

# 2) Find any other mention of current_unix_minute / unix_minute placeholders
echo
echo "=== occurrences of current_unix_minute in repo ==="
rg -n 'current_unix_minute' --hidden --glob '!.git/*' || true

# 3) Find any mentions of the data endpoint minute placeholder style
echo
echo "=== occurrences of /data/{current_*_minute} ==="
rg -n '/data/\{current_.*_minute\}' --type=md --glob 'src/routes/(docs)/**' || true

# 4) Look for API/code route parameter naming for monitors data patch
echo
echo "=== server/routes code mentioning monitors data patch and unix minute ==="
rg -n 'monitors.*data.*(minute|unix)' --hidden --glob 'src/**' || true

Repository: rajnandan1/kener

Length of output: 181


🏁 Script executed:

#!/bin/bash
set -euo pipefail

TARGET_FILE="src/routes/(docs)/docs/content/v4/monitors/overview.md"

# 1) Inspect the relevant section in the target file
echo "=== monitors/overview.md lines 40-90 ==="
nl -ba "$TARGET_FILE" | sed -n '40,95p'

# 2) Find any other mention of current_unix_minute / unix_minute placeholders
echo
echo "=== occurrences of current_unix_minute in repo ==="
rg -n 'current_unix_minute' --hidden --glob '!.git/*' || true

echo
echo "=== occurrences of unix_minute placeholder ==="
rg -n 'unix_minute' --hidden --glob '!.git/*' || true

# 3) Find any mentions of the data endpoint minute placeholder style
echo
echo "=== occurrences of /data/{current_*_minute} in docs ==="
rg -n '/data/\{current_.*_minute\}' --type=md --glob 'src/routes/(docs)/**' || true

# 4) Look for server-side route param naming in code
echo
echo "=== server/code references to monitors data + unix minute ==="
rg -n 'monitors.*data.*(minute|unix)' --hidden --glob 'src/**' || true

Repository: rajnandan1/kener

Length of output: 162


🏁 Script executed:

#!/bin/bash
set -euo pipefail

TARGET_FILE="src/routes/(docs)/docs/content/v4/monitors/overview.md"

# 1) Inspect the relevant section in the target file
echo "=== monitors/overview.md lines 40-95 ==="
cat -n "$TARGET_FILE" | sed -n '40,100p'

# 2) Find any other mention of current_unix_minute / unix_minute placeholders
echo
echo "=== occurrences of current_unix_minute in repo ==="
rg -n 'current_unix_minute' --hidden --glob '!.git/*' || true

echo
echo "=== occurrences of unix_minute placeholder in repo ==="
rg -n 'unix_minute' --hidden --glob '!.git/*' || true

# 3) Find any mentions of the data endpoint minute placeholder style
echo
echo "=== occurrences of /data/{current_*_minute} in docs ==="
rg -n '/data/\{current_.*_minute\}' --type=md --glob 'src/routes/(docs)/**' || true

# 4) Look for server-side route param naming in code
echo
echo "=== server/code references to monitors data + (minute|unix) ==="
rg -n 'monitors.*data.*(minute|unix)' --hidden --glob 'src/**' || true

Repository: rajnandan1/kener

Length of output: 4640


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the other doc that uses {current_unix_minute}
FILE="docs/superpowers/plans/2026-06-07-last-known-status.md"

echo "=== $FILE (lines 670-730) ==="
cat -n "$FILE" | sed -n '670,730p'

echo
echo "=== $FILE occurrences of current_unix_minute ==="
rg -n 'current_unix_minute' --hidden --glob '!.git/*' "$FILE" || true

Repository: rajnandan1/kener

Length of output: 3670


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Locate the PATCH route implementation for monitors data
echo "=== Search for PATCH monitors data route in src/ ==="
rg -n "PATCH.*monitors.*data" --hidden --glob 'src/**' || true

echo
echo "=== Search for '/api/v4/monitors' and 'data' route handlers ==="
rg -n "/api/v4/monitors" --hidden --glob 'src/**' || true

echo
echo "=== Search for 'current_unix_minute' and 'unix minute' in server code ==="
rg -n "current_unix_minute|unix.?minute|unix_minute" --hidden --glob 'src/**' || true

echo
echo "=== Search for route param names like ':.*minute' near monitors data ==="
rg -n "monitors.*data.*:.*minute|monitors.*:.*data.*:.*minute" --hidden --glob 'src/**' || true

Repository: rajnandan1/kener

Length of output: 1964


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Repo-wide search for monitors data PATCH patterns ==="
rg -n "monitors/\{?tag\}?.*data.*\{?timestamp\}?|\/api\/v4\/monitors\/\{?\w+\}?\/data" --hidden --glob '!.git/*' . || true

echo
echo "=== Repo-wide search for 'monitors/{tag}/data' and 'data/{' ==="
rg -n "monitors\/\{tag\}\/data|\/data\/\{[a-zA-Z_]+\}" --hidden --glob '!.git/*' . || true

echo
echo "=== Repo-wide search for 'minute' route param naming ==="
rg -n "minute[s]?|unix.?minute|unix_minute|timestamp" --hidden --glob '!.git/*' src || true

Repository: rajnandan1/kener

Length of output: 50698


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Search: /api/v4/monitors + data + patch in src/lib/server ==="
rg -n "/api/v4/monitors" src/lib/server --hidden -g'*.ts' -S || true

echo
echo "=== Search: monitors.*data in api-server folder ==="
rg -n "monitors.*data|data.*monitors" src/lib/server/api-server --hidden -g'*.ts' -S || true

echo
echo "=== Search: PATCH handlers in api-server folder ==="
rg -n "patch\\(" src/lib/server/api-server --hidden -g'*.ts' -S || true

echo
echo "=== Inspect monitorsController.ts for data/timestamp handling ==="
FILE="src/lib/server/controllers/monitorsController.ts"
if [ -f "$FILE" ]; then
  sed -n '1,220p' "$FILE" | nl -ba | sed -n '1,220p'
  echo
  echo "=== monitor controller occurrences of 'data' and 'timestamp' ==="
  rg -n "data|timestamp" "$FILE" -g'*.ts' || true
else
  echo "Missing: $FILE"
fi

Repository: rajnandan1/kener

Length of output: 615


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect monitorsController.ts (where timestamp likely validated)
FILE="src/lib/server/controllers/monitorsController.ts"
echo "=== $FILE (head 260 lines) ==="
if [ -f "$FILE" ]; then
  cat -n "$FILE" | sed -n '1,260p'
else
  echo "Missing: $FILE"
fi

# 2) Search for route paths / param names in server code
echo
echo "=== Search (fixed strings) for monitors data patch paths ==="
rg -n -F "/api/v4/monitors" src/lib/server --hidden -g'*.ts' -S || true

echo
echo "=== Search (fixed strings) for 'data/{' patterns ==="
rg -n -F "data/" src/lib/server --hidden -g'*.ts' -S || true

echo
echo "=== Search for 'timestamp' param parsing in monitors controller ==="
rg -n "timestamp|minuteStart|MinuteStart|minute" src/lib/server/controllers/monitorsController.ts --hidden -g'*.ts' -S || true

# 3) Search elsewhere for monitors data endpoint implementation
echo
echo "=== Search for 'monitorsController' usage ==="
rg -n "monitorsController" src/lib/server --hidden -g'*.ts' -S || true

echo
echo "=== Search for 'monitors' route registration (express/fastify) ==="
rg -n "router\\.|app\\.|route\\(" src/lib/server --hidden -g'*.ts' -S || true

Repository: rajnandan1/kener

Length of output: 12344


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect tool.ts functions
TOOL_FILE="src/lib/server/tool.ts"
echo "=== $TOOL_FILE (relevant UTC minute helpers) ==="
rg -n "GetMinuteStartTimestampUTC|GetMinuteStartNowTimestampUTC" "$TOOL_FILE" || true
cat -n "$TOOL_FILE" | sed -n '1,120p'

echo
# Find which API endpoints call these controller helpers
echo "=== Find usages of InsertMonitoringData / UpdateMonitoringData ==="
rg -n "InsertMonitoringData\\b|UpdateMonitoringData\\b" src/lib/server --hidden -g'*.ts' -S

echo
# Inspect the endpoint file(s) found above (show small surrounding windows)
FILES=$(rg -l "InsertMonitoringData\\b|UpdateMonitoringData\\b" src/lib/server --hidden -g'*.ts' -S || true)
echo "=== Files found ==="
echo "$FILES" | head -n 50
for f in $FILES; do
  echo
  echo "=== $f (mentions) ==="
  rg -n "InsertMonitoringData\\b|UpdateMonitoringData\\b" "$f" -n -S
  # show a small neighborhood around the first match
  line=$(rg -n "InsertMonitoringData\\b|UpdateMonitoringData\\b" "$f" | head -n 1 | cut -d: -f1)
  if [ -n "${line:-}" ]; then
    start=$((line-40)); end=$((line+80))
    cat -n "$f" | sed -n "${start},${end}p"
  fi
done

Repository: rajnandan1/kener

Length of output: 8595


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect monitorsController around where InsertMonitoringData is called
CTRL="src/lib/server/controllers/monitorsController.ts"
echo "=== monitorsController.ts: lines 340-430 ==="
awk 'NR>=340 && NR<=430 {printf "%6d\t%s\n", NR, $0}' "$CTRL"

echo
echo "=== monitorsController.ts: occurrences of InsertMonitoringData( / UpdateMonitoringData( ==="
rg -n "InsertMonitoringData\\(|UpdateMonitoringData\\(" "$CTRL" -S

# 2) Inspect tool.ts for minute start helper usage (already partially seen; grab remaining lines too)
TOOL="src/lib/server/tool.ts"
echo
echo "=== tool.ts: GetMinuteStartTimestampUTC / GetMinuteStartNowTimestampUTC definitions (lines 20-80) ==="
awk 'NR>=20 && NR<=90 {printf "%6d\t%s\n", NR, $0}' "$TOOL"

# 3) Find api-server endpoints for monitors "data" operations
echo
echo "=== api-server: files that mention monitorsController and/or 'monitor.*data' ==="
rg -l "monitorsController|monitor.*data|/api/v4/monitors|data/\\{|" src/lib/server/api-server -S --glob '*.ts' || true

echo
echo "=== api-server: any routes/controllers mentioning 'data' for monitors ==="
rg -n "monitors.*data|data.*monitors|monitor.*data" src/lib/server/api-server --glob '*.ts' -S || true

# 4) If there are dynamic route patterns like :timestamp or {timestamp}, search globally in src/lib/server
echo
echo "=== server: route param patterns for timestamp and monitors data ==="
rg -n "monitors.*data.*(:|\\{).*(timestamp|minute)|data.*(:|\\{).*(timestamp|minute)|:timestamp" src/lib/server --glob '*.ts' -S || true

Repository: rajnandan1/kener

Length of output: 11492


Adjust the {current_unix_minute} curl placeholder + keep the callout syntax suggestion as-is

  • The docs use the same > [!WARNING] callout syntax elsewhere in src/routes/(docs)/docs/content/v4, so the callout format is consistent across the repo; no change needed there.
  • {current_unix_minute} only appears in this page (and in a planning doc), and nothing in the docs explains what to replace it with; clarify that it must be the Unix timestamp (seconds) for the start of the target minute (the API rounds minute timestamps to the UTC minute boundary in its minute-start helpers).
  • Brevity: the two warning bullets are fine given they describe distinct failure/alerting implications; optional only.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/routes/`(docs)/docs/content/v4/monitors/overview.md around lines 32 - 68,
The example curl uses the unclear placeholder {current_unix_minute}; update the
explanatory text (near the "Example push flow" curl block) to state succinctly
that {current_unix_minute} must be the Unix timestamp in seconds representing
the start of the target minute (the API will round to the UTC minute boundary
using its minute-start helpers), keep the existing > [!WARNING] callout syntax
as-is, and ensure the curl command and surrounding prose mention this
replacement so readers know to substitute the timestamp seconds value.

Comment on lines +57 to +62
curl -X PATCH 'https://status.example.com/api/v4/monitors/my-service/data/{current_unix_minute}' \
-H 'Authorization: Bearer <api-key>' \
-H 'Content-Type: application/json' \
--data '{"status": "DOWN", "latency": 100}'
# With Default Status = Last known status, the monitor stays DOWN until you push UP.
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Clarify the timestamp placeholder in the curl example.

The example uses {current_unix_minute} as a placeholder. While developers familiar with the API will understand this, first-time users might benefit from a more explicit note.

📝 Proposed improvement
 ```bash
-curl -X PATCH 'https://status.example.com/api/v4/monitors/my-service/data/{current_unix_minute}' \
+# Replace {unix_timestamp} with the Unix timestamp of the current minute (e.g., 1686139200)
+curl -X PATCH 'https://status.example.com/api/v4/monitors/my-service/data/{unix_timestamp}' \
   -H 'Authorization: Bearer <api-key>' \
   -H 'Content-Type: application/json' \
   --data '{"status": "DOWN", "latency": 100}'
 # With Default Status = Last known status, the monitor stays DOWN until you push UP.

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @src/routes/(docs)/docs/content/v4/monitors/overview.md around lines 57 - 62,
Update the curl example to clarify the timestamp placeholder: replace
{current_unix_minute} with a clearer placeholder like {unix_timestamp} and add a
short inline comment above the command stating "Replace {unix_timestamp} with
the Unix timestamp of the current minute (e.g., 1686139200)". Ensure the example
PATCH request line in the docs content (the curl invocation) uses the new
placeholder {unix_timestamp} so readers know to substitute a numeric Unix
timestamp representing the current minute.


</details>

<!-- fingerprinting:phantom:poseidon:puma -->

<!-- cr-comment:v1:93fb35bd8f15ff5ca59677ca -->

<!-- This is an auto-generated comment by CodeRabbit -->

@rajnandan1 rajnandan1 closed this Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Kener v4 - Latest monitor status is not kept when the default status is set to NONE

2 participants