instar 1.3.326 → 1.3.327
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +2 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/core/ForwardedTopicContext.d.ts.map +1 -1
- package/dist/core/ForwardedTopicContext.js +4 -6
- package/dist/core/ForwardedTopicContext.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +23 -5
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
- package/dist/lifeline/TelegramLifeline.js +2 -1
- package/dist/lifeline/TelegramLifeline.js.map +1 -1
- package/dist/memory/TopicMemory.d.ts.map +1 -1
- package/dist/memory/TopicMemory.js +3 -2
- package/dist/memory/TopicMemory.js.map +1 -1
- package/dist/messaging/shared/compactionResumePayload.d.ts.map +1 -1
- package/dist/messaging/shared/compactionResumePayload.js +2 -1
- package/dist/messaging/shared/compactionResumePayload.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +3 -2
- package/dist/server/routes.js.map +1 -1
- package/dist/utils/localTime.d.ts +42 -0
- package/dist/utils/localTime.d.ts.map +1 -0
- package/dist/utils/localTime.js +60 -0
- package/dist/utils/localTime.js.map +1 -0
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +67 -67
- package/src/templates/hooks/compaction-recovery.sh +15 -3
- package/src/templates/hooks/slack-channel-context.sh +1 -1
- package/src/templates/hooks/telegram-topic-context.sh +8 -2
- package/upgrades/1.3.327.md +57 -0
- package/upgrades/local-time-coherence.eli16.md +11 -0
- package/upgrades/side-effects/local-time-coherence.md +89 -0
|
@@ -105,6 +105,12 @@ fi
|
|
|
105
105
|
# Format and output context with unanswered message detection
|
|
106
106
|
echo "$RECENT_MSGS" | python3 -c "
|
|
107
107
|
import sys, json
|
|
108
|
+
def _localts(raw):
|
|
109
|
+
try:
|
|
110
|
+
from datetime import datetime
|
|
111
|
+
return datetime.fromisoformat(str(raw).replace('Z', '+00:00')).astimezone().strftime('%Y-%m-%d %H:%M %Z')
|
|
112
|
+
except Exception:
|
|
113
|
+
return str(raw)[:16].replace('T', ' ')
|
|
108
114
|
try:
|
|
109
115
|
data = json.load(sys.stdin)
|
|
110
116
|
msgs = data.get('messages', [])
|
|
@@ -114,7 +120,7 @@ try:
|
|
|
114
120
|
print('TOPIC ${TOPIC_ID} RECENT HISTORY (auto-injected — read this before responding):')
|
|
115
121
|
|
|
116
122
|
for m in msgs:
|
|
117
|
-
ts = m.get('timestamp', '')
|
|
123
|
+
ts = _localts(m.get('timestamp', ''))
|
|
118
124
|
from_user = m.get('fromUser', m.get('direction', 'in') == 'in')
|
|
119
125
|
text = m.get('text', '').strip()
|
|
120
126
|
sender = 'User' if from_user else 'Agent'
|
|
@@ -139,7 +145,7 @@ try:
|
|
|
139
145
|
print('*** UNANSWERED MESSAGE(S) FROM USER ***')
|
|
140
146
|
for pm in pending_user:
|
|
141
147
|
pm_text = pm.get('text', '')[:200]
|
|
142
|
-
pm_ts = pm.get('timestamp', '')
|
|
148
|
+
pm_ts = _localts(pm.get('timestamp', ''))
|
|
143
149
|
print(f' [{pm_ts}] \"{pm_text}\"')
|
|
144
150
|
print()
|
|
145
151
|
print('You MUST address these messages substantively. Do NOT respond with just')
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Fixes a **time-incoherency** class of bug: every context block that shows an
|
|
9
|
+
agent its conversation history rendered timestamps as **unlabeled UTC**
|
|
10
|
+
(`[21:23:10]`), while the CURRENT TIME hook block speaks labeled local time.
|
|
11
|
+
Agents read both as one clock — live incident 2026-06-05: an agent told its
|
|
12
|
+
user "you heard nothing between **9:23pm** and now" about an event at
|
|
13
|
+
**2:23pm** the user's local time.
|
|
14
|
+
|
|
15
|
+
Now every agent-facing timestamp renders in the **host's local timezone with
|
|
16
|
+
an explicit tz label and date**: `[2026-06-05 14:23 PDT]`.
|
|
17
|
+
|
|
18
|
+
Surfaces covered:
|
|
19
|
+
|
|
20
|
+
- Bootstrap Thread History (new/respawned sessions), auto-spawn history
|
|
21
|
+
- Moved-session context relay (multi-machine transfers)
|
|
22
|
+
- Per-message Telegram topic history hook + unanswered-messages block
|
|
23
|
+
- Post-compaction recovery context (Telegram + Slack blocks)
|
|
24
|
+
- Session-start RECENT MESSAGES, TopicMemory context blocks
|
|
25
|
+
- Slack channel context (tz label added)
|
|
26
|
+
- Lifeline "Last healthy" status line
|
|
27
|
+
|
|
28
|
+
New shared helper `src/utils/localTime.ts` (`formatLocalTimestamp`); hook
|
|
29
|
+
python blocks carry an equivalent `_localts()` with a safe fallback to the
|
|
30
|
+
old rendering on any parse failure. Stored timestamps remain ISO-UTC —
|
|
31
|
+
rendering only. Existing agents pick the hook changes up automatically
|
|
32
|
+
(built-in hooks are always-overwritten on migration).
|
|
33
|
+
|
|
34
|
+
## What to Tell Your User
|
|
35
|
+
|
|
36
|
+
Your agent no longer gets confused about what time things happened. Before
|
|
37
|
+
this, the agent saw conversation history stamped in UTC but the current time
|
|
38
|
+
in your local timezone — and could misquote a 2pm event as "9pm." Now every
|
|
39
|
+
timestamp it reads carries your local time and timezone, so "when did I last
|
|
40
|
+
hear from you?" answers come out right.
|
|
41
|
+
|
|
42
|
+
## Summary of New Capabilities
|
|
43
|
+
|
|
44
|
+
- None user-invocable — this is a correctness fix to how agents perceive
|
|
45
|
+
time. (Internal: `formatLocalTimestamp()` in `src/utils/localTime.ts` is
|
|
46
|
+
the one helper all history/status renderers now use.)
|
|
47
|
+
|
|
48
|
+
## Evidence
|
|
49
|
+
|
|
50
|
+
- New `tests/unit/localTime.test.ts` pins local-not-UTC semantically
|
|
51
|
+
(TZ-portable: compares against the same instant's local Date getters),
|
|
52
|
+
including the verbatim incident instant `2026-06-05T21:23:10Z`.
|
|
53
|
+
- Hook python smoke test: the incident payload now renders
|
|
54
|
+
`[2026-06-05 14:23 PDT] Agent: executing now` (was `[2026-06-05 21:23]`).
|
|
55
|
+
- Updated `ForwardedTopicContext` / `compactionResumePayload` /
|
|
56
|
+
`telegram-autospawn-history` tests to TZ-portable assertions through the
|
|
57
|
+
helper; affected-area suites green; `tsc --noEmit` clean.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# The agent stops misreading its own clock
|
|
2
|
+
|
|
3
|
+
The agent kept two clocks without knowing it. Every hook that tells the agent "here's the current time" speaks in YOUR local time ("5:49pm PDT") — but every block that shows it conversation history spoke in unlabeled UTC ("[21:23]"). The agent has no way to tell those apart, so it did the natural thing: read both as the same clock. That's how it told Justin "you heard nothing between **9:23pm** and now" about a message sent at **2:23pm** his time — off by exactly the 7-hour UTC gap. The user experiences this as the agent being confused about basic reality.
|
|
4
|
+
|
|
5
|
+
The fix makes every timestamp the agent ever sees speak ONE language: the machine's local time, with the timezone written right on it — `[2026-06-05 14:23 PDT]` instead of `[21:23:10]`. History lines also now carry the date, so a conversation spanning midnight can't be misread either ("was that 12:30am today or yesterday?" stops being a guess).
|
|
6
|
+
|
|
7
|
+
Where this applies — every surface that renders history or status timestamps into an agent's context: the thread history a new session boots with, the history relayed when a conversation moves between machines, the recent-messages block injected on every Telegram message, the post-compaction recovery context, the Slack channel context, the session-start recent messages, and the lifeline's "last healthy" status line. One new shared helper does the rendering in code; the hook scripts get a tiny equivalent helper with a safe fallback (if a timestamp ever fails to parse, it renders the old way instead of crashing the hook).
|
|
8
|
+
|
|
9
|
+
Existing agents get this automatically: the built-in hook scripts are always refreshed on update, and the code paths ship with the next release. Nothing about WHEN things happen changes — only how the time is written down. There is no new config, no new decision surface, and the worst possible failure (a malformed timestamp) renders the way it used to render rather than breaking anything.
|
|
10
|
+
|
|
11
|
+
What you need to decide: nothing — this is a pure rendering fix for a live mis-statement the agent made to you. The PR is the review surface.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Side-Effects Review — Local-time + tz-label rendering for all agent-facing timestamps
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `local-time-coherence`
|
|
4
|
+
**Date:** `2026-06-05`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `not required (no block/allow surface, no lifecycle decisions — pure rendering)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Every surface that renders timestamps into agent-facing context blocks switched from unlabeled UTC (`toISOString().slice(11, 19)` in TS, `timestamp[:16].replace('T', ' ')` in hook python) to host-local time with an explicit timezone label and date (`[2026-06-05 14:23 PDT]`). New shared helper `src/utils/localTime.ts` (`formatLocalTimestamp`, `localTzAbbreviation`); call sites: `ForwardedTopicContext.ts`, `TopicMemory.ts` ×2, `commands/server.ts` (bootstrap Thread History), `server/routes.ts` ×2 (auto-spawn/respawn history), `compactionResumePayload.ts`, `TelegramLifeline.ts` (status line). Hook python blocks get an equivalent `_localts()` helper with parse-failure fallback to the old rendering: `templates/hooks/telegram-topic-context.sh`, `templates/hooks/compaction-recovery.sh` (telegram + slack blocks), `templates/hooks/slack-channel-context.sh` (tz label only), and the `PostUpdateMigrator.ts` inline copies (session-start, telegram-topic-context, compaction-recovery). Driven by the 2026-06-05 live incident: the agent reported a 14:23-local event as "9:23pm" because history was unlabeled UTC while CURRENT TIME blocks are local-labeled.
|
|
11
|
+
|
|
12
|
+
## Decision-point inventory
|
|
13
|
+
|
|
14
|
+
No decision-point surface. This change renders strings; it adds, removes, or modifies no block/allow decision, no gate, no lifecycle action. The only conditional logic is "did the timestamp parse?" with a render-the-old-way fallback.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. Over-block
|
|
19
|
+
|
|
20
|
+
No block/allow surface — over-block not applicable.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 2. Under-block
|
|
25
|
+
|
|
26
|
+
No block/allow surface — under-block not applicable.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 3. Level-of-abstraction fit
|
|
31
|
+
|
|
32
|
+
Right layer: a formatting primitive at the render chokepoints. The alternative — teaching agents (prompt-level) that history is UTC — is exactly the willpower-dependent design that caused the incident. A lower-level primitive did not exist (`formatLocalTimeHHMM` in `RestartCascadeDampener.ts` is HH:MM-only, no tz label, no date, not exported for this purpose); this PR creates the shared primitive and routes all sites through it. Hook python cannot import TS, so it carries a minimal equivalent — acceptable duplication at the language boundary, kept identical across all blocks.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 4. Signal vs authority compliance
|
|
37
|
+
|
|
38
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
39
|
+
|
|
40
|
+
- [x] No — this change has no block/allow surface.
|
|
41
|
+
|
|
42
|
+
Pure rendering. Nothing here holds authority over any action.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 5. Interactions
|
|
47
|
+
|
|
48
|
+
- **Shadowing:** none — no checks run before/after; the rendered string feeds the same downstream consumers (context injection, tmux paste) unchanged in shape (`[ts] Sender: text`).
|
|
49
|
+
- **Double-fire:** none — formatting is idempotent and side-effect-free.
|
|
50
|
+
- **Races:** none — no shared mutable state; `Intl.DateTimeFormat` is constructed per call.
|
|
51
|
+
- **Feedback loops:** one considered: agents QUOTE history timestamps back into conversation, and those quotes can land in future history. Since both the injected history and the CURRENT TIME hook now speak local-labeled time, the loop converges toward coherence instead of propagating UTC misreads.
|
|
52
|
+
- **Unanswered-message detection:** verified untouched — detection logic compares message order/sender, never parses the rendered timestamp.
|
|
53
|
+
- **Tests that mirror renderers:** `telegram-autospawn-history.test.ts` contains a local mirror of the routes.ts logic; updated in the same PR so the mirror stays faithful.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 6. External surfaces
|
|
58
|
+
|
|
59
|
+
- **Other agents on the same machine:** the hook-template changes reach every instar agent on next update (built-in hooks are always-overwritten by `PostUpdateMigrator`). The change is rendering-only; no agent behavior contract depends on UTC timestamps (verified: no consumer parses the bracketed time back out of context blocks — grepped for consumers of the rendered format).
|
|
60
|
+
- **External systems:** none — Telegram/Slack/GitHub payloads unchanged; only locally-injected context strings change.
|
|
61
|
+
- **Persistent state:** none written. Stored timestamps remain ISO-UTC everywhere (JSONL, SQLite); ONLY rendering changes. No migration of stored data.
|
|
62
|
+
- **Timing/runtime:** `%Z` in python `strftime` and `Intl` tz short-names vary by platform locale data; on a host where no label resolves, the label is simply omitted (TS) or the naive fallback renders (python) — degraded to the status quo, never an error.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 7. Rollback cost
|
|
67
|
+
|
|
68
|
+
Pure code + template change — revert and ship a patch. No persistent state, no data migration, no agent state repair. During a rollback window, agents would briefly render local-labeled and then UTC again; cosmetic only.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Conclusion
|
|
73
|
+
|
|
74
|
+
The review confirmed no decision surface and no persistence surface; the main risks identified and addressed were (a) hook python crashing on unparseable timestamps — covered by the try/except fallback to the previous rendering, and (b) test mirrors drifting from real renderers — the mirror was updated in the same change. One pre-existing inconsistency was found and normalized: `formatInlineHistory` treated numeric-0 timestamps as missing while `ForwardedTopicContext` rendered them; the shared helper renders them (epoch is a valid instant). Clear to ship.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Second-pass review (if required)
|
|
79
|
+
|
|
80
|
+
**Reviewer:** not required
|
|
81
|
+
**Independent read of the artifact:** not required — no messaging block/allow, no session lifecycle, no sentinel/gate/guard surface.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Evidence pointers
|
|
86
|
+
|
|
87
|
+
- `tests/unit/localTime.test.ts` — semantic local-not-UTC pinning incl. the verbatim incident instant `2026-06-05T21:23:10Z`.
|
|
88
|
+
- Hook python smoke test: incident payload renders `[2026-06-05 14:23 PDT] Agent: executing now` (was `[2026-06-05 21:23]`).
|
|
89
|
+
- Full local suite (74 min on a loaded box): 28329 passed / 8 failed across 5 files. The one failure whose identity survived output truncation (`session-management-e2e`, a waitFor timeout) re-ran green in isolation; a full re-run with complete capture was started for the rest, and CI (clean, sharded runners) is the merge gate either way.
|