plan-verify 0.0.0-stage → 0.1.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/.github/workflows/ci.yml +48 -0
- package/README.md +1431 -2
- package/assets/icon.png +0 -0
- package/assets/logo-mark.png +0 -0
- package/assets/logo.png +0 -0
- package/examples/checkout.ears.md +74 -0
- package/examples/order-always.ears.md +3 -0
- package/examples/order-awkward.ears.md +8 -0
- package/examples/order-bad.json +1 -0
- package/examples/order-chain.ears.md +9 -0
- package/examples/order-chosen.ears.md +7 -0
- package/examples/order-clear.ears.md +8 -0
- package/examples/order-combined.ears.md +10 -0
- package/examples/order-conflict.ears.md +8 -0
- package/examples/order-covered.ears.md +9 -0
- package/examples/order-duplicate.ears.md +8 -0
- package/examples/order-fail.json +5 -0
- package/examples/order-misuse.ears.md +7 -0
- package/examples/order-negation.ears.md +7 -0
- package/examples/order-pass.json +5 -0
- package/examples/order-quantity.ears.md +8 -0
- package/examples/order-redundant.ears.md +9 -0
- package/examples/order-repair.ears.md +9 -0
- package/examples/order-repeat.ears.md +13 -0
- package/examples/order-same.ears.md +3 -0
- package/examples/order-status.ears.md +7 -0
- package/examples/order-unanswered.ears.md +8 -0
- package/examples/order-unhandled.ears.md +8 -0
- package/examples/order-unmeasured.ears.md +10 -0
- package/examples/order-unused.ears.md +13 -0
- package/examples/order-vacuous.ears.md +9 -0
- package/examples/order-vague.ears.md +7 -0
- package/examples/order-wide.ears.md +5 -0
- package/examples/order-wording.ears.md +8 -0
- package/examples/order.ears.md +7 -0
- package/examples/payment-if.ears.md +7 -0
- package/examples/plan-to-problems/README.md +54 -0
- package/examples/plan-to-problems/expected-problems.md +25 -0
- package/examples/plan-to-problems/generate.mjs +186 -0
- package/examples/plan-to-problems/generated.ears.md +27 -0
- package/examples/plan-to-problems/lint.json +576 -0
- package/examples/plan-to-problems/plan.md +5 -0
- package/examples/plan-to-problems/planted.txt +5 -0
- package/examples/plan-to-problems/problems.md +112 -0
- package/examples/status-placed.ears.md +3 -0
- package/package.json +25 -4
- package/scripts/install-scriptc.sh +16 -0
- package/skills/plan-verify/SKILL.md +1515 -0
- package/src/check.ts +250 -0
- package/src/decide.ts +1324 -0
- package/src/ears.ts +1520 -0
- package/src/jsonvalue.ts +228 -0
- package/src/lint.ts +1245 -0
- package/src/main.ts +273 -0
- package/src/policy.ts +148 -0
- package/src/repair.ts +567 -0
- package/src/report.ts +329 -0
- package/src/scenarios.ts +149 -0
- package/src/smt.ts +97 -0
- package/src/solver.ts +868 -0
- package/src/spec.ts +307 -0
- package/src/term.ts +331 -0
- package/src/text.ts +95 -0
- package/test/fixtures/malformed.ears.md +3 -0
- package/test/fixtures/unknown-phrase.ears.md +5 -0
- package/test/golden/check-fail-json.exit +1 -0
- package/test/golden/check-fail-json.stderr +0 -0
- package/test/golden/check-fail-json.stdout +13 -0
- package/test/golden/check-fail.exit +1 -0
- package/test/golden/check-fail.stderr +0 -0
- package/test/golden/check-fail.stdout +7 -0
- package/test/golden/check-pass-json.exit +1 -0
- package/test/golden/check-pass-json.stderr +0 -0
- package/test/golden/check-pass-json.stdout +6 -0
- package/test/golden/check-pass.exit +1 -0
- package/test/golden/check-pass.stderr +0 -0
- package/test/golden/check-pass.stdout +3 -0
- package/test/golden/emit-smt-json-usage.exit +1 -0
- package/test/golden/emit-smt-json-usage.stderr +0 -0
- package/test/golden/emit-smt-json-usage.stdout +4 -0
- package/test/golden/emit-smt-json.exit +1 -0
- package/test/golden/emit-smt-json.stderr +0 -0
- package/test/golden/emit-smt-json.stdout +5 -0
- package/test/golden/emit-smt.exit +1 -0
- package/test/golden/emit-smt.stderr +0 -0
- package/test/golden/emit-smt.stdout +10 -0
- package/test/golden/help.exit +1 -0
- package/test/golden/help.stderr +0 -0
- package/test/golden/help.stdout +8 -0
- package/test/golden/lint-awkward.exit +1 -0
- package/test/golden/lint-awkward.stderr +0 -0
- package/test/golden/lint-awkward.stdout +29 -0
- package/test/golden/lint-chain.exit +1 -0
- package/test/golden/lint-chain.stderr +0 -0
- package/test/golden/lint-chain.stdout +56 -0
- package/test/golden/lint-checkout.exit +1 -0
- package/test/golden/lint-checkout.stderr +0 -0
- package/test/golden/lint-checkout.stdout +301 -0
- package/test/golden/lint-clean.exit +1 -0
- package/test/golden/lint-clean.stderr +0 -0
- package/test/golden/lint-clean.stdout +9 -0
- package/test/golden/lint-clear.exit +1 -0
- package/test/golden/lint-clear.stderr +0 -0
- package/test/golden/lint-clear.stdout +9 -0
- package/test/golden/lint-conflict-json.exit +1 -0
- package/test/golden/lint-conflict-json.stderr +0 -0
- package/test/golden/lint-conflict-json.stdout +80 -0
- package/test/golden/lint-conflict.exit +1 -0
- package/test/golden/lint-conflict.stderr +0 -0
- package/test/golden/lint-conflict.stdout +41 -0
- package/test/golden/lint-duplicate.exit +1 -0
- package/test/golden/lint-duplicate.stderr +0 -0
- package/test/golden/lint-duplicate.stdout +14 -0
- package/test/golden/lint-gap.exit +1 -0
- package/test/golden/lint-gap.stderr +0 -0
- package/test/golden/lint-gap.stdout +12 -0
- package/test/golden/lint-misuse.exit +1 -0
- package/test/golden/lint-misuse.stderr +0 -0
- package/test/golden/lint-misuse.stdout +18 -0
- package/test/golden/lint-negation.exit +1 -0
- package/test/golden/lint-negation.stderr +0 -0
- package/test/golden/lint-negation.stdout +13 -0
- package/test/golden/lint-quantity.exit +1 -0
- package/test/golden/lint-quantity.stderr +0 -0
- package/test/golden/lint-quantity.stdout +41 -0
- package/test/golden/lint-redundant.exit +1 -0
- package/test/golden/lint-redundant.stderr +0 -0
- package/test/golden/lint-redundant.stdout +14 -0
- package/test/golden/lint-repair-json.exit +1 -0
- package/test/golden/lint-repair-json.stderr +0 -0
- package/test/golden/lint-repair-json.stdout +127 -0
- package/test/golden/lint-repair.exit +1 -0
- package/test/golden/lint-repair.stderr +0 -0
- package/test/golden/lint-repair.stdout +54 -0
- package/test/golden/lint-repeat.exit +1 -0
- package/test/golden/lint-repeat.stderr +0 -0
- package/test/golden/lint-repeat.stdout +48 -0
- package/test/golden/lint-status.exit +1 -0
- package/test/golden/lint-status.stderr +0 -0
- package/test/golden/lint-status.stdout +44 -0
- package/test/golden/lint-unanswered.exit +1 -0
- package/test/golden/lint-unanswered.stderr +0 -0
- package/test/golden/lint-unanswered.stdout +12 -0
- package/test/golden/lint-unhandled.exit +1 -0
- package/test/golden/lint-unhandled.stderr +0 -0
- package/test/golden/lint-unhandled.stdout +12 -0
- package/test/golden/lint-unmeasured.exit +1 -0
- package/test/golden/lint-unmeasured.stderr +0 -0
- package/test/golden/lint-unmeasured.stdout +13 -0
- package/test/golden/lint-unused-json.exit +1 -0
- package/test/golden/lint-unused-json.stderr +0 -0
- package/test/golden/lint-unused-json.stdout +37 -0
- package/test/golden/lint-unused.exit +1 -0
- package/test/golden/lint-unused.stderr +0 -0
- package/test/golden/lint-unused.stdout +25 -0
- package/test/golden/lint-vacuous-json.exit +1 -0
- package/test/golden/lint-vacuous-json.stderr +0 -0
- package/test/golden/lint-vacuous-json.stdout +27 -0
- package/test/golden/lint-vacuous.exit +1 -0
- package/test/golden/lint-vacuous.stderr +0 -0
- package/test/golden/lint-vacuous.stdout +19 -0
- package/test/golden/lint-vague.exit +1 -0
- package/test/golden/lint-vague.stderr +0 -0
- package/test/golden/lint-vague.stdout +21 -0
- package/test/golden/lint-wide.exit +1 -0
- package/test/golden/lint-wide.stderr +0 -0
- package/test/golden/lint-wide.stdout +9 -0
- package/test/golden/lint-wording.exit +1 -0
- package/test/golden/lint-wording.stderr +0 -0
- package/test/golden/lint-wording.stdout +21 -0
- package/test/golden/malformed-scenario.exit +1 -0
- package/test/golden/malformed-scenario.stderr +1 -0
- package/test/golden/malformed-scenario.stdout +0 -0
- package/test/golden/malformed-spec.exit +1 -0
- package/test/golden/malformed-spec.stderr +1 -0
- package/test/golden/malformed-spec.stdout +0 -0
- package/test/golden/policy-counterexample.exit +1 -0
- package/test/golden/policy-counterexample.stderr +0 -0
- package/test/golden/policy-counterexample.stdout +13 -0
- package/test/golden/policy-covered.exit +1 -0
- package/test/golden/policy-covered.stderr +0 -0
- package/test/golden/policy-covered.stdout +19 -0
- package/test/golden/policy-holds.exit +1 -0
- package/test/golden/policy-holds.stderr +0 -0
- package/test/golden/policy-holds.stdout +3 -0
- package/test/golden/policy-json.exit +1 -0
- package/test/golden/policy-json.stderr +0 -0
- package/test/golden/policy-json.stdout +34 -0
- package/test/golden/policy-status.exit +1 -0
- package/test/golden/policy-status.stderr +0 -0
- package/test/golden/policy-status.stdout +16 -0
- package/test/golden/policy-vacuous.exit +1 -0
- package/test/golden/policy-vacuous.stderr +0 -0
- package/test/golden/policy-vacuous.stdout +3 -0
- package/test/golden/policy-wide.exit +1 -0
- package/test/golden/policy-wide.stderr +0 -0
- package/test/golden/policy-wide.stdout +15 -0
- package/test/golden/policy.exit +1 -0
- package/test/golden/policy.stderr +0 -0
- package/test/golden/policy.stdout +19 -0
- package/test/golden/scenarios-json.exit +1 -0
- package/test/golden/scenarios-json.stderr +0 -0
- package/test/golden/scenarios-json.stdout +75 -0
- package/test/golden/scenarios-status.exit +1 -0
- package/test/golden/scenarios-status.stderr +0 -0
- package/test/golden/scenarios-status.stdout +24 -0
- package/test/golden/scenarios.exit +1 -0
- package/test/golden/scenarios.stderr +0 -0
- package/test/golden/scenarios.stdout +26 -0
- package/test/golden/unit.exit +1 -0
- package/test/golden/unit.stderr +0 -0
- package/test/golden/unit.stdout +2 -0
- package/test/golden/unknown-phrase.exit +1 -0
- package/test/golden/unknown-phrase.stderr +1 -0
- package/test/golden/unknown-phrase.stdout +0 -0
- package/test/golden/usage.exit +1 -0
- package/test/golden/usage.stderr +9 -0
- package/test/golden/usage.stdout +0 -0
- package/test/run-all.ts +499 -0
- package/test/soundness.ts +375 -0
- package/test/unit.ts +1352 -0
- package/tsconfig.json +15 -0
package/src/text.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/** Quote a string for human and JSON-adjacent messages. */
|
|
2
|
+
export function displayQuote(value: string): string {
|
|
3
|
+
let out = "\"";
|
|
4
|
+
for (let i = 0; i < value.length; i++) {
|
|
5
|
+
const code = value.charCodeAt(i);
|
|
6
|
+
if (code === 34 || code === 92) {
|
|
7
|
+
out += "\\" + value.slice(i, i + 1);
|
|
8
|
+
} else if (code === 10) {
|
|
9
|
+
out += "\\n";
|
|
10
|
+
} else if (code === 13) {
|
|
11
|
+
out += "\\r";
|
|
12
|
+
} else if (code === 9) {
|
|
13
|
+
out += "\\t";
|
|
14
|
+
} else if (code < 32) {
|
|
15
|
+
out += "\\u00" + hexByte(code);
|
|
16
|
+
} else {
|
|
17
|
+
out += value.slice(i, i + 1);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return out + "\"";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function formatInt(value: number): string {
|
|
24
|
+
return String(Math.trunc(value));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Capitalize the first letter when it is a lowercase ascii letter. */
|
|
28
|
+
export function capitalize(text: string): string {
|
|
29
|
+
if (text.length === 0) return text;
|
|
30
|
+
const code = text.charCodeAt(0);
|
|
31
|
+
if (code >= 97 && code <= 122) return String.fromCharCode(code - 32) + text.slice(1);
|
|
32
|
+
return text;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Replace the first whole word. The replacement may itself contain spaces. */
|
|
36
|
+
export function replaceWord(text: string, word: string, replacement: string): string {
|
|
37
|
+
const end = wordEnd(text, word);
|
|
38
|
+
if (end < 0) return text;
|
|
39
|
+
const start = end - word.length;
|
|
40
|
+
return text.slice(0, start) + replacement + text.slice(end);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Turn the first "is" into "was". Other words stay put. */
|
|
44
|
+
export function pastVoice(text: string): string {
|
|
45
|
+
return replaceWord(text, "is", "was");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function wordEnd(text: string, word: string): number {
|
|
49
|
+
const target = lowerAscii(word);
|
|
50
|
+
let start = 0;
|
|
51
|
+
for (let i = 0; i <= text.length; i++) {
|
|
52
|
+
if (i === text.length || text.charCodeAt(i) === 32) {
|
|
53
|
+
if (i > start && lowerAscii(text.slice(start, i)) === target) return i;
|
|
54
|
+
start = i + 1;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return -1;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function lowerAscii(text: string): string {
|
|
61
|
+
let out = "";
|
|
62
|
+
for (let i = 0; i < text.length; i++) {
|
|
63
|
+
const code = text.charCodeAt(i);
|
|
64
|
+
if (code >= 65 && code <= 90) out += String.fromCharCode(code + 32);
|
|
65
|
+
else out += text.slice(i, i + 1);
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** "a", "a and b", or "a, b, and c". */
|
|
71
|
+
export function englishList(parts: string[]): string {
|
|
72
|
+
if (parts.length === 0) return "";
|
|
73
|
+
if (parts.length === 1) return parts[0];
|
|
74
|
+
if (parts.length === 2) return parts[0] + " and " + parts[1];
|
|
75
|
+
let out = "";
|
|
76
|
+
for (let i = 0; i < parts.length; i++) {
|
|
77
|
+
if (i === parts.length - 1) out += ", and ";
|
|
78
|
+
else if (i > 0) out += ", ";
|
|
79
|
+
out += parts[i];
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function formatSmtInt(value: number): string {
|
|
85
|
+
const n = Math.trunc(value);
|
|
86
|
+
if (n < 0) return "(- " + formatInt(-n) + ")";
|
|
87
|
+
return formatInt(n);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function hexByte(code: number): string {
|
|
91
|
+
const hex = "0123456789abcdef";
|
|
92
|
+
const hi = Math.trunc(code / 16);
|
|
93
|
+
const lo = code - hi * 16;
|
|
94
|
+
return hex.slice(hi, hi + 1) + hex.slice(lo, lo + 1);
|
|
95
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
event order_submitted: Bool "The customer submits an order." phrase "an order is submitted"
|
|
2
|
+
state inventory_available: Bool "Enough stock is on hand to fill the order." phrase "inventory is available"
|
|
3
|
+
output order_fulfilled: Bool "The order is fulfilled." phrase "fulfill the order" outcome "the order was fulfilled" / "the order was not fulfilled"
|
|
4
|
+
|
|
5
|
+
R1 When an order was submitted, the Order System shall fulfill the order.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ok": false,
|
|
3
|
+
"spec": "examples/order.ears.md",
|
|
4
|
+
"scenario": "examples/order-fail.json",
|
|
5
|
+
"violations": [
|
|
6
|
+
{
|
|
7
|
+
"id": "R1",
|
|
8
|
+
"line": 7,
|
|
9
|
+
"sentence": "WHEN an order is submitted AND inventory is available, THE Order System SHALL fulfill the order.",
|
|
10
|
+
"because": "An order was submitted and inventory was available, but the order was not fulfilled."
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1
|
|
File without changes
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
spec: examples/order.ears.md
|
|
2
|
+
scenario: examples/order-fail.json
|
|
3
|
+
violations: 1
|
|
4
|
+
|
|
5
|
+
R1 line 7
|
|
6
|
+
WHEN an order is submitted AND inventory is available, THE Order System SHALL fulfill the order.
|
|
7
|
+
An order was submitted and inventory was available, but the order was not fulfilled.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0
|
|
File without changes
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ok": true,
|
|
3
|
+
"spec": "examples/order.ears.md",
|
|
4
|
+
"smt": "; spec: examples/order.ears.md\n(set-logic ALL)\n; event order_submitted: Bool \"The customer submits an order.\" phrase \"an order is submitted\"\n(declare-fun order_submitted () Bool)\n; state inventory_available: Bool \"Enough stock is on hand to fill the order.\" phrase \"inventory is available\"\n(declare-fun inventory_available () Bool)\n; output order_fulfilled: Bool \"The order is fulfilled.\" phrase \"fulfill the order\" outcome \"the order was fulfilled\" / \"the order was not fulfilled\"\n(declare-fun order_fulfilled () Bool)\n; R1_L7 line 7: WHEN an order is submitted AND inventory is available, THE Order System SHALL fulfill the order.\n(assert (! (=> (and order_submitted inventory_available) order_fulfilled) :named R1_L7))"
|
|
5
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
; spec: examples/order.ears.md
|
|
2
|
+
(set-logic ALL)
|
|
3
|
+
; event order_submitted: Bool "The customer submits an order." phrase "an order is submitted"
|
|
4
|
+
(declare-fun order_submitted () Bool)
|
|
5
|
+
; state inventory_available: Bool "Enough stock is on hand to fill the order." phrase "inventory is available"
|
|
6
|
+
(declare-fun inventory_available () Bool)
|
|
7
|
+
; output order_fulfilled: Bool "The order is fulfilled." phrase "fulfill the order" outcome "the order was fulfilled" / "the order was not fulfilled"
|
|
8
|
+
(declare-fun order_fulfilled () Bool)
|
|
9
|
+
; R1_L7 line 7: WHEN an order is submitted AND inventory is available, THE Order System SHALL fulfill the order.
|
|
10
|
+
(assert (! (=> (and order_submitted inventory_available) order_fulfilled) :named R1_L7))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0
|
|
File without changes
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
usage:
|
|
2
|
+
plan-verify check [--json] <spec> --input <scenario>
|
|
3
|
+
plan-verify emit-smt [--json] <spec>
|
|
4
|
+
plan-verify lint [--json] <spec>
|
|
5
|
+
plan-verify report <spec>
|
|
6
|
+
plan-verify scenarios [--json] <spec>
|
|
7
|
+
plan-verify policy [--json] <spec> [--property <file>]
|
|
8
|
+
plan-verify help
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1
|
|
File without changes
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
spec: examples/order-awkward.ears.md
|
|
2
|
+
conflicts: 0
|
|
3
|
+
gaps: 0
|
|
4
|
+
misuse: 0
|
|
5
|
+
wording: 5
|
|
6
|
+
redundant: 0
|
|
7
|
+
duplicate: 0
|
|
8
|
+
vacuous: 0
|
|
9
|
+
unused: 0
|
|
10
|
+
|
|
11
|
+
wording line 7
|
|
12
|
+
"shall the ... is ..." is awkward. Write the response as a verb phrase, such as "bill at most 2 seats", and bind it with as.
|
|
13
|
+
When start the subscription, the Checkout shall the lane is fulfill.
|
|
14
|
+
|
|
15
|
+
wording line 7
|
|
16
|
+
"When" needs a condition with "is", not a bare verb. "When the subscription is started" is the form.
|
|
17
|
+
When start the subscription, the Checkout shall the lane is fulfill.
|
|
18
|
+
|
|
19
|
+
wording line 8
|
|
20
|
+
"shall the ... is ..." is awkward. Write the response as a verb phrase, such as "bill at most 2 seats", and bind it with as.
|
|
21
|
+
When not start the subscription, the Checkout shall the lane is hold.
|
|
22
|
+
|
|
23
|
+
wording line 8
|
|
24
|
+
"When" needs a condition with "is", not a bare verb. "When the subscription is started" is the form.
|
|
25
|
+
When not start the subscription, the Checkout shall the lane is hold.
|
|
26
|
+
|
|
27
|
+
wording line 8
|
|
28
|
+
The trigger is a bare negation. Write a positive condition, such as "When a non-member asks", or declare a positive event.
|
|
29
|
+
When not start the subscription, the Checkout shall the lane is hold.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1
|
|
File without changes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
spec: examples/order-chain.ears.md
|
|
2
|
+
conflicts: 1
|
|
3
|
+
gaps: 0
|
|
4
|
+
misuse: 0
|
|
5
|
+
wording: 0
|
|
6
|
+
redundant: 0
|
|
7
|
+
duplicate: 0
|
|
8
|
+
vacuous: 0
|
|
9
|
+
unused: 0
|
|
10
|
+
|
|
11
|
+
conflict {R1, R2, R3}
|
|
12
|
+
R1, R2, and R3 cannot all hold.
|
|
13
|
+
|
|
14
|
+
R1 line 7
|
|
15
|
+
When an order is submitted, the Order System shall accept the order.
|
|
16
|
+
|
|
17
|
+
R2 line 8
|
|
18
|
+
When the order is accepted, the Order System shall ship the order.
|
|
19
|
+
|
|
20
|
+
R3 line 9
|
|
21
|
+
When an order is submitted, the Order System shall not ship the order.
|
|
22
|
+
|
|
23
|
+
They clash when an order was submitted.
|
|
24
|
+
R1 requires that the order was accepted.
|
|
25
|
+
R3 requires that the order was not shipped.
|
|
26
|
+
|
|
27
|
+
Example scenario:
|
|
28
|
+
{
|
|
29
|
+
"order_submitted": true,
|
|
30
|
+
"order_accepted": true,
|
|
31
|
+
"order_shipped": true
|
|
32
|
+
}
|
|
33
|
+
This scenario keeps R1 and R2 and breaks R3.
|
|
34
|
+
|
|
35
|
+
Suggested fix: ask which requirement should win. Removing any one of R1, R2, and R3 leaves the rest consistent.
|
|
36
|
+
|
|
37
|
+
Candidate repairs follow. This report does not choose one.
|
|
38
|
+
|
|
39
|
+
repair drop R1
|
|
40
|
+
One repair is to drop R1 and keep R2 and R3 as written.
|
|
41
|
+
When the order is accepted, the Order System shall ship the order.
|
|
42
|
+
When an order is submitted, the Order System shall not ship the order.
|
|
43
|
+
|
|
44
|
+
repair drop R2
|
|
45
|
+
One repair is to drop R2 and keep R1 and R3 as written.
|
|
46
|
+
When an order is submitted, the Order System shall accept the order.
|
|
47
|
+
When an order is submitted, the Order System shall not ship the order.
|
|
48
|
+
|
|
49
|
+
repair drop R3
|
|
50
|
+
One repair is to drop R3 and keep R1 and R2 as written.
|
|
51
|
+
When an order is submitted, the Order System shall accept the order.
|
|
52
|
+
When the order is accepted, the Order System shall ship the order.
|
|
53
|
+
|
|
54
|
+
repair strengthen R2
|
|
55
|
+
One repair is to add "and an order is not submitted" to the condition of R2. R1 and R3 stay as written.
|
|
56
|
+
When the order is accepted and an order is not submitted, the Order System shall ship the order.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1
|
|
File without changes
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
spec: examples/checkout.ears.md
|
|
2
|
+
conflicts: 3
|
|
3
|
+
gaps: 2
|
|
4
|
+
misuse: 0
|
|
5
|
+
wording: 0
|
|
6
|
+
redundant: 23
|
|
7
|
+
duplicate: 0
|
|
8
|
+
vacuous: 0
|
|
9
|
+
unused: 0
|
|
10
|
+
|
|
11
|
+
conflict {R8, R12, R14}
|
|
12
|
+
R8, R12, and R14 cannot all hold.
|
|
13
|
+
|
|
14
|
+
R8 line 32
|
|
15
|
+
When the customer is subscribing and the customer is not cancelling and the customer is signed in, the Checkout shall start the subscription.
|
|
16
|
+
|
|
17
|
+
R12 line 36
|
|
18
|
+
When the subscription is started, the Checkout shall route the order to the fulfill lane.
|
|
19
|
+
|
|
20
|
+
R14 line 38
|
|
21
|
+
When the customer is subscribing, the Checkout shall route the order to the hold lane.
|
|
22
|
+
|
|
23
|
+
They clash when the cart was not open, an item was not added, checkout was not started, payment was not submitted, payment was not declined, the address was not confirmed, the customer was subscribing, the customer was not cancelling, the customer was signed in, a card was not saved, and stock was not available.
|
|
24
|
+
R8 requires that the subscription was started.
|
|
25
|
+
R14 requires that the order was routed to the hold lane.
|
|
26
|
+
|
|
27
|
+
Example scenario:
|
|
28
|
+
{
|
|
29
|
+
"cart_opened": false,
|
|
30
|
+
"item_added": false,
|
|
31
|
+
"checkout_started": false,
|
|
32
|
+
"payment_submitted": false,
|
|
33
|
+
"payment_declined": false,
|
|
34
|
+
"address_confirmed": false,
|
|
35
|
+
"subscribe_clicked": true,
|
|
36
|
+
"cancel_requested": false,
|
|
37
|
+
"signed_in": true,
|
|
38
|
+
"card_saved": false,
|
|
39
|
+
"stock_ok": false,
|
|
40
|
+
"order_accepted": false,
|
|
41
|
+
"order_rejected": false,
|
|
42
|
+
"subscription_started": true,
|
|
43
|
+
"receipt_sent": false,
|
|
44
|
+
"lane": "fulfill",
|
|
45
|
+
"billed_seats": 1
|
|
46
|
+
}
|
|
47
|
+
This scenario keeps R8 and R12 and breaks R14.
|
|
48
|
+
|
|
49
|
+
Suggested fix: ask which requirement should win. Removing any one of R8, R12, and R14 leaves the rest consistent.
|
|
50
|
+
|
|
51
|
+
Candidate repairs follow. This report does not choose one.
|
|
52
|
+
|
|
53
|
+
repair drop R8
|
|
54
|
+
One repair is to drop R8 and keep R12 and R14 as written.
|
|
55
|
+
When the subscription is started, the Checkout shall route the order to the fulfill lane.
|
|
56
|
+
When the customer is subscribing, the Checkout shall route the order to the hold lane.
|
|
57
|
+
|
|
58
|
+
repair drop R12
|
|
59
|
+
One repair is to drop R12 and keep R8 and R14 as written.
|
|
60
|
+
When the customer is subscribing and the customer is not cancelling and the customer is signed in, the Checkout shall start the subscription.
|
|
61
|
+
When the customer is subscribing, the Checkout shall route the order to the hold lane.
|
|
62
|
+
|
|
63
|
+
repair drop R14
|
|
64
|
+
One repair is to drop R14 and keep R8 and R12 as written.
|
|
65
|
+
When the customer is subscribing and the customer is not cancelling and the customer is signed in, the Checkout shall start the subscription.
|
|
66
|
+
When the subscription is started, the Checkout shall route the order to the fulfill lane.
|
|
67
|
+
|
|
68
|
+
repair strengthen R12
|
|
69
|
+
One repair is to add "and the customer is not subscribing" to the condition of R12. R8 and R14 stay as written.
|
|
70
|
+
When the subscription is started and the customer is not subscribing, the Checkout shall route the order to the fulfill lane.
|
|
71
|
+
|
|
72
|
+
repair strengthen R12
|
|
73
|
+
One repair is to add "and the customer is cancelling" to the condition of R12. R8 and R14 stay as written.
|
|
74
|
+
When the subscription is started and the customer is cancelling, the Checkout shall route the order to the fulfill lane.
|
|
75
|
+
|
|
76
|
+
repair strengthen R12
|
|
77
|
+
One repair is to add "and the customer is not signed in" to the condition of R12. R8 and R14 stay as written.
|
|
78
|
+
When the subscription is started and the customer is not signed in, the Checkout shall route the order to the fulfill lane.
|
|
79
|
+
|
|
80
|
+
repair strengthen R14
|
|
81
|
+
One repair is to add "and the customer is cancelling" to the condition of R14. R8 and R12 stay as written.
|
|
82
|
+
When the customer is subscribing and the customer is cancelling, the Checkout shall route the order to the hold lane.
|
|
83
|
+
|
|
84
|
+
repair strengthen R14
|
|
85
|
+
One repair is to add "and the customer is not signed in" to the condition of R14. R8 and R12 stay as written.
|
|
86
|
+
When the customer is subscribing and the customer is not signed in, the Checkout shall route the order to the hold lane.
|
|
87
|
+
|
|
88
|
+
conflict {R1, R4}
|
|
89
|
+
R1 and R4 cannot both hold.
|
|
90
|
+
|
|
91
|
+
R1 line 25
|
|
92
|
+
When payment is submitted and the address is confirmed, the Checkout shall accept the order.
|
|
93
|
+
|
|
94
|
+
R4 line 28
|
|
95
|
+
When payment is submitted and the address is confirmed, the Checkout shall not accept the order.
|
|
96
|
+
|
|
97
|
+
They clash when the cart was not open, an item was not added, checkout was not started, payment was submitted, payment was not declined, the address was confirmed, the customer was not subscribing, the customer was not cancelling, the customer was not signed in, a card was not saved, and stock was not available.
|
|
98
|
+
R1 requires that the order was accepted.
|
|
99
|
+
R4 requires that the order was not accepted.
|
|
100
|
+
|
|
101
|
+
Example scenario:
|
|
102
|
+
{
|
|
103
|
+
"cart_opened": false,
|
|
104
|
+
"item_added": false,
|
|
105
|
+
"checkout_started": false,
|
|
106
|
+
"payment_submitted": true,
|
|
107
|
+
"payment_declined": false,
|
|
108
|
+
"address_confirmed": true,
|
|
109
|
+
"subscribe_clicked": false,
|
|
110
|
+
"cancel_requested": false,
|
|
111
|
+
"signed_in": false,
|
|
112
|
+
"card_saved": false,
|
|
113
|
+
"stock_ok": false,
|
|
114
|
+
"order_accepted": true,
|
|
115
|
+
"order_rejected": false,
|
|
116
|
+
"subscription_started": false,
|
|
117
|
+
"receipt_sent": false,
|
|
118
|
+
"lane": "hold",
|
|
119
|
+
"billed_seats": 1
|
|
120
|
+
}
|
|
121
|
+
This scenario keeps R1 and breaks R4.
|
|
122
|
+
|
|
123
|
+
Suggested fix: ask which requirement should win. To keep R1, remove R4. To keep R4, remove R1.
|
|
124
|
+
|
|
125
|
+
Candidate repairs follow. This report does not choose one.
|
|
126
|
+
|
|
127
|
+
repair drop R1
|
|
128
|
+
One repair is to drop R1 and keep R4 as written.
|
|
129
|
+
When payment is submitted and the address is confirmed, the Checkout shall not accept the order.
|
|
130
|
+
|
|
131
|
+
repair drop R4
|
|
132
|
+
One repair is to drop R4 and keep R1 as written.
|
|
133
|
+
When payment is submitted and the address is confirmed, the Checkout shall accept the order.
|
|
134
|
+
|
|
135
|
+
conflict {R15, R16}
|
|
136
|
+
R15 and R16 cannot both hold.
|
|
137
|
+
|
|
138
|
+
R15 line 39
|
|
139
|
+
When checkout is started and stock is available, the Checkout shall bill at most 2 seats.
|
|
140
|
+
|
|
141
|
+
R16 line 40
|
|
142
|
+
When checkout is started and stock is available, the Checkout shall bill 3 seats.
|
|
143
|
+
|
|
144
|
+
They clash when the cart was not open, an item was not added, checkout was started, payment was not submitted, payment was not declined, the address was not confirmed, the customer was not subscribing, the customer was not cancelling, the customer was not signed in, a card was not saved, and stock was available.
|
|
145
|
+
R15 requires that at most 2 seats were billed.
|
|
146
|
+
R16 requires that 3 seats were billed.
|
|
147
|
+
|
|
148
|
+
Example scenario:
|
|
149
|
+
{
|
|
150
|
+
"cart_opened": false,
|
|
151
|
+
"item_added": false,
|
|
152
|
+
"checkout_started": true,
|
|
153
|
+
"payment_submitted": false,
|
|
154
|
+
"payment_declined": false,
|
|
155
|
+
"address_confirmed": false,
|
|
156
|
+
"subscribe_clicked": false,
|
|
157
|
+
"cancel_requested": false,
|
|
158
|
+
"signed_in": false,
|
|
159
|
+
"card_saved": false,
|
|
160
|
+
"stock_ok": true,
|
|
161
|
+
"order_accepted": false,
|
|
162
|
+
"order_rejected": false,
|
|
163
|
+
"subscription_started": false,
|
|
164
|
+
"receipt_sent": false,
|
|
165
|
+
"lane": "hold",
|
|
166
|
+
"billed_seats": 1
|
|
167
|
+
}
|
|
168
|
+
This scenario keeps R15 and breaks R16.
|
|
169
|
+
|
|
170
|
+
Suggested fix: ask which requirement should win. To keep R15, remove R16. To keep R16, remove R15.
|
|
171
|
+
|
|
172
|
+
Candidate repairs follow. This report does not choose one.
|
|
173
|
+
|
|
174
|
+
repair drop R15
|
|
175
|
+
One repair is to drop R15 and keep R16 as written.
|
|
176
|
+
When checkout is started and stock is available, the Checkout shall bill 3 seats.
|
|
177
|
+
|
|
178
|
+
repair drop R16
|
|
179
|
+
One repair is to drop R16 and keep R15 as written.
|
|
180
|
+
When checkout is started and stock is available, the Checkout shall bill at most 2 seats.
|
|
181
|
+
|
|
182
|
+
gap receipt_sent
|
|
183
|
+
Nothing says whether a receipt was sent when the cart was open, an item was added, checkout was started, payment was submitted, payment was declined, the address was not confirmed, the customer was subscribing, the customer was cancelling, the customer was signed in, a card was saved, and stock was available. Suggested fix: add a requirement for this situation, and ask what the system shall do. Do not choose the response.
|
|
184
|
+
|
|
185
|
+
gap billed_seats
|
|
186
|
+
Nothing covers the billed seats when the cart was open, an item was added, checkout was started, payment was submitted, payment was declined, the address was confirmed, the customer was subscribing, the customer was cancelling, the customer was signed in, a card was saved, and stock was not available. Suggested fix: add a requirement for this situation, and ask what the system shall do. Do not choose the response.
|
|
187
|
+
|
|
188
|
+
redundant R10 line 34
|
|
189
|
+
R10 adds nothing. Whenever the requirements outside a conflict hold, R10 holds too.
|
|
190
|
+
When the customer is cancelling, the Checkout shall not start the subscription.
|
|
191
|
+
Suggested fix: remove R10, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
192
|
+
|
|
193
|
+
redundant R25 line 49
|
|
194
|
+
R25 adds nothing. Whenever the requirements outside a conflict hold, R25 holds too.
|
|
195
|
+
When payment is submitted and the address is not confirmed and the customer is signed in, the Checkout shall not accept the order.
|
|
196
|
+
Suggested fix: remove R25, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
197
|
+
|
|
198
|
+
redundant R26 line 50
|
|
199
|
+
R26 adds nothing. Whenever the requirements outside a conflict hold, R26 holds too.
|
|
200
|
+
When payment is submitted and the address is not confirmed and the cart is open, the Checkout shall not accept the order.
|
|
201
|
+
Suggested fix: remove R26, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
202
|
+
|
|
203
|
+
redundant R27 line 51
|
|
204
|
+
R27 adds nothing. Whenever the requirements outside a conflict hold, R27 holds too.
|
|
205
|
+
When payment is submitted and the address is not confirmed and an item is added, the Checkout shall not accept the order.
|
|
206
|
+
Suggested fix: remove R27, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
207
|
+
|
|
208
|
+
redundant R28 line 52
|
|
209
|
+
R28 adds nothing. Whenever the requirements outside a conflict hold, R28 holds too.
|
|
210
|
+
When payment is submitted and the address is not confirmed and a card is saved, the Checkout shall not accept the order.
|
|
211
|
+
Suggested fix: remove R28, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
212
|
+
|
|
213
|
+
redundant R29 line 53
|
|
214
|
+
R29 adds nothing. Whenever the requirements outside a conflict hold, R29 holds too.
|
|
215
|
+
When payment is not submitted and the cart is open, the Checkout shall not accept the order.
|
|
216
|
+
Suggested fix: remove R29, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
217
|
+
|
|
218
|
+
redundant R30 line 54
|
|
219
|
+
R30 adds nothing. Whenever the requirements outside a conflict hold, R30 holds too.
|
|
220
|
+
When payment is not submitted and an item is added, the Checkout shall not accept the order.
|
|
221
|
+
Suggested fix: remove R30, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
222
|
+
|
|
223
|
+
redundant R31 line 55
|
|
224
|
+
R31 adds nothing. Whenever the requirements outside a conflict hold, R31 holds too.
|
|
225
|
+
When payment is not submitted and checkout is started, the Checkout shall not accept the order.
|
|
226
|
+
Suggested fix: remove R31, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
227
|
+
|
|
228
|
+
redundant R32 line 56
|
|
229
|
+
R32 adds nothing. Whenever the requirements outside a conflict hold, R32 holds too.
|
|
230
|
+
When payment is not submitted and the customer is signed in, the Checkout shall not accept the order.
|
|
231
|
+
Suggested fix: remove R32, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
232
|
+
|
|
233
|
+
redundant R33 line 57
|
|
234
|
+
R33 adds nothing. Whenever the requirements outside a conflict hold, R33 holds too.
|
|
235
|
+
When payment is not submitted and a card is saved, the Checkout shall not accept the order.
|
|
236
|
+
Suggested fix: remove R33, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
237
|
+
|
|
238
|
+
redundant R34 line 58
|
|
239
|
+
R34 adds nothing. Whenever the requirements outside a conflict hold, R34 holds too.
|
|
240
|
+
When payment is not submitted and stock is available, the Checkout shall not accept the order.
|
|
241
|
+
Suggested fix: remove R34, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
242
|
+
|
|
243
|
+
redundant R35 line 59
|
|
244
|
+
R35 adds nothing. Whenever the requirements outside a conflict hold, R35 holds too.
|
|
245
|
+
When payment is not submitted and the customer is subscribing, the Checkout shall not accept the order.
|
|
246
|
+
Suggested fix: remove R35, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
247
|
+
|
|
248
|
+
redundant R39 line 63
|
|
249
|
+
R39 adds nothing. Whenever the requirements outside a conflict hold, R39 holds too.
|
|
250
|
+
When the customer is subscribing and the customer is cancelling, the Checkout shall not start the subscription.
|
|
251
|
+
Suggested fix: remove R39, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
252
|
+
|
|
253
|
+
redundant R40 line 64
|
|
254
|
+
R40 adds nothing. Whenever the requirements outside a conflict hold, R40 holds too.
|
|
255
|
+
When the customer is cancelling and the cart is open, the Checkout shall not start the subscription.
|
|
256
|
+
Suggested fix: remove R40, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
257
|
+
|
|
258
|
+
redundant R41 line 65
|
|
259
|
+
R41 adds nothing. Whenever the requirements outside a conflict hold, R41 holds too.
|
|
260
|
+
When the customer is cancelling and an item is added, the Checkout shall not start the subscription.
|
|
261
|
+
Suggested fix: remove R41, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
262
|
+
|
|
263
|
+
redundant R42 line 66
|
|
264
|
+
R42 adds nothing. Whenever the requirements outside a conflict hold, R42 holds too.
|
|
265
|
+
When the customer is not subscribing and the cart is open, the Checkout shall not start the subscription.
|
|
266
|
+
Suggested fix: remove R42, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
267
|
+
|
|
268
|
+
redundant R43 line 67
|
|
269
|
+
R43 adds nothing. Whenever the requirements outside a conflict hold, R43 holds too.
|
|
270
|
+
When the customer is not subscribing and an item is added, the Checkout shall not start the subscription.
|
|
271
|
+
Suggested fix: remove R43, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
272
|
+
|
|
273
|
+
redundant R44 line 68
|
|
274
|
+
R44 adds nothing. Whenever the requirements outside a conflict hold, R44 holds too.
|
|
275
|
+
When the customer is not subscribing and a card is saved, the Checkout shall not start the subscription.
|
|
276
|
+
Suggested fix: remove R44, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
277
|
+
|
|
278
|
+
redundant R45 line 69
|
|
279
|
+
R45 adds nothing. Whenever the requirements outside a conflict hold, R45 holds too.
|
|
280
|
+
When the customer is subscribing and the customer is not cancelling and the customer is not signed in and the cart is open, the Checkout shall not start the subscription.
|
|
281
|
+
Suggested fix: remove R45, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
282
|
+
|
|
283
|
+
redundant R46 line 70
|
|
284
|
+
R46 adds nothing. Whenever the requirements outside a conflict hold, R46 holds too.
|
|
285
|
+
When the subscription is not started and the cart is open, the Checkout shall route the order to the hold lane.
|
|
286
|
+
Suggested fix: remove R46, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
287
|
+
|
|
288
|
+
redundant R47 line 71
|
|
289
|
+
R47 adds nothing. Whenever the requirements outside a conflict hold, R47 holds too.
|
|
290
|
+
When the subscription is not started and an item is added, the Checkout shall route the order to the hold lane.
|
|
291
|
+
Suggested fix: remove R47, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
292
|
+
|
|
293
|
+
redundant R49 line 73
|
|
294
|
+
R49 adds nothing. Whenever the requirements outside a conflict hold, R49 holds too.
|
|
295
|
+
When payment is submitted and the address is confirmed and the customer is signed in, the Checkout shall send a receipt.
|
|
296
|
+
Suggested fix: remove R49, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
297
|
+
|
|
298
|
+
redundant R50 line 74
|
|
299
|
+
R50 adds nothing. Whenever the requirements outside a conflict hold, R50 holds too.
|
|
300
|
+
When payment is submitted and the address is confirmed and the cart is open, the Checkout shall send a receipt.
|
|
301
|
+
Suggested fix: remove R50, or ask whether it was meant to say something the others do not already require. Do not delete it until the PM agrees.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0
|
|
File without changes
|