instar 1.2.12 → 1.2.14
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/setup-wizard/codex-driver.d.ts.map +1 -1
- package/dist/commands/setup-wizard/codex-driver.js +68 -2
- package/dist/commands/setup-wizard/codex-driver.js.map +1 -1
- package/dist/commands/setup-wizard/state-machine.d.ts +26 -0
- package/dist/commands/setup-wizard/state-machine.d.ts.map +1 -1
- package/dist/commands/setup-wizard/state-machine.js +53 -10
- package/dist/commands/setup-wizard/state-machine.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +28 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +17 -17
- package/upgrades/1.2.13.md +42 -0
- package/upgrades/1.2.14.md +79 -0
- package/upgrades/side-effects/fix-wizard-validation.md +98 -0
- package/upgrades/side-effects/inject-current-time-into-hooks.md +63 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-05-
|
|
5
|
-
"instarVersion": "1.2.
|
|
4
|
+
"generatedAt": "2026-05-21T23:32:22.253Z",
|
|
5
|
+
"instarVersion": "1.2.14",
|
|
6
6
|
"entryCount": 191,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"domain": "identity",
|
|
12
12
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
13
13
|
"installedPath": ".instar/hooks/instar/session-start.sh",
|
|
14
|
-
"contentHash": "
|
|
14
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
15
15
|
"since": "2025-01-01"
|
|
16
16
|
},
|
|
17
17
|
"hook:dangerous-command-guard": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"domain": "safety",
|
|
21
21
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
22
22
|
"installedPath": ".instar/hooks/instar/dangerous-command-guard.sh",
|
|
23
|
-
"contentHash": "
|
|
23
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
24
24
|
"since": "2025-01-01"
|
|
25
25
|
},
|
|
26
26
|
"hook:grounding-before-messaging": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"domain": "safety",
|
|
30
30
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
31
31
|
"installedPath": ".instar/hooks/instar/grounding-before-messaging.sh",
|
|
32
|
-
"contentHash": "
|
|
32
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
33
33
|
"since": "2025-01-01"
|
|
34
34
|
},
|
|
35
35
|
"hook:compaction-recovery": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"domain": "identity",
|
|
39
39
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
40
40
|
"installedPath": ".instar/hooks/instar/compaction-recovery.sh",
|
|
41
|
-
"contentHash": "
|
|
41
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
42
42
|
"since": "2025-01-01"
|
|
43
43
|
},
|
|
44
44
|
"hook:external-operation-gate": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"domain": "safety",
|
|
48
48
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
49
49
|
"installedPath": ".instar/hooks/instar/external-operation-gate.js",
|
|
50
|
-
"contentHash": "
|
|
50
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
51
51
|
"since": "2025-01-01"
|
|
52
52
|
},
|
|
53
53
|
"hook:deferral-detector": {
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"domain": "safety",
|
|
57
57
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
58
58
|
"installedPath": ".instar/hooks/instar/deferral-detector.js",
|
|
59
|
-
"contentHash": "
|
|
59
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
60
60
|
"since": "2025-01-01"
|
|
61
61
|
},
|
|
62
62
|
"hook:post-action-reflection": {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"domain": "evolution",
|
|
66
66
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
67
67
|
"installedPath": ".instar/hooks/instar/post-action-reflection.js",
|
|
68
|
-
"contentHash": "
|
|
68
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
69
69
|
"since": "2025-01-01"
|
|
70
70
|
},
|
|
71
71
|
"hook:external-communication-guard": {
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"domain": "safety",
|
|
75
75
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
76
76
|
"installedPath": ".instar/hooks/instar/external-communication-guard.js",
|
|
77
|
-
"contentHash": "
|
|
77
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
78
78
|
"since": "2025-01-01"
|
|
79
79
|
},
|
|
80
80
|
"hook:scope-coherence-collector": {
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"domain": "coherence",
|
|
84
84
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
85
85
|
"installedPath": ".instar/hooks/instar/scope-coherence-collector.js",
|
|
86
|
-
"contentHash": "
|
|
86
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
87
87
|
"since": "2025-01-01"
|
|
88
88
|
},
|
|
89
89
|
"hook:scope-coherence-checkpoint": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"domain": "coherence",
|
|
93
93
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
94
94
|
"installedPath": ".instar/hooks/instar/scope-coherence-checkpoint.js",
|
|
95
|
-
"contentHash": "
|
|
95
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
96
96
|
"since": "2025-01-01"
|
|
97
97
|
},
|
|
98
98
|
"hook:free-text-guard": {
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"domain": "safety",
|
|
102
102
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
103
103
|
"installedPath": ".instar/hooks/instar/free-text-guard.sh",
|
|
104
|
-
"contentHash": "
|
|
104
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
105
105
|
"since": "2025-01-01"
|
|
106
106
|
},
|
|
107
107
|
"hook:claim-intercept": {
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"domain": "coherence",
|
|
111
111
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
112
112
|
"installedPath": ".instar/hooks/instar/claim-intercept.js",
|
|
113
|
-
"contentHash": "
|
|
113
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
114
114
|
"since": "2025-01-01"
|
|
115
115
|
},
|
|
116
116
|
"hook:claim-intercept-response": {
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"domain": "coherence",
|
|
120
120
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
121
121
|
"installedPath": ".instar/hooks/instar/claim-intercept-response.js",
|
|
122
|
-
"contentHash": "
|
|
122
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
123
123
|
"since": "2025-01-01"
|
|
124
124
|
},
|
|
125
125
|
"hook:auto-approve-permissions": {
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"domain": "safety",
|
|
129
129
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
130
130
|
"installedPath": ".instar/hooks/instar/auto-approve-permissions.js",
|
|
131
|
-
"contentHash": "
|
|
131
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
132
132
|
"since": "2025-01-01"
|
|
133
133
|
},
|
|
134
134
|
"job:health-check": {
|
|
@@ -1472,7 +1472,7 @@
|
|
|
1472
1472
|
"type": "subsystem",
|
|
1473
1473
|
"domain": "updates",
|
|
1474
1474
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
1475
|
-
"contentHash": "
|
|
1475
|
+
"contentHash": "c05e308a956d13c08a2aecdbec64591b4a94ef3c083e4b4ce95202b03ebce284",
|
|
1476
1476
|
"since": "2025-01-01"
|
|
1477
1477
|
},
|
|
1478
1478
|
"subsystem:scheduler": {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT (current-time injection in agent hooks)
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
<!-- patch = behavior fix that closes a recurring failure mode, no new surface -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
**Fix: every instar agent now sees the current wall-clock time at session start AND on every user prompt.**
|
|
9
|
+
|
|
10
|
+
Claude Code's harness injects `currentDate: YYYY-MM-DD` into the agent's system prompt — but NOT the current time of day. In long-running sessions (hours, days), agents that try to say "it's 2am" or "you've been up X hours" or "we just talked an hour ago" were either hallucinating clock times outright or pulling stale time strings from earlier conversation context. Iris hit this on 2026-05-21: she told a user "it's 2am" when it was actually 5:45am, and only realized it after the user contradicted her with a timestamped screenshot.
|
|
11
|
+
|
|
12
|
+
The fix is structural, not behavioral. Two existing hooks every instar agent already runs now emit a `--- CURRENT TIME ---` block backed by a live `date(1)` call:
|
|
13
|
+
|
|
14
|
+
- **`session-start.sh`** (SessionStart hook, startup / resume / clear) — emits the time block immediately after `=== SESSION START ===`, before any other context. Refreshed on every session lifecycle event including post-compaction resume.
|
|
15
|
+
- **`telegram-topic-context.sh`** (UserPromptSubmit hook) — emits the time block on **every** user prompt, BEFORE the `[telegram:N]` prefix early-exit. So agents get a fresh wall-clock anchor on every turn, not just at session start, regardless of whether the prompt arrived via Telegram or direct CLI use.
|
|
16
|
+
|
|
17
|
+
Format: `2026-05-21 14:15:29 -0500 (CDT)` — ISO date + 24h time + signed offset + tz abbreviation. Same line every time. Agents are told explicitly: "Quote this — do not carry stale clock times from prior context."
|
|
18
|
+
|
|
19
|
+
The hook content lives inline in `src/core/PostUpdateMigrator.ts` (functions `getSessionStartHook()` and `getTelegramTopicContextHook()`), which is the source of truth that both `init` (new agents) and `migrate` (existing agents) write to disk. Built-in hooks are unconditionally overwritten on every migration run, so existing agents pick up the fix automatically on their next `npx instar` invocation — no manual migration required.
|
|
20
|
+
|
|
21
|
+
## What to Tell Your User
|
|
22
|
+
|
|
23
|
+
If your agent has ever made a clock-time claim that turned out to be wrong (saying it's the middle of the night when it isn't, miscalculating "how long ago" something happened, mismatching AM/PM), that failure mode is closed after this release. Your agent now sees the actual current time on every interaction and is structurally instructed to quote it rather than guess.
|
|
24
|
+
|
|
25
|
+
No action needed from you. The next time your agent updates, the fix lands.
|
|
26
|
+
|
|
27
|
+
## Summary of New Capabilities
|
|
28
|
+
|
|
29
|
+
| Capability | How to Use |
|
|
30
|
+
|-----------|-----------|
|
|
31
|
+
| Wall-clock time injected at session start | Automatic — `--- CURRENT TIME ---` block at the top of session-start output |
|
|
32
|
+
| Wall-clock time refreshed on every user prompt | Automatic — same block emitted ahead of telegram-topic-context every UserPromptSubmit |
|
|
33
|
+
|
|
34
|
+
## Evidence
|
|
35
|
+
|
|
36
|
+
- New test: `tests/unit/PostUpdateMigrator-time-injection.test.ts` — 13 cases. Static assertions on the inlined bash (date format, guard, delimiters, ordering) PLUS end-to-end execution of both hook scripts against a fresh sandboxed temp dir, asserting the actual emitted output matches the expected `YYYY-MM-DD HH:MM:SS +ZZZZ (TZ)` shape.
|
|
37
|
+
- Existing tests still pass: `tests/unit/PostUpdateMigrator-sharedState.test.ts` (Integrated-Being session-start regression) and `tests/unit/scaffold-identity-hooks.test.ts` (scaffold integrity) verified green against the patched migrator.
|
|
38
|
+
- Side-effects review: `upgrades/side-effects/inject-current-time-into-hooks.md`.
|
|
39
|
+
|
|
40
|
+
## Original Incident
|
|
41
|
+
|
|
42
|
+
Iris session, Business Plan topic, 2026-05-21 ~5:45am CDT. Agent said "It's 2am. The laptop can wait. Goodnight." User's actual local time was 5:45am Central. Memory note `feedback_clock_time_must_call_date.md` captured the rule per-agent; this release lifts the fix to the framework so every instar agent benefits without each agent having to learn the lesson independently.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Upgrade Guide — v1.2.14 (wizard validation + composing indicator)
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
<!-- patch = bug fixes, refactors, test additions, doc updates -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
**Fix: the wizard now catches buffered-Enter and surfaces a visible
|
|
9
|
+
indicator during Codex narrative calls.**
|
|
10
|
+
|
|
11
|
+
End-to-end testing v1.2.13 on a real Codex install surfaced a UX
|
|
12
|
+
failure. The user typed an answer and pressed Enter, then — because
|
|
13
|
+
the next Codex-narrative call took several seconds with no visible
|
|
14
|
+
feedback — pressed Enter again thinking the terminal was frozen. The
|
|
15
|
+
extra Enter buffered in stdin, was consumed by the next prompt as
|
|
16
|
+
an empty submission, and the wizard silently defaulted the agent's
|
|
17
|
+
name to "agent". The user ended up with an agent that had a generic
|
|
18
|
+
identity they never picked.
|
|
19
|
+
|
|
20
|
+
Two structural fixes, both in `src/commands/setup-wizard/`:
|
|
21
|
+
|
|
22
|
+
1. **Per-state validators** on the state machine. Each
|
|
23
|
+
narrative-then-prompt state can now declare a `validate` function
|
|
24
|
+
that rejects invalid input and surfaces a friendly retry message
|
|
25
|
+
without re-generating the Codex narrative paragraph (cheap loop,
|
|
26
|
+
no extra LLM calls). Reusable validators:
|
|
27
|
+
- `requireNonEmpty(fieldLabel)`: rejects whitespace-only
|
|
28
|
+
submissions on required text fields with an explicit
|
|
29
|
+
"did an extra Enter slip through?" nudge.
|
|
30
|
+
- `requireChoice(choices)`: rejects unmatched input on choice
|
|
31
|
+
prompts with a "try one of these numbers" nudge.
|
|
32
|
+
|
|
33
|
+
Wired on every narrative state in the fresh-project-install
|
|
34
|
+
graph. Bounded at 5 retry attempts to prevent infinite loops
|
|
35
|
+
on wedged input.
|
|
36
|
+
|
|
37
|
+
2. **Composing spinner** during codex narrative calls. A braille
|
|
38
|
+
spinner ("⠋ composing…") animates on a single line while
|
|
39
|
+
`codex exec` runs; clears cleanly when the paragraph arrives.
|
|
40
|
+
On non-TTY (CI, piped output) it prints "composing…" once and
|
|
41
|
+
stops. Eliminates the silent-dead-air window that triggered
|
|
42
|
+
buffered-Enter in the first place.
|
|
43
|
+
|
|
44
|
+
The silent-default fallback that accepted empty agent-name as
|
|
45
|
+
"agent" is removed. With validators upstream, the state machine
|
|
46
|
+
only ever sees valid input.
|
|
47
|
+
|
|
48
|
+
Spec: `specs/dev-infrastructure/wizard-validation.md`.
|
|
49
|
+
ELI16: `specs/dev-infrastructure/wizard-validation.eli16.md`.
|
|
50
|
+
Side-effects review: `upgrades/side-effects/fix-wizard-validation.md`.
|
|
51
|
+
|
|
52
|
+
## What to Tell Your User
|
|
53
|
+
|
|
54
|
+
The setup wizard now shows a spinner while it's thinking, so you
|
|
55
|
+
can tell the system is working during the longer steps. If you
|
|
56
|
+
accidentally press Enter twice (which is easy to do during the
|
|
57
|
+
think pauses), the wizard will catch it and re-ask the question
|
|
58
|
+
instead of silently moving on with a blank answer.
|
|
59
|
+
|
|
60
|
+
## Summary of New Capabilities
|
|
61
|
+
|
|
62
|
+
No new capabilities. UX hardening on top of v1.2.13's hybrid wizard.
|
|
63
|
+
|
|
64
|
+
## Evidence
|
|
65
|
+
|
|
66
|
+
Reproduction prior to fix: v1.2.13 install on `instar-codey` with
|
|
67
|
+
Codex CLI. User entered "1" + Enter at welcome, then pressed Enter
|
|
68
|
+
again during the silent codex-narrative call. The second Enter was
|
|
69
|
+
consumed by the agent-name prompt as an empty submission;
|
|
70
|
+
agentName defaulted to "agent"; wizard proceeded with the generic
|
|
71
|
+
identity.
|
|
72
|
+
|
|
73
|
+
After fix:
|
|
74
|
+
- 14 new state-machine unit tests cover the two validator helpers
|
|
75
|
+
and the per-state validator wiring (welcome, agent-name,
|
|
76
|
+
agent-role, user-name, autonomy, messaging).
|
|
77
|
+
- Existing 12 state-graph tests still pass.
|
|
78
|
+
- Existing 5 dispatch canary tests still pass.
|
|
79
|
+
- Manual end-to-end re-test pending on publish.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Side-effects review — Wizard input validation + spinner
|
|
2
|
+
|
|
3
|
+
Per L6. Seven dimensions.
|
|
4
|
+
|
|
5
|
+
## 1. Over-block / under-block
|
|
6
|
+
|
|
7
|
+
Before: UNDER. The v1.2.13 hybrid wizard accepted empty submissions
|
|
8
|
+
on required identity fields with a silent fallback default
|
|
9
|
+
(agentName: 'agent'). Combined with the invisible-latency window on
|
|
10
|
+
codex-narrative calls, this produced the buffered-Enter bug Justin
|
|
11
|
+
hit on his first real Codex install — agent named "agent" without
|
|
12
|
+
the user ever typing a name.
|
|
13
|
+
|
|
14
|
+
After: precisely targeted. Validators enforce non-empty input on
|
|
15
|
+
required text fields and reject unmatched input on choice prompts.
|
|
16
|
+
Spinner during codex calls eliminates the silent-dead-air window
|
|
17
|
+
that triggers buffered-Enter in the first place. No over-block:
|
|
18
|
+
optional/derived fields keep their defaults; the validation
|
|
19
|
+
machinery only kicks in for fields the wizard explicitly marks as
|
|
20
|
+
required.
|
|
21
|
+
|
|
22
|
+
## 2. Level-of-abstraction fit
|
|
23
|
+
|
|
24
|
+
The `validate?` field is an optional addition to the existing
|
|
25
|
+
`NarrativeState` interface. Two reusable validators
|
|
26
|
+
(`requireNonEmpty`, `requireChoice`) live alongside the state
|
|
27
|
+
graph in `state-machine.ts`. The driver's `renderNarrativeState`
|
|
28
|
+
adds a bounded retry loop around `askUser`. The spinner is a
|
|
29
|
+
single utility function with a `{stop}` handle pattern.
|
|
30
|
+
|
|
31
|
+
No new module, no new abstraction layer. The state machine's API
|
|
32
|
+
grew by exactly one optional field.
|
|
33
|
+
|
|
34
|
+
## 3. Signal vs Authority compliance
|
|
35
|
+
|
|
36
|
+
- The validator's return value is the AUTHORITY for "is this
|
|
37
|
+
answer accepted." The driver respects it without second-guessing.
|
|
38
|
+
- The user's input remains the SIGNAL; the validator transforms
|
|
39
|
+
invalid SIGNALs into "retry with this hint" rather than silently
|
|
40
|
+
defaulting.
|
|
41
|
+
- The spinner is purely visual feedback — no authority, no signal.
|
|
42
|
+
|
|
43
|
+
## 4. Interactions with adjacent systems
|
|
44
|
+
|
|
45
|
+
- **State machine `next` functions**: simplified. The pre-fix code
|
|
46
|
+
on agent-name etc. was `answer.trim() || 'agent'`; post-fix is
|
|
47
|
+
`answer.trim()`. The validator ensures `next` only sees non-empty
|
|
48
|
+
trimmed input.
|
|
49
|
+
- **Codex driver dispatch in setup.ts**: unchanged. setup.ts still
|
|
50
|
+
routes codex-cli installs through `runCodexWizard`.
|
|
51
|
+
- **runCodexNarrative**: now wraps its spawnSync in a spinner
|
|
52
|
+
start/stop. Spinner is a no-op on non-TTY (CI, piped output) so
|
|
53
|
+
test environments aren't affected.
|
|
54
|
+
- **Existing canary test** (`tests/unit/setup-codex-model-canary.test.ts`):
|
|
55
|
+
unchanged. Asserts the same dispatch contract; the validator
|
|
56
|
+
additions don't touch the dispatch shape.
|
|
57
|
+
- **State-machine unit tests**: expanded from 12 to 26 cases.
|
|
58
|
+
Added validator-specific tests (requireNonEmpty, requireChoice,
|
|
59
|
+
per-state validator wiring).
|
|
60
|
+
- **Claude wizard path**: completely unaffected. Validators live on
|
|
61
|
+
the state-machine API, but the Claude path doesn't go through
|
|
62
|
+
the state machine — it spawns the existing /setup-wizard
|
|
63
|
+
slash-command directly.
|
|
64
|
+
|
|
65
|
+
## 5. Rollback cost
|
|
66
|
+
|
|
67
|
+
Low. New optional `validate` field on NarrativeState; new
|
|
68
|
+
validators; new spinner helper; one retry loop in the driver.
|
|
69
|
+
`git revert` restores v1.2.13 (with the buffered-Enter bug).
|
|
70
|
+
|
|
71
|
+
## 6. Backwards compatibility / drift surface
|
|
72
|
+
|
|
73
|
+
Fully backwards-compatible.
|
|
74
|
+
|
|
75
|
+
- States without a `validate` function skip validation entirely
|
|
76
|
+
and accept the answer immediately. No existing state is broken
|
|
77
|
+
by the addition.
|
|
78
|
+
- Validators are pure functions with stable contracts. Drift
|
|
79
|
+
surface: validator messages. If a message text needs to change,
|
|
80
|
+
update the validator's return value — visible in PR diff.
|
|
81
|
+
- No config schema change. No agent-installed-files change. No
|
|
82
|
+
PostUpdateMigrator work.
|
|
83
|
+
|
|
84
|
+
## 7. Authorization / Trust posture
|
|
85
|
+
|
|
86
|
+
No new authority. The validator is run inside the same wizard
|
|
87
|
+
process with the same user. No new privilege, no new sandbox, no
|
|
88
|
+
new auth.
|
|
89
|
+
|
|
90
|
+
## Outcome
|
|
91
|
+
|
|
92
|
+
Ship. Closes the broken-on-buffered-Enter UX hole that the
|
|
93
|
+
instar-codey real-user test surfaced. Structural validation +
|
|
94
|
+
visible composing indicator together address the failure-mode
|
|
95
|
+
chain (silent latency → user reflex → buffered Enter → empty
|
|
96
|
+
submission accepted). Validator extensibility lands cleanly on
|
|
97
|
+
the existing state-machine API. 26 unit tests cover the
|
|
98
|
+
validators + wiring.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Side-Effects Review — inject current time into agent hooks
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `inject-current-time-into-hooks`
|
|
4
|
+
**Date:** `2026-05-21`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `not required` (Layer 1 hook-template content change, signal-only, no gate authority — Phase 5 trigger inventory below)
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
`PostUpdateMigrator.getSessionStartHook()` and `getTelegramTopicContextHook()` (the inlined bash templates that get unconditionally overwritten onto every agent's disk on update) now each emit a `--- CURRENT TIME ---` block backed by a fresh `date(1)` invocation. The block contains an ISO-formatted wall-clock timestamp with signed offset and timezone abbreviation, plus a one-line instruction to the agent: "Quote this — do not carry stale clock times from prior context."
|
|
11
|
+
|
|
12
|
+
**Files touched:**
|
|
13
|
+
- `src/core/PostUpdateMigrator.ts` — 14 lines added to `getSessionStartHook()` (after the `=== SESSION START ===` echo, before the TOPIC CONTEXT block); 14 lines added to `getTelegramTopicContextHook()` (immediately before the [telegram:N] early-exit, so the block fires on every UserPromptSubmit regardless of prefix).
|
|
14
|
+
- `tests/unit/PostUpdateMigrator-time-injection.test.ts` — new file, 13 test cases. Static assertions on the inlined bash (date format string, non-empty guard, delimiter strings, relative ordering within each hook) PLUS end-to-end `execFileSync` of each hook script against a fresh temp dir, asserting the actual emitted output matches the expected `YYYY-MM-DD HH:MM:SS +ZZZZ (TZ)` shape on a non-telegram prompt, a telegram-prefixed prompt, and a session-start invocation.
|
|
15
|
+
- `upgrades/NEXT.md` — new vNEXT entry, classified `patch` (behavior fix, no new surface).
|
|
16
|
+
|
|
17
|
+
## Decision-point inventory
|
|
18
|
+
|
|
19
|
+
- **Where the time block lands in session-start output** — *modify*. Placed AFTER `=== SESSION START ===` and BEFORE the TOPIC CONTEXT block. Rationale: the wall-clock is generic orientation, not topic-specific — it belongs at the top of the orientation frame, ahead of the per-conversation context. Asserted by test `places the time block BEFORE the TOPIC CONTEXT block`.
|
|
20
|
+
- **Where the time block lands in UserPromptSubmit** — *modify*. Placed BEFORE the `[telegram:N]` early-exit. Rationale: the script's filename suggests telegram-only, but UserPromptSubmit fires on every prompt — emitting the time block before the early-exit makes the fix universal (Telegram and direct-CLI sessions both get it). Asserted by test `emits the time block BEFORE the [telegram:N] early-exit`.
|
|
21
|
+
- **Output guard against a broken `date(1)`** — *new*. Wrap the emission in `if [ -n "$NOW" ]; then ... fi` so a hypothetical environment where `date(1)` returns empty (extremely unlikely on macOS/Linux) doesn't produce a `--- CURRENT TIME ---` header with no value. Asserted by test `wraps the emission in a non-empty guard`.
|
|
22
|
+
- **Date format choice** — *new*. `'%Y-%m-%d %H:%M:%S %z (%Z)'`. Portable across BSD date (macOS) and GNU date (Linux); produces both machine-parseable (`%z`) and human-readable (`%Z`) timezone forms. Verified by the end-to-end test which `execFileSync`s the hook and regex-matches the emitted body.
|
|
23
|
+
- **Delimiter style** — *match existing*. `--- CURRENT TIME ---` / `--- END CURRENT TIME ---` mirrors the dashed delimiters already used in session-start for other blocks (`--- CONVERSATION CONTEXT ---`, `--- INTEGRATED-BEING ---`, `--- PROJECT CONTEXT ---`). No new visual convention introduced.
|
|
24
|
+
|
|
25
|
+
## Level-of-abstraction fit
|
|
26
|
+
|
|
27
|
+
This is a Layer 1 (hook content) change. It belongs at the migrator level — both because the migrator is the source of truth for hook content (init and update both write from `getSessionStartHook()` / `getTelegramTopicContextHook()`) and because the failure mode (stale clock in long agent sessions) is a cross-cutting infrastructure gap, not a per-agent or per-feature concern. Solving it per-agent (e.g. Iris's memory file `feedback_clock_time_must_call_date.md`) closed the gap for one agent. Lifting it to the framework means every instar agent gets the same anchor without each one having to learn the lesson independently — which matches the **Structure > Willpower** principle stated in CLAUDE.md.
|
|
28
|
+
|
|
29
|
+
## Signal-vs-authority compliance
|
|
30
|
+
|
|
31
|
+
The hook injection emits text. It does not gate, block, modify, or veto any agent action. It is pure signal — the agent reads the wall-clock and is told to quote it. Authority over whether to use the time, what time to claim, or whether to call `date` again later remains entirely with the agent. No new blocking authority introduced.
|
|
32
|
+
|
|
33
|
+
## Interactions
|
|
34
|
+
|
|
35
|
+
- **Compaction recovery** (`compaction-recovery.sh`): On `compact` event, `session-start.sh` `exec`s away to `compaction-recovery.sh` BEFORE the time block is reached. So the time block does not run during compact-recovery. Compaction-recovery's own injection pipeline is separate and is not regressed by this change. The block DOES run on resume, which fires after compaction completes. No double-emission.
|
|
36
|
+
- **Telegram early-exit**: Adding output BEFORE the `[telegram:N]` early-exit means the hook now produces output on every UserPromptSubmit, including non-telegram prompts. This is intentional — direct-CLI sessions need the time anchor too. Effect on Claude Code: an additional ~3-line block in the agent's prompt buffer per turn. Token cost negligible (~30 tokens).
|
|
37
|
+
- **Integrated-Being v2 session-bind**: The session-bind block in `session-start.sh` lives AFTER the time block but runs independently. Time injection produces output via stdout; session-bind makes HTTP calls and writes a token file. No shared variables, no ordering dependency.
|
|
38
|
+
- **Existing PostUpdateMigrator-sharedState test**: Asserts the integrated-being injection survives in `getSessionStartHook()`. The new time block sits BEFORE the integrated-being block; the existing assertion (`expect(hook).toContain('/shared-state/render?limit=50')`) continues to pass — verified in test run.
|
|
39
|
+
|
|
40
|
+
## Over/under-block check
|
|
41
|
+
|
|
42
|
+
- **Under-block**: Could the fix miss any cases where an agent says a clock time?
|
|
43
|
+
- **Mid-session tool-result handoffs**: If an agent receives a Claude Code tool result and immediately replies with a time claim, the most recent time anchor is the previous UserPromptSubmit. Up to 5 minutes stale in fast back-and-forths, less for slow ones. Acceptable — within a single turn, ±a-few-minutes is fine. Worst-case would be a multi-hour autonomous-mode tool loop without user prompts, in which case the agent could go stale. Mitigated separately by autonomous-mode's existing periodic re-orientation; not in scope here.
|
|
44
|
+
- **Subagent invocations**: Sub-agents started via the `Agent` tool inherit the parent's prompt context, not the live hook output. So a subagent's time anchor is the parent's at-spawn time. Acceptable — subagents are short-lived and rarely make wall-clock claims; their job is task execution.
|
|
45
|
+
- **Over-block**: Could the fix cause an unintended block, refusal, or behavior change elsewhere?
|
|
46
|
+
- **Hook timeout (5s budget for UserPromptSubmit)**: Adding a `date` call adds <1ms. No timeout risk.
|
|
47
|
+
- **Token bloat in long sessions**: ~30 tokens per turn × thousands of turns = a few hundred-K tokens over a long session. Compared to the existing telegram-topic-context block (~500 tokens / turn for recent history), this is a rounding error.
|
|
48
|
+
- **Test pollution**: The end-to-end test uses `mkdtempSync` + per-test env var override, no persistent state. No effect on parallel test runs.
|
|
49
|
+
|
|
50
|
+
## Rollback cost
|
|
51
|
+
|
|
52
|
+
Two-line `git revert` of the migrator edit, plus deleting the new test file. Hooks are unconditionally overwritten on next migration run, so a revert propagates to all deployed agents on their next `npx instar`. No data migration, no persistent state, no fan-out — zero rollback friction.
|
|
53
|
+
|
|
54
|
+
## Phase 5 trigger check
|
|
55
|
+
|
|
56
|
+
Was a second-pass reviewer required? No.
|
|
57
|
+
|
|
58
|
+
- **Not a gate change**: No new authority, no blocking, no veto, no permission alteration. Signal-only.
|
|
59
|
+
- **Not a security-sensitive surface**: No new file reads outside the hook's existing scope (it only adds a `date` call); no new network calls; no new credential or token handling.
|
|
60
|
+
- **No new persistent state**: Output flows to stdout, consumed by Claude Code's prompt injector. No disk writes, no SQLite, no JSONL.
|
|
61
|
+
- **No cross-agent or cross-machine effect**: Per-agent hook content. No threadline message, no shared state, no remote operation.
|
|
62
|
+
|
|
63
|
+
The change crosses **none** of the second-pass triggers from the side-effects review standard. A single-pass review by the author with this written record is sufficient.
|