featureparity 0.0.14 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -130,36 +130,75 @@ In JUnit mode:
130
130
 
131
131
  ### fp propose
132
132
 
133
- Propose a new requirement as draft.
133
+ Propose a new requirement as a draft. Before proposing, inventory the full request and compare
134
+ it with both active and draft requirements. The catalog should tell a reviewer what the product
135
+ promises, not preserve the first implementation idea somebody mentioned.
136
+
137
+ Use one focused requirement per independently testable or failable product promise. Use a
138
+ parent plus children for a broad capability with distinct behaviours, policies, or
139
+ surface-specific promises. If the work makes an existing requirement inaccurate, use
140
+ `fp propose-change` as well as adding anything new.
141
+
142
+ Before adding or changing a requirement, compare its acceptance criteria with related active
143
+ and draft requirements and their history. Ask whether both promises can be true for the same
144
+ user, state, and conditions. A failing bound test or an implementation that requires changing
145
+ an existing promise is a contradiction signal: decide which promise reflects product intent,
146
+ then record that decision with `fp propose-change` or `--removal`. Do not weaken the test or add
147
+ a second requirement around the conflict; ask a human when product intent is unclear.
134
148
 
135
149
  ```bash
136
150
  fp propose --project stowzilla \
137
- --slug print_container_qr \
138
- --name "Print QR on container label" \
139
- --why "Staff scan the label to find a container; without a QR they key the ID by hand and mis-type it" \
140
- --required api,customer_android \
141
- --acceptance "QR scans to the container's detail page"
151
+ --slug current_shipment_status \
152
+ --name "Dispatchers see current shipment status" \
153
+ --why "Dispatchers need to spot delayed shipments before they miss a delivery window" \
154
+ --required api,web \
155
+ --acceptance "When a shipment's status changes, the dashboard shows the new status; if status is unavailable, it says so instead of presenting stale data as current" \
156
+ --source-type fizzy \
157
+ --source-url https://app.fizzy.do/123/cards/456
142
158
  ```
143
159
 
144
160
  | Flag | Required | Description |
145
161
  |------|----------|-------------|
146
162
  | `--project` | Yes | Project slug |
147
- | `--slug` | Yes | Requirement slug (immutable, choose carefully) |
148
- | `--name` | Yes | Human-readable name |
149
- | `--why` | No | One plain sentence: the user need or outcome the feature serves (see below) |
163
+ | `--slug` | Yes | Initial requirement key (later corrections use `propose-change`) |
164
+ | `--name` | Yes | Short product promise in present tense |
165
+ | `--why` | No | User need, problem or risk, and valuable outcome |
150
166
  | `--required` | No | Comma-separated surfaces that must implement this |
151
- | `--acceptance` | No | The observable condition that proves it's done |
152
-
153
- **Writing `--why`:** brief, and it actually explains why. Whoever approves this should
154
- grasp in one read the user need or outcome the feature serves. Longer is fine when it
155
- earns its length; wordy is not. Avoid filler, and avoid describing *how* it works
156
- instead of *why* anyone wants it.
157
-
158
- - ✅ `"Staff scan the label to find a container; without a QR they key the ID by hand and mis-type it."`
159
- - ❌ `"Ensures a high-quality experience across all surfaces."` (filler)
160
- - ❌ `"The label renders a QR image encoding the container ID at print time."` (how it works, not why)
161
-
162
- **Agents always create requirements as draft.** A human must activate in the web app.
167
+ | `--acceptance` | No | Observable behaviour and material boundaries |
168
+
169
+ **Write for a decision-maker, not an implementer.** The result should sound natural and be
170
+ ready for management review without someone translating AI boilerplate or reverse-engineering
171
+ the intended outcome. Treat it as the current record of an ongoing conversation, not a finished
172
+ decree from product to engineering. Humans decide value and priority; agents surface gaps,
173
+ inconsistencies, alternatives, and useful splits. Prefer outcomes over feature lists.
174
+
175
+ - **Title:** name the capability or outcome, not the work (`Dispatchers see current shipment
176
+ status`, not `Implement status polling`).
177
+ - **Why:** use one or two natural sentences to say who needs this, the problem or risk, and the
178
+ outcome worth protecting. Do not repeat the title, sell the feature, explain the mechanism,
179
+ or pad it with phrases such as “ensure a seamless, robust experience.”
180
+ - **Acceptance:** state the relevant trigger or situation, the observable result, and material
181
+ boundaries such as permissions, unavailable states, and affected surfaces. Concrete examples
182
+ and tests ground and double-check the rule; they do not define every case or replace the
183
+ general rule and continued conversation.
184
+ - **Numbers and policy:** include prices, quotas, timeouts, counts, dates, roles, and fallbacks
185
+ only when the source made them real product decisions or external constraints. Never invent a
186
+ plausible value to fill silence; ask when the answer changes the promise.
187
+ - **Implementation detail:** omit components, data models, algorithms, endpoints, polling
188
+ intervals, and UI controls unless the interface or constraint is itself part of the promise.
189
+
190
+ Learn from observed user behaviour and other evidence when available: what people attempt,
191
+ where they abandon a task, what they actually use, and what experiments reveal. The first
192
+ proposed solution may point at the need without defining the right scope. Preserve meaningful
193
+ uncertainty as a question instead of laundering a guess into acceptance criteria. Concise does
194
+ not mean vague: keep every sentence that changes the decision and cut everything that only
195
+ sounds thorough.
196
+
197
+ Before saving, ask: Is the value clear? Can the result be observed? Are decided policies
198
+ separated from guesses? Could clauses fail independently and need splitting? Does every sentence
199
+ earn its place?
200
+
201
+ **Agents always create requirements as draft.** A human must activate them in the web app.
163
202
 
164
203
  ### fp propose-change
165
204
 
@@ -191,7 +230,7 @@ fp propose-change print_container_qr --project stowzilla \
191
230
  | `--required` | No | Proposed surfaces (comma-separated; agents cannot remove existing ones) |
192
231
  | `--category` | No | Proposed category |
193
232
  | `--parent` | No | Proposed parent requirement, by slug |
194
- | `--slug` | No | Proposed new slug — **humans only**; breaks existing `fp:<slug>` markers |
233
+ | `--slug` | No | Proposed new key; evidence follows it, but existing `fp:<slug>` markers must be updated |
195
234
  | `--reason` | No | Why the change is needed |
196
235
  | `--source-type` | No | `fizzy`, `discord`, `github_issue`, `jira`, `notion`, `manual`, `ai_chat` |
197
236
  | `--source-url` | No | Link to the card/message/issue that prompted it |
@@ -204,7 +243,7 @@ Refusals, all printed verbatim:
204
243
 
205
244
  | Situation | Status |
206
245
  |-----------|--------|
207
- | Agent tries to change `--slug` | 403 |
246
+ | Proposed key belongs to another requirement | 422 |
208
247
  | Agent tries to remove a required surface | 403 |
209
248
  | Proposed values match the current text | 422 |
210
249
  | Requirement already has a proposal awaiting review | 409 |
@@ -231,6 +270,31 @@ the review decision where one was made. An open proposal is called out at the en
231
270
 
232
271
  `--project` is optional when the repo has a `.featureparity.yml`.
233
272
 
273
+ ### fp changes
274
+
275
+ Show requirement activity prompted by a work item, rather than opening every requirement's
276
+ history separately.
277
+
278
+ ```bash
279
+ fp changes --source-url https://app.fizzy.do/6098707/cards/1434
280
+ fp changes --project stowzilla --source-url https://github.com/acme/app/issues/42
281
+ fp changes --github-pr --github-summary
282
+ ```
283
+
284
+ `--source-url` may be repeated. The API matches the URL exactly against the source recorded
285
+ when a requirement was created, directly edited, proposed for modification, or proposed for
286
+ removal. Results include the requirement, activity kind, review state, actor, and a link to the
287
+ requirement.
288
+
289
+ In a GitHub pull-request workflow, `--github-pr` reads the live PR through the GitHub API and
290
+ writes or replaces one marker-managed requirement table in its description. It requires
291
+ `GITHUB_TOKEN`, `GITHUB_REPOSITORY`, `GITHUB_EVENT_PATH`, and `pull-requests: write`; inability
292
+ to read or update the PR is an error, so a missing table cannot silently pass. Add
293
+ `--github-summary` to keep the same table in `GITHUB_STEP_SUMMARY`. A PR with no linked work
294
+ item says FeatureParity cannot determine the activity; a linked work item with no events
295
+ explicitly says no requirement changes were recorded. Generated `fp init` workflows configure
296
+ both outputs before the parity gate.
297
+
234
298
  ### fp matrix
235
299
 
236
300
  Display the parity matrix. Cells show the state of the evidence filed for each
@@ -334,7 +398,7 @@ fp init --project stowzilla --dir path/to/repo
334
398
  | File | Purpose |
335
399
  |------|---------|
336
400
  | `.featureparity.yml` | declares the project slug, so `--project` becomes optional |
337
- | `.github/workflows/feature-parity.yml` | the CI gate |
401
+ | `.github/workflows/feature-parity.yml` | the CI gate and PR requirement-change summary |
338
402
  | `AGENTS.md` (appended) | instructions telling agents to mark and report their tests |
339
403
 
340
404
  Existing files are skipped unless `--force`. The `AGENTS.md` section is appended between
@@ -26,6 +26,31 @@ Examples:
26
26
 
27
27
  When using `fp report --junit`, each pinned surface produces a separate evidence upload.
28
28
 
29
+ ## Test-type pinning
30
+
31
+ A requirement can demand several *kinds* of test (a unit test and an end-to-end test,
32
+ say). Pin a marker's kind with a `:type` suffix, after the surfaces if any:
33
+
34
+ ```
35
+ fp:<slug>:<type>
36
+ fp:<slug>@<surface>:<type>
37
+ fp:<slug>@<surface1>,<surface2>:<type>
38
+ ```
39
+
40
+ Valid types: `unit`, `integration`, `e2e`, `manual`, `other`.
41
+
42
+ Examples:
43
+ - `fp:print_qr` — unspecified type (and the `--surface` default)
44
+ - `fp:print_qr:unit` — filed as a unit test
45
+ - `fp:print_qr@api:e2e` — the `api` surface, filed as an e2e test
46
+ - `fp:print_qr@api,web:e2e` — both surfaces, each filed as an e2e test
47
+
48
+ A marker that pins no type takes the `--test-type` flag's value (if given), otherwise
49
+ `unspecified`. A requirement declares which kinds it needs with
50
+ `fp propose --required-types unit,e2e`; a surface is covered only once every demanded
51
+ kind has evidence. A requirement naming no types inherits the project default, and when
52
+ neither is set any one test satisfies a surface.
53
+
29
54
  ## Language examples
30
55
 
31
56
  ### Ruby/RSpec
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: featureparity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stowzilla
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-21 00:00:00.000000000 Z
11
+ date: 2026-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-http
@@ -94,10 +94,14 @@ files:
94
94
  - lib/fp/cli.rb
95
95
  - lib/fp/client.rb
96
96
  - lib/fp/commands.rb
97
+ - lib/fp/commands/attach.rb
98
+ - lib/fp/commands/attachments.rb
97
99
  - lib/fp/commands/base.rb
100
+ - lib/fp/commands/changes.rb
98
101
  - lib/fp/commands/check.rb
99
102
  - lib/fp/commands/ci_report.rb
100
103
  - lib/fp/commands/config_cmd.rb
104
+ - lib/fp/commands/conversation.rb
101
105
  - lib/fp/commands/export.rb
102
106
  - lib/fp/commands/help.rb
103
107
  - lib/fp/commands/history.rb