@suss/checker-intent 0.34.1 → 0.35.1

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/dist/index.cjs CHANGED
@@ -73,12 +73,19 @@ function checkCoveringTests(claims, lookup) {
73
73
  }
74
74
  const honouring = lookup.facts.reachedFromEach(
75
75
  waiting.map((one) => one.test),
76
- { pastMocks: true }
76
+ { pastMocks: true, certainOnly: true }
77
77
  );
78
78
  const missed = waiting.filter(
79
79
  (one) => pathInto(one.test, honouring.get(one.test), one.subject) === null && callOnSubjectClass(one.test, one.subject, lookup, true) === null
80
80
  );
81
- const ignoring = missed.length === 0 ? /* @__PURE__ */ new Map() : lookup.facts.reachedFromEach(missed.map((one) => one.test));
81
+ const ignoring = missed.length === 0 ? /* @__PURE__ */ new Map() : lookup.facts.reachedFromEach(
82
+ missed.map((one) => one.test),
83
+ { certainOnly: true }
84
+ );
85
+ const possibly = missed.length === 0 ? /* @__PURE__ */ new Map() : lookup.facts.reachedFromEach(
86
+ missed.map((one) => one.test),
87
+ { pastMocks: true }
88
+ );
82
89
  for (const one of waiting) {
83
90
  const claim = claims[one.at];
84
91
  if (!missed.includes(one)) {
@@ -95,6 +102,15 @@ function checkCoveringTests(claims, lookup) {
95
102
  );
96
103
  continue;
97
104
  }
105
+ const throughPossible = pathInto(
106
+ one.test,
107
+ possibly.get(one.test),
108
+ one.subject
109
+ );
110
+ if (throughPossible !== null) {
111
+ verdicts[one.at] = reachesOnlyMaybe(claim, one.subject, throughPossible);
112
+ continue;
113
+ }
98
114
  const unfollowed = unfollowedOnTheWay(one.unit, one.test, reached, lookup);
99
115
  const nameMatches = unfollowedToSubject(one.unit, one.subject, lookup);
100
116
  verdicts[one.at] = unfollowed.length === 0 && nameMatches.length === 0 ? finding(
@@ -122,6 +138,19 @@ function notChecked(claim, subject, nameMatches, unfollowed) {
122
138
  }
123
139
  };
124
140
  }
141
+ function reachesOnlyMaybe(claim, subject, path) {
142
+ const choosing = path.find((hop) => hop.recorded === "possible");
143
+ return {
144
+ kind: "unchecked",
145
+ unchecked: {
146
+ intent: claim.prd.title,
147
+ reason: "possibleCall",
148
+ scenario: claim.label,
149
+ coveredBy: claim.spelled.spelledAs,
150
+ detail: `Scenario ${claim.label} lists the test "${claim.spelled.spelledAs}": it reaches ${subject.label} only through ${choosing?.callee ?? "a call"}, which picks one of several functions at run time, so suss cannot say the test runs it (${(0, import_checker.callSpellings)(path).join(" -> ")}).`
151
+ }
152
+ };
153
+ }
125
154
  function unfollowedOnTheWay(test, key, reached, lookup) {
126
155
  const units = [
127
156
  test,
package/dist/index.d.cts CHANGED
@@ -125,7 +125,7 @@ type CheckedIntent = CheckedBoundaryIntent | CheckedPrd;
125
125
  interface UncheckedIntent {
126
126
  /** The intent doc's `name` (boundary) or `title` (prd). */
127
127
  intent: string;
128
- reason: "unkeyable" | "unreadValue" | "unfollowedCall";
128
+ reason: "unkeyable" | "unreadValue" | "unfollowedCall" | "possibleCall";
129
129
  /** The outcome the claim is on, for a claim narrower than the document. */
130
130
  outcomeId?: string;
131
131
  /** The scenario the claim is on, by its title or its position, for a covering test. */
package/dist/index.d.ts CHANGED
@@ -125,7 +125,7 @@ type CheckedIntent = CheckedBoundaryIntent | CheckedPrd;
125
125
  interface UncheckedIntent {
126
126
  /** The intent doc's `name` (boundary) or `title` (prd). */
127
127
  intent: string;
128
- reason: "unkeyable" | "unreadValue" | "unfollowedCall";
128
+ reason: "unkeyable" | "unreadValue" | "unfollowedCall" | "possibleCall";
129
129
  /** The outcome the claim is on, for a claim narrower than the document. */
130
130
  outcomeId?: string;
131
131
  /** The scenario the claim is on, by its title or its position, for a covering test. */
package/dist/index.js CHANGED
@@ -65,12 +65,19 @@ function checkCoveringTests(claims, lookup) {
65
65
  }
66
66
  const honouring = lookup.facts.reachedFromEach(
67
67
  waiting.map((one) => one.test),
68
- { pastMocks: true }
68
+ { pastMocks: true, certainOnly: true }
69
69
  );
70
70
  const missed = waiting.filter(
71
71
  (one) => pathInto(one.test, honouring.get(one.test), one.subject) === null && callOnSubjectClass(one.test, one.subject, lookup, true) === null
72
72
  );
73
- const ignoring = missed.length === 0 ? /* @__PURE__ */ new Map() : lookup.facts.reachedFromEach(missed.map((one) => one.test));
73
+ const ignoring = missed.length === 0 ? /* @__PURE__ */ new Map() : lookup.facts.reachedFromEach(
74
+ missed.map((one) => one.test),
75
+ { certainOnly: true }
76
+ );
77
+ const possibly = missed.length === 0 ? /* @__PURE__ */ new Map() : lookup.facts.reachedFromEach(
78
+ missed.map((one) => one.test),
79
+ { pastMocks: true }
80
+ );
74
81
  for (const one of waiting) {
75
82
  const claim = claims[one.at];
76
83
  if (!missed.includes(one)) {
@@ -87,6 +94,15 @@ function checkCoveringTests(claims, lookup) {
87
94
  );
88
95
  continue;
89
96
  }
97
+ const throughPossible = pathInto(
98
+ one.test,
99
+ possibly.get(one.test),
100
+ one.subject
101
+ );
102
+ if (throughPossible !== null) {
103
+ verdicts[one.at] = reachesOnlyMaybe(claim, one.subject, throughPossible);
104
+ continue;
105
+ }
90
106
  const unfollowed = unfollowedOnTheWay(one.unit, one.test, reached, lookup);
91
107
  const nameMatches = unfollowedToSubject(one.unit, one.subject, lookup);
92
108
  verdicts[one.at] = unfollowed.length === 0 && nameMatches.length === 0 ? finding(
@@ -114,6 +130,19 @@ function notChecked(claim, subject, nameMatches, unfollowed) {
114
130
  }
115
131
  };
116
132
  }
133
+ function reachesOnlyMaybe(claim, subject, path) {
134
+ const choosing = path.find((hop) => hop.recorded === "possible");
135
+ return {
136
+ kind: "unchecked",
137
+ unchecked: {
138
+ intent: claim.prd.title,
139
+ reason: "possibleCall",
140
+ scenario: claim.label,
141
+ coveredBy: claim.spelled.spelledAs,
142
+ detail: `Scenario ${claim.label} lists the test "${claim.spelled.spelledAs}": it reaches ${subject.label} only through ${choosing?.callee ?? "a call"}, which picks one of several functions at run time, so suss cannot say the test runs it (${callSpellings(path).join(" -> ")}).`
143
+ }
144
+ };
145
+ }
117
146
  function unfollowedOnTheWay(test, key, reached, lookup) {
118
147
  const units = [
119
148
  test,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/checker-intent",
3
- "version": "0.34.1",
3
+ "version": "0.35.1",
4
4
  "type": "module",
5
5
  "description": "Compare the intent your team wrote down against what suss read out of the code, and report where the two have drifted apart.",
6
6
  "keywords": [
@@ -49,10 +49,10 @@
49
49
  "zod": "^4.0.0"
50
50
  },
51
51
  "dependencies": {
52
- "@suss/behavioral-ir": "0.34.1",
53
- "@suss/checker": "0.34.1",
54
- "@suss/intent-ir": "0.34.1",
55
- "@suss/ir-core": "0.34.1"
52
+ "@suss/behavioral-ir": "0.35.1",
53
+ "@suss/checker": "0.35.1",
54
+ "@suss/intent-ir": "0.35.1",
55
+ "@suss/ir-core": "0.35.1"
56
56
  },
57
57
  "devDependencies": {
58
58
  "tsup": "*",