fullstackgtm 0.15.0 → 0.17.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/src/resolve.ts CHANGED
@@ -118,30 +118,50 @@ function resolveDeal(snapshot: CanonicalGtmSnapshot, c: ResolveCandidate): Resol
118
118
  if (!c.name) {
119
119
  return { ...base, verdict: "ambiguous", matches: [], reason: "Supply --name (and ideally --account-id) to resolve a deal." };
120
120
  }
121
- const key = `${c.accountId ?? "unlinked"}:${normalizeName(c.name)}`;
121
+ const nameKey = normalizeName(c.name);
122
122
  const open = snapshot.deals.filter((d) => d.isClosed !== true && d.isWon !== true);
123
- const matches = open
124
- .filter((d) => `${d.accountId ?? "unlinked"}:${normalizeName(d.name)}` === key)
125
- .map((d) => match(d.id, d.name, "deal_key", `open deal with the same name on ${c.accountId ? `account ${c.accountId}` : "no account"}`));
126
- if (matches.length > 0) {
123
+ if (c.accountId) {
124
+ const key = `${c.accountId}:${nameKey}`;
125
+ const matches = open
126
+ .filter((d) => `${d.accountId ?? "unlinked"}:${normalizeName(d.name)}` === key)
127
+ .map((d) => match(d.id, d.name, "deal_key", `open deal with the same name on account ${c.accountId}`));
128
+ if (matches.length > 0) {
129
+ return {
130
+ ...base,
131
+ verdict: "exists",
132
+ matches,
133
+ reason: `${matches.length} open deal(s) already match "${c.name}" on account ${c.accountId} — creating another would double-count pipeline. Update the existing deal.`,
134
+ };
135
+ }
136
+ const closedSameName = snapshot.deals.filter(
137
+ (d) =>
138
+ (d.isClosed === true || d.isWon === true) &&
139
+ d.accountId === c.accountId &&
140
+ normalizeName(d.name) === nameKey,
141
+ );
142
+ return {
143
+ ...base,
144
+ verdict: "safe_to_create",
145
+ matches: [],
146
+ reason: closedSameName.length > 0
147
+ ? `No open deal matches on account ${c.accountId}; ${closedSameName.length} closed deal(s) on it share the name (a re-open/renewal may be intended). Safe to create.`
148
+ : `No open deal matches "${c.name}" on account ${c.accountId}. Safe to create.`,
149
+ };
150
+ }
151
+ // No account scope: name-only matches across ALL open deals are ambiguous,
152
+ // never safe — a gate that ignores name collisions protects nobody.
153
+ const sameName = open
154
+ .filter((d) => normalizeName(d.name) === nameKey)
155
+ .map((d) => match(d.id, d.name, "name", `open deal with the same name on ${d.accountId ? `account ${d.accountId}` : "no account"}`));
156
+ if (sameName.length > 0) {
127
157
  return {
128
158
  ...base,
129
- verdict: "exists",
130
- matches,
131
- reason: `${matches.length} open deal(s) already match "${c.name}" on ${c.accountId ? `account ${c.accountId}` : "unlinked"} creating another would double-count pipeline. Update the existing deal.`,
159
+ verdict: "ambiguous",
160
+ matches: sameName,
161
+ reason: `${sameName.length} open deal(s) named "${c.name}" exist (no --account-id supplied to scope the check). Confirm before creating supply --account-id to resolve definitively.`,
132
162
  };
133
163
  }
134
- const closedSameName = snapshot.deals.filter(
135
- (d) => (d.isClosed === true || d.isWon === true) && normalizeName(d.name) === normalizeName(c.name!),
136
- );
137
- return {
138
- ...base,
139
- verdict: "safe_to_create",
140
- matches: [],
141
- reason: closedSameName.length > 0
142
- ? `No open deal matches; ${closedSameName.length} closed deal(s) share the name (a re-open/renewal may be intended). Safe to create.`
143
- : `No open deal matches "${c.name}". Safe to create.`,
144
- };
164
+ return { ...base, verdict: "safe_to_create", matches: [], reason: `No open deal named "${c.name}" anywhere. Safe to create.` };
145
165
  }
146
166
 
147
167
  function contactName(row: { firstName?: string; lastName?: string }) {
package/src/types.ts CHANGED
@@ -34,6 +34,7 @@ export type GtmEvidenceSourceSystem =
34
34
  | "manual"
35
35
  | "csv"
36
36
  | "mock"
37
+ | "web"
37
38
  | "unknown";
38
39
 
39
40
  export type PatchOperationType =