Skip to content

v0.7.4 — plugin-root paths, Summer-only X-Userinfo, token: none

Choose a tag to compare

@tranquocthong tranquocthong released this 04 Aug 06:06
· 5 commits to main since this release

Three dogfooding bugs, all found running spec-flow against an external Node/Express project (claude-code-provider / tenant-usage-monitoring). None are in the target project's code — all three are spec-flow defects that cost real debugging time.

  • bin/task-master was invoked cwd-relative in the skill instructions. commands/{phase,ingest,init,change,resync}.md and agents/hybrid-executor.md told the agent to run node bin/task-master …, but those commands execute in the user's project, which has no bin/task-master — the binary lives in the plugin. Result: MODULE_NOT_FOUND, and the agent had to hand-resolve the plugin's absolute path to continue. Now node ${CLAUDE_PLUGIN_ROOT}/bin/task-master …, matching how every flow-tools.cjs invocation was already written. Root cause: scripts/cutover.cjs's NATIVE_CLI_PREFIX (v0.7.0) rewrote the old npx invocations to a relative path. The cutover/rollback script pair is left as-is — it is one-shot historical migration tooling and the legacy dependency it targets is already removed. docs/ invocations are unchanged: those are run from the spec-flow repo root, where the relative path is correct.
  • detect-auth.sh missed custom Authorization: Bearer schemes, and checklist-gen defaulted the wrong way. Two compounding bugs. (1) The detector classifies by dependency fingerprint (jsonwebtoken, jjwt, pyjwt, …), so a service that reads the Authorization header itself and validates an opaque API key — no JWT library anywhere — fell through to unknown. It now also greps the source for header-read + Bearer prefix, across every stack, and reports jwt-basic (same wire form; only how you mint the token differs). (2) checklist-gen treated the Summer/APISIX payload:/X-Userinfo form as the default and bearer: as the special case — exactly backwards. X-Userinfo is a Summer/APISIX-specific convention that is only trusted behind a real gateway upstream; an unclassified project got a scaffold that 401s every generated test with a failure that reads like an app bug. Now inverted: only an explicitly-detected summer project gets payload:; jwt-basic, session, no-auth, and unknown all scaffold bearer: "${TOKEN}" with an advisory comment naming the detected type. (Hit twice in one session, on two different projects.)
  • token: none failed instead of sending an unauthenticated request. The natural way to write a 401 / public-endpoint test — token: none — was looked up as a token named "none" in the tokens: map, missed, and failed the test with unknown token 'none'. The working spelling (omit the token: line entirely) was documented nowhere. checklist_lib/runner.py now treats none / null / no-auth / noauth / anonymous / false / - as "send no auth header", while a token genuinely declared under that name still wins (backward-compatible). The error for a real typo now lists the declared token names and points at the no-auth spelling. Documented in references/checklist.md, templates/CHECKLIST.yaml, commands/checklist.md, and the generated scaffold's own header comment.
  • .mcp.json made plugin-root-absolute too (same root cause as the first item): the bundled MCP server entry was ["bin/mcp-server.js"], now ["${CLAUDE_PLUGIN_ROOT}/bin/mcp-server.js"]. Caveat: ${CLAUDE_PLUGIN_ROOT} is only defined when the file is loaded as a plugin manifest — opening the spec-flow repo directly as a project no longer resolves it. Plugin distribution is the primary path, so that is the right trade; revert this one line if you need the repo-as-project case back.
  • 778 Node tests green (assertions updated for the flipped auth default), 48 Python tests green (5 new).