Commit cd52c1c
committed
fix(mcode-island): exercise Get-5hUsage via dot-source + matching fixture + token-source precedence (PR #21 round-9)
## What
amszuidas round-8 P2 review on PR #21 (`812dd29`):
> The mocked usage-API step in `.github/workflows/mcode-island-windows.yml`
> reconstructs its own HTTP request rather than invoking the plugin's
> `Get-5hUsage` function. Its fixture uses `model/remainingPct/resetMs`,
> whereas the implementation reads
> `model_name/current_interval_remaining_percent/remains_time`. Please
> exercise the actual function against a matching fixture and cover
> token-source precedence, so a regression in the implementation fails
> the test.
Two problems in the round-5 step 4:
1. The step calls `Invoke-RestMethod` itself instead of
`mcode-status-detect.ps1::Get-5hUsage`. A future regression in
`Get-5hUsage` (field-name contract, URL composition, header
construction) would NOT fail this CI step, because the CI step
never goes through the implementation.
2. The fixture body uses field names the implementation does NOT
read (`model` / `remainingPct` / `resetMs` instead of
`model_name` / `current_interval_remaining_percent` /
`remains_time`). Even if the CI step did call the function, a
future field-name change would silently produce `$null` and the
step would not catch it.
## Fix
### `.github/workflows/mcode-island-windows.yml` step 4
The step now dot-sources `mcode-status-detect.ps1` with `-Once`
so all functions are imported (the `$Once` switch in the file
guards the main loop - see line 519 `if (-not $Once) { ... }`
and line 639 `if ($Once) { break }` - so the main loop runs
exactly once and breaks before `Start-Sleep`). The step then:
1. Reassigns `$script:PLAN_API_HOST` to `http://127.0.0.1:$freePort`
so `Get-5hUsage`'s `Invoke-RestMethod` points at the local
mock listener. `$script:PLAN_API_PATH` stays as
`/v1/coding_plan/remains`.
2. Runs **three** sub-tests, each with its own mock listener
(so a failure in one cannot corrupt the next):
- **Test a (env-var token):** set `$env:MINIMAX_OAUTH_TOKEN`,
call `Get-5hUsage`, assert the mock saw
`Bearer $env:FAKE_TOKEN` + path `/v1/coding_plan/remains`,
and assert the return value is `@{ remainingPct=84; resetMs=16200000 }`.
- **Test b (config.json only):** clear env vars, write a
different token to `config.json`, re-derive
`$script:plan5hToken` the same way the file's top-level
init does (line 124-125), call `Get-5hUsage`, assert the
mock saw the config.json token.
- **Test c (no token):** clear all sources, call
`Get-5hUsage`, assert the function returns `$null` at
line 419 without hitting the network.
3. Fixture body now uses the field names the implementation
reads:
```json
{"model_remains":[{"model_name":"general","current_interval_remaining_percent":84,"remains_time":16200000}]}
```
### `plugins/antianqi/mcode-island/scripts/test-windows-workflow-local.ps1`
The local-runner mirror that ships with the plugin (PR #21
round-5 `86247c7`) is updated to the same three sub-tests, so a
developer running `pwsh -File test-windows-workflow-local.ps1`
locally sees the same pass/fail signal as CI.
## What this pins
- `Get-5hUsage` actually runs. A future change to the function
(renamed field, swapped header, accidentally removed bearer
token) will fail this step.
- The mock fixture's field names match what the implementation
reads. A future rename in the function without updating the
fixture will fail this step with `Get-5hUsage returned null`
(line 432 condition).
- Token-source precedence contract (`$env:MINIMAX_OAUTH_TOKEN`
> `$env:MINIMAX_API_KEY` > `config.json` planApiToken) is
exercised end-to-end, with both the env-var path and the
config.json path individually verified.
## Test evidence
```
$ pwsh -File test-windows-workflow-local.ps1
Step 1: parses 28 .ps1 files clean (Parser::ParseFile)
Step 2: token set/show/clear roundtrip 4/4 OK
Step 3: hook PreToolUse writes status.json (state=working, source=agent)
Step 4a (env token, matching fixture): OK remainingPct=84% resetMs=16200000
Step 4b (config-only token): OK remainingPct=84% resetMs=16200000
Step 4c (no token): OK returned null
All 4 steps OK
```
Self-parse check (CI step 1 mirrored locally):
```
$ pwsh -Command "Parser::ParseFile on all 28 .ps1"
OK: 28 .ps1 files parsed cleanly
```
## Design compliance
- **One Plugin, one commit, one branch.** Only files inside
`plugins/antianqi/mcode-island/` and the workflow that
exercises it are touched. The `mcode-status-detect.ps1`
implementation is not modified - the contract change is
exercised on the consumer (CI / local runner) side.
- **No credentials, no network, no telemetry, no third-party
services.** The mock listener binds to `127.0.0.1`, returns
a hard-coded JSON, and is reaped via job cleanup. No real
`api.minimax.io` round-trip happens.
- **No hardcoded paths in source code.** `mcode-island`'s own
`scripts/smoke.mjs` static check still passes after this
change.
- **PowerShell parser portability.** Backtick-escape sequences
in `Write-Host` arguments are avoided in the new code; the
few places that previously used them now emit the literal
token name. PowerShell 5.1 (Windows PowerShell, GBK codepage)
and PowerShell 7.6 (UTF-8) both parse the new step cleanly
under `Parser::ParseFile` (the parser used by the workflow's
step 1).1 parent 812dd29 commit cd52c1c
2 files changed
Lines changed: 282 additions & 138 deletions
File tree
- .github/workflows
- plugins/antianqi/mcode-island/scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
215 | 215 | | |
216 | 216 | | |
217 | 217 | | |
218 | | - | |
219 | | - | |
220 | | - | |
221 | | - | |
222 | | - | |
223 | | - | |
224 | | - | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
231 | | - | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
232 | 257 | | |
233 | 258 | | |
234 | 259 | | |
235 | | - | |
236 | | - | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
237 | 273 | | |
238 | 274 | | |
239 | 275 | | |
240 | 276 | | |
241 | 277 | | |
242 | 278 | | |
243 | | - | |
244 | | - | |
245 | | - | |
246 | | - | |
247 | | - | |
248 | | - | |
249 | | - | |
250 | | - | |
251 | | - | |
252 | | - | |
253 | | - | |
254 | | - | |
255 | | - | |
256 | | - | |
257 | | - | |
258 | | - | |
259 | | - | |
260 | | - | |
261 | | - | |
262 | | - | |
263 | | - | |
264 | | - | |
265 | | - | |
266 | | - | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
267 | 286 | | |
268 | | - | |
269 | | - | |
270 | | - | |
271 | | - | |
272 | | - | |
273 | | - | |
274 | | - | |
275 | | - | |
276 | | - | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
277 | 295 | | |
278 | | - | |
279 | | - | |
280 | | - | |
281 | | - | |
282 | | - | |
283 | | - | |
284 | | - | |
285 | | - | |
286 | | - | |
287 | | - | |
288 | | - | |
289 | | - | |
290 | | - | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
291 | 327 | | |
292 | | - | |
293 | | - | |
294 | | - | |
295 | | - | |
296 | | - | |
297 | | - | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
298 | 338 | | |
299 | | - | |
| 339 | + | |
300 | 340 | | |
301 | 341 | | |
302 | | - | |
| 342 | + | |
303 | 343 | | |
304 | | - | |
305 | | - | |
306 | | - | |
307 | | - | |
308 | | - | |
309 | | - | |
| 344 | + | |
| 345 | + | |
310 | 346 | | |
311 | | - | |
312 | | - | |
313 | | - | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
314 | 386 | | |
315 | | - | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
316 | 391 | | |
317 | | - | |
318 | | - | |
319 | | - | |
320 | | - | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
321 | 404 | | |
| 405 | + | |
| 406 | + | |
0 commit comments