Skip to content

feat(gate): hew gate primitive + /hew:ship skill fix (hew-y4sf, hew-pi36)#51

Merged
droidnoob merged 1 commit into
mainfrom
feat/hew-gate-and-ship-skill-fix
May 29, 2026
Merged

feat(gate): hew gate primitive + /hew:ship skill fix (hew-y4sf, hew-pi36)#51
droidnoob merged 1 commit into
mainfrom
feat/hew-gate-and-ship-skill-fix

Conversation

@droidnoob
Copy link
Copy Markdown
Owner

hew gate — external-state gates + /hew:ship skill fix

Two follow-ups discovered during PR #49's ship process:

  • hew-pi36 (chore): /hew:ship skill body documents bd create --type=gate --await-type=gh:pr --await-id=N — those flags don't exist in bd v1.0.3 (--type is closed enum bug|feature|task|epic|chore|decision; no --await-*). Skill body rewritten to use the new primitive below.
  • hew-y4sf (feature): Add hew gate for tasks that wait on an external condition. v1 backend: GitHub PR merged.

Usage

hew gate new --gh-pr=49 --title="PR #49 merged"
# → created gate hew-4fp8 — waits on PR #49
#     next: hew dep add <next-epic> hew-4fp8

hew dep add <next-epic> hew-4fp8    # block the next epic until merge
hew gate poll                       # poll all open gates; closes those whose state resolved
hew gate list                       # inspect open gates

Architecture

Pure logic in hew_core::external_gate (10 unit tests):

  • GateKind { GhPr { id } } — tagged enum, kind: "gh:pr" serde tag
  • GateSpec — wraps under metadata.hew_gate so future hew-managed keys don't collide
  • classify_gh_pr_viewMERGED resolves with mergedAt in the reason; OPEN and CLOSED-without-merge stay pending (operator may reopen / re-push); unknown state → Indeterminate so the gate stays open and the operator sees a warning rather than an auto-close on something they didn't intend

CLI in hew/src/commands/gate.rs (11 unit tests):

  • newbd create --type=task --labels=hew-gate --metadata=… --json …, parses .id
  • pollbd show <id> --json (accepts both bd 1.0.3's array-wrapped and bare-object shapes), gh pr view N --json state,mergedAt, classifies, closes via bd close <id> --reason …
  • list → text-mode bd list --label hew-gate --status=open

Smoke

  • Created gate against just-merged PR feat: multi-runtime install (epic hew-3ei) + runtime-kind substrate #49 → poll closed task with reason PR merged at 2026-05-29T09:07:45Z
  • Created gate against bogus PR #9999 → poll surfaced gh pr view 9999 exited Some(1): GraphQL: Could not resolve… as Indeterminate, gate stayed open
  • Empty poll prints no open gate tasks

Quality

  • 924 tests pass (+19 from main): 10 core + 11 CLI
  • cargo clippy --all-targets -- -D warnings clean
  • cargo fmt --check clean
  • .gitignore: **/.hew/loop/ catches loop artifacts from subcrate test runs

Deferred / scaffolded but not in v1

GhIssue, GhRun, Cmd backends — the GateKind enum is extensible; add a variant + match arm in poll_one to wire each. Filed implicitly behind hew-y4sf since the design accommodates them; no new task needed unless a real use case shows up.

🤖 Generated with Claude Code

…l fix

Adds `hew gate new/poll/list` for tasks that wait on an external
condition (currently: a GitHub PR being merged). The skill body for
/hew:ship now points at this primitive instead of the bd flags that
never existed (`--type=gate --await-type=gh:pr --await-id=N`).

Closes hew-y4sf, hew-pi36.

Substrate (`hew_core::external_gate`):
- `GateKind { GhPr { id } }` — extensible enum with `kind: gh:pr` serde tag
- `GateSpec` — typed wrapper, round-trips through bd's `--metadata` blob
  under a top-level `"hew_gate"` key
- `classify_gh_pr_view` — MERGED resolves, OPEN/CLOSED-not-merged stay
  pending, unknown state surfaces as Indeterminate (operator decides)

CLI (`hew gate`):
- `new --gh-pr=N --title=T` creates a bd task with the typed metadata
  + `hew-gate` label, parses the new id out of bd's `--json` output
- `poll [<id>]` reads each open gate's spec, calls `gh pr view N
  --json state,mergedAt`, classifies, closes resolved tasks with a
  reason that carries the mergedAt timestamp
- `list` filters bd's open issues to the `hew-gate` label

Resilience:
- bd 1.0.3's `show --json` wraps the issue in a one-element array;
  parser accepts both array-wrapped and bare-object forms
- bd's `list --json` has varied across versions between top-level
  array and `{"issues":[...]}` envelope; parser accepts both
- Strict on metadata read: missing `hew_gate` key fails loudly rather
  than silently coercing into the wrong shape

Smoke-tested end-to-end:
- Created gate against merged PR #49 → poll closed task with reason
  "PR merged at 2026-05-29T09:07:45Z"
- Created gate against nonexistent PR #9999 → poll surfaced
  `gh pr view 9999 exited Some(1): GraphQL: Could not resolve...`
  as Indeterminate, gate stayed open

Also tightens .gitignore: `**/.hew/loop/` now catches loop artifacts
from tests/smoke runs inside subcrates, not just the workspace root.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@droidnoob droidnoob merged commit d8a3436 into main May 29, 2026
14 checks passed
droidnoob added a commit that referenced this pull request May 29, 2026
Same ghost primitive caught in ship.md (PR #51) and hew-decompose.md
(PR #52): bd's --type enum doesn't include `gate`, and the dedicated
hew gate command now owns external-state gating.

- skills/SKILL.md: "Beads has native types: --type=gate, --type=epic,
  bd mol bond" rewritten. --type=gate is gone; epic/decision are
  surfaced as the real typed surfaces; bd mol bond now correctly
  flagged as broken-don't-use rather than recommended.
- skills/core/hew-plan.md: the hand-off line that mentioned `bd
  create --type=gate` now points at `hew gate new --gh-pr=N` and
  recommends `bd create --graph` for the task batch.

Audit complete across all 22 skill files + 41 command files. No
remaining ghost bd references.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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