Commit Graph

5 Commits

Author SHA1 Message Date
756e36c720 refactor(work): move epic folders into docs/work/epics/
The previous layout placed epic folders directly under docs/work/
alongside prds/ and _system/. Tightening: epics now live in their
own docs/work/epics/ subfolder, peer to prds/ and _system/. Same
shape as the existing prds/ bucket.

Final docs/work/ layout:
  README.md
  prds/<slug>.prd.md
  _system/_state.json
  epics/<slug>/_epic.md + <story-folder>/_story.md

Renames (git mv preserves history):
- docs/work/binder-wrap-helper/
    -> docs/work/epics/binder-wrap-helper/
- docs/work/library-evaluation-policy/
    -> docs/work/epics/library-evaluation-policy/
- docs/work/ci-security-and-supply-chain/
    -> docs/work/epics/ci-security-and-supply-chain/

Tooling updates:
- state-builder.mjs walks workRoot/epics/ directly; SKIP_FOLDERS
  obsoleted (no more sibling folders to filter out).
- dispatch.mjs's findNextTask, tickStoryBulletInEpic, and
  flipEpicDoneIfAllStoriesDone all join with "epics" segment.
- prd-ship.mjs's deriveShippingCommits walks workRoot/epics/ and
  git-logs docs/work/epics/<epic>/.
- decomposer.prompt.md emits epics under docs/work/epics/<epic-id>/.
- handoff + grill-with-docs glossary references updated.
- Glossary entry for Epic updated.

Reserved future shape: when a task-tracker integration (ClickUp,
Linear) ships, the epics/ subfolder hosts <task-id>-<slug>/
folders. Today it just hosts bare slugs.
2026-05-14 21:21:51 +02:00
eadbb7ebd9 fix(work): emit completion signal to stop sandcastle agent loops
Sandcastle re-invokes agents up to maxIterations even when the work is
already done — the decomposer was looping 4x re-writing the same epic
on every dispatch. Two halves to the fix:

- Pass completionSignal: "<promise>COMPLETE</promise>" explicitly on
  all three run() calls (decompose, implementer, reviewer). Makes the
  contract visible alongside maxIterations instead of relying on
  sandcastle's default.
- Append a "Signal completion (required)" section to each prompt
  telling the agent to emit the literal marker as its final line when
  the work is genuinely done, plus a "do NOT emit if..." list to
  discourage premature signaling.
2026-05-13 19:11:44 +02:00
26aa97f0ef fix(work): bump sandcastle maxIterations so agents finish + commit
Sandcastle's default maxIterations: 1 cut every agent off after its
first response, so files written inside the sandbox never made it
into a captured commit. The decomposer wrote 9 epic + story files,
hit the limit, and sandcastle returned 0 commits — the host saw
nothing.

decompose.mjs: maxIterations 10 (small authoring task — read
context, write files, commit). Override via env
SANDCASTLE_DECOMPOSE_ITERATIONS.

dispatch.mjs:
- Implementer: maxIterations 30 (full TDD slice — read context,
  red test, green impl, run all five gates, commit). Override via
  SANDCASTLE_IMPLEMENTER_ITERATIONS.
- Reviewer: maxIterations 10 (read diff + task spec, decide).
  Override via SANDCASTLE_REVIEWER_ITERATIONS.

Each call site documents WHY the value was picked + names the env
override inline so tuning is discoverable from the code.
2026-05-13 18:56:59 +02:00
9d4b801909 fix(work): wire inline macOS keychain hint into dispatch + decompose error paths
The dispatch.mjs + decompose.mjs error handlers grew an image-not-
found hint in cd0a332 but the macOS keychain hint that the earlier
commit's message claimed wasn't actually applied (the Edit tool
required re-reading those files post-commit).

This commit applies the keychain hint to both error handlers: when
the sandcastle error matches /Not logged in|Please run \/login/ AND
process.platform === "darwin", the dispatcher prints the
`security find-generic-password ... > ~/.claude/.credentials.json`
one-liner + chmod 600 + the API-key fallback inline above the
generic "See runbook" line.

Now future agents hitting this on macOS see the fix at the failure
site, not just in docs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 18:03:13 +02:00
014578c9a8 feat(work): pnpm work decompose subcommand
Closes the gap surfaced by the user: `pnpm work` usage referenced
`decompose` (via docs + the to-prd skill) but the subcommand was
never built. Mirrors `pnpm work dispatch`'s shape.

scripts/work/decompose.mjs (new):
  - validatePrdForDecompose(prdPath) — refuses draft (must go
    through human review first), in-review (review incomplete),
    shipped (epic already exists); accepts only approved
  - printDecomposePlan(prdId, prdPath, frontmatter) — print-mode
    output showing the PRD's eligibility + sandcastle invocation
    plan + auth modes
  - executeDecompose(prdId, prdPath, prdText) — invokes sandcastle
    with .sandcastle/decomposer.prompt.md, passing PRD_FILE_CONTENT
    promptArg. The decomposer agent writes the epic + per-story
    files to disk on a sandcastle branch the human can review
  - runCli(args, { workRoot }) — entry point used by cli.mjs
  - Direct invocation also supported (mirrors dispatch.mjs's
    invokedDirectly guard, NEW pattern after this commit)

scripts/work/decompose.test.mjs (new, 9 tests, all green):
  - validatePrdForDecompose: accepts approved; rejects draft,
    in-review, shipped, unknown status, missing file
  - runCli: writes error + returns 1 on missing PRD; writes error
    + returns 1 on draft PRD; prints plan + returns 0 on approved

scripts/work/cli.mjs:
  - Adds `decompose` subcommand to usage + dispatch
  - Usage formatting realigned for the 3-line subcommand block

scripts/work/dispatch.mjs:
  - **Fix** the bug surfaced by the user: dispatch.mjs's CLI ran
    as a top-level side effect whenever any of its exports was
    imported. decompose.mjs imports resolveClaudeAuth from it, so
    importing decompose.mjs printed "No ready task to dispatch."
    Added an `import.meta.url === \`file://${process.argv[1]}\``
    guard so the CLI only runs when invoked directly. This unblocks
    cross-import without side effects.

Smoke-tested end-to-end:
  - `pnpm work decompose` (no id) prints usage + exits 2
  - `pnpm work decompose 2026-05-13-binder-wrap-helper` prints the
    decompose plan with status: approved (eligible)
  - 9/9 unit tests green
  - dispatch.mjs's existing direct-invocation path unchanged

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 17:46:57 +02:00