Skip to content

refactor: rename stax plans to stax work-items - #40

Merged
tsaqib merged 2 commits into
mainfrom
rename-plans-to-work-items
May 29, 2026
Merged

tsaqib merged 2 commits into
mainfrom
rename-plans-to-work-items

Conversation

@tsaqib

@tsaqib tsaqib commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Renames the artifact noun and CLI surface concept-wide. The .stax/*.md files the binary tracks are now called work items everywhere — CLI verb, Go identifiers, on-disk schema, HTTP API, frontend, bundled skills, docs, e2e harness, and skills-evals. Hard cut; stax plans is removed (no alias).

The /scope and /ship skill names, the /api/scopes HTTP route, and the web UI's "scope" terminology are intentionally unchanged — those are a separate naming axis from the artifact noun.

What changed

  • CLI: stax plans <verb> → stax work-items <verb>. Help table, usage panel, and unknown-subcommand error all updated.
  • Files: scope.go → work_items.go, scope_test.go → work_items_test.go (the old names were misnomers — both files held the work-item tooling, not anything scope-related).
  • Go symbols: runPlans, printPlansUsage, planList, lintPlanFile, parsePlan, listPlans, planRow, planDetail, plansListOverflowThreshold, defaultMaxPlanLines, reviewPerPlan, planFileExt, writePlansScaffold, promptMaxPlanLines, et al. → workItem/workItems/WorkItem variants.
  • On-disk schema: _config.lock max_plan_lines → max_work_item_lines; review_per value "plan" → "work-item". Existing files with the old key/value silently fall back to defaults (hard cut, no migration).
  • HTTP API: /api/systems?id= response field plans → workItems; Go struct planDetail → workItemDetail. Frontend updated to consume the new key. /api/scopes keeps its existing naming.
  • Frontend: type Plan → WorkItem; DOM ids #system-plans / tpl-plan → #system-work-items / tpl-work-item; user-visible strings ("Loading plans…", "No plans for this system yet.") updated.
  • Bundled skills: agents/skills/scope/SKILL.md and ship/SKILL.md rewritten — artifact noun renamed throughout; hook commands stax plans lint → stax work-items lint in agents/claude/settings.json and agents/codex/hooks.json. The proposal-pattern wording (plan-first protocol, sub-plan, ## Plan approval-prompt heading, Build the plan, Present the plan) is preserved as English usage — distinct from the renamed artifact.
  • Docs: AGENTS.md, CLAUDE.md, README.md, docs/public/reference.md, docs/internal/*.md — artifact noun renamed; reference.md gains a new .stax/_config.lock schema subsection covering all three keys + the post-rename migration note.
  • Scripts: scripts/e2e_test.sh and scripts/e2e_test.ps1 — every plans invocation routed through work-items; shell constant PLANS_LIST_OVERFLOW_THRESHOLD → WORK_ITEMS_LIST_OVERFLOW_THRESHOLD with matching update in constants_e2e_test.go's drift check; PS1 helpers Add-ManyPlans / Write-PlanWithBody → Add-ManyWorkItems / Write-WorkItemWithBody; fixture slug stems -plan{NNN} → -work-item{NNN} with all assertions following.
  • Skills-evals: test_*_plan_extends.py → test_*_work_item_extends.py; plan_judge.py → work_item_judge.py; fixture loaders and judgments updated.
  • Sample data: .stax.example/_config.lock schema key updated. Sample work-item bodies that use "plan" in a billing/subscription sense (e.g. "subscription plan changes") left untouched — domain English, not the renamed artifact.

Test plan

  • go vet ./... clean
  • go test ./... clean
  • npm run check (typecheck + Biome + Knip) clean
  • npm run build (Vite production build) clean
  • scripts/e2e_test.sh 624/624 cases pass locally
  • CI: govulncheck / test / e2e / windows-cli / skills-eval-* matrices
  • Manual smoke: stax init → /scope author a work item → stax work-items lint → /ship execute → confirm hook fires stax work-items lint

tsaqib added 2 commits May 28, 2026 22:50
Rename the artifact noun and CLI surface concept-wide: the `.stax/*.md`
files the binary tracks are now called "work items" everywhere. Hard cut;
no `stax plans` alias.

- CLI: `stax plans <verb>` → `stax work-items <verb>`; usage table,
  error messages ("unknown work-items subcommand"), and `-h` output
  all updated.
- Go: scope.go → work_items.go (the file was a misnomer — it held the
  work-item tooling, not anything scope-related). Symbol renames:
  runPlans, printPlansUsage, planList, lintPlanFile, planRow,
  planDetail, plansListOverflowThreshold, defaultMaxPlanLines,
  reviewPerPlan, planFileExt, parsePlan, listPlans, writePlansScaffold,
  promptMaxPlanLines, et al. → workItem/workItems/WorkItem variants.
- On-disk schema: `_config.lock` `max_plan_lines` → `max_work_item_lines`;
  `review_per` value "plan" → "work-item". Existing files with the old
  key/value silently fall back to defaults (hard cut, no migration).
- HTTP API: `/api/systems?id=` response field `plans` → `workItems`;
  Go struct `planDetail` → `workItemDetail`. Frontend updated to
  consume the new key. `/api/scopes` keeps its existing naming.
- Frontend: type `Plan` → `WorkItem`; DOM ids `#system-plans`/`tpl-plan`
  → `#system-work-items`/`tpl-work-item`; user-visible strings
  ("Loading plans…", "No plans for this system yet.") updated.
- Bundled skills: scope/SKILL.md + ship/SKILL.md rewritten to use
  "work item" for the artifact; hook commands (`stax plans lint` →
  `stax work-items lint`) in agents/claude/settings.json and
  agents/codex/hooks.json. The proposal-pattern wording ("plan-first
  protocol", "sub-plan", "## Plan" approval-prompt heading, "Build
  the plan", "Present the plan") is preserved as English usage,
  distinct from the renamed artifact.
- Docs: AGENTS.md, CLAUDE.md, README.md, docs/public/reference.md,
  docs/internal/*.md — artifact noun renamed; reference.md gains a
  new `.stax/_config.lock` schema subsection covering all three keys
  + the post-rename migration note.
- Scripts: scripts/e2e_test.sh + scripts/e2e_test.ps1 — every `plans`
  invocation routed through `work-items`; shell constant
  `PLANS_LIST_OVERFLOW_THRESHOLD` → `WORK_ITEMS_LIST_OVERFLOW_THRESHOLD`
  with matching update in constants_e2e_test.go's drift check; PS1
  helpers `Add-ManyPlans`/`Write-PlanWithBody` → `Add-ManyWorkItems`/
  `Write-WorkItemWithBody`; fixture slug stems `-plan{NNN}` →
  `-work-item{NNN}` with all assertions following.
- Skills-evals: `test_*_plan_extends.py` → `test_*_work_item_extends.py`;
  `plan_judge.py` → `work_item_judge.py`; fixture loaders/judgments
  updated to match.
- Sample data: `.stax.example/_config.lock` schema key updated. Sample
  work-item bodies that use "plan" in a billing/subscription sense
  (e.g. "subscription plan changes") left untouched — domain English,
  not the renamed artifact.

Verified locally: go vet + go test clean, npm run check + frontend
build clean, scripts/e2e_test.sh 624/624 cases pass.

Signed-off-by: Tanzim Saqib <[email protected]>
The committed lock file was missing node_modules/@emnapi/core and
node_modules/@emnapi/runtime — peer deps that oxc-parser bindings
pull in on Linux x64. Locally npm install on macOS ARM64 doesn't
notice because the local platform binding doesn't need them, but
GitHub Actions runs npm ci on linux/amd64 and rejects the lock as
out-of-sync.

Regenerated the lock file with `npm install --include=optional`
from a clean state so all platform-specific bindings + their
transitive peer deps are recorded. No package.json changes.

Signed-off-by: Tanzim Saqib <[email protected]>
@tsaqib
tsaqib merged commit 8ed25f9 into main May 29, 2026
6 checks passed
@tsaqib
tsaqib deleted the rename-plans-to-work-items branch May 29, 2026 03:31
tsaqib added a commit that referenced this pull request May 29, 2026
Aligns the web UI with the renamed artifact noun (PR #40 moved the
CLI from `stax plans` to `stax work-items`). The user-visible URLs,
nav rail labels, page identifiers, and the HTTP API the page TS
consumes all migrate together so the naming axis is one consistent
"work item" everywhere.

Frontend:
- Page files: scopes.html → work-items.html, scope.html → work-item.html;
  scopes.ts → work-items.ts, scope.ts → work-item.ts. Layout block-helper
  args (title/page/active) updated to match.
- Nav rail (header.html + mobile-nav.html): "Scopes" → "Work items";
  href /scopes → /work-items; data-active-key follows. Flag icon kept.
- Detail page back-link, list-page empty-state, home-page card +
  Latest section, /search results section, and all DOM ids that
  embedded "scope" (`#scope-icon`, `#scope-title`, `#scope-body`,
  `#scopes-list`, `#latest-scopes`, `tpl-scope`, `tpl-scope-link`)
  renamed to the work-item equivalents.
- Page dispatcher in bundle.ts uses bracketed keys for the
  kebab-cased page names; vite.config.ts pages array follows.
- Internal hrefs `/scope?id=…` → `/work-item?id=…` across home.ts,
  search.ts, system.ts.
- CSS: `.scope-body` → `.work-item-body`.

HTTP API + Go server:
- /api/scopes → /api/work-items, /api/scope → /api/work-item;
  apiScopesPath/apiScopePath constants renamed.
- Handler renames: handleAPIScopes → handleAPIWorkItems,
  handleAPIScope → handleAPIWorkItem; readScopesForAPI →
  readWorkItemsForAPI.
- Struct renames (with collision resolution): scopeListItem →
  workItemListItem, scopesListResponse → workItemsListResponse,
  scopeRelation → workItemRelation, scopeDetail → workItemDetail.
  The previous `workItemDetail` (per-system-row inner type used by
  /api/systems?id=) renames to `systemWorkItem` to free the better
  name for the detail response.
- JSON wire keys: `"scopes"` → `"workItems"` on statsResponse,
  workItemsListResponse, searchResponse, and systemEntry. Frontend
  TS types follow.

Tests / docs:
- server_test.go: clean-URL fallback expects /work-items and
  /work-item; every fixture/assertion updated to body.WorkItems
  and `"workItems":` wire shape.
- scripts/e2e_test.sh + e2e_test.ps1: curl + assert_contains paths
  and JSON-key substring assertions updated.
- AGENTS.md: frontend hard rules now reference /work-item URL,
  #work-item-body, active="work-items", and {workItems: [...]}.
- frontend/package-lock.json: regenerated with `npm install
  --include=optional` (same pre-existing @emnapi gap PR #40 hit).

Verified locally: go vet + go test clean, npm run check clean,
scripts/e2e_test.sh 624/624 cases pass.

Signed-off-by: Tanzim Saqib <[email protected]>
tsaqib added a commit that referenced this pull request May 29, 2026
* refactor(frontend): rename /scopes route to /work-items

Aligns the web UI with the renamed artifact noun (PR #40 moved the
CLI from `stax plans` to `stax work-items`). The user-visible URLs,
nav rail labels, page identifiers, and the HTTP API the page TS
consumes all migrate together so the naming axis is one consistent
"work item" everywhere.

Frontend:
- Page files: scopes.html → work-items.html, scope.html → work-item.html;
  scopes.ts → work-items.ts, scope.ts → work-item.ts. Layout block-helper
  args (title/page/active) updated to match.
- Nav rail (header.html + mobile-nav.html): "Scopes" → "Work items";
  href /scopes → /work-items; data-active-key follows. Flag icon kept.
- Detail page back-link, list-page empty-state, home-page card +
  Latest section, /search results section, and all DOM ids that
  embedded "scope" (`#scope-icon`, `#scope-title`, `#scope-body`,
  `#scopes-list`, `#latest-scopes`, `tpl-scope`, `tpl-scope-link`)
  renamed to the work-item equivalents.
- Page dispatcher in bundle.ts uses bracketed keys for the
  kebab-cased page names; vite.config.ts pages array follows.
- Internal hrefs `/scope?id=…` → `/work-item?id=…` across home.ts,
  search.ts, system.ts.
- CSS: `.scope-body` → `.work-item-body`.

HTTP API + Go server:
- /api/scopes → /api/work-items, /api/scope → /api/work-item;
  apiScopesPath/apiScopePath constants renamed.
- Handler renames: handleAPIScopes → handleAPIWorkItems,
  handleAPIScope → handleAPIWorkItem; readScopesForAPI →
  readWorkItemsForAPI.
- Struct renames (with collision resolution): scopeListItem →
  workItemListItem, scopesListResponse → workItemsListResponse,
  scopeRelation → workItemRelation, scopeDetail → workItemDetail.
  The previous `workItemDetail` (per-system-row inner type used by
  /api/systems?id=) renames to `systemWorkItem` to free the better
  name for the detail response.
- JSON wire keys: `"scopes"` → `"workItems"` on statsResponse,
  workItemsListResponse, searchResponse, and systemEntry. Frontend
  TS types follow.

Tests / docs:
- server_test.go: clean-URL fallback expects /work-items and
  /work-item; every fixture/assertion updated to body.WorkItems
  and `"workItems":` wire shape.
- scripts/e2e_test.sh + e2e_test.ps1: curl + assert_contains paths
  and JSON-key substring assertions updated.
- AGENTS.md: frontend hard rules now reference /work-item URL,
  #work-item-body, active="work-items", and {workItems: [...]}.
- frontend/package-lock.json: regenerated with `npm install
  --include=optional` (same pre-existing @emnapi gap PR #40 hit).

Verified locally: go vet + go test clean, npm run check clean,
scripts/e2e_test.sh 624/624 cases pass.

Signed-off-by: Tanzim Saqib <[email protected]>

* chore(ci): rename test workflows to E2E test naming

User-driven rename of the test workflow names — the two top-level
workflows (Linux and Windows) now share an E2E test prefix for
visual grouping in the GitHub Actions sidebar.

Signed-off-by: Tanzim Saqib <[email protected]>

---------

Signed-off-by: Tanzim Saqib <[email protected]>
tsaqib added a commit that referenced this pull request May 29, 2026
Commit 8ed25f9 (#40) renamed the artifact concept project-wide but the
text-substitution pass missed three classes of identifiers in
`skills-evals/`, all of which break the pytest run end-to-end:

  1. A list-comprehension f-string `[p.slug for p in plans]` got
     rewritten to `[p.slug for p in work items]` — two tokens with a
     space, so Python aborts at parse time. Twelve test files all
     share this identical pattern (every backend's
     `*_reminders_supersedes_todo.py` and `*_work_item_extends.py`),
     so every workflow that runs pytest hits the same collection-time
     SyntaxError on the first import.
  2. `skills-evals/src/skills_evals/workspace.py` still exports
     `load_all_plans` / `ParsedPlan` / `collect_plan_files` /
     `_parse_plan`. Every test file already imports
     `load_all_work_items` from that module, so once the SyntaxError
     is fixed the next collection error is an `ImportError` of the
     same shape — i.e. all twelve workflows would still fail.
  3. `skills-eval-cline.yml`, `skills-eval-cline-user-scope.yml`,
     `skills-eval-copilot.yml`, and `skills-eval-copilot-user-scope.yml`
     still pass `tests/test_<agent>_plan_extends.py` to pytest, but
     the rename moved that file to `tests/test_<agent>_work_item_extends.py`.
     With pytest's default selector (`--strict-config`) a missing
     path is a hard failure, so all four cline/copilot workflows
     fail before collection even starts.

Single bundled fix because the three layers are coupled — fixing any
one alone still leaves CI red. Verified locally that
`uv run pytest --collect-only` collects 25 tests with zero errors
(20 deselected by the existing agent filter, 5 collected for
`STAX_AGENT_KEY=claude`).

The judges' user-facing label (`name="PlanQuality"` in
`work_item_judge.py`) is intentionally left alone — it appears in
DeepEval output, not the wire, and renaming it would also drift the
historical score series.

Signed-off-by: Tanzim Saqib <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant