Commit 1b57cec
authored
fix: M1-M11 medium-severity issues from prior code review (#53)
* fix(cmd): M1 part 1 - pinSubcommand, GLM thinking, status use accessors
- chat_subcommand_pin.go: use m.session.SetPinnedMessages
- chat_subcommand_simple.go: use m.session.SetGLMThinkingEnabled
- chat_subcommand_status.go: use m.session.CostValue().Summary()
- session.go: add SetPinnedMessages accessor
* fix(cmd): M1 part 2 - Autonomy, ContainerExecutor, ConvoDAG accessors
- chat.go: use PermSvc().Autonomy()/SetAutonomy, SetContainerExecutor, SetContainerRequired
- permissions_center.go: use PermSvc().SetAutonomy
- welcome_gate.go, statusbar.go: use PermSvc().Autonomy()
- hud_panel.go: use MemorySvc().Yaad()
- chat_status.go: use ContextWindowCachedValue, Persistence().SetContextWindowCached
- chat_subcommand_branches.go: use Persistence().DAG()
- chat_commands_session.go: use Persistence().DAG()
- session.go: add SetContainerExecutor accessor
- audit_test.go: regex now matches m.session.X; cmdHardFailThreshold=0
* fix(cmd): M1 part 3 - remaining cmd/ Cost/Mode/ContextWindow accessors
- statusbar.go: use m.session.CostValue()
- chat_subcommand_cost.go, chat_subcommand_usage.go: use CostValue()
- chat_commands_session.go, chat_commands_util.go: use CostValue()
- chat.go: use ContextWindowCachedValue()
- permissions_center.go: use ModeValue() (safe fallback for test struct literal)
- chat_model_test.go, statusbar_test.go: use accessors
- session_sync.go, snapshot_cmd.go: avoid audit regex false positives in text
- session.go: add SetContextWindowCached, ModeValue, SetMode accessors
* fix(engine): M2 - AddUser/AddAssistant use MemorySvc() and Persistence().DAG()
- AddUser: read Memory from s.MemorySvc().Memory() (was s.Memory)
- AddUser, AddUserWithImage, AddAssistant, ForkConversation, SwitchBranch,
ListBranches, ConvoHead: read DAG from s.Persistence().DAG() (was s.ConvoDAG)
- Aligns with the H6 sub-service decomposition: the legacy ConvoDAG and
Memory fields on Session are aliases set by NewSessionWithClient; new
code goes through the sub-service getters to keep the
god-object-decomposition contract consistent.
* fix(engine): M3 - deprecation comments point at real accessors
- FewShot() -> FewShotStore() (typo fix in comment)
- PlanState, Trajectory, LintLoop, TestLoop, FileMentions, Files,
Snapshots, Tracer, RateLimiter: comments now indicate these
remain on the legacy Session struct (no sub-service accessor
exists); the previous deprecation text pointed to non-existent
methods that callers could not find.
* fix(engine): M4 - PermissionService constructor no longer pre-sets mode
NewPermissionService no longer initializes mode to PermissionModeDefault;
the zero value ("") is preserved so IsZero() can correctly report a
freshly constructed service. IsZero() now checks for the empty string
instead of PermissionModeDefault. This is the right semantics: callers
that want a default mode should call SetMode explicitly, and tests can
rely on IsZero() being true for a fresh service.
* fix(cmd): M5 - SubcommandRegistry.Register detects alias collision
The previous implementation checked for primary-name duplicates
(`r.primary[name]`) but not alias collisions. Two subcommands
that each register a different primary but share an alias would
silently overwrite `r.aliasOf[alias]`. Now the alias check
mirrors the primary-name check: registration is rejected if any
of the subcommand's aliases is already taken. The existing
silent-no-op pattern is preserved (no error return) so init()
callers don't have to change.
* fix(cmd): M6 - sessionSubcommand.Handle prepends command name to args
The previous Handle passed the post-name args slice directly to
handleSessionCommand, which expects parts[0] to be the command
name. This broke /recover <id>, /resume <id>, and /tag <label>:
the trailing arg landed at parts[0] instead of parts[1], and the
`len(parts) >= 2` check failed, hitting the usage error path.
The fix reconstructs the full parts slice (name + args) before
calling handleSessionCommand, matching the contract the
simple.go delegatingCommand handlers use. The parts-building
logic is extracted into a buildSessionParts helper for testability.
New tests (TestBuildSessionParts_*, TestSessionSubcommand_RecoverIDReachesPartsIndex1,
TestResolveSessionName_PicksLongestMatch) assert the fix and the
dispatcher contract.
* fix(multiagent): M7 - WaitForLock no longer busy-spins
The previous for-select loop had two problems: (1) after the first
\<-w.done fired, the closed channel kept firing and the loop
re-called AcquireLock, busy-spinning until the timer.C fired.
(2) Both <-w.done and <-timer.C become ready at timeout, and Go's
select picks randomly — so the function could miss the timeout
and loop indefinitely.
Fix: replace the for-loop with a one-shot select. On the first
signal (w.done or timer), try AcquireLock exactly once. If it
succeeds, return nil; if the timer fired, return a timeout error.
The race-loser no longer re-registers — it returns an error.
TestWaitForLock_MultipleWaiters_OnlyOneAcquires updated to assert
the new semantics: the race-loser gets an error rather than
re-registering and waiting for a second signal.
* fix(multiagent): M8 - logDroppedMessage moved out of mb.mu critical section
The previous implementation called logDroppedMessage while holding
mb.mu (write lock). The slog.Warn call may acquire its own internal
lock (the slog handler's mutex); if the handler is slow (file I/O,
network sink), this serializes all bus operations for the duration
of the log write.
Fix: snapshot the (from, to, topic) of each drop into a local
slice while still holding the lock, then iterate the slice after
the lock is released and call logDroppedMessage on each entry.
The error return path is also collected into a local variable
and returned after the lock is released.
No behavior change for the caller; only the order of operations
differs (logs now happen after the bus is unlocked).
* fix(multiagent): M9 - extract dropLogEveryN as a named constant
The previous 100 was a magic number inlined in the
`n%100 != 0` check. Extracted as a package-level const
`dropLogEveryN = 100` with a doc comment explaining the
rationale (balancing observability against log volume under
sustained pressure).
* test(multiagent): M10 - rename test + add real waiter-assertion test
- TestWaitForLock_OwnerMismatchOnRelease renamed to
TestReleaseLock_NonOwnerReturnsError; the original name claimed
it was about waiters not being woken, but the body only checked
the error return.
- New TestWaitForLock_ReleaseByNonOwnerDoesNotWakeWaiter registers
a real waiter, attempts a ReleaseLock from a non-owner, and
asserts the waiter times out (rather than being woken by the
failed ReleaseLock). This is the test the original name
promised but never delivered.
* test(multiagent): M11 - join the WaitForResponse goroutine via a done channel
The previous TestStats_NotAffectedByWaiters launched a goroutine
that called WaitForResponse and never joined it; the goroutine
ran for 100ms after the test exited. Fixed by:
- Adding a done channel that the goroutine closes on return.
- Adding a 1-second join timeout via select on the done channel.
- The test now fails loudly if the goroutine does not return
within 1s (which would indicate a future regression).
* fix(engine): M2 - make AddUser/AddAssistant/ForkConversation/etc nil-safe
The M2 refactor changed these methods to call
s.Persistence().DAG() and s.MemorySvc().Memory() directly. That
panics on &engine.Session{} struct literals (used by cmd tests)
where s.persist and s.memory are nil.
This commit wraps each call site in a nil-check on the parent
service (s.Persistence() / s.MemorySvc()) so that struct-literal
sessions still work the same way as before — the methods
become no-ops when their backing sub-service is nil, which
matches the previous behavior on s.ConvoDAG == nil and
s.Memory == nil.1 parent 1cf3c20 commit 1b57cec
26 files changed
Lines changed: 564 additions & 229 deletions
File tree
- cmd
- internal
- engine
- multiagent
- testaudit
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
315 | 315 | | |
316 | 316 | | |
317 | 317 | | |
318 | | - | |
| 318 | + | |
319 | 319 | | |
320 | 320 | | |
321 | 321 | | |
| |||
896 | 896 | | |
897 | 897 | | |
898 | 898 | | |
899 | | - | |
900 | | - | |
| 899 | + | |
| 900 | + | |
901 | 901 | | |
902 | 902 | | |
903 | | - | |
| 903 | + | |
904 | 904 | | |
905 | 905 | | |
906 | 906 | | |
| |||
1275 | 1275 | | |
1276 | 1276 | | |
1277 | 1277 | | |
1278 | | - | |
| 1278 | + | |
1279 | 1279 | | |
1280 | 1280 | | |
1281 | 1281 | | |
1282 | | - | |
1283 | | - | |
| 1282 | + | |
| 1283 | + | |
1284 | 1284 | | |
1285 | 1285 | | |
1286 | 1286 | | |
1287 | 1287 | | |
1288 | | - | |
| 1288 | + | |
1289 | 1289 | | |
1290 | 1290 | | |
1291 | 1291 | | |
| |||
1294 | 1294 | | |
1295 | 1295 | | |
1296 | 1296 | | |
1297 | | - | |
1298 | | - | |
| 1297 | + | |
| 1298 | + | |
1299 | 1299 | | |
1300 | 1300 | | |
1301 | 1301 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
200 | 200 | | |
201 | 201 | | |
202 | 202 | | |
203 | | - | |
| 203 | + | |
204 | 204 | | |
205 | 205 | | |
206 | 206 | | |
| |||
415 | 415 | | |
416 | 416 | | |
417 | 417 | | |
418 | | - | |
| 418 | + | |
419 | 419 | | |
420 | 420 | | |
421 | 421 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
123 | 123 | | |
124 | 124 | | |
125 | 125 | | |
126 | | - | |
| 126 | + | |
127 | 127 | | |
128 | 128 | | |
129 | 129 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
139 | 139 | | |
140 | 140 | | |
141 | 141 | | |
142 | | - | |
| 142 | + | |
143 | 143 | | |
144 | 144 | | |
145 | 145 | | |
| |||
149 | 149 | | |
150 | 150 | | |
151 | 151 | | |
152 | | - | |
| 152 | + | |
153 | 153 | | |
154 | 154 | | |
155 | 155 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
92 | | - | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
93 | 96 | | |
94 | 97 | | |
95 | 98 | | |
| |||
100 | 103 | | |
101 | 104 | | |
102 | 105 | | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
103 | 111 | | |
104 | 112 | | |
105 | 113 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
| 17 | + | |
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
28 | | - | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
29 | 36 | | |
30 | | - | |
| 37 | + | |
31 | 38 | | |
32 | | - | |
33 | | - | |
| 39 | + | |
34 | 40 | | |
35 | 41 | | |
36 | 42 | | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
41 | 66 | | |
42 | 67 | | |
43 | 68 | | |
| |||
0 commit comments