|
| 1 | +--- |
| 2 | +name: feature-design |
| 3 | +description: Turn a multi-repo feature (or cross-repo bug fix) into a concrete spec at xtest/features/<name>.yaml plus the tests-side artifacts that have to land first (scenario, draft pytest, feature_type entry in tdfs.py). Pulls Jira context, drafts a complete spec from the ticket, then iterates with the user. Use when a feature touches more than one repo (e.g. platform + Go SDK + Java SDK + JS SDK) and you want to set up the cross-repo work in one go without manually authoring each piece. |
| 4 | +allowed-tools: Bash, Read, Write, Edit, Grep, Glob, Skill |
| 5 | +--- |
| 6 | + |
| 7 | +# feature-design |
| 8 | + |
| 9 | +You turn a fuzzy "let's build X across the OpenTDF repos" into a concrete bundle of artifacts that pin down the tests-side work first and stage the cross-repo work for handoff to `feature-orchestrate`. |
| 10 | + |
| 11 | +Two ideas to internalize before reading the steps: |
| 12 | + |
| 13 | +1. **Tests-side artifacts land first, dormant.** The scenario + draft test + `feature_type` entry merge to `tests/main` as a regular PR. They stay "all skipped" until each SDK opens its own PR adding a `supports <feature>` case to its `cli.sh` source — that PR's CI activates the test for that SDK. This means no cross-PR lockstep coordination; per-repo PRs land async, in any order. |
| 14 | +2. **Propose, don't ask.** Draft a complete spec from the Jira ticket on the first pass and let the user redirect what's wrong in a single revision. Only ask one composite question. If you're missing information you can't fill in (no Jira ticket, ambiguous scope, unclear feature name), bail — don't fabricate. |
| 15 | + |
| 16 | +## Inputs |
| 17 | + |
| 18 | +- Jira key (Story/Task usually; Bug works the same way), OR a free-text description of the feature. |
| 19 | +- (Optional) explicit list of repos to scope to, if the user wants something tighter than the default. |
| 20 | + |
| 21 | +## Steps |
| 22 | + |
| 23 | +### Step 1 — Pull the Jira context |
| 24 | + |
| 25 | +If a Jira key was given, run both — comments often carry scope refinements that aren't in the description: |
| 26 | + |
| 27 | +```bash |
| 28 | +acli jira workitem view <JIRA-KEY> --fields '*all' --json |
| 29 | +acli jira workitem comment list <JIRA-KEY> |
| 30 | +``` |
| 31 | + |
| 32 | +Extract Issue Type, summary, description, status, and any comments about scope or implementation notes. If no Jira key, the user's description IS the spec input. |
| 33 | + |
| 34 | +### Step 2 — Propose a complete draft |
| 35 | + |
| 36 | +Draft the full spec body and the per-repo todo lists inline in your reply. Don't ask the user one field at a time — produce a complete first draft they can react to: |
| 37 | + |
| 38 | +- **Feature flag name** — snake_case identifier derived from the Jira summary. Becomes the `supports("<name>")` gate string AND the `feature_type` entry in `xtest/tdfs.py`. Validate it's a valid Python identifier and doesn't collide with an existing `feature_type` member. |
| 39 | +- **Touched repos** — default set is `tests, platform, sdk-go, sdk-java, sdk-web`. Trim or expand based on what the ticket says. Pure platform features skip the SDK repos; pure SDK-only features skip platform; `tests` is always present (the dormant scenario + tdfs.py entry has to live there). |
| 40 | +- **Per-repo todo lists** — 2-4 bullets per repo, derived from the description plus each repo's known role: |
| 41 | + - `tests` — register the feature in `feature_type`, author the scenario, draft the test gated on `supports("<feature>")`. |
| 42 | + - `platform` — service-side implementation (KAS path, policy plumbing, etc.) and any env-var handling in the dev harness (e.g. honoring `XT_WITH_<FEATURE>`). |
| 43 | + - `sdk-go` / `sdk-java` / `sdk-web` — encrypt/decrypt path implementation, plus a `supports <feature>` case in that SDK's `cli.sh` source. **Don't pin the version bound in the spec** — the implementing engineer sets the `awk` predicate at PR time, since the bound depends on which release will ship the impl. |
| 44 | +- **Branch name** — `<JIRA-KEY>-<feature-slug>`, the same string across every touched repo so `feature-orchestrate` (and the user) can find each repo's PR by branch alone. |
| 45 | + |
| 46 | +Present the draft, then ask exactly one composite question: "Anything to redirect — feature name, touched repos, todo items, branch?" Apply edits in a single revision rather than turn-by-turn. The user can always drop into plain chat if they want to think out loud — just answer them and re-invoke this skill once the design firms up. |
| 47 | + |
| 48 | +If no Jira key was given AND the user's description doesn't pin down a clear scope (feature flag name, touched repos, intended behavior), bail rather than fabricate: |
| 49 | + |
| 50 | +``` |
| 51 | +I need either (a) a Jira Story/Task/Bug key, or (b) a description that names |
| 52 | +the feature flag, the repos it touches, and the intended behavior. Add either |
| 53 | +and re-invoke this skill. |
| 54 | +``` |
| 55 | + |
| 56 | +### Step 3 — Write the spec |
| 57 | + |
| 58 | +Write `xtest/features/<feature-name>.yaml`. Shape (still informal — no Pydantic model yet): |
| 59 | + |
| 60 | +```yaml |
| 61 | +apiVersion: opentdf.io/v1alpha1 |
| 62 | +kind: Feature |
| 63 | +metadata: |
| 64 | + name: <feature-name> # supports() string + feature_type entry, snake_case |
| 65 | + jira: <JIRA-KEY> # omit if no ticket |
| 66 | + title: "<one-line title>" |
| 67 | + created: <YYYY-MM-DD> |
| 68 | +repos: |
| 69 | + tests: |
| 70 | + branch: <JIRA-KEY>-<feature-slug> |
| 71 | + todo: |
| 72 | + - Register "<feature-name>" in xtest/tdfs.py feature_type |
| 73 | + - Author scenario + draft test (via scenario-from-ticket) |
| 74 | + platform: |
| 75 | + branch: <JIRA-KEY>-<feature-slug> |
| 76 | + todo: [ ... ] |
| 77 | + sdk-go: |
| 78 | + branch: <JIRA-KEY>-<feature-slug> |
| 79 | + todo: |
| 80 | + - Implement <feature> in the encrypt/decrypt path |
| 81 | + - Add `supports <feature>` case to cli.sh with version-bound awk predicate |
| 82 | + sdk-java: { branch: ..., todo: [ ... ] } |
| 83 | + sdk-web: { branch: ..., todo: [ ... ] } |
| 84 | +scenarios: |
| 85 | + - xtest/scenarios/<jira-key-lowercased>.yaml |
| 86 | +``` |
| 87 | +
|
| 88 | +PR status (open/merged/CI passing) deliberately is NOT in the spec — it's auto-discovered from `gh pr list --search "head:<branch>"` per repo whenever something asks "where are we?" The spec is a declaration of intent. |
| 89 | + |
| 90 | +### Step 4 — Drive the tests-side artifacts |
| 91 | + |
| 92 | +In this order, so each step's output feeds the next: |
| 93 | + |
| 94 | +1. **Add the feature flag to `xtest/tdfs.py`**. Find the `feature_type` Literal alias near the top of the file. Insert the new entry alphabetically. Don't touch any `cli.sh` files — `supports <feature>` cases land per-SDK in their own PRs. |
| 95 | + |
| 96 | +2. **Invoke `scenario-from-ticket`** via the Skill tool (`skill: scenario-from-ticket`, `args: <JIRA-KEY>`). It runs its Story/Task branch and produces the scenario + draft test gated on `supports("<feature>")` — pinning the feature-introducing components to `main` via `source.ref:`. If no Jira key was given, draft the scenario directly using the same shape (`xtest/scenarios/<feature-name>.yaml`). |
| 97 | + |
| 98 | +3. **Validate the scenario**: |
| 99 | + |
| 100 | + ```bash |
| 101 | + uv run python -m otdf_sdk_mgr.schema validate xtest/scenarios/<jira-key>.yaml |
| 102 | + ``` |
| 103 | + |
| 104 | +### Step 5 — Report |
| 105 | + |
| 106 | +One block summarizing: |
| 107 | + |
| 108 | +- The spec path (`xtest/features/<feature-name>.yaml`). |
| 109 | +- The scenario + draft test paths. |
| 110 | +- The line(s) added to `xtest/tdfs.py`. |
| 111 | +- A one-liner suggesting the next step: `feature-orchestrate xtest/features/<feature-name>.yaml`. |
| 112 | + |
| 113 | +## Notes |
| 114 | + |
| 115 | +- This skill produces **tests-side artifacts only**. It does NOT create branches in other repos, does NOT open PRs, does NOT install platform/SDK builds. That's `feature-orchestrate`'s job. |
| 116 | +- Bugs that span repos use the same shape — pass the Bug ticket key and `scenario-from-ticket`'s Bug branch fills `expected:` / `actual:` from the reproduction prose. The cross-repo gating still works: tests land dormant, each per-repo PR activates them by adding the supports case as part of the fix. |
| 117 | +- For an existing spec being revised, read it first and propose a diff rather than a full rewrite. The tests-side artifacts (scenario, tdfs.py entry) usually shouldn't be regenerated — just edit them surgically. |
| 118 | +- If the user starts the conversation by describing the feature in plain chat rather than invoking this skill, answer normally — re-invoke the skill once the scope firms up. Don't gatekeep. |
0 commit comments