@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.
- package/CHANGELOG.md +91 -42
- package/dist/packages/core/src/domain/AgentPrompt.js +12 -0
- package/dist/packages/core/src/domain/AgentPrompt.js.map +1 -1
- package/dist/packages/core/src/domain/Clarification.js +178 -0
- package/dist/packages/core/src/domain/Clarification.js.map +1 -0
- package/dist/packages/core/src/domain/DraftChecklist.js +16 -16
- package/dist/packages/core/src/domain/DraftChecklist.js.map +1 -1
- package/dist/packages/core/src/domain/HarnessConfig.js.map +1 -1
- package/dist/packages/core/src/domain/HarnessRun.js.map +1 -1
- package/dist/packages/core/src/domain/RequirementPlan.js +11 -0
- package/dist/packages/core/src/domain/RequirementPlan.js.map +1 -1
- package/dist/packages/core/src/infrastructure/ChangeWorkspace.js +15 -3
- package/dist/packages/core/src/infrastructure/ChangeWorkspace.js.map +1 -1
- package/dist/packages/core/src/infrastructure/HarnessConfigFile.js +5 -0
- package/dist/packages/core/src/infrastructure/HarnessConfigFile.js.map +1 -1
- package/dist/packages/core/src/infrastructure/IdsAcrossBranches.js +4 -1
- package/dist/packages/core/src/infrastructure/IdsAcrossBranches.js.map +1 -1
- package/dist/packages/core/test/unit/clarification.test.js +161 -0
- package/dist/packages/core/test/unit/clarification.test.js.map +1 -0
- package/dist/packages/core/test/unit/rework.test.js +62 -0
- package/dist/packages/core/test/unit/rework.test.js.map +1 -0
- package/dist/scripts/answer.js +10 -0
- package/dist/scripts/answer.js.map +1 -0
- package/dist/scripts/ask.js +10 -0
- package/dist/scripts/ask.js.map +1 -0
- package/dist/scripts/brief_add.js +10 -0
- package/dist/scripts/brief_add.js.map +1 -0
- package/dist/scripts/cli/commands/change/ChangeCommand.js +124 -1
- package/dist/scripts/cli/commands/change/ChangeCommand.js.map +1 -1
- package/dist/scripts/cli/commands/harness/RunCommand.js +135 -5
- package/dist/scripts/cli/commands/harness/RunCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/ClarifyCommands.js +275 -0
- package/dist/scripts/cli/commands/spec/ClarifyCommands.js.map +1 -0
- package/dist/scripts/cli/commands/spec/DraftCommand.js +44 -4
- package/dist/scripts/cli/commands/spec/DraftCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/StatusCommand.js +5 -1
- package/dist/scripts/cli/commands/spec/StatusCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/StudioCommand.js +194 -1
- package/dist/scripts/cli/commands/spec/StudioCommand.js.map +1 -1
- package/dist/scripts/docs/record-journey.js +1 -0
- package/dist/scripts/docs/record-journey.js.map +1 -1
- package/dist/scripts/docs/record-terminal.js +18 -0
- package/dist/scripts/docs/record-terminal.js.map +1 -1
- package/dist/scripts/draft/drafting-guide.js +11 -1
- package/dist/scripts/draft/drafting-guide.js.map +1 -1
- package/dist/scripts/harness/prompt.js +2 -0
- package/dist/scripts/harness/prompt.js.map +1 -1
- package/dist/scripts/lib/brief-add.js +197 -0
- package/dist/scripts/lib/brief-add.js.map +1 -0
- package/dist/scripts/lib/change-impact.js +156 -0
- package/dist/scripts/lib/change-impact.js.map +1 -0
- package/dist/scripts/lib/change-review.js +145 -0
- package/dist/scripts/lib/change-review.js.map +1 -0
- package/dist/scripts/lib/clarification.js +319 -0
- package/dist/scripts/lib/clarification.js.map +1 -0
- package/dist/scripts/lib/harness-guard.js +18 -0
- package/dist/scripts/lib/harness-guard.js.map +1 -1
- package/dist/scripts/lib/in-flight.js +17 -11
- package/dist/scripts/lib/in-flight.js.map +1 -1
- package/dist/scripts/lib/live-detail.js +3 -2
- package/dist/scripts/lib/live-detail.js.map +1 -1
- package/dist/scripts/lib/live-model.js +35 -4
- package/dist/scripts/lib/live-model.js.map +1 -1
- package/dist/scripts/lib/live-page.js +80 -15
- package/dist/scripts/lib/live-page.js.map +1 -1
- package/dist/scripts/lib/screen-requirements.js +149 -0
- package/dist/scripts/lib/screen-requirements.js.map +1 -0
- package/dist/scripts/lib/studio-app-page.js +960 -0
- package/dist/scripts/lib/studio-app-page.js.map +1 -0
- package/dist/scripts/lib/studio-app.js +362 -0
- package/dist/scripts/lib/studio-app.js.map +1 -0
- package/dist/scripts/lib/studio-route.js +933 -0
- package/dist/scripts/lib/studio-route.js.map +1 -0
- package/dist/scripts/lib/surface.js +52 -0
- package/dist/scripts/lib/surface.js.map +1 -1
- package/dist/scripts/questions.js +10 -0
- package/dist/scripts/questions.js.map +1 -0
- package/package.json +1 -1
- 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":";;;
|
|
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":";AAAA;;;;;;;GAOG;;AAaH,wCAGC;AA0DD,sCAsBC;AAOD,wCAkBC;AAoCD,kCAcC;AAGD,sCAaC;AAsBD,kDAEC;AAGD,8CAcC;AAlOD;;;;;;GAMG;AACH,MAAM,QAAQ,GACZ,uLAAuL,CAAC;AAC1L,MAAM,cAAc,GAAG,iDAAiD,CAAC;AAEzE,SAAgB,cAAc,CAAC,MAAc;IAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAChD,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1D,CAAC;AAmBD,MAAM,eAAe,GAAG,4DAA4D,CAAC;AACrF,MAAM,iBAAiB,GAAG,6CAA6C,CAAC;AACxE,MAAM,SAAS,GAAG,WAAW,CAAC;AAE9B,oFAAoF;AACpF,SAAS,IAAI,CAAC,IAAY;IACxB,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACxE,CAAC;AAED,sEAAsE;AACtE,SAAS,KAAK,CAAC,IAAY;IACzB,OAAO,IAAI;SACR,KAAK,CAAC,WAAW,CAAC;SAClB,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;SACZ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AAC1B,CAAC;AASD,SAAS,KAAK,CAAC,EAAU,EAAE,IAAY;IACrC,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,IAAI,MAAM,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACvC,CAAC;AAED,SAAS,GAAG,CAAC,CAAQ,EAAE,GAAG,KAAe;IACvC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,kGAAkG;AAClG,SAAgB,aAAa,CAAC,EAAU;IACtC,MAAM,CAAC,GAAG,KAAK,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;IACnC,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAClB,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAChE,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACtB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,OAAO;YACL,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;YACd,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;YACxC,MAAM,EAAE,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,IAAI,EAAE;YAClF,QAAQ,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC;YACtD,IAAI,EAAE,CAAC,GAAG,CAAC;YACX,OAAO,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAChD,KAAK,CAAC,YAAY,CAAC;iBACnB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACpB,MAAM,CAAC,OAAO,CAAC;SACnB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAMD,8FAA8F;AAC9F,SAAgB,cAAc,CAAC,EAAU,EAAE,EAAU,EAAE,MAAc;IACnE,IAAI,cAAc,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;IAC1E,MAAM,CAAC,GAAG,KAAK,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;IACnC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3E,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,SAAS;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;IAC7E,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7B,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM;QAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5C,IAAI,QAAQ,IAAI,CAAC;QAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9C,IAAI,QAAQ,IAAI,CAAC;QAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC;IAC5C,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACrC,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAClC,OAAO;QACL,EAAE,EAAE,IAAI;QACR,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QACtB,MAAM,EAAE,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,IAAI,EAAE;KAC7E,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,GAAa,EAAE,MAAc;IAC3C,MAAM,CAAC,GAAG,GAAG;SACV,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACxE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;AAC3D,CAAC;AAED,SAAS,SAAS,CAChB,EAAsB,EACtB,KAAa,EACb,MAAc,EACd,IAAY,EACZ,GAA2B,EAC3B,MAAc;IAEd,IAAI,IAAI,GACN,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;QAC3B,CAAC,CAAC,GAAG,KAAK,OAAO,MAAM,KAAK,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC;IACpE,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,MAAM,KAAK,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC;QACxF,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,CAAE,CAAC;IACzB,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,CACf,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACxC,MAAM,CACP,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACtE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;AACxC,CAAC;AAED,kFAAkF;AAClF,SAAgB,WAAW,CACzB,EAAsB,EACtB,MAAc,EACd,IAAY,EACZ,MAAgB;IAEhB,OAAO,SAAS,CACd,EAAE,EACF,iBAAiB,MAAM,EAAE,EACzB,eAAe,EACf,aAAa,EACb,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EACvE,GAAG,CACJ,CAAC;AACJ,CAAC;AAED,mGAAmG;AACnG,SAAgB,aAAa,CAC3B,EAAsB,EACtB,MAAc,EACd,CAAkD;IAElD,OAAO,SAAS,CACd,EAAE,EACF,mBAAmB,MAAM,EAAE,EAC3B,iBAAiB,EACjB,cAAc,EACd,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,SAAS,IAAI,EAC9F,GAAG,CACJ,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,EAAU;IAChC,MAAM,CAAC,GAAG,KAAK,CAAC,EAAE,EAAE,cAAc,CAAC,CAAC;IACpC,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5C,OAAO;QACL,CAAC;QACD,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACrB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5B,OAAO;gBACL,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;gBACd,GAAG,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;gBACrC,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE;gBAC9D,IAAI,EAAE,CAAC,GAAG,CAAC;aACZ,CAAC;QACJ,CAAC,CAAC;KACH,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,SAAgB,mBAAmB,CAAC,EAAU;IAC5C,OAAO,cAAc,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AACvE,CAAC;AAED,iFAAiF;AACjF,SAAgB,iBAAiB,CAAC,EAAU,EAAE,QAAgB;IAC5D,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC;IACvC,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAG,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,mBAAmB,QAAQ,iBAAiB,CAAC,CAAC;IACvE,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;YAAE,SAAS;QAC3D,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;QACxB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAC7C,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;AACzC,CAAC"}
|
|
@@ -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
|