@rsaglobaltech/specgate 0.24.0 → 0.26.0

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.
Files changed (79) hide show
  1. package/CHANGELOG.md +91 -42
  2. package/dist/packages/core/src/domain/AgentPrompt.js +12 -0
  3. package/dist/packages/core/src/domain/AgentPrompt.js.map +1 -1
  4. package/dist/packages/core/src/domain/Clarification.js +178 -0
  5. package/dist/packages/core/src/domain/Clarification.js.map +1 -0
  6. package/dist/packages/core/src/domain/DraftChecklist.js +16 -16
  7. package/dist/packages/core/src/domain/DraftChecklist.js.map +1 -1
  8. package/dist/packages/core/src/domain/HarnessConfig.js.map +1 -1
  9. package/dist/packages/core/src/domain/HarnessRun.js.map +1 -1
  10. package/dist/packages/core/src/domain/RequirementPlan.js +11 -0
  11. package/dist/packages/core/src/domain/RequirementPlan.js.map +1 -1
  12. package/dist/packages/core/src/infrastructure/ChangeWorkspace.js +15 -3
  13. package/dist/packages/core/src/infrastructure/ChangeWorkspace.js.map +1 -1
  14. package/dist/packages/core/src/infrastructure/HarnessConfigFile.js +5 -0
  15. package/dist/packages/core/src/infrastructure/HarnessConfigFile.js.map +1 -1
  16. package/dist/packages/core/src/infrastructure/IdsAcrossBranches.js +4 -1
  17. package/dist/packages/core/src/infrastructure/IdsAcrossBranches.js.map +1 -1
  18. package/dist/packages/core/test/unit/clarification.test.js +161 -0
  19. package/dist/packages/core/test/unit/clarification.test.js.map +1 -0
  20. package/dist/packages/core/test/unit/rework.test.js +62 -0
  21. package/dist/packages/core/test/unit/rework.test.js.map +1 -0
  22. package/dist/scripts/answer.js +10 -0
  23. package/dist/scripts/answer.js.map +1 -0
  24. package/dist/scripts/ask.js +10 -0
  25. package/dist/scripts/ask.js.map +1 -0
  26. package/dist/scripts/brief_add.js +10 -0
  27. package/dist/scripts/brief_add.js.map +1 -0
  28. package/dist/scripts/cli/commands/change/ChangeCommand.js +124 -1
  29. package/dist/scripts/cli/commands/change/ChangeCommand.js.map +1 -1
  30. package/dist/scripts/cli/commands/harness/RunCommand.js +135 -5
  31. package/dist/scripts/cli/commands/harness/RunCommand.js.map +1 -1
  32. package/dist/scripts/cli/commands/spec/ClarifyCommands.js +275 -0
  33. package/dist/scripts/cli/commands/spec/ClarifyCommands.js.map +1 -0
  34. package/dist/scripts/cli/commands/spec/DraftCommand.js +44 -4
  35. package/dist/scripts/cli/commands/spec/DraftCommand.js.map +1 -1
  36. package/dist/scripts/cli/commands/spec/StatusCommand.js +5 -1
  37. package/dist/scripts/cli/commands/spec/StatusCommand.js.map +1 -1
  38. package/dist/scripts/cli/commands/spec/StudioCommand.js +194 -1
  39. package/dist/scripts/cli/commands/spec/StudioCommand.js.map +1 -1
  40. package/dist/scripts/docs/record-journey.js +1 -0
  41. package/dist/scripts/docs/record-journey.js.map +1 -1
  42. package/dist/scripts/docs/record-terminal.js +18 -0
  43. package/dist/scripts/docs/record-terminal.js.map +1 -1
  44. package/dist/scripts/draft/drafting-guide.js +11 -1
  45. package/dist/scripts/draft/drafting-guide.js.map +1 -1
  46. package/dist/scripts/harness/prompt.js +2 -0
  47. package/dist/scripts/harness/prompt.js.map +1 -1
  48. package/dist/scripts/lib/brief-add.js +197 -0
  49. package/dist/scripts/lib/brief-add.js.map +1 -0
  50. package/dist/scripts/lib/change-impact.js +156 -0
  51. package/dist/scripts/lib/change-impact.js.map +1 -0
  52. package/dist/scripts/lib/change-review.js +145 -0
  53. package/dist/scripts/lib/change-review.js.map +1 -0
  54. package/dist/scripts/lib/clarification.js +319 -0
  55. package/dist/scripts/lib/clarification.js.map +1 -0
  56. package/dist/scripts/lib/harness-guard.js +18 -0
  57. package/dist/scripts/lib/harness-guard.js.map +1 -1
  58. package/dist/scripts/lib/in-flight.js +17 -11
  59. package/dist/scripts/lib/in-flight.js.map +1 -1
  60. package/dist/scripts/lib/live-detail.js +3 -2
  61. package/dist/scripts/lib/live-detail.js.map +1 -1
  62. package/dist/scripts/lib/live-model.js +35 -4
  63. package/dist/scripts/lib/live-model.js.map +1 -1
  64. package/dist/scripts/lib/live-page.js +80 -15
  65. package/dist/scripts/lib/live-page.js.map +1 -1
  66. package/dist/scripts/lib/screen-requirements.js +149 -0
  67. package/dist/scripts/lib/screen-requirements.js.map +1 -0
  68. package/dist/scripts/lib/studio-app-page.js +960 -0
  69. package/dist/scripts/lib/studio-app-page.js.map +1 -0
  70. package/dist/scripts/lib/studio-app.js +362 -0
  71. package/dist/scripts/lib/studio-app.js.map +1 -0
  72. package/dist/scripts/lib/studio-route.js +933 -0
  73. package/dist/scripts/lib/studio-route.js.map +1 -0
  74. package/dist/scripts/lib/surface.js +52 -0
  75. package/dist/scripts/lib/surface.js.map +1 -1
  76. package/dist/scripts/questions.js +10 -0
  77. package/dist/scripts/questions.js.map +1 -0
  78. package/package.json +1 -1
  79. package/templates/harness/harness.config.yaml.tpl +10 -1
package/CHANGELOG.md CHANGED
@@ -9,6 +9,76 @@ The release process is in [`docs/release-process.md`](docs/release-process.md).
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.26.0] — 2026-10-27
13
+
14
+ The studio becomes an app: from an empty folder to the report of what was built, step by step, without the commands. And a clean slate: everything a brief-to-app run left on the list, the test suite green on Windows.
15
+
16
+ ### Added
17
+
18
+ - **The studio is an app you use without the commands** (REQ-204): `specgate studio` opens on a route of seven steps — Project, Brief, Drafts, Questions, Review, Build, Report — each done, current or locked as the project's files say, with one next action (REQ-212). A simple mode hides the commands and an advanced one shows each action's; Spanish and English. Every write is a POST with the page's token; the overview it replaced is at `/overview`.
19
+ - **A project from an empty folder** (REQ-213): four questions — name, web/API/mobile, stack, agent — and the studio runs `specgate init`, writes the harness configuration and the agent's profiles, a brief to fill and a first commit. A folder with files is left alone, with the command that adopts it.
20
+ - **The brief as a form** (REQ-214): product, who uses it, and per module its rules, examples and open questions, saved into `docs/brief.md` keeping every other line; markdown in advanced mode; the brief rules come back with each save. A client's text can be pasted for the agent to structure (REQ-215).
21
+ - **Drafting each module from the studio** (REQ-216): in the background, one at a time, with its progress and the checklist in plain words, and a way to stop it.
22
+ - **Review and approve a draft** (REQ-206, REQ-207): `specgate change approve <id>` records that a person approved it, refused while the checklist has errors or a question is open; `specgate change note <id> "<text>" --req REQ-x` asks for a change in your words. Review in the studio does both.
23
+ - **Build from the studio** (REQ-208, REQ-209): what is ready, an estimate, the harness started in the background, its steps in plain words, and a stop that takes effect after the requirement in progress. Answering a question releases the requirements it held (REQ-210).
24
+ - **The agent chosen per run** (REQ-211): `harness run --profile <name>` and `propose --from-brief --profile <name>` run that profile of `.harness/profiles.yaml`; the studio lists the profiles with their cost hint and whether they stream usage.
25
+ - **The report** (REQ-217): what was built of the total, each requirement with the scenario that proves it, what is missing and why, the decisions taken, cost and time; downloadable as one HTML page.
26
+ - **Answer a question from the live view** (REQ-201): under each question the agent asked, Needs attention has a form to answer it and then mark it reviewed. The write, `POST /live/answer`, goes through the same code as `specgate answer` and needs the token its own page carries, a JSON body and a loopback origin; any other method than GET or HEAD gets 405.
27
+ - **Every open question in the live view** (REQ-203): an Open questions section lists what `specgate questions` lists, each with the same form, so drafts' questions are answered from studio too; a question the agent asked shows as waiting for an answer, not as a failure.
28
+ - **A requirement used on a screen needs an end-to-end test** (REQ-199): with `e2e_dir` in `harness.config.yaml`, a requirement whose actor uses web, mobile, tablet or desktop passes the gate only once a file there names it, and its prompt says so.
29
+ - **A requirement an open change modifies is reworked** (REQ-198): the harness gives it `NEEDS_REWORK` instead of `NEEDS_STATUS_UPDATE`, and its prompt says the tests and code are for the old text.
30
+
31
+ ### Changed
32
+
33
+ - **The harness template shows the streaming agent** (REQ-200): the Claude Code command that feeds studio's live view, and `e2e_dir`.
34
+ - **Opening a module says which drafts stop growing** (REQ-197).
35
+ - **Status names the module** of the next use case (REQ-193), and **DRAFTING.md gives the draft's real limit** with how to grow it (REQ-194).
36
+
37
+ ### Fixed
38
+
39
+ - **The dry run names the agent only when one is set**, so `harness prompt` prints no `Agent none`.
40
+ - **The Cucumber gate on Windows** (REQ-196): the message stream went to a path Cucumber did not write, so a filter matching nothing passed. The four tests that failed only on Windows pass, tests remove their temp folders, and `docs:terminal` / `docs:journey` say they need a POSIX shell.
41
+ - **Ids reserved from a mention** (REQ-202): "GIVEN REQ-999 is defined nowhere" in a scenario made the next change start at REQ-1000; only headings, matrix rows and `req_range` count now.
42
+ - **No inline code split across changelog lines** (REQ-195), checked by a test.
43
+
44
+ ## [0.25.0] — 2026-10-27
45
+
46
+ Questions you answer with a command, and a specification that evolves without copying by hand: what taking a brief to a delivered app asked for.
47
+
48
+ ### Added
49
+
50
+ - **Everything waiting for an answer, in one list** (REQ-187):
51
+ `specgate questions` lists the open questions of every open change and of
52
+ `docs/specs/questions.md`, with what each blocks, and the requirements in
53
+ Needs Clarification that no question names.
54
+ - **Answering writes the answer and what it decides** (REQ-188):
55
+ `specgate answer Q6 "…"` fills the question's row, adds an assumption to
56
+ review and names the requirements to revise. The draft checklist (D13)
57
+ waits until `specgate answer Q6 --reviewed` says the spec reflects it; an
58
+ answer that decides nothing, such as "TBD", is refused.
59
+ - **The agent can ask instead of guessing** (REQ-189):
60
+ `specgate ask REQ-049 "…"` records the question where the requirement is
61
+ defined and sets it Needs Clarification. Inside the harness the attempt
62
+ ends as a question, no retry is spent, the harness commits the question,
63
+ and the live view shows it under Needs attention with the command that
64
+ answers it. The harness prompt tells the agent so.
65
+ - **Modifying a delivered requirement starts from its text** (REQ-190):
66
+ `specgate change new <id> --modify REQ-017` copies the requirement into a
67
+ MODIFIED delta, reopened as Draft.
68
+ - **What a change to a requirement touches** (REQ-191):
69
+ `specgate change impact <REQ|change>` lists its spec file and line,
70
+ features, tests, the files its commits changed and the requirements that
71
+ name it.
72
+ - **A new requirement for a module the brief covers** (REQ-192):
73
+ `specgate brief add <module> "…"` appends the line to the brief and adds a
74
+ requirement quoting it to the module's open change, or creates
75
+ `<module>-additions`, even when the module is archived.
76
+
77
+ ### Fixed
78
+
79
+ - **The live matrix reads a quoted status whole**: `status="Needs Clarification"`
80
+ was read as `Needs`.
81
+
12
82
  ## [0.24.0] — 2026-10-26
13
83
 
14
84
  A live view you can work from, and a harness that survives a night: what a twenty-requirement chain in a Next.js app ran into.
@@ -75,8 +145,7 @@ What a first project from a brief tripped over, from statuses to the harness's f
75
145
 
76
146
  ### Fixed
77
147
 
78
- - **Approved owes a test, as the strict gate says** (REQ-173): `apply
79
- --status Approved` wrote Approved on a requirement no test named, and the
148
+ - **Approved owes a test, as the strict gate says** (REQ-173): `apply --status Approved` wrote Approved on a requirement no test named, and the
80
149
  next `validate --strict` failed TDD-1 for the whole project, so every
81
150
  `harness run` went red whatever requirement it worked on. `apply` and `done`
82
151
  now refuse it with the TDD-1 reason and the fix, as they already did for
@@ -222,8 +291,7 @@ ticket to Done, the board moved by its own automation.
222
291
 
223
292
  ### Changed
224
293
 
225
- - **A draft is not opened over a broken brief.** `propose --from-brief
226
- <module>` refuses with `brief_not_ready` while the brief has an error: an
294
+ - **A draft is not opened over a broken brief.** `propose --from-brief <module>` refuses with `brief_not_ready` while the brief has an error: an
227
295
  empty body, an empty module section, a module without its section once the
228
296
  brief uses sections, or rules without examples. A brief with no module
229
297
  sections — a pasted email — drafts as before.
@@ -408,8 +476,7 @@ while it works (ADR-0037).
408
476
  first. forja is fetched with `npx` only when chosen, so Specgate keeps zero
409
477
  runtime dependencies; `SPECGATE_FORJA_CMD` points at another forja.
410
478
  - **`specgate add usecase|entity|port`** in a forja project: the class where the
411
- architecture expects it, its test and its wiring, through `forja add`; `add
412
- usecase` also creates the requirement and names it in the test. Outside a forja
479
+ architecture expects it, its test and its wiring, through `forja add`; `add usecase` also creates the requirement and names it in the test. Outside a forja
413
480
  project it says to use `new`. In a forja project, `status` suggests it as the
414
481
  next step for a requirement with no code.
415
482
  - **`arch_cmd`: your architecture check in the gate** ([ADR-0028](docs/specs/adr/0028-architecture-conformance-is-part-of-the-gate.md), points 1–2).
@@ -799,8 +866,7 @@ From a second and third cycle on the same product (reservas_app), on 0.17.1.
799
866
  archiving names the scenarios it lacks (`archive_feature_stale`).
800
867
  - **`plan` and `status` agree with `validate` about untested scenarios.** A
801
868
  requirement with two scenarios no test named was "Ready to close — its test
802
- is in place", and `NEEDS_STATUS_UPDATE` to the harness, while `validate
803
- --strict` said "Nothing proves" them. It is now `NEEDS_TEST`.
869
+ is in place", and `NEEDS_STATUS_UPDATE` to the harness, while `validate --strict` said "Nothing proves" them. It is now `NEEDS_TEST`.
804
870
  - **`draft --check`:** a requirement can say it lives on one surface
805
871
  (`surfaces=web` in its trace), so a menu is not asked for an API scenario
806
872
  (D3); a value already in the project's specification — reviewed in an
@@ -825,8 +891,7 @@ From a second and third cycle on the same product (reservas_app), on 0.17.1.
825
891
  Found building a second real product from a client brief (reservas_app,
826
892
  written in Spanish).
827
893
 
828
- - **A draft archives into feature files, in its own language.** `change
829
- archive` wrote no `.feature` for a requirement whose trace named none — a
894
+ - **A draft archives into feature files, in its own language.** `change archive` wrote no `.feature` for a requirement whose trace named none — a
830
895
  draft that passed `draft --check` archived with "0 materialised". Each
831
896
  requirement with scenarios now gets `features/<capability>/<REQ>.feature`.
832
897
  Scenarios written with `DADO / CUANDO / ENTONCES` become Spanish Gherkin
@@ -849,8 +914,7 @@ archive` wrote no `.feature` for a requirement whose trace named none — a
849
914
  without saying which, or how. The warning now names the detected command and
850
915
  the one line that turns it on (`specgate harness init`). The first gate after
851
916
  adoption still checks the specification only, as documented.
852
- - **`draft --check`:** an answered question (an `Answer` column, or `Answer
853
- (Q1): …` below the table) no longer keeps its requirement waiting; a value
917
+ - **`draft --check`:** an answered question (an `Answer` column, or `Answer (Q1): …` below the table) no longer keeps its requirement waiting; a value
854
918
  repeated in a scenario is one finding, not one per mention; "responsive" is
855
919
  not read as a promised response time, and `px` is a unit.
856
920
  - **`status` shows the title of a requirement archived from a change** instead
@@ -941,8 +1005,7 @@ archive` wrote no `.feature` for a requirement whose trace named none — a
941
1005
  (`openspec:<capability>/<requirement>/<scenario>`), while the suite is red
942
1006
  (`--run`), or after a scenario's text changed since `--record` pinned it.
943
1007
  `--since <ref>` gates only claims made after the ref, so adopting it never
944
- fails a project for its past. `--ids` prints the ids to name; `--format
945
- github` annotates the spec lines; `actions/verify` runs it on pull requests.
1008
+ fails a project for its past. `--ids` prints the ids to name; `--format github` annotates the spec lines; `actions/verify` runs it on pull requests.
946
1009
  Read against OpenSpec's own repository: 747 scenarios, 108 claims, including
947
1010
  its archived history from before the structured format.
948
1011
 
@@ -1031,8 +1094,7 @@ Found adopting the Golden State Reinforcing app with six domain packs on the
1031
1094
  published 0.14.1:
1032
1095
 
1033
1096
  - **A pack keeps a generated matrix generated.** Installing a pack wrote
1034
- matrix rows and turned the project back into a hand-kept matrix; `matrix
1035
- --migrate` then wrote 47 placeholder sections into `spec.md` titled after
1097
+ matrix rows and turned the project back into a hand-kept matrix; `matrix --migrate` then wrote 47 placeholder sections into `spec.md` titled after
1036
1098
  use cases. Now each requirement's use case, command, aggregate, event and
1037
1099
  context go into the `csda:trace` of its section — the pack's capability
1038
1100
  spec, or a new `spec.md` section carrying the pack's own description — and
@@ -1046,8 +1108,7 @@ published 0.14.1:
1046
1108
  - **The harness runs each requirement once.** It processed one plan row per
1047
1109
  scenario: a requirement with two scenarios ran two paid agent sessions on
1048
1110
  the same branch.
1049
- - **`setup_cmd`** prepares each fresh worktree before the agent (`harness
1050
- init` proposes `npm ci` / `pnpm install` / `yarn install` from the
1111
+ - **`setup_cmd`** prepares each fresh worktree before the agent (`harness init` proposes `npm ci` / `pnpm install` / `yarn install` from the
1051
1112
  lockfile), so the agent can run the tests it writes and `check` no longer
1052
1113
  needs `npm ci` in `test_cmd`. The generated prompt prefix teaches linking by
1053
1114
  mention instead of "the test named in the matrix".
@@ -1244,8 +1305,7 @@ Found by following the documentation step by step on the published 0.13.0:
1244
1305
  `fix`, `plan`, `report`, `req list/done/rm`, `config`, `schema`,
1245
1306
  `completion`, `studio`, `onboard` — take it from 14 to 34 of 60 commands, and
1246
1307
  offline journeys for packs — `specops add/diff/sync/remove` against a local
1247
- git remote with tags, `pack bundle` for an air-gapped install, `pack
1248
- init/lint/infer`, `expand` — to 43, and the change cycle (`new` → `archive`
1308
+ git remote with tags, `pack bundle` for an air-gapped install, `pack init/lint/infer`, `expand` — to 43, and the change cycle (`new` → `archive`
1249
1309
  → delivered with `done`), `change author` reverting an agent's write outside
1250
1310
  the change, `harness init/prompt/run/report` and `specops contribute` to 55.
1251
1311
 
@@ -1547,8 +1607,7 @@ Agent files generated by earlier versions are named `csda`; run
1547
1607
  - **`git worktree add` raced itself under `--concurrency`.** Each requirement
1548
1608
  runs in its own process and every one creates a worktree in the same
1549
1609
  repository; git writes `.git/worktrees/<name>/` incrementally, so a sibling
1550
- read an entry that was half there and failed with `failed to read …
1551
- /commondir`. Worse, the failure was _attributed_: the run reported the
1610
+ read an entry that was half there and failed with `failed to read … /commondir`. Worse, the failure was _attributed_: the run reported the
1552
1611
  requirement as failed with "the agent produced no files", so a race in the
1553
1612
  harness read as the agent's fault.
1554
1613
 
@@ -1642,8 +1701,7 @@ the one that finishes the rename past the layer where it had stopped.
1642
1701
  `ghcr.io/<owner>/specgate`. Images already published as `csda` are never
1643
1702
  rebuilt in place and keep working.
1644
1703
 
1645
- `docs/release-process.md` gains the one-time cutover: the exact `npm
1646
- deprecate` invocation for `create-spec-driven-app`, why the old package is
1704
+ `docs/release-process.md` gains the one-time cutover: the exact `npm deprecate` invocation for `create-spec-driven-app`, why the old package is
1647
1705
  deprecated and never unpublished (npm blocks reusing an unpublished name, and
1648
1706
  a pinned dependency would break for no gain), and the sequencing constraint —
1649
1707
  the rename and the release that publishes `specgate` are one event, because
@@ -1690,8 +1748,7 @@ deliberately _not_ built, is [ADR-0023](docs/specs/adr/0023-checking-content-gat
1690
1748
  a response clause reliably, and a check claiming a grammar it cannot parse is
1691
1749
  the H13 mistake. These two rules are what a regex can assert honestly.
1692
1750
 
1693
- The point is upstream of any code checking: `- Max 5 failed attempts per hour
1694
- per user` is not something a machine can hold code to. RFC 2119 detection also
1751
+ The point is upstream of any code checking: `- Max 5 failed attempts per hour per user` is not something a machine can hold code to. RFC 2119 detection also
1695
1752
  stops being duplicated — `DeltaSpec` enforced it for requirements inside a
1696
1753
  change while a capability spec at rest was never checked; both now read one
1697
1754
  definition.
@@ -1727,8 +1784,7 @@ per user` is not something a machine can hold code to. RFC 2119 detection also
1727
1784
  different values here, on purpose.
1728
1785
 
1729
1786
  - **`csda change new <id> --from-value-drift <REQ-ID>:<value_id>`** turns a
1730
- diverging value into a reviewable change. It writes a `## MODIFIED
1731
- Requirements` delta carrying the full requirement, with the structured
1787
+ diverging value into a reviewable change. It writes a `## MODIFIED Requirements` delta carrying the full requirement, with the structured
1732
1788
  `value_<id>` rewritten to the value the code declares.
1733
1789
 
1734
1790
  **The prose is left alone.** Turning "expires after 15 minutes" into "after
@@ -1832,8 +1888,7 @@ Requirements` delta carrying the full requirement, with the structured
1832
1888
 
1833
1889
  - **`specgate adopt` did not run at all.** `templates/adopt/spec.md.tpl` asks
1834
1890
  for `{{PROPOSED_REQUIREMENTS}}` and nothing supplied it, so the brownfield
1835
- entry point died on `Missing variable 'PROPOSED_REQUIREMENTS' required by
1836
- template` for every repository.
1891
+ entry point died on `Missing variable 'PROPOSED_REQUIREMENTS' required by template` for every repository.
1837
1892
 
1838
1893
  Two parallel branches caused it. P6 taught `adopt` to seed one requirement per
1839
1894
  capability `onboard` reads off the layout, and added `--monorepo` and
@@ -1933,8 +1988,7 @@ H16, all four measured before anything was written and reproduced after.
1933
1988
  is the gradual path for a repository brought in with `csda adopt`.
1934
1989
 
1935
1990
  - **`csda harness run --skip-not-ready`** skips a requirement an agent could not
1936
- succeed at — no feature file, unmet dependencies, `Deprecated`, or `Needs
1937
- Clarification`. `csda plan --format json` now carries `ready` and `blockers[]`
1991
+ succeed at — no feature file, unmet dependencies, `Deprecated`, or `Needs Clarification`. `csda plan --format json` now carries `ready` and `blockers[]`
1938
1992
  per requirement, each blocker with a fix. Default is to warn and run it
1939
1993
  anyway; an unrunnable scenario skips regardless, because an empty scenario
1940
1994
  passes and a green run over one proves nothing.
@@ -1966,8 +2020,7 @@ Clarification`. `csda plan --format json` now carries `ready` and `blockers[]`
1966
2020
  or let the harness add the flag to a direct `cucumber-js` invocation.
1967
2021
 
1968
2022
  - **`csda harness report`** gains where attempts end, which requirements spend
1969
- every attempt, a series over time, and `--mark-false-failure REQ-NNN --reason
1970
- "…"`. The real-failure rate reads `—` until somebody marks one: nothing
2023
+ every attempt, a series over time, and `--mark-false-failure REQ-NNN --reason "…"`. The real-failure rate reads `—` until somebody marks one: nothing
1971
2024
  recorded can tell a gate that was wrong from work that was.
1972
2025
 
1973
2026
  - **`depends_on`** on a pack's requirements. The harness cuts a dependent's
@@ -2016,8 +2069,7 @@ Clarification`. `csda plan --format json` now carries `ready` and `blockers[]`
2016
2069
  installer's did not.
2017
2070
 
2018
2071
  - **`parseYamlLite` split inline sequences on every comma**, including the ones
2019
- inside quotes, so `responsibilities: ["Invoice line items, totals, status,
2020
- aging"]` parsed as four items carrying stray quote characters.
2072
+ inside quotes, so `responsibilities: ["Invoice line items, totals, status, aging"]` parsed as four items carrying stray quote characters.
2021
2073
 
2022
2074
  ### Security
2023
2075
 
@@ -2073,8 +2125,7 @@ date.
2073
2125
  28 scenarios under `packs/**` wrote their keywords in upper case —
2074
2126
  `GIVEN` / `WHEN` / `THEN` — and Gherkin keywords are case-sensitive. Cucumber
2075
2127
  read those lines as the scenario's _description_, so the scenario existed with
2076
- **zero steps**, and an empty scenario passes: `1 scenario (1 passed) · 0 steps
2077
- · exit 0`.
2128
+ **zero steps**, and an empty scenario passes: `1 scenario (1 passed) · 0 steps · exit 0`.
2078
2129
 
2079
2130
  Every project seeded with `csda specops add` therefore inherited an acceptance
2080
2131
  criterion that approves anything, and a harness run over those requirements
@@ -2103,8 +2154,7 @@ date.
2103
2154
  full agent run with `--keep-worktrees`, fifteen minutes to recover what the
2104
2155
  first run already had.
2105
2156
 
2106
- The attempt is now committed on the branch with a `wip(REQ-NNN): FAILED the
2107
- gate — do not merge as is` subject. The requirement stays `Draft`, because
2157
+ The attempt is now committed on the branch with a `wip(REQ-NNN): FAILED the gate — do not merge as is` subject. The requirement stays `Draft`, because
2108
2158
  `csda done` never ran, so nothing about the matrix claims the work is good. A
2109
2159
  human reads it and decides; git just stops throwing it away. The report says
2110
2160
  whether the work was preserved, and distinguishes that from an agent that
@@ -2500,8 +2550,7 @@ and brownfield onboarding have all landed since.
2500
2550
 
2501
2551
  ### Added
2502
2552
 
2503
- - **Change lifecycle** — `csda change new | list | show | status | validate |
2504
- archive`. Modify a spec that already shipped through a reviewable delta.
2553
+ - **Change lifecycle** — `csda change new | list | show | status | validate | archive`. Modify a spec that already shipped through a reviewable delta.
2505
2554
  Archiving merges it into the spec tree, writes the traceability rows and
2506
2555
  materialises the feature files.
2507
2556
  - **`csda change instructions <artifact>`** — the single context engine.
@@ -24,7 +24,19 @@ class AgentPrompt {
24
24
  `- Test artifact (write this first — TDD): ${field("testArtifact", "test_artifact") || "(none declared)"}`,
25
25
  `- Production artifact: ${field("technicalArtifact", "technical_artifact") || "(none declared)"}`,
26
26
  `- Current status: ${req.status || "(none)"}`,
27
+ ...(opts.e2eDir
28
+ ? [
29
+ `- Screen requirement: its actor uses a screen, so the gate also needs an end-to-end test under \`${opts.e2eDir}\` whose name or content says ${req.requirement} — a use case and a unit test alone do not pass.`,
30
+ ]
31
+ : []),
27
32
  ].join("\n");
33
+ // REQ-198: a modified requirement already has a test and code, for its old text.
34
+ if (req.category === "NEEDS_REWORK") {
35
+ parts.push(AgentPrompt.section("This requirement changed", "An open change modified this requirement: its tests and code exist, but for the old text. " +
36
+ "Bring the tests to the requirement and scenarios below first — they must fail against the " +
37
+ "current behaviour — then change the code until they pass. Do not leave a test that only " +
38
+ "checks the old behaviour."));
39
+ }
28
40
  // Before the facts, because it is the thing being implemented and the facts
29
41
  // are only pointers to where it goes.
30
42
  if (opts.requirementText && String(opts.requirementText).trim()) {
@@ -1 +1 @@
1
- {"version":3,"file":"AgentPrompt.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/AgentPrompt.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AgentPrompt.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/AgentPrompt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ /**
3
+ * Questions and their answers as rows of `questions.md` and `assumptions.md`
4
+ * (REQ-187..189). The tables keep the format people already write by hand;
5
+ * these functions read and write one row at a time, so `answer` and `ask` do
6
+ * what an author did by editing cells.
7
+ *
8
+ * Pure: text in, text out. The commands do the reading and writing.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.deferredAnswer = deferredAnswer;
12
+ exports.questionTable = questionTable;
13
+ exports.answerQuestion = answerQuestion;
14
+ exports.addQuestion = addQuestion;
15
+ exports.addAssumption = addAssumption;
16
+ exports.assumptionsToReview = assumptionsToReview;
17
+ exports.reviewAssumptions = reviewAssumptions;
18
+ /**
19
+ * An answer that puts the decision off is not an answer. "Se decidirá con el
20
+ * cliente antes de implementarlo" filled the Answer cell, D7 took the question
21
+ * as answered and its requirement stopped waiting, though nobody had decided
22
+ * anything (HealthTech, #82). A proposal ("propuesta, a validar") is an answer;
23
+ * "pending", "TBD" or "will be decided" is not.
24
+ */
25
+ const DEFERRED = /(?<![\p{L}])(se decidir[aá]n?|por decidir|a decidir|sin decidir|pendiente de (?:decidir|decisi[oó]n|respuesta|confirmar)|to be decided|will be decided|decide later|tbd)(?![\p{L}])/iu;
26
+ const DEFERRED_ALONE = /^(pendiente|pending|later|tbd|todo|\?+|-+)\.?$/i;
27
+ function deferredAnswer(answer) {
28
+ const text = answer.replace(/\*\*/g, "").trim();
29
+ return DEFERRED.test(text) || DEFERRED_ALONE.test(text);
30
+ }
31
+ const QUESTION_HEADER = "| # | Question | Blocks | Options seen | Answer | Status |";
32
+ const ASSUMPTION_HEADER = "| # | Assumption | Used in | Why | Status |";
33
+ const TO_REVIEW = "to review";
34
+ /** A cell's value as written into a Markdown table: one line, its pipes escaped. */
35
+ function cell(text) {
36
+ return String(text).replace(/\s+/g, " ").trim().replace(/\|/g, "\\|");
37
+ }
38
+ /** The cells of a table line, split on pipes that are not escaped. */
39
+ function cells(line) {
40
+ return line
41
+ .split(/(?<!\\)\|/)
42
+ .slice(1, -1)
43
+ .map((c) => c.trim());
44
+ }
45
+ function table(md, must) {
46
+ const lines = md.replace(/\r\n/g, "\n").split("\n");
47
+ const header = lines.findIndex((l) => /^\|/.test(l) && must.test(l));
48
+ if (header === -1)
49
+ return null;
50
+ const cols = cells(lines[header]).map((c) => c.toLowerCase());
51
+ const rows = [];
52
+ for (let i = header + 2; i < lines.length && /^\|/.test(lines[i]); i += 1)
53
+ rows.push(i);
54
+ return { lines, header, cols, rows };
55
+ }
56
+ function col(t, ...names) {
57
+ return t.cols.findIndex((c) => names.includes(c));
58
+ }
59
+ /** The rows of a `questions.md` table: id, text, what each blocks, and whether it is answered. */
60
+ function questionTable(md) {
61
+ const t = table(md, /\bBlocks\b/i);
62
+ if (!t)
63
+ return [];
64
+ const textAt = col(t, "question", "pregunta");
65
+ const blocksAt = col(t, "blocks");
66
+ const answerAt = col(t, "answer", "respuesta");
67
+ const optionsAt = col(t, "options seen", "options", "opciones");
68
+ return t.rows.map((i) => {
69
+ const c = cells(t.lines[i]);
70
+ const answer = answerAt >= 0 ? c[answerAt] || "" : "";
71
+ return {
72
+ id: c[0] || "",
73
+ text: textAt >= 0 ? c[textAt] || "" : "",
74
+ blocks: (blocksAt >= 0 ? c[blocksAt] || "" : "").match(/REQ-[A-Za-z0-9.]+/g) || [],
75
+ answered: answer.length > 0 && !deferredAnswer(answer),
76
+ line: i + 1,
77
+ options: (optionsAt >= 0 ? c[optionsAt] || "" : "")
78
+ .split(/\s*[;·]\s*/)
79
+ .map((o) => o.trim())
80
+ .filter(Boolean),
81
+ };
82
+ });
83
+ }
84
+ /** `questions.md` with the answer in the row's Answer cell and its Status set to answered. */
85
+ function answerQuestion(md, id, answer) {
86
+ if (deferredAnswer(answer))
87
+ return { ok: false, code: "answer_deferred" };
88
+ const t = table(md, /\bBlocks\b/i);
89
+ const at = t ? t.rows.find((i) => cells(t.lines[i])[0] === id) : undefined;
90
+ if (!t || at === undefined)
91
+ return { ok: false, code: "question_not_found" };
92
+ const c = cells(t.lines[at]);
93
+ while (c.length < t.cols.length)
94
+ c.push("");
95
+ const answerAt = col(t, "answer", "respuesta");
96
+ const statusAt = col(t, "status", "estado");
97
+ if (answerAt >= 0)
98
+ c[answerAt] = cell(answer);
99
+ if (statusAt >= 0)
100
+ c[statusAt] = "answered";
101
+ t.lines[at] = `| ${c.join(" | ")} |`;
102
+ const blocksAt = col(t, "blocks");
103
+ return {
104
+ ok: true,
105
+ md: t.lines.join("\n"),
106
+ blocks: (blocksAt >= 0 ? c[blocksAt] : "").match(/REQ-[A-Za-z0-9.]+/g) || [],
107
+ };
108
+ }
109
+ function nextId(ids, prefix) {
110
+ const n = ids
111
+ .map((id) => Number((new RegExp(`^${prefix}(\\d+)$`).exec(id) || [])[1]))
112
+ .filter((x) => Number.isFinite(x));
113
+ return `${prefix}${(n.length ? Math.max(...n) : 0) + 1}`;
114
+ }
115
+ function appendRow(md, title, header, must, row, prefix) {
116
+ let text = md && md.trim()
117
+ ? md.replace(/\r\n/g, "\n")
118
+ : `${title}\n\n${header}\n${header.replace(/[^|]+/g, "---")}\n`;
119
+ let t = table(text, must);
120
+ if (!t) {
121
+ text = `${text.replace(/\n*$/, "\n")}\n${header}\n${header.replace(/[^|]+/g, "---")}\n`;
122
+ t = table(text, must);
123
+ }
124
+ const id = nextId(t.rows.map((i) => cells(t.lines[i])[0]), prefix);
125
+ const last = t.rows.length ? t.rows[t.rows.length - 1] : t.header + 1;
126
+ t.lines.splice(last + 1, 0, row(id));
127
+ return { md: t.lines.join("\n"), id };
128
+ }
129
+ /** `questions.md` with a new open question that blocks the given requirements. */
130
+ function addQuestion(md, change, text, blocks) {
131
+ return appendRow(md, `# Questions — ${change}`, QUESTION_HEADER, /\bBlocks\b/i, (id) => `| ${id} | ${cell(text)} | ${blocks.join(", ")} | | | open |`, "Q");
132
+ }
133
+ /** `assumptions.md` with a new assumption from an answer, to review until the spec reflects it. */
134
+ function addAssumption(md, change, a) {
135
+ return appendRow(md, `# Assumptions — ${change}`, ASSUMPTION_HEADER, /\bUsed in\b/i, (id) => `| ${id} | ${cell(a.text)} | ${a.usedIn.join(", ")} | ${cell(a.why)} | ${TO_REVIEW} |`, "A");
136
+ }
137
+ function assumptionRows(md) {
138
+ const t = table(md, /\bUsed in\b/i);
139
+ if (!t)
140
+ return { t, rows: [] };
141
+ const whyAt = col(t, "why", "por qué", "porque");
142
+ const statusAt = col(t, "status", "estado");
143
+ return {
144
+ t,
145
+ rows: t.rows.map((i) => {
146
+ const c = cells(t.lines[i]);
147
+ return {
148
+ id: c[0] || "",
149
+ why: whyAt >= 0 ? c[whyAt] || "" : "",
150
+ status: statusAt >= 0 ? (c[statusAt] || "").toLowerCase() : "",
151
+ line: i + 1,
152
+ };
153
+ }),
154
+ };
155
+ }
156
+ /** The assumptions written from an answer whose spec nobody has confirmed yet. */
157
+ function assumptionsToReview(md) {
158
+ return assumptionRows(md).rows.filter((a) => a.status === TO_REVIEW);
159
+ }
160
+ /** `assumptions.md` with the question's assumptions to review set to decided. */
161
+ function reviewAssumptions(md, question) {
162
+ const { t, rows } = assumptionRows(md);
163
+ if (!t)
164
+ return { md, ids: [] };
165
+ const statusAt = col(t, "status", "estado");
166
+ const named = new RegExp(`(^|[^A-Za-z0-9])${question}(?![A-Za-z0-9])`);
167
+ const ids = [];
168
+ for (const a of rows) {
169
+ if (a.status !== TO_REVIEW || !named.test(a.why))
170
+ continue;
171
+ const c = cells(t.lines[a.line - 1]);
172
+ c[statusAt] = "decided";
173
+ t.lines[a.line - 1] = `| ${c.join(" | ")} |`;
174
+ ids.push(a.id);
175
+ }
176
+ return { md: t.lines.join("\n"), ids };
177
+ }
178
+ //# sourceMappingURL=Clarification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Clarification.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/Clarification.ts"],"names":[],"mappings":"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"}
@@ -13,12 +13,11 @@
13
13
  * `questions.md` and hands the text in.
14
14
  */
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.KINDS = void 0;
16
+ exports.KINDS = exports.deferredAnswer = void 0;
17
17
  exports.actorSurfaces = actorSurfaces;
18
18
  exports.briefModules = briefModules;
19
19
  exports.statedValues = statedValues;
20
20
  exports.rowNamesId = rowNamesId;
21
- exports.deferredAnswer = deferredAnswer;
22
21
  exports.openQuestions = openQuestions;
23
22
  exports.unmeasured = unmeasured;
24
23
  exports.apiCalls = apiCalls;
@@ -29,6 +28,8 @@ const Diagnostic_1 = require("./Diagnostic");
29
28
  const SpecParser_1 = require("./SpecParser");
30
29
  const GherkinQuality_1 = require("./GherkinQuality");
31
30
  const QuotedText_1 = require("./QuotedText");
31
+ const Clarification_1 = require("./Clarification");
32
+ Object.defineProperty(exports, "deferredAnswer", { enumerable: true, get: function () { return Clarification_1.deferredAnswer; } });
32
33
  exports.KINDS = new Set(["functional", "non-functional", "business-rule"]);
33
34
  // ── The brief's front matter ──────────────────────────────────────────────────
34
35
  /**
@@ -141,19 +142,6 @@ function rowNamesId(row, id) {
141
142
  * row", which a Markdown table cannot hold; D7 then kept an answered question
142
143
  * open and demanded its requirement stay `Needs Clarification` (#45).
143
144
  */
144
- /**
145
- * An answer that puts the decision off is not an answer. "Se decidirá con el
146
- * cliente antes de implementarlo" filled the Answer cell, D7 took the question
147
- * as answered and its requirement stopped waiting, though nobody had decided
148
- * anything (HealthTech, #82). A proposal ("propuesta, a validar") is an answer;
149
- * "pending", "TBD" or "will be decided" is not.
150
- */
151
- const DEFERRED = /(?<![\p{L}])(se decidir[aá]n?|por decidir|a decidir|sin decidir|pendiente de (?:decidir|decisi[oó]n|respuesta|confirmar)|to be decided|will be decided|decide later|tbd)(?![\p{L}])/iu;
152
- const DEFERRED_ALONE = /^(pendiente|pending|later|tbd|todo|\?+|-+)\.?$/i;
153
- function deferredAnswer(answer) {
154
- const text = answer.replace(/\*\*/g, "").trim();
155
- return DEFERRED.test(text) || DEFERRED_ALONE.test(text);
156
- }
157
145
  /** A Blocks cell that says, on purpose, that nothing waits for the question (REQ-176). */
158
146
  const NONE_BLOCKED = /^(none|nothing|ninguno|ninguna|nada|n\/a|—|–|-)\.?$/i;
159
147
  function questionRows(md) {
@@ -174,7 +162,7 @@ function questionRows(md) {
174
162
  ...(answerCol > 0 && (cells[answerCol] || "").length > 0 ? [cells[answerCol]] : []),
175
163
  ...answerLines.filter((l) => named.test(l)).map((l) => l.replace(/^[^:]*:\s*/, "")),
176
164
  ];
177
- const deferred = answers.length > 0 && answers.every(deferredAnswer);
165
+ const deferred = answers.length > 0 && answers.every(Clarification_1.deferredAnswer);
178
166
  out.push({
179
167
  row,
180
168
  blocks: (cells[at] || "").match(/REQ-[A-Za-z0-9.]+/g) || [],
@@ -459,6 +447,18 @@ function checkDraft(files) {
459
447
  }
460
448
  }
461
449
  }
450
+ // D13 — an answer written by `specgate answer` waits until its author says
451
+ // the spec reflects it (REQ-188): the answer alone changes no requirement.
452
+ for (const a of (0, Clarification_1.assumptionsToReview)(files.assumptions || "")) {
453
+ const q = (/Q\d+/.exec(a.why) || [])[0];
454
+ status.push((0, Diagnostic_1.error)("D13_assumption_to_review", `Assumption ${a.id} comes from an answer${q ? ` to ${q}` : ""} the specification may not reflect yet.`, {
455
+ file: "assumptions.md",
456
+ line: a.line,
457
+ fix: q
458
+ ? `Update the requirements it is used in, then run \`specgate answer ${q} --reviewed\`.`
459
+ : `Update the requirements it is used in, then set its Status to decided.`,
460
+ }));
461
+ }
462
462
  // D9 — every scenario passes the rules the harness gate will apply to it.
463
463
  // The scenario-quality rules run once a requirement leaves Draft, so a draft
464
464
  // that passed this checklist could still fail the harness on a title — and