Skip to content

feat(channel): add deterministic temporal context#239

Merged
jamiepine merged 9 commits intospacedriveapp:mainfrom
vsumner:vsumner/temporal-context-datetime
Feb 27, 2026
Merged

feat(channel): add deterministic temporal context#239
jamiepine merged 9 commits intospacedriveapp:mainfrom
vsumner:vsumner/temporal-context-datetime

Conversation

@vsumner
Copy link
Contributor

@vsumner vsumner commented Feb 26, 2026

Summary

  • Added a first-class user_timezone config (defaults + per-agent + env + hot reload) to control channel/worker temporal grounding independently from cron scheduling.
  • Injected a live current date/time line (timezone + UTC) into channel status context so relative references like "today/tomorrow/now" are anchored deterministically.
  • Updated single-message and batched-message formatting to include absolute timestamp context, while preserving relative hints in coalesced bursts.
  • Added worker task time-context preambles for both builtin and OpenCode workers so delegated work interprets relative date language consistently.
  • Updated channel/branch prompt guidance to prefer concrete dates for time-sensitive responses.
  • Updated config docs with user_timezone examples and explicit precedence.
  • Added targeted tests for timezone precedence/fallback, status rendering, message formatting, and worker preamble behavior.

Testing

  • cargo fmt --all --check
  • cargo clippy --all-targets -- -D warnings
  • cargo check
  • cargo test --lib
  • cargo test --lib test_user_timezone_resolution_precedence
  • cargo test --lib test_user_timezone_falls_back_to_cron_timezone
  • cargo test --lib test_user_timezone_invalid_falls_back_to_cron_timezone
  • cargo test --lib format_user_message_handles_empty_text
  • cargo test --lib format_batched_message_includes_absolute_and_relative_time
  • cargo test --lib worker_task_temporal_context_preamble_includes_absolute_dates
  • cargo test --lib render_with_time_context_renders_current_time_when_empty
  • cargo test currently fails locally only on tests/bulletin.rs because those tests require real ~/.spacebot runtime data/credentials; CI should validate in the intended environment.

Note

This PR introduces deterministic temporal grounding to Spacebot by adding first-class user_timezone configuration. Every channel now receives a live current date/time context line in its status block, anchoring relative time references (today/tomorrow/now) to a specific timezone. Worker tasks are prefixed with absolute date/time context to ensure delegated work interprets time-sensitive language consistently. Configuration supports per-agent overrides, environment variables, and hot-reload via ArcSwap. All user-facing messages now include absolute timestamps alongside relative hints, improving clarity in multi-user scenarios. The resolution precedence is agent → defaults → env → fallback to cron timezone → system local.

Written by Tembo for commit c1cd228. This will update automatically on new commits.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds per-channel/worker user_timezone config with inheritance and precedence; wires it through config loading, API creation, runtime reload, and runtime usage; implements temporal context (current local/UTC lines and absolute timestamps) across message formatting, worker task preambles, status rendering, prompts, and docs.

Changes

Cohort / File(s) Summary
Configuration & Documentation
docs/content/docs/(configuration)/config.mdx
Added user_timezone in [defaults] and [[agents]], documented inheritance and new "Channel/worker temporal context timezone precedence" section.
Prompts & prompt engine
prompts/en/branch.md.j2, prompts/en/channel.md.j2, prompts/en/fragments/system/worker_time_context.md.j2, src/prompts/engine.rs, src/prompts/text.rs
Added guidance to prefer explicit timestamps and include current date/time lines; introduced worker_time_context fragment, registered it, and added rendering API.
Config types, env, and resolution
src/config.rs
Added USER_TIMEZONE_ENV_VAR; introduced user_timezone across TOML structs, Defaults/Agent/ResolvedAgent/RuntimeConfig; implemented resolve_user_timezone precedence (agent > defaults > env > cron/system fallback), validation, and tests; wired reloads.
API agent creation
src/api/agents.rs
Initialized user_timezone to None in agent creation flow so new agents carry the optional field.
Channel temporal context & message formatting
src/agent/channel.rs
Introduced TemporalTimezone and TemporalContext, utilities for current time lines and formatted absolute timestamps; updated per-message and batched formatting, elapsed calculations, and integrated temporal context into worker/OpenCode task construction and tests.
Status rendering
src/agent/status.rs
Added pub fn render_with_time_context(&self, current_time_line: Option<&str>) -> String (existing render() delegates to it) to optionally inject a "Current date/time" line; added tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(channel): add deterministic temporal context' directly corresponds to the main change: adding deterministic temporal grounding via new user_timezone config and live current date/time context injection into channel status.
Description check ✅ Passed The description comprehensively covers the changeset, detailing user_timezone configuration, temporal context injection, message formatting updates, worker task preambles, prompt guidance updates, documentation, and testing performed.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/agent/channel.rs`:
- Around line 665-676: The relative time is being calculated from
first_timestamp which makes later messages show as older; change the calculation
to compute seconds between the batch tail (the latest timestamp) and each
message timestamp instead. Replace the use of first_timestamp in the
relative_secs computation with the batch tail / last message timestamp (e.g.,
derive tail_timestamp from messages.last().timestamp or your existing
batch_tail_timestamp), so relative_secs =
tail_timestamp.signed_duration_since(message.timestamp).num_seconds().max(0) and
keep the existing relative_text formatting logic unchanged; update references to
message.timestamp, first_timestamp, and relative_secs accordingly in channel.rs.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d0d58b7 and c1cd228.

📒 Files selected for processing (7)
  • docs/content/docs/(configuration)/config.mdx
  • prompts/en/branch.md.j2
  • prompts/en/channel.md.j2
  • src/agent/channel.rs
  • src/agent/status.rs
  • src/api/agents.rs
  • src/config.rs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/agent/channel.rs (1)

2378-2385: ⚠️ Potential issue | 🟡 Minor

Batched formatter still renders blank payloads for attachment-only messages.

raw_text is passed through directly, so empty media-text messages produce a dangling colon with no placeholder. This is the same issue already noted previously and remains unresolved.

🔧 Proposed fix
 fn format_batched_user_message(
     display_name: &str,
     absolute_timestamp: &str,
     relative_text: &str,
     raw_text: &str,
 ) -> String {
-    format!("[{display_name}] ({absolute_timestamp}; {relative_text}): {raw_text}")
+    let text_content = if raw_text.trim().is_empty() {
+        "[attachment or empty message]"
+    } else {
+        raw_text
+    };
+    format!("[{display_name}] ({absolute_timestamp}; {relative_text}): {text_content}")
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agent/channel.rs` around lines 2378 - 2385, The batched formatter
function format_batched_user_message currently inserts raw_text unconditionally,
producing a dangling colon for attachment-only messages; update
format_batched_user_message to detect when raw_text is empty or whitespace (use
the raw_text parameter) and conditionally either omit the ": {raw_text}" segment
or substitute a clear placeholder such as "<attachment-only>" so the output for
attachment-only messages is well-formed; ensure the change preserves the
existing display_name, absolute_timestamp, and relative_text formatting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/agent/channel.rs`:
- Around line 119-125: The prompt text hard-coded in worker_task_preamble should
be moved to a markdown prompt file (e.g., prompts/worker_time_context.md) and
worker_task_preamble should load and render that template with the current
timestamps instead of returning a string constant. Replace the string literal in
fn worker_task_preamble(&self) with logic that reads the prompt template from
prompts/worker_time_context.md (or uses a prompt-loading helper if one exists),
substitute/format placeholders with self.format_timestamp(self.now_utc) and
self.now_utc.format(...) (or pass those values into the template renderer), and
return the rendered string; keep the function name worker_task_preamble and use
format_timestamp and self.now_utc as the substitution values. Ensure file read
errors are handled or surfaced consistently with existing prompt-loading
conventions.
- Around line 51-83: The from_runtime function currently picks user_timezone (or
cron_timezone only if user is None) and if a present user_timezone fails to
parse it falls back directly to SystemLocal; change the logic to try parsing
user_timezone first and if parsing fails (after logging the warning) then
attempt parsing cron_timezone before finally falling back to
TemporalTimezone::SystemLocal. Concretely, in from_runtime use
runtime_config.user_timezone.load() and runtime_config.cron_timezone.load()
separately, attempt timezone_name.parse::<Tz>() on user_timezone (returning
TemporalTimezone::Named on success), on Err log the existing warning and then
attempt parsing cron_timezone and return its TemporalTimezone::Named if it
parses, otherwise return the SystemLocal variant; keep existing now_utc,
TemporalTimezone::Named construction, and warning text/fields.

---

Duplicate comments:
In `@src/agent/channel.rs`:
- Around line 2378-2385: The batched formatter function
format_batched_user_message currently inserts raw_text unconditionally,
producing a dangling colon for attachment-only messages; update
format_batched_user_message to detect when raw_text is empty or whitespace (use
the raw_text parameter) and conditionally either omit the ": {raw_text}" segment
or substitute a clear placeholder such as "<attachment-only>" so the output for
attachment-only messages is well-formed; ensure the change preserves the
existing display_name, absolute_timestamp, and relative_text formatting.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c1cd228 and 58bc4be.

📒 Files selected for processing (1)
  • src/agent/channel.rs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/agent/channel.rs (2)

119-125: 🛠️ Refactor suggestion | 🟠 Major

Move worker time-context prompt text to prompts/ instead of embedding it in Rust.

Line 121 embeds system prompt instruction text as a string constant. This should be template-driven from markdown prompt files for consistency and prompt governance.

As per coding guidelines "System prompts must live in prompts/ as markdown files; do not store prompts as string constants in Rust".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agent/channel.rs` around lines 119 - 125, The hard-coded time-context
prompt string inside worker_task_preamble should be moved to a markdown template
under prompts/ (e.g., worker_time_context.md) and worker_task_preamble should be
changed to load that template and interpolate timestamps instead of embedding
the text; use the existing format_timestamp(self.now_utc) and
self.now_utc.format(...) values as replacements when rendering the template so
worker_task_preamble returns the filled string, and ensure any file I/O or
template-loading errors are handled or propagated by the same function.

51-57: ⚠️ Potential issue | 🟠 Major

Fallback chain skips cron_timezone when user_timezone is present but invalid.

At Line 52-Line 57, or_else selects cron_timezone only when user_timezone is None. If user_timezone exists but fails parse at Line 61, execution falls straight to SystemLocal (Line 80-Line 83), skipping cron fallback.

🔧 Proposed fix
 fn from_runtime(runtime_config: &crate::config::RuntimeConfig) -> Self {
-    let configured_timezone = runtime_config
-        .user_timezone
-        .load()
-        .as_ref()
-        .clone()
-        .or_else(|| runtime_config.cron_timezone.load().as_ref().clone());
     let now_utc = Utc::now();

-    if let Some(timezone_name) = configured_timezone {
+    if let Some(timezone_name) = runtime_config.user_timezone.load().as_ref().cloned() {
         match timezone_name.parse::<Tz>() {
             Ok(timezone) => {
                 return Self {
                     now_utc,
                     timezone: TemporalTimezone::Named {
                         timezone_name,
                         timezone,
                     },
                 };
             }
             Err(_) => {
                 tracing::warn!(
                     timezone = %timezone_name,
-                    "invalid runtime timezone for channel temporal context, falling back to system local"
+                    "invalid user timezone for channel temporal context, falling back to cron timezone"
                 );
             }
         }
     }

+    if let Some(timezone_name) = runtime_config.cron_timezone.load().as_ref().cloned() {
+        match timezone_name.parse::<Tz>() {
+            Ok(timezone) => {
+                return Self {
+                    now_utc,
+                    timezone: TemporalTimezone::Named {
+                        timezone_name,
+                        timezone,
+                    },
+                };
+            }
+            Err(_) => {
+                tracing::warn!(
+                    timezone = %timezone_name,
+                    "invalid cron timezone for channel temporal context, falling back to system local"
+                );
+            }
+        }
+    }
+
     Self {
         now_utc,
         timezone: TemporalTimezone::SystemLocal,
     }
 }

Also applies to: 60-83

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agent/channel.rs` around lines 51 - 57, In from_runtime, the
configured_timezone logic uses or_else on user_timezone causing cron_timezone to
be skipped when user_timezone is present but invalid; modify from_runtime (and
the configured_timezone variable logic) to attempt parsing user_timezone and if
parsing fails or it's None then try cron_timezone, and only after both fail
fallback to SystemLocal — i.e., explicitly check result of parsing user_timezone
(not just presence), then parse cron_timezone as the next fallback before
defaulting to SystemLocal.
🧹 Nitpick comments (1)
src/agent/channel.rs (1)

680-685: Use formatted_author in batched formatting for parity with single-message formatting.

At Line 680-Line 685 batched formatting bypasses formatted_author, while single-message formatting prefers it at Line 2327-Line 2337. Aligning these paths avoids platform-specific display-name drift between single and batched turns.

Also applies to: 686-691, 2327-2337

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agent/channel.rs` around lines 680 - 685, Batched formatting currently
builds display_name by directly reading message.metadata ("sender_display_name")
and falling back to message.sender_id; update the batched path to call and use
the existing formatted_author helper (the same used in single-message
formatting) instead of manual metadata lookup so both batched and single-message
flows use identical display-name logic—replace the code around display_name (and
the similar block at 686-691) to invoke formatted_author with the message (or
its sender id/metadata as its signature requires) and use that result for
rendering.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/config.rs`:
- Around line 1051-1061: resolve_cron_timezone currently returns None as soon as
the first non-empty candidate fails validation, which prevents
resolve_user_timezone from seeing a valid SPACEBOT_CRON_TIMEZONE fallback;
update resolve_cron_timezone so it iterates through all timezone candidates
(explicit config, defaults, then env SPACEBOT_CRON_TIMEZONE) validating each and
only returns Some(valid_tz) for the first valid candidate or None after all have
been tried, so resolve_user_timezone receives the correct resolved_cron_timezone
value.

---

Duplicate comments:
In `@src/agent/channel.rs`:
- Around line 119-125: The hard-coded time-context prompt string inside
worker_task_preamble should be moved to a markdown template under prompts/
(e.g., worker_time_context.md) and worker_task_preamble should be changed to
load that template and interpolate timestamps instead of embedding the text; use
the existing format_timestamp(self.now_utc) and self.now_utc.format(...) values
as replacements when rendering the template so worker_task_preamble returns the
filled string, and ensure any file I/O or template-loading errors are handled or
propagated by the same function.
- Around line 51-57: In from_runtime, the configured_timezone logic uses or_else
on user_timezone causing cron_timezone to be skipped when user_timezone is
present but invalid; modify from_runtime (and the configured_timezone variable
logic) to attempt parsing user_timezone and if parsing fails or it's None then
try cron_timezone, and only after both fail fallback to SystemLocal — i.e.,
explicitly check result of parsing user_timezone (not just presence), then parse
cron_timezone as the next fallback before defaulting to SystemLocal.

---

Nitpick comments:
In `@src/agent/channel.rs`:
- Around line 680-685: Batched formatting currently builds display_name by
directly reading message.metadata ("sender_display_name") and falling back to
message.sender_id; update the batched path to call and use the existing
formatted_author helper (the same used in single-message formatting) instead of
manual metadata lookup so both batched and single-message flows use identical
display-name logic—replace the code around display_name (and the similar block
at 686-691) to invoke formatted_author with the message (or its sender
id/metadata as its signature requires) and use that result for rendering.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 58bc4be and 42509d7.

📒 Files selected for processing (2)
  • src/agent/channel.rs
  • src/config.rs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/agent/channel.rs (1)

83-93: Consider logging when cron_timezone is also invalid.

When cron_timezone fails to parse, the code silently falls through to SystemLocal. Adding a debug/warn log here would aid troubleshooting configuration issues.

🔧 Suggested enhancement
     if let Some(timezone_name) = cron_timezone
         && let Ok(timezone) = timezone_name.parse::<Tz>()
     {
         return TemporalTimezone::Named {
             timezone_name,
             timezone,
         };
+    } else if let Some(timezone_name) = cron_timezone {
+        tracing::debug!(
+            timezone = %timezone_name,
+            "invalid cron timezone, falling back to system local"
+        );
     }

     TemporalTimezone::SystemLocal
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agent/channel.rs` around lines 83 - 93, When cron_timezone is present but
fails to parse into Tz, the code currently falls through silently to
TemporalTimezone::SystemLocal; update the branch handling cron_timezone in the
function that returns TemporalTimezone so that if let Some(timezone_name) =
cron_timezone && let Err(err) = timezone_name.parse::<Tz>() triggers a log
(debug or warn) that includes timezone_name and the parse error; keep successful
parses returning TemporalTimezone::Named { timezone_name, timezone } and only
return TemporalTimezone::SystemLocal after logging the parse failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/agent/channel.rs`:
- Around line 74-79: The warning text in the Err arm that currently logs
timezone = %timezone_name should be changed so it accurately describes the
fallback chain (it does not immediately fall back to system local but next
attempts cron_timezone and only then system local); update the tracing::warn
message in that Err branch to something like "invalid runtime timezone for
channel temporal context, will try cron_timezone then fall back to system local"
and include timezone_name and cron_timezone variables to make the subsequent
behavior clear (locate the tracing::warn call that references timezone_name in
the channel temporal context handling and adjust its message accordingly).

---

Nitpick comments:
In `@src/agent/channel.rs`:
- Around line 83-93: When cron_timezone is present but fails to parse into Tz,
the code currently falls through silently to TemporalTimezone::SystemLocal;
update the branch handling cron_timezone in the function that returns
TemporalTimezone so that if let Some(timezone_name) = cron_timezone && let
Err(err) = timezone_name.parse::<Tz>() triggers a log (debug or warn) that
includes timezone_name and the parse error; keep successful parses returning
TemporalTimezone::Named { timezone_name, timezone } and only return
TemporalTimezone::SystemLocal after logging the parse failure.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42509d7 and e553b6b.

📒 Files selected for processing (4)
  • prompts/en/fragments/system/worker_time_context.md.j2
  • src/agent/channel.rs
  • src/prompts/engine.rs
  • src/prompts/text.rs
✅ Files skipped from review due to trivial changes (1)
  • prompts/en/fragments/system/worker_time_context.md.j2

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/config.rs (1)

2239-2244: Warning message is misleading after the refactor.

The code now correctly iterates through all candidates before falling back to system local, but the warning message still says "falling back to system local timezone". This is inaccurate when there are remaining candidates to try (e.g., env var after an invalid config value).

Consider aligning the message with resolve_user_timezone which says "trying next fallback":

✏️ Suggested fix
         tracing::warn!(
             agent_id,
             cron_timezone = %timezone,
-            "invalid cron timezone configured, falling back to system local timezone"
+            "invalid cron timezone configured, trying next fallback"
         );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/config.rs` around lines 2239 - 2244, The warning message logged by the
tracing::warn! call (with fields agent_id and cron_timezone = %timezone) is now
misleading because the code iterates remaining candidates before ultimately
falling back; update the log text to match resolve_user_timezone's wording
(e.g., "invalid cron timezone configured, trying next fallback") so it
accurately reflects that the resolver will continue to the next candidate rather
than immediately falling back to system local timezone; keep the same structured
fields (agent_id, cron_timezone) and only change the message string.
src/agent/channel.rs (1)

800-805: Consider a small helper to remove duplicated temporal status rendering.

TemporalContext::from_runtime(...) + current_time_line() + render_with_time_context(...) repeats in multiple methods; extracting one helper would reduce drift risk.

Also applies to: 1093-1098, 1763-1766

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agent/channel.rs` around lines 800 - 805, The repeated pattern creating a
TemporalContext from a runtime, grabbing current_time_line, then rendering the
status with that time is duplicated (TemporalContext::from_runtime(...),
current_time_line(), status.render_with_time_context(...)), so add a small
helper method (e.g., render_status_with_runtime_time or
Status::render_with_runtime_time) that takes &self (or &Runtime/rc) and returns
the rendered status string by performing self.state.status_block.read().await
and calling render_with_time_context with the current_time_line computed via
TemporalContext::from_runtime(rc.as_ref()). Replace the duplicated blocks in the
spots using this pattern (including where the snippet appears and at the other
noted locations) with calls to the new helper to centralize the logic and reduce
drift risk.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/agent/channel.rs`:
- Around line 800-805: The repeated pattern creating a TemporalContext from a
runtime, grabbing current_time_line, then rendering the status with that time is
duplicated (TemporalContext::from_runtime(...), current_time_line(),
status.render_with_time_context(...)), so add a small helper method (e.g.,
render_status_with_runtime_time or Status::render_with_runtime_time) that takes
&self (or &Runtime/rc) and returns the rendered status string by performing
self.state.status_block.read().await and calling render_with_time_context with
the current_time_line computed via TemporalContext::from_runtime(rc.as_ref()).
Replace the duplicated blocks in the spots using this pattern (including where
the snippet appears and at the other noted locations) with calls to the new
helper to centralize the logic and reduce drift risk.

In `@src/config.rs`:
- Around line 2239-2244: The warning message logged by the tracing::warn! call
(with fields agent_id and cron_timezone = %timezone) is now misleading because
the code iterates remaining candidates before ultimately falling back; update
the log text to match resolve_user_timezone's wording (e.g., "invalid cron
timezone configured, trying next fallback") so it accurately reflects that the
resolver will continue to the next candidate rather than immediately falling
back to system local timezone; keep the same structured fields (agent_id,
cron_timezone) and only change the message string.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e553b6b and 7e313fc.

📒 Files selected for processing (2)
  • src/agent/channel.rs
  • src/config.rs

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.

2 participants