@gotgenes/pi-subagents 6.9.3 → 6.9.4
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/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [6.9.4](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v6.9.3...pi-subagents-v6.9.4) (2026-05-22)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Documentation
|
|
12
|
+
|
|
13
|
+
* plan consolidate shared test fixtures ([#131](https://github.com/gotgenes/pi-packages/issues/131)) ([2fe1e65](https://github.com/gotgenes/pi-packages/commit/2fe1e65024743384981c057b405f97f9c76f9b05))
|
|
14
|
+
|
|
8
15
|
## [6.9.3](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v6.9.2...pi-subagents-v6.9.3) (2026-05-22)
|
|
9
16
|
|
|
10
17
|
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
---
|
|
2
|
+
issue: 131
|
|
3
|
+
issue_title: Consolidate shared test fixtures
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Consolidate shared test fixtures
|
|
7
|
+
|
|
8
|
+
## Problem Statement
|
|
9
|
+
|
|
10
|
+
Three `mockSession()` factories and three `makeDeps()` factories are duplicated across the test suite.
|
|
11
|
+
Each copy drifts independently when production interfaces change, creating maintenance burden and inconsistent mock shapes.
|
|
12
|
+
The architecture doc (Phase 8, Step F) identifies this as the first testability improvement before the IO-injection steps (G and H).
|
|
13
|
+
|
|
14
|
+
## Goals
|
|
15
|
+
|
|
16
|
+
- Extract `createMockSession()` into `test/helpers/mock-session.ts` — single source of truth for the subscribable session mock.
|
|
17
|
+
- Extract `createToolDeps()` into `test/helpers/make-deps.ts` — builds `AgentToolDeps` with sensible defaults and override support.
|
|
18
|
+
- Update all six test files to use the shared factories and remove their local copies.
|
|
19
|
+
- Keep existing test behavior unchanged — this is a pure refactor with no production code changes.
|
|
20
|
+
|
|
21
|
+
## Non-Goals
|
|
22
|
+
|
|
23
|
+
- IO injection into `session-config` (Step G, #132) — deferred.
|
|
24
|
+
- SDK boundary injection into `agent-runner` (Step H, #133) — deferred.
|
|
25
|
+
- Consolidating `makeCtx()` or `makeParams()` helpers — those are specific to each tool's parameter shape and do not share enough structure to justify extraction.
|
|
26
|
+
|
|
27
|
+
## Background
|
|
28
|
+
|
|
29
|
+
### Existing helper
|
|
30
|
+
|
|
31
|
+
`test/helpers/make-record.ts` exports `createTestRecord()`, which builds an `AgentRecord` with sensible defaults and override support.
|
|
32
|
+
It has its own unit test file (`test/helpers/make-record.test.ts`).
|
|
33
|
+
The two new factories follow the same pattern.
|
|
34
|
+
|
|
35
|
+
### `mockSession()` — 3 copies
|
|
36
|
+
|
|
37
|
+
| File | Shape |
|
|
38
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
39
|
+
| `agent-manager.test.ts` | `subscribe` (vi.fn), `emit`, `dispose` (vi.fn), `steer` (vi.fn), `sessionManager` — cast as `any` |
|
|
40
|
+
| `record-observer.test.ts` | `subscribe` (vi.fn), `emit` |
|
|
41
|
+
| `ui/ui-observer.test.ts` | `subscribe` (plain fn), `emit` |
|
|
42
|
+
|
|
43
|
+
The common core is `subscribe` + `emit` (the subscribable event bus).
|
|
44
|
+
The `agent-manager` copy adds extra properties the other two don't need.
|
|
45
|
+
|
|
46
|
+
### `makeDeps()` — 3 copies
|
|
47
|
+
|
|
48
|
+
| File | Type | Manager methods | Widget methods | Extra fields |
|
|
49
|
+
| ---------------------------------- | ---------------- | -------------------------------------------------------- | ------------------------------------------- | ---------------------------- |
|
|
50
|
+
| `tools/agent-tool.test.ts` | `AgentToolDeps` | spawn, spawnAndWait, resume, getRecord, getMaxConcurrent | setUICtx, ensureTimer, update, markFinished | registry, agentDir, settings |
|
|
51
|
+
| `tools/background-spawner.test.ts` | `BackgroundDeps` | spawn, getRecord, getMaxConcurrent | ensureTimer, update | — |
|
|
52
|
+
| `tools/foreground-runner.test.ts` | `ForegroundDeps` | spawnAndWait | ensureTimer, markFinished | — |
|
|
53
|
+
|
|
54
|
+
`AgentToolDeps` is a structural superset of both `BackgroundDeps` and `ForegroundDeps`.
|
|
55
|
+
TypeScript's structural type system allows an `AgentToolDeps` value to be passed where `BackgroundDeps` or `ForegroundDeps` is expected — the narrower interfaces require a strict subset of the methods present on the wider one.
|
|
56
|
+
|
|
57
|
+
## Design Overview
|
|
58
|
+
|
|
59
|
+
### `createMockSession(overrides?)`
|
|
60
|
+
|
|
61
|
+
Returns the subscribable event bus (core shape) merged with optional overrides.
|
|
62
|
+
The core shape includes:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
interface MockSession {
|
|
66
|
+
subscribe: Mock<[fn: (event: any) => void], () => void>;
|
|
67
|
+
emit(event: any): void; // test-only helper, not on production Session
|
|
68
|
+
dispose: Mock;
|
|
69
|
+
steer: Mock;
|
|
70
|
+
sessionManager: { getSessionFile: Mock };
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
All fields are present in every call — callers that don't need `dispose` or `steer` simply ignore them.
|
|
75
|
+
This avoids a discriminated "minimal vs. full" shape that would reintroduce the divergence problem.
|
|
76
|
+
The `subscribe` spy is wired to a `Set<fn>` internally so `emit()` broadcasts to all subscribers, matching the existing hand-rolled pattern.
|
|
77
|
+
The return type is `MockSession & Record<string, unknown>` so call sites can pass it as `any`-typed session parameters without explicit casts.
|
|
78
|
+
|
|
79
|
+
Override support lets `agent-manager.test.ts` customize `steer` behavior or add fields:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const session = createMockSession({ steer: vi.fn().mockRejectedValue(new Error("fail")) });
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### `createToolDeps(overrides?)`
|
|
86
|
+
|
|
87
|
+
Builds a full `AgentToolDeps` with mock manager, widget, activity map, registry, agent dir, and settings.
|
|
88
|
+
Accepts `Partial<AgentToolDeps>` for overrides, following the same pattern as `createTestRecord()`.
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
function createToolDeps(overrides?: Partial<AgentToolDeps>): AgentToolDeps;
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Consumer call sites:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// agent-tool.test.ts — uses the full type directly
|
|
98
|
+
const deps = createToolDeps();
|
|
99
|
+
const tool = createAgentTool(deps);
|
|
100
|
+
|
|
101
|
+
// background-spawner.test.ts — structural typing narrows automatically
|
|
102
|
+
const deps = createToolDeps();
|
|
103
|
+
spawnBackground(deps, makeParams());
|
|
104
|
+
|
|
105
|
+
// foreground-runner.test.ts — same structural narrowing
|
|
106
|
+
const deps = createToolDeps({ manager: { spawnAndWait: vi.fn().mockResolvedValue(customRecord) } });
|
|
107
|
+
await runForeground(deps, makeParams(), undefined, undefined);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The background and foreground tests gain unused mock methods on `manager` and `widget`, but this is harmless — the production code's ISP compliance ensures only the narrow interface methods are called.
|
|
111
|
+
Tests that assert specific mock interactions (e.g., `expect(deps.manager.spawn).toHaveBeenCalled()`) continue to work because every method is a distinct `vi.fn()`.
|
|
112
|
+
|
|
113
|
+
When a test needs to override a single manager method, it spreads into the nested object:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
createToolDeps({
|
|
117
|
+
manager: { ...createToolDeps().manager, spawnAndWait: vi.fn().mockRejectedValue(err) },
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This is slightly more verbose than today's flat override, but it happens rarely and the tradeoff is worthwhile for a single source of truth.
|
|
122
|
+
|
|
123
|
+
Alternatively, `createToolDeps` can accept a `managerOverrides` shorthand if the nested-spread pattern proves too noisy during implementation.
|
|
124
|
+
|
|
125
|
+
## Module-Level Changes
|
|
126
|
+
|
|
127
|
+
### New files
|
|
128
|
+
|
|
129
|
+
1. `test/helpers/mock-session.ts` — exports `createMockSession(overrides?)`.
|
|
130
|
+
2. `test/helpers/mock-session.test.ts` — unit tests for `createMockSession`: verifies event broadcasting, subscribe/unsubscribe, and override merging.
|
|
131
|
+
3. `test/helpers/make-deps.ts` — exports `createToolDeps(overrides?)`.
|
|
132
|
+
4. `test/helpers/make-deps.test.ts` — unit tests for `createToolDeps`: verifies default shape satisfies `AgentToolDeps`, `BackgroundDeps`, and `ForegroundDeps`; verifies override merging.
|
|
133
|
+
|
|
134
|
+
### Modified files
|
|
135
|
+
|
|
136
|
+
1. `test/agent-manager.test.ts` — remove local `mockSession()`, import `createMockSession` from helpers.
|
|
137
|
+
2. `test/record-observer.test.ts` — remove local `mockSession()`, import `createMockSession` from helpers.
|
|
138
|
+
3. `test/ui/ui-observer.test.ts` — remove local `mockSession()`, import `createMockSession` from helpers.
|
|
139
|
+
4. `test/tools/agent-tool.test.ts` — remove local `makeDeps()`, import `createToolDeps` from helpers.
|
|
140
|
+
5. `test/tools/background-spawner.test.ts` — remove local `makeDeps()`, import `createToolDeps` from helpers.
|
|
141
|
+
6. `test/tools/foreground-runner.test.ts` — remove local `makeDeps()`, import `createToolDeps` from helpers.
|
|
142
|
+
|
|
143
|
+
## Test Impact Analysis
|
|
144
|
+
|
|
145
|
+
1. The new factory unit tests (`mock-session.test.ts`, `make-deps.test.ts`) verify the shared fixture behavior that was previously only implicitly tested through the consumer test files.
|
|
146
|
+
This enables targeted debugging when a mock shape drifts from the production interface.
|
|
147
|
+
2. No existing tests become redundant — the consumer tests exercise distinct production behavior that the factory tests do not cover.
|
|
148
|
+
3. All existing tests stay as-is in terms of assertions.
|
|
149
|
+
Only the setup code (local factory → shared import) changes.
|
|
150
|
+
|
|
151
|
+
## TDD Order
|
|
152
|
+
|
|
153
|
+
1. **Red → Green: `createMockSession` factory.**
|
|
154
|
+
Write `test/helpers/mock-session.test.ts` — verify subscribe/emit broadcasting, unsubscribe, dispose/steer are vi.fn stubs, override merging.
|
|
155
|
+
Implement `test/helpers/mock-session.ts`.
|
|
156
|
+
Commit: `test: add createMockSession shared test fixture`
|
|
157
|
+
|
|
158
|
+
2. **Green: migrate `record-observer.test.ts` to `createMockSession`.**
|
|
159
|
+
Replace local `mockSession()` with import from helpers.
|
|
160
|
+
Run test file — all tests pass unchanged.
|
|
161
|
+
Commit: `test: use createMockSession in record-observer tests`
|
|
162
|
+
|
|
163
|
+
3. **Green: migrate `ui/ui-observer.test.ts` to `createMockSession`.**
|
|
164
|
+
Replace local `mockSession()` with import from helpers.
|
|
165
|
+
Run test file — all tests pass unchanged.
|
|
166
|
+
Commit: `test: use createMockSession in ui-observer tests`
|
|
167
|
+
|
|
168
|
+
4. **Green: migrate `agent-manager.test.ts` to `createMockSession`.**
|
|
169
|
+
Replace local `mockSession()` with import from helpers.
|
|
170
|
+
This file uses extra fields (`sessionManager`, `steer`, `dispose`) — verify overrides or defaults cover them.
|
|
171
|
+
Run test file — all tests pass unchanged.
|
|
172
|
+
Commit: `test: use createMockSession in agent-manager tests`
|
|
173
|
+
|
|
174
|
+
5. **Red → Green: `createToolDeps` factory.**
|
|
175
|
+
Write `test/helpers/make-deps.test.ts` — verify default shape, override merging, structural compatibility with `BackgroundDeps` and `ForegroundDeps`.
|
|
176
|
+
Implement `test/helpers/make-deps.ts`.
|
|
177
|
+
Commit: `test: add createToolDeps shared test fixture`
|
|
178
|
+
|
|
179
|
+
6. **Green: migrate `tools/agent-tool.test.ts` to `createToolDeps`.**
|
|
180
|
+
Replace local `makeDeps()` with import from helpers.
|
|
181
|
+
Run test file — all tests pass unchanged.
|
|
182
|
+
Commit: `test: use createToolDeps in agent-tool tests`
|
|
183
|
+
|
|
184
|
+
7. **Green: migrate `tools/background-spawner.test.ts` to `createToolDeps`.**
|
|
185
|
+
Replace local `makeDeps()` with import from helpers.
|
|
186
|
+
Adjust any override patterns for the wider type.
|
|
187
|
+
Run test file — all tests pass unchanged.
|
|
188
|
+
Commit: `test: use createToolDeps in background-spawner tests`
|
|
189
|
+
|
|
190
|
+
8. **Green: migrate `tools/foreground-runner.test.ts` to `createToolDeps`.**
|
|
191
|
+
Replace local `makeDeps()` with import from helpers.
|
|
192
|
+
Adjust any override patterns for the wider type.
|
|
193
|
+
Run test file — all tests pass unchanged.
|
|
194
|
+
Commit: `test: use createToolDeps in foreground-runner tests`
|
|
195
|
+
|
|
196
|
+
## Risks and Mitigations
|
|
197
|
+
|
|
198
|
+
| Risk | Mitigation |
|
|
199
|
+
| ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
200
|
+
| Wider mock shape causes false-positive tests (tests pass even when production code calls wrong method) | The production interfaces are already ISP-narrow; the mock width only affects tests. Existing assertions on specific mock calls catch regressions. |
|
|
201
|
+
| Override merging doesn't handle nested objects (e.g., overriding a single manager method) | Factory uses shallow merge for top-level fields; document that nested overrides require spreading the default nested object. Evaluate a `managerOverrides` shorthand during implementation if the pattern is too noisy. |
|
|
202
|
+
| `createMockSession` return type is too loose (`any`) and hides type errors in tests | Return a named `MockSession` interface rather than `any`. Consumer sites that pass the mock as `any`-typed SDK parameters are already untyped at that boundary. |
|
|
203
|
+
|
|
204
|
+
## Open Questions
|
|
205
|
+
|
|
206
|
+
- Should `createToolDeps` accept a flat `managerOverrides` shorthand or require the caller to spread the nested object?
|
|
207
|
+
Decide during step 5 based on how verbose the migration turns out in steps 6–8.
|