featureparity 0.0.28 → 0.0.29

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.
@@ -210,17 +210,74 @@ fp report --junit junit.xml \
210
210
 
211
211
  | Flag | Required | Description |
212
212
  |------|----------|-------------|
213
- | `--junit` | Yes | Path to JUnit XML report |
213
+ | `--junit` | Yes | Path to a JUnit XML report, or RSpec's own `--format json` report |
214
214
  | `--project` | Yes | Project slug |
215
215
  | `--surface` | Conditional | Default surface for markers without `@suffix`. Required if any matched marker pins no surface. |
216
216
  | `--repo` | Yes | GitHub repo as `org/repo` |
217
217
  | `--base-dir` | No | Where to resolve relative file paths (defaults to cwd) |
218
+ | `--attach-media` | No | Upload the screenshots and videos the run recorded (Playwright's `[[ATTACHMENT|…]]` entries) as visual evidence, one set per bound test, titled with the test's name. Unknown slugs and unsupported or oversized files are skipped with a reason |
218
219
 
219
220
  In JUnit mode:
220
221
  - Slugs come from `fp:<slug>` markers in the test files referenced by the report
221
222
  - A marker binds to the test directly below it
222
223
  - Skipped/pending tests become `stub`; all others `present`
223
224
  - Unknown slugs and unmarked tests are skipped with a warning
225
+ - A JSON report from `rspec --format json --out rspec.json` works as-is (recognised by its
226
+ content, no extra flag), so an RSpec suite needs no `rspec_junit_formatter`. `fp ci-report`
227
+ and `fp check --junit` take it the same way.
228
+
229
+ ### fp run
230
+
231
+ Run a test command with a report formatter fp adds itself, then report the results exactly
232
+ as `fp report --junit` would. Nothing is added to the project under test.
233
+
234
+ ```bash
235
+ fp run --surface api --repo stowzilla/marketplace -- bundle exec rspec
236
+ fp run --surface api --repo stowzilla/marketplace -- pytest tests/
237
+ (cd frontend && fp run --surface web --repo stowzilla/marketplace -- npx vitest run)
238
+ fp run --surface web --repo stowzilla/marketplace -- npx playwright test
239
+ ```
240
+
241
+ | Runner | What fp adds |
242
+ |--------|--------------|
243
+ | rspec | `--format json --out <tmp>`, plus `--format progress` when the command names no formatter |
244
+ | pytest | `-o junit_family=xunit1 --junitxml=<tmp>` (xunit1 carries each test's file and line) |
245
+ | vitest | `--reporter=default --reporter=junit --outputFile.junit=<tmp>` |
246
+ | playwright | `--reporter=list,junit`, with `PLAYWRIGHT_JUNIT_OUTPUT_NAME=<tmp>` |
247
+
248
+ Everything before `--` is an `fp report` flag (`--surface`, `--repo`, `--project`,
249
+ `--test-type`, `--work-item`, `--pr`, `--base-dir`, ...); everything after it is the test
250
+ command, left alone (global flags like `--json` or `-p` there belong to the runner). Agents
251
+ still report `present`/`stub` only. When the tests fail, fp reports first and then exits with
252
+ the test command's status. Any other runner errors with the supported list: make it write
253
+ JUnit XML and use `fp report --junit <file>`.
254
+
255
+ ### fp attach / fp attachments
256
+
257
+ Attach a screenshot, video or file to a requirement as evidence. Visual captures sit under the
258
+ receipt of the test they prove on the requirement page, and the team can copy one into the
259
+ client showroom. This is optional and stores the file in FeatureParity, so an agent uploads
260
+ only with permission from the person it works for, and never captures someone's own screen.
261
+
262
+ ```bash
263
+ fp attach checkout_flow e2e/results/checkout.webm --project stowzilla --surface web \
264
+ --example-title "pays by card" --sha $(git rev-parse HEAD)
265
+ fp attachments checkout_flow --project stowzilla # list
266
+ fp attachments checkout_flow <id> --project stowzilla # download URL
267
+ fp attach rm checkout_flow <id> --project stowzilla # delete
268
+ ```
269
+
270
+ | Flag | Required | Description |
271
+ |------|----------|-------------|
272
+ | `--surface` | For images/videos | Surface the capture is for |
273
+ | `--example-title` | No | Name of the test this capture proves (nests it under that receipt) |
274
+ | `--evidence-key` | No | Bind to a specific receipt (`surface:repo:test_type`) |
275
+ | `--deployment-url` / `--deployed-at` | No | The deployment the capture observed |
276
+ | `--captured-at` / `--sha` / `--test-run-url` | No | When, at which commit, and in which run |
277
+
278
+ Images and video: png, jpg, gif, webp, mp4, webm, mov. Files: txt, md, json, svg, pdf. Up to
279
+ 100 MB each, and several files per call. For a Playwright run, `fp report --junit ... --attach-media`
280
+ does this for every bound test at once (with the same permission). A capture never changes a cell's state.
224
281
 
225
282
  ### fp propose
226
283
 
@@ -265,6 +322,14 @@ fp propose --project stowzilla \
265
322
  | `--why` | No | User need, problem or risk, and valuable outcome |
266
323
  | `--required` | No | Comma-separated surfaces that must implement this |
267
324
  | `--acceptance` | No | Observable behaviour and material boundaries |
325
+ | `--required-types` | No | Comma-separated kinds of test each surface needs |
326
+ | `--parent` | No | Parent requirement's slug (nests one level) |
327
+ | `--category` | No | `functional`, `non-functional`, `ux`, `performance`, `security`, `compliance` |
328
+ | `--tags` | No | Comma-separated labels |
329
+ | `--source-type` / `--source-url` / `--source-context` | No | Where it came from |
330
+ | `--source-ref` | No | A repository place it was read from, e.g. `app/models/order.rb:42`. Repeatable |
331
+ | `--dry-run` | No | Validate and lint the wording, and check the catalog for a taken slug or missing parent. Writes nothing |
332
+ | `--file` | No | YAML or JSON batch (below). Other flags become defaults for every entry |
268
333
 
269
334
  After creating the draft, `fp propose` prints its quality feedback — a verdict, the issues
270
335
  found, and suggestions — in the same run (`analysis` in `--json`). Act on it: revise a weak
@@ -306,6 +371,53 @@ earn its place?
306
371
 
307
372
  **Agents always create requirements as draft.** A human must activate them in the web app.
308
373
 
374
+ #### Checking wording first: `--dry-run`
375
+
376
+ `fp propose ... --dry-run` prints what would be created and a list of wording notes. These
377
+ cover a title that names the work (`Implement…`), commentary openings (`This feature…`,
378
+ `Users should be able to…`), filler (`seamless`, `robust`), a missing why or acceptance, an
379
+ acceptance with no `Example:`, several sentences of rule that may be separate promises, and a
380
+ number in the rule that a source has to have decided. Notes are advice, not errors. A taken
381
+ slug or a missing parent is an error, and it exits 1. Without `--dry-run`, the notes go to
382
+ stderr and the draft is still created.
383
+
384
+ #### A batch: `--file`
385
+
386
+ ```yaml
387
+ defaults: # optional; merged into every entry
388
+ required: [api, web]
389
+ source_type: repo_scan
390
+ requirements:
391
+ - slug: profile_editing
392
+ name: People keep their profile current
393
+ why: ...
394
+ acceptance: "... Example: ..."
395
+ - slug: profile_required_fields
396
+ parent: profile_editing # another entry, or a requirement already in the project
397
+ name: A profile can't be saved without a school
398
+ source_refs: [app/models/academic_experience.rb:12]
399
+ ```
400
+
401
+ Every entry is checked before anything is written: an unknown field (a typo like
402
+ `acceptence`), a bad category or source type, a slug that appears twice or already exists, and
403
+ a parent that isn't found or is itself a child. If any of these fails, nothing is created.
404
+ Parents in the file are created before their children, and the created drafts are printed as
405
+ one table. Run with `--dry-run` first to hand a human the batch for review.
406
+
407
+ ### fp mark
408
+
409
+ ```bash
410
+ fp mark academic_experience_required_fields spec/models/academic_experience_spec.rb:52
411
+ fp mark checkout_flow e2e/checkout.spec.ts:10 --surface web --type e2e
412
+ ```
413
+
414
+ Inserts `fp:<slug>` (with `@surfaces` and `:type` when given) directly above the test on that
415
+ line, using the file's own comment syntax (`#`, `//` or `--`) and indentation, then names the
416
+ test it binds to. Running it again on the same marker changes nothing. `--comment` sets the
417
+ prefix for an extension fp doesn't know, and `--dry-run` shows the line without writing it.
418
+ This is purely local and needs no API key. Never mark a failing test to make a requirement
419
+ look covered.
420
+
309
421
  ### fp propose-change
310
422
 
311
423
  Propose a change to a requirement that already exists — or propose deleting it.
@@ -338,9 +450,10 @@ fp propose-change print_container_qr --project stowzilla \
338
450
  | `--parent` | No | Proposed parent requirement, by slug |
339
451
  | `--slug` | No | Proposed new key; evidence follows it, but existing `fp:<slug>` markers must be updated |
340
452
  | `--reason` | No | Why the change is needed |
341
- | `--source-type` | No | `fizzy`, `discord`, `github_issue`, `jira`, `notion`, `manual`, `ai_chat` |
453
+ | `--source-type` | No | `fizzy`, `discord`, `github_issue`, `jira`, `notion`, `manual`, `ai_chat`, `repo_scan` (an agent derived it from the code) |
342
454
  | `--source-url` | No | Link to the card/message/issue that prompted it |
343
455
  | `--source-context` | No | Free-text context |
456
+ | `--source-ref` | No | A repository place that prompted it, e.g. `app/models/order.rb:42`. Repeatable |
344
457
 
345
458
  At least one proposed value (or `--removal`) is required — a bare invocation would knock a
346
459
  live requirement back to draft for nothing, so it errors instead.
@@ -376,6 +489,33 @@ the review decision where one was made. An open proposal is called out at the en
376
489
 
377
490
  `--project` is optional when the repo has a `.featureparity.yml`.
378
491
 
492
+ ### fp question / fp questions
493
+
494
+ Attach an open question for a human to the requirement it concerns, and read the answers.
495
+ Use it for the decisions a draft can't settle by itself, instead of leaving them in chat.
496
+
497
+ ```bash
498
+ fp question upload_limits "Is the 5 MB cap per file or per upload?"
499
+ fp question upload_limits --body "Does the cap apply to admins?" --project stowzilla
500
+ fp questions upload_limits # every question, open and resolved, with answers
501
+ fp questions upload_limits --open --json # only the open ones
502
+ ```
503
+
504
+ Asking never changes the requirement's status or wording. The human reviewing it sees the
505
+ question in Quick Review and on the requirement page, and answers it (the answer is kept
506
+ with the question) or dismisses it. `fp show <slug>` lists the open questions, and `fp
507
+ history` shows each question and its answer in the timeline. Agents can ask but cannot
508
+ answer or dismiss; there is no CLI command for that.
509
+
510
+ Draft and active requirements take questions, including a draft awaiting review of a
511
+ proposed change. Refusals, printed verbatim:
512
+
513
+ | Situation | Status |
514
+ |-----------|--------|
515
+ | No question text, or more than 2000 characters | 422 |
516
+ | Requirement is archived or rejected | 422 |
517
+
518
+ `--project` is optional when the repo has a `.featureparity.yml`.
379
519
  ### fp comments
380
520
 
381
521
  Read or join the team's conversation on a requirement, and tag people or agents in it.
@@ -579,6 +719,45 @@ A slug suffixed with `✎` has a proposed change awaiting review — it is still
579
719
  the gate, and its evidence is `suspect` until someone reviews the change. `--csv` writes
580
720
  `<slug> (under review)` instead of the glyph.
581
721
 
722
+ `--status draft --gaps` lists *drafts* with a required surface lacking real evidence
723
+ (missing, stubbed, or failing). Plain `--gaps` reads the gate, which never measures a
724
+ never-approved draft, so on a freshly onboarded project it says "No gaps found". See
725
+ `fp coverage` for the full drafts × surfaces table.
726
+
727
+ ### fp coverage
728
+
729
+ Draft coverage: which draft requirements have marked tests or evidence on which surfaces,
730
+ and which have none. The gate measures only active requirements (plus ones an open
731
+ proposal demoted), so on a new project where every requirement is still a draft `fp check`
732
+ says "Nothing to enforce yet". This is how an onboarding agent confirms its work before a
733
+ human activates anything.
734
+
735
+ ```bash
736
+ fp coverage # drafts × surfaces, then the drafts with no evidence
737
+ fp coverage --surface api
738
+ fp coverage --all # also the measured (active / under review) rows
739
+ fp coverage --json # drafts, untested, and with --all, measured
740
+ ```
741
+
742
+ | Flag | Description |
743
+ |------|-------------|
744
+ | `--project` | Project slug (optional if `.featureparity.yml` declares one) |
745
+ | `--surface` | Restrict to one surface |
746
+ | `--all` | Also list the requirements the gate measures |
747
+
748
+ Each cell is resolved from evidence exactly as the matrix will resolve it once the draft is
749
+ active. The command ends with a plain list — the "requirements with no test" section to hand
750
+ the human:
751
+
752
+ ```
753
+ 2 draft(s) with no evidence on a required surface:
754
+ export_csv — no evidence on: web
755
+ bulk_delete — no evidence on: api, web
756
+ ```
757
+
758
+ "No evidence" means `missing`: nothing at all is filed, not even a stub. Drafts are
759
+ reported, never gated — this command exits 0 on a successful read, whatever it shows.
760
+
582
761
  ### fp check
583
762
 
584
763
  The enforcement gate. Exits **1** when the project violates its enforcement level, so it
@@ -601,6 +780,7 @@ fp check --surface api --junit junit.xml # gate on this run's results (preview)
601
780
  | `--junit` | Evaluate this run's JUnit results without saving them (repeatable) |
602
781
  | `--pr [url]` | With `--junit`: this run is a pull request — fail only on parity it makes worse |
603
782
  | `--warn-only` | Report violations but exit 0 |
783
+ | `--include-drafts` | After the verdict, print draft coverage (as `fp coverage`); never changes the exit code. `--json` adds `drafts` |
604
784
 
605
785
  **Enforcement levels** (the level is configured on the project; don't hardcode one):
606
786
 
@@ -689,6 +869,8 @@ Onboard a repo onto FeatureParity. Writes three files and makes no API calls (so
689
869
  before a key is configured).
690
870
 
691
871
  ```bash
872
+ fp init --detect # suggest slug, surfaces, test commands; writes nothing
873
+ fp init --detect --json
692
874
  fp init --project stowzilla --surface api
693
875
  fp init --project stowzilla --no-workflow # skip the CI workflow
694
876
  fp init --project stowzilla --no-agents # skip the AGENTS.md section
@@ -708,7 +890,53 @@ marker comments and recognised on re-run, so it is never duplicated.
708
890
  The `AGENTS.md` section tells agents to bind a test to a requirement with `fp:<slug>`, to
709
891
  propose a new requirement when none covers the work, and to use `fp propose-change`
710
892
  instead of editing or ignoring a requirement that no longer says the right thing — plus
711
- the guards they would otherwise learn from a 403.
893
+ the guards they would otherwise learn from a 403. It opens with the fp version that wrote
894
+ it (`Written by fp X.Y.Z`), has an *Onboarding a repo* first-run path and a
895
+ *Troubleshooting* list, and copies its modeling, writing, onboarding and troubleshooting
896
+ blocks from the skill's `SKILL.md` (between `fp-shared` comments) rather than keeping a
897
+ second copy.
898
+
899
+ `--detect` reads the checkout (Gemfile, package.json, Podfile and Xcode projects, Android
900
+ manifests, pyproject/requirements, Rails routes and `config/database.yml`, docker-compose),
901
+ in the root and one directory down, and prints:
902
+
903
+ - a suggested slug (the git remote's repo name, else the directory name);
904
+ - suggested surfaces with the reason for each, and the rubric to judge them by: a surface is
905
+ somewhere a user interacts with the product, and an internal API with no separate client
906
+ isn't one;
907
+ - each test runner (rspec, minitest, jest, vitest, playwright, pytest, xctest, gradle), the
908
+ command that makes it write a report fp reads, the dependency that needs adding (or none),
909
+ and the `fp run` form where there is one;
910
+ - whether the tests need a database server, and whether there's a `.devcontainer`.
911
+
912
+ A plain `fp init` prints the detected test command and the database note in its closing
913
+ guidance. When the tests need a database server, the generated workflow's report recipe gets
914
+ a TODO and a commented-out service block. Committing the workflow before the `FP_API_KEY`
915
+ secret exists is fine: the gate skips with an explanation and stays green.
916
+
917
+ ### fp doctor
918
+
919
+ Check that fp works here, with no API key and no API calls.
920
+
921
+ ```bash
922
+ fp doctor
923
+ fp doctor --dir path/to/repo
924
+ fp doctor --json
925
+ ```
926
+
927
+ - **Ruby:** the Ruby running fp, the gem's version and path, the `fp` on `PATH` (and whether
928
+ it's a version-manager shim), and whether this directory pins a different Ruby in
929
+ `.ruby-version`, `.tool-versions`, `mise.toml` or `.mise.toml`. On a mismatch it prints
930
+ the fix: install the gem under the pinned Ruby (`mise exec ruby@<pinned> -- gem install
931
+ featureparity`, or `gem install featureparity` in the repo), or put the running Ruby's bin
932
+ directory first on `PATH`.
933
+ - **Config:** the API environment (warning when it isn't production), whether a key is
934
+ present, which `.featureparity.yml` applies, and which fp wrote the `AGENTS.md` section.
935
+ - **Repo:** the same summary as `fp init --detect`.
936
+
937
+ `mise ERROR No version is set for shim: fp` comes from the shim, before fp runs, so doctor
938
+ can't catch it from inside that repo. Run it from somewhere fp works (another directory, or
939
+ with the other Ruby's bin directory on `PATH`) to get the commands.
712
940
 
713
941
  ### fp profile
714
942
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: featureparity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.28
4
+ version: 0.0.29
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stowzilla
@@ -106,18 +106,23 @@ files:
106
106
  - lib/fp/commands/comments.rb
107
107
  - lib/fp/commands/config_cmd.rb
108
108
  - lib/fp/commands/conversation.rb
109
+ - lib/fp/commands/coverage.rb
110
+ - lib/fp/commands/doctor.rb
109
111
  - lib/fp/commands/export.rb
110
112
  - lib/fp/commands/help.rb
111
113
  - lib/fp/commands/history.rb
112
114
  - lib/fp/commands/init.rb
113
115
  - lib/fp/commands/list.rb
116
+ - lib/fp/commands/mark.rb
114
117
  - lib/fp/commands/matrix.rb
115
118
  - lib/fp/commands/profile.rb
116
119
  - lib/fp/commands/projects.rb
117
120
  - lib/fp/commands/propose.rb
118
121
  - lib/fp/commands/propose_change.rb
122
+ - lib/fp/commands/question.rb
119
123
  - lib/fp/commands/report.rb
120
124
  - lib/fp/commands/repos.rb
125
+ - lib/fp/commands/run.rb
121
126
  - lib/fp/commands/setup.rb
122
127
  - lib/fp/commands/show.rb
123
128
  - lib/fp/commands/showroom.rb
@@ -132,6 +137,9 @@ files:
132
137
  - lib/fp/output.rb
133
138
  - lib/fp/parity.rb
134
139
  - lib/fp/project_config.rb
140
+ - lib/fp/repo_detector.rb
141
+ - lib/fp/requirement_lint.rb
142
+ - lib/fp/rspec_json.rb
135
143
  - lib/fp/source_fingerprint.rb
136
144
  - lib/fp/tutorial/hexhaven/AGENTS.md
137
145
  - lib/fp/tutorial/hexhaven/README.md