@zzzen/pyright-internal 1.2.0-dev.20260927 → 1.2.0-dev.20261011

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/dist/analyzer/analyzerNodeInfo.js +7 -2
  2. package/dist/analyzer/analyzerNodeInfo.js.map +1 -1
  3. package/dist/analyzer/binder.js +17 -6
  4. package/dist/analyzer/binder.js.map +1 -1
  5. package/dist/analyzer/checker.d.ts +0 -2
  6. package/dist/analyzer/checker.js +23 -47
  7. package/dist/analyzer/checker.js.map +1 -1
  8. package/dist/analyzer/codeFlowEngine.d.ts +2 -0
  9. package/dist/analyzer/codeFlowEngine.js +155 -18
  10. package/dist/analyzer/codeFlowEngine.js.map +1 -1
  11. package/dist/analyzer/codeFlowTypes.d.ts +2 -1
  12. package/dist/analyzer/codeFlowTypes.js +1 -0
  13. package/dist/analyzer/codeFlowTypes.js.map +1 -1
  14. package/dist/analyzer/codeFlowUtils.js +4 -1
  15. package/dist/analyzer/codeFlowUtils.js.map +1 -1
  16. package/dist/analyzer/constraintSolver.js +3 -2
  17. package/dist/analyzer/constraintSolver.js.map +1 -1
  18. package/dist/analyzer/operations.d.ts +2 -0
  19. package/dist/analyzer/operations.js +2 -1
  20. package/dist/analyzer/operations.js.map +1 -1
  21. package/dist/analyzer/parameterUtils.js +2 -1
  22. package/dist/analyzer/parameterUtils.js.map +1 -1
  23. package/dist/analyzer/patternMatching.js +80 -11
  24. package/dist/analyzer/patternMatching.js.map +1 -1
  25. package/dist/analyzer/program.js +4 -1
  26. package/dist/analyzer/program.js.map +1 -1
  27. package/dist/analyzer/properties.d.ts +2 -2
  28. package/dist/analyzer/properties.js +2 -2
  29. package/dist/analyzer/properties.js.map +1 -1
  30. package/dist/analyzer/protocols.d.ts +3 -1
  31. package/dist/analyzer/protocols.js +35 -5
  32. package/dist/analyzer/protocols.js.map +1 -1
  33. package/dist/analyzer/symbolNameUtils.d.ts +1 -0
  34. package/dist/analyzer/symbolNameUtils.js +5 -0
  35. package/dist/analyzer/symbolNameUtils.js.map +1 -1
  36. package/dist/analyzer/typeEvaluator.js +269 -32
  37. package/dist/analyzer/typeEvaluator.js.map +1 -1
  38. package/dist/analyzer/typeEvaluatorTypes.d.ts +4 -2
  39. package/dist/analyzer/typeEvaluatorTypes.js +4 -0
  40. package/dist/analyzer/typeEvaluatorTypes.js.map +1 -1
  41. package/dist/analyzer/typeGuards.js +208 -68
  42. package/dist/analyzer/typeGuards.js.map +1 -1
  43. package/dist/analyzer/typePrinter.js +32 -6
  44. package/dist/analyzer/typePrinter.js.map +1 -1
  45. package/dist/analyzer/typeUtils.d.ts +1 -0
  46. package/dist/analyzer/typeUtils.js +24 -2
  47. package/dist/analyzer/typeUtils.js.map +1 -1
  48. package/dist/analyzer/typedDicts.js +8 -4
  49. package/dist/analyzer/typedDicts.js.map +1 -1
  50. package/dist/analyzer/types.d.ts +2 -1
  51. package/dist/analyzer/types.js +9 -0
  52. package/dist/analyzer/types.js.map +1 -1
  53. package/dist/common/extensibility.d.ts +1 -0
  54. package/dist/common/processUtils.d.ts +9 -1
  55. package/dist/common/processUtils.js +52 -10
  56. package/dist/common/processUtils.js.map +1 -1
  57. package/dist/common/windowsProcessTree.d.ts +4 -0
  58. package/dist/common/windowsProcessTree.js +47 -0
  59. package/dist/common/windowsProcessTree.js.map +1 -0
  60. package/dist/common/windowsProcessTree.json +310 -0
  61. package/dist/languageService/callHierarchyProvider.js +12 -4
  62. package/dist/languageService/callHierarchyProvider.js.map +1 -1
  63. package/dist/localization/package.nls.pl.json +2 -2
  64. package/dist/localization/package.nls.pt-br.json +1 -1
  65. package/dist/localization/package.nls.zh-cn.json +2 -2
  66. package/dist/localization/package.nls.zh-tw.json +1 -1
  67. package/dist/tests/cacheManager.test.js +19 -15
  68. package/dist/tests/cacheManager.test.js.map +1 -1
  69. package/dist/tests/constraintSolver.test.d.ts +1 -0
  70. package/dist/tests/constraintSolver.test.js +39 -0
  71. package/dist/tests/constraintSolver.test.js.map +1 -0
  72. package/dist/tests/fourslash/findDefinitions.metaclass.fourslash.d.ts +1 -0
  73. package/dist/tests/fourslash/findDefinitions.metaclass.fourslash.js +44 -0
  74. package/dist/tests/fourslash/findDefinitions.metaclass.fourslash.js.map +1 -0
  75. package/dist/tests/fourslash/findDefinitions.metaclassDict.fourslash.d.ts +1 -0
  76. package/dist/tests/fourslash/findDefinitions.metaclassDict.fourslash.js +42 -0
  77. package/dist/tests/fourslash/findDefinitions.metaclassDict.fourslash.js.map +1 -0
  78. package/dist/tests/fourslash/hover.typedDictUnpacking.dictDisplay.fourslash.d.ts +1 -0
  79. package/dist/tests/fourslash/hover.typedDictUnpacking.dictDisplay.fourslash.js +16 -0
  80. package/dist/tests/fourslash/hover.typedDictUnpacking.dictDisplay.fourslash.js.map +1 -0
  81. package/dist/tests/mypyPrimerAnalysis.test.js +67 -11
  82. package/dist/tests/mypyPrimerAnalysis.test.js.map +1 -1
  83. package/dist/tests/mypyPrimerMcp.test.js +2 -1
  84. package/dist/tests/mypyPrimerMcp.test.js.map +1 -1
  85. package/dist/tests/service.test.js +36 -0
  86. package/dist/tests/service.test.js.map +1 -1
  87. package/dist/tests/typeEquality.test.js +85 -2
  88. package/dist/tests/typeEquality.test.js.map +1 -1
  89. package/dist/tests/typeEvaluator1.test.js +55 -2
  90. package/dist/tests/typeEvaluator1.test.js.map +1 -1
  91. package/dist/tests/typeEvaluator3.test.js +23 -0
  92. package/dist/tests/typeEvaluator3.test.js.map +1 -1
  93. package/dist/tests/typeEvaluator6.test.js +75 -1
  94. package/dist/tests/typeEvaluator6.test.js.map +1 -1
  95. package/dist/tests/typeEvaluator7.test.js +22 -0
  96. package/dist/tests/typeEvaluator7.test.js.map +1 -1
  97. package/dist/tests/typeEvaluator8.test.js +41 -0
  98. package/dist/tests/typeEvaluator8.test.js.map +1 -1
  99. package/dist/tests/typeServer/inProcTypeServerTestUtils.d.ts +7 -2
  100. package/dist/tests/typeServer/inProcTypeServerTestUtils.js +14 -7
  101. package/dist/tests/typeServer/inProcTypeServerTestUtils.js.map +1 -1
  102. package/dist/tests/typeServer/stubGenerator.test.js +29 -0
  103. package/dist/tests/typeServer/stubGenerator.test.js.map +1 -1
  104. package/dist/tests/typeServer/typeServer.inProc.test.js +87 -1
  105. package/dist/tests/typeServer/typeServer.inProc.test.js.map +1 -1
  106. package/dist/tests/typeServer/typeServer.virtualFileRedirect.test.js +15 -0
  107. package/dist/tests/typeServer/typeServer.virtualFileRedirect.test.js.map +1 -1
  108. package/dist/typeServer/stubGenerator.js +5 -6
  109. package/dist/typeServer/stubGenerator.js.map +1 -1
  110. package/dist/workspaceFactory.js +5 -0
  111. package/dist/workspaceFactory.js.map +1 -1
  112. package/package.json +3 -3
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ /*
3
+ * constraintSolver.test.ts
4
+ * Copyright (c) Microsoft Corporation.
5
+ * Licensed under the MIT license.
6
+ *
7
+ * Unit tests for the constraint solver.
8
+ */
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ const assert_1 = __importDefault(require("assert"));
14
+ const parseTreeUtils_1 = require("../analyzer/parseTreeUtils");
15
+ const types_1 = require("../analyzer/types");
16
+ const testState_1 = require("./harness/fourslash/testState");
17
+ test('Recursive source must satisfy the TypeVar bound without a constraint tracker', () => {
18
+ const code = `
19
+ // @filename: test.py
20
+ //// class Foo: ...
21
+ //// class Box[T]: ...
22
+ //// class FooBox[T](Foo): ...
23
+ ////
24
+ //// def /*marker*/func[T: Foo](dest: T, unrelated: Box[T], bounded: FooBox[T]) -> None: ...
25
+ `;
26
+ const state = (0, testState_1.parseAndGetTestState)(code).state;
27
+ const evaluator = state.program.evaluator;
28
+ const node = (0, testState_1.getNodeAtMarker)(state, 'marker');
29
+ (0, assert_1.default)(node.nodeType === 38 /* ParseNodeType.Name */);
30
+ const functionNode = (0, parseTreeUtils_1.getEnclosingFunction)(node);
31
+ (0, assert_1.default)(functionNode?.nodeType === 31 /* ParseNodeType.Function */);
32
+ const functionType = evaluator.getTypeOfFunction(functionNode)?.functionType;
33
+ (0, assert_1.default)(functionType);
34
+ const [destType, unrelatedType, boundedType] = [0, 1, 2].map((index) => types_1.FunctionType.getParamType(functionType, index));
35
+ (0, assert_1.default)((0, types_1.isTypeVar)(destType) && !types_1.TypeVarType.isBound(destType));
36
+ assert_1.default.strictEqual(evaluator.assignType(destType, unrelatedType), false);
37
+ assert_1.default.strictEqual(evaluator.assignType(destType, boundedType), true);
38
+ });
39
+ //# sourceMappingURL=constraintSolver.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constraintSolver.test.js","sourceRoot":"","sources":["../../../../../src/tests/constraintSolver.test.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;;AAEH,oDAA4B;AAE5B,+DAAkE;AAClE,6CAAyE;AAEzE,6DAAsF;AAEtF,IAAI,CAAC,8EAA8E,EAAE,GAAG,EAAE;IACtF,MAAM,IAAI,GAAG;;;;;;;KAOZ,CAAC;IAEF,MAAM,KAAK,GAAG,IAAA,gCAAoB,EAAC,IAAI,CAAC,CAAC,KAAK,CAAC;IAC/C,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,SAAU,CAAC;IAE3C,MAAM,IAAI,GAAG,IAAA,2BAAe,EAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC9C,IAAA,gBAAM,EAAC,IAAI,CAAC,QAAQ,gCAAuB,CAAC,CAAC;IAE7C,MAAM,YAAY,GAAG,IAAA,qCAAoB,EAAC,IAAI,CAAC,CAAC;IAChD,IAAA,gBAAM,EAAC,YAAY,EAAE,QAAQ,oCAA2B,CAAC,CAAC;IAE1D,MAAM,YAAY,GAAG,SAAS,CAAC,iBAAiB,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC7E,IAAA,gBAAM,EAAC,YAAY,CAAC,CAAC;IAErB,MAAM,CAAC,QAAQ,EAAE,aAAa,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACnE,oBAAY,CAAC,YAAY,CAAC,YAAY,EAAE,KAAK,CAAC,CACjD,CAAC;IACF,IAAA,gBAAM,EAAC,IAAA,iBAAS,EAAC,QAAQ,CAAC,IAAI,CAAC,mBAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE9D,gBAAM,CAAC,WAAW,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC;IACzE,gBAAM,CAAC,WAAW,CAAC,SAAS,CAAC,UAAU,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC;AAC1E,CAAC,CAAC,CAAC"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /// <reference path="typings/fourslash.d.ts" />
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ // @filename: test.py
5
+ //// class Fields:
6
+ //// def install(self):
7
+ //// self.[|mixin_tag|]: str = "installed"
8
+ ////
9
+ //// class Meta(type, Fields):
10
+ //// def __init__(cls, name, bases, namespace):
11
+ //// cls.[|tag|]: str = "created"
12
+ //// cls.install()
13
+ ////
14
+ //// class Custom(metaclass=Meta):
15
+ //// pass
16
+ ////
17
+ //// class Derived(Custom):
18
+ //// pass
19
+ ////
20
+ //// def check(value: Custom, derived: Derived):
21
+ //// value.[|/*instance*/tag|]
22
+ //// derived.[|/*derived*/tag|]
23
+ //// Custom.[|/*classObject*/tag|]
24
+ //// value.[|/*mixinInstance*/mixin_tag|]
25
+ //// derived.[|/*mixinDerived*/mixin_tag|]
26
+ //// Custom.[|/*mixinClassObject*/mixin_tag|]
27
+ {
28
+ const definitions = (name) => helper
29
+ .getRangesByText()
30
+ .get(name)
31
+ .filter((r) => !r.marker)
32
+ .map((r) => {
33
+ return { path: r.fileName, range: helper.convertPositionRange(r) };
34
+ });
35
+ helper.verifyFindDefinitions({
36
+ instance: { definitions: definitions('tag') },
37
+ derived: { definitions: definitions('tag') },
38
+ classObject: { definitions: definitions('tag') },
39
+ mixinInstance: { definitions: definitions('mixin_tag') },
40
+ mixinDerived: { definitions: definitions('mixin_tag') },
41
+ mixinClassObject: { definitions: definitions('mixin_tag') },
42
+ });
43
+ }
44
+ //# sourceMappingURL=findDefinitions.metaclass.fourslash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findDefinitions.metaclass.fourslash.js","sourceRoot":"","sources":["../../../../../../src/tests/fourslash/findDefinitions.metaclass.fourslash.ts"],"names":[],"mappings":";AAAA,+CAA+C;;AAE/C,qBAAqB;AACrB,kBAAkB;AAClB,2BAA2B;AAC3B,kDAAkD;AAClD,IAAI;AACJ,8BAA8B;AAC9B,mDAAmD;AACnD,yCAAyC;AACzC,0BAA0B;AAC1B,IAAI;AACJ,kCAAkC;AAClC,aAAa;AACb,IAAI;AACJ,2BAA2B;AAC3B,aAAa;AACb,IAAI;AACJ,gDAAgD;AAChD,kCAAkC;AAClC,mCAAmC;AACnC,sCAAsC;AACtC,6CAA6C;AAC7C,8CAA8C;AAC9C,iDAAiD;AAEjD,CAAC;IACG,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CACjC,MAAM;SACD,eAAe,EAAE;SACjB,GAAG,CAAC,IAAI,CAAE;SACV,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;SACxB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACP,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC;IACvE,CAAC,CAAC,CAAC;IAEX,MAAM,CAAC,qBAAqB,CAAC;QACzB,QAAQ,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;QAC7C,OAAO,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;QAC5C,WAAW,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE;QAChD,aAAa,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,EAAE;QACxD,YAAY,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,EAAE;QACvD,gBAAgB,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,EAAE;KAC9D,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ /// <reference path="typings/fourslash.d.ts" />
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ // @filename: test.py
5
+ //// class Meta(type):
6
+ //// pass
7
+ ////
8
+ //// class Custom(metaclass=Meta):
9
+ //// pass
10
+ ////
11
+ //// class Derived(Custom):
12
+ //// pass
13
+ ////
14
+ //// def check(value: Custom, derived: Derived, meta: Meta):
15
+ //// value.[|/*instance*/__dict__|]
16
+ //// derived.[|/*derived*/__dict__|]
17
+ //// Custom.[|/*classObject*/__dict__|]
18
+ //// Derived.[|/*derivedClassObject*/__dict__|]
19
+ //// meta.[|/*metaclassInstance*/__dict__|]
20
+ // @filename: typeshed-fallback/stdlib/builtins.pyi
21
+ //// class object:
22
+ //// [|__dict__|]: object
23
+ ////
24
+ //// class type:
25
+ //// [|__dict__|]: object
26
+ {
27
+ const [instanceDefinition, classDefinition] = helper
28
+ .getRangesByText()
29
+ .get('__dict__')
30
+ .filter((r) => !r.marker)
31
+ .map((r) => {
32
+ return { path: r.fileName, range: helper.convertPositionRange(r) };
33
+ });
34
+ helper.verifyFindDefinitions({
35
+ instance: { definitions: [instanceDefinition] },
36
+ derived: { definitions: [instanceDefinition] },
37
+ classObject: { definitions: [classDefinition] },
38
+ derivedClassObject: { definitions: [classDefinition] },
39
+ metaclassInstance: { definitions: [classDefinition] },
40
+ });
41
+ }
42
+ //# sourceMappingURL=findDefinitions.metaclassDict.fourslash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findDefinitions.metaclassDict.fourslash.js","sourceRoot":"","sources":["../../../../../../src/tests/fourslash/findDefinitions.metaclassDict.fourslash.ts"],"names":[],"mappings":";AAAA,+CAA+C;;AAE/C,qBAAqB;AACrB,sBAAsB;AACtB,aAAa;AACb,IAAI;AACJ,kCAAkC;AAClC,aAAa;AACb,IAAI;AACJ,2BAA2B;AAC3B,aAAa;AACb,IAAI;AACJ,4DAA4D;AAC5D,uCAAuC;AACvC,wCAAwC;AACxC,2CAA2C;AAC3C,mDAAmD;AACnD,+CAA+C;AAE/C,mDAAmD;AACnD,kBAAkB;AAClB,6BAA6B;AAC7B,IAAI;AACJ,gBAAgB;AAChB,6BAA6B;AAE7B,CAAC;IACG,MAAM,CAAC,kBAAkB,EAAE,eAAe,CAAC,GAAG,MAAM;SAC/C,eAAe,EAAE;SACjB,GAAG,CAAC,UAAU,CAAE;SAChB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;SACxB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACP,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC;IACvE,CAAC,CAAC,CAAC;IAEP,MAAM,CAAC,qBAAqB,CAAC;QACzB,QAAQ,EAAE,EAAE,WAAW,EAAE,CAAC,kBAAkB,CAAC,EAAE;QAC/C,OAAO,EAAE,EAAE,WAAW,EAAE,CAAC,kBAAkB,CAAC,EAAE;QAC9C,WAAW,EAAE,EAAE,WAAW,EAAE,CAAC,eAAe,CAAC,EAAE;QAC/C,kBAAkB,EAAE,EAAE,WAAW,EAAE,CAAC,eAAe,CAAC,EAAE;QACtD,iBAAiB,EAAE,EAAE,WAAW,EAAE,CAAC,eAAe,CAAC,EAAE;KACxD,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ /// <reference path="typings/fourslash.d.ts" />
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ // @filename: test.py
5
+ //// from typing import TypedDict
6
+ ////
7
+ //// class User(TypedDict):
8
+ //// name: str
9
+ //// age: int
10
+ ////
11
+ //// user: User = {"name": "Alice", "age": 30}
12
+ //// [|/*marker1*/res|] = {**user}
13
+ helper.verifyHover('markdown', {
14
+ marker1: '```python\n(variable) res: dict[str, Unknown]\n```',
15
+ });
16
+ //# sourceMappingURL=hover.typedDictUnpacking.dictDisplay.fourslash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hover.typedDictUnpacking.dictDisplay.fourslash.js","sourceRoot":"","sources":["../../../../../../src/tests/fourslash/hover.typedDictUnpacking.dictDisplay.fourslash.ts"],"names":[],"mappings":";AAAA,+CAA+C;;AAE/C,qBAAqB;AACrB,iCAAiC;AACjC,IAAI;AACJ,2BAA2B;AAC3B,kBAAkB;AAClB,iBAAiB;AACjB,IAAI;AACJ,8CAA8C;AAC9C,kCAAkC;AAElC,MAAM,CAAC,WAAW,CAAC,UAAU,EAAE;IAC3B,OAAO,EAAE,oDAAoD;CAChE,CAAC,CAAC"}
@@ -216,7 +216,9 @@ function fixture(contents = sample, headRepository = repository) {
216
216
  head_branch: 'feature',
217
217
  pull_requests: source.pullRequests.map((number) => ({ number })),
218
218
  run_started_at: '2026-09-10T00:00:00Z',
219
+ display_title: '',
219
220
  };
221
+ const validation = { ...run, id: 41, path: '.github/workflows/validation.yml' };
220
222
  const artifacts = [
221
223
  'mypy_primer_diffs_pr_number',
222
224
  ...Array.from({ length: 8 }, (_, shard) => `mypy_primer_diffs_${shard}`),
@@ -225,7 +227,7 @@ function fixture(contents = sample, headRepository = repository) {
225
227
  const associated = [pr];
226
228
  const request = jest.fn(async (route, parameters) => {
227
229
  if (route === 'GET /repos/{owner}/{repo}/actions/runs/{run_id}') {
228
- return { data: run };
230
+ return { data: parameters.run_id === 41 ? validation : run };
229
231
  }
230
232
  if (route.endsWith('/artifacts')) {
231
233
  return { data: { artifacts } };
@@ -270,7 +272,7 @@ function fixture(contents = sample, headRepository = repository) {
270
272
  report: JSON.stringify(report),
271
273
  })),
272
274
  });
273
- return { source, manifest, pr, run, artifacts, comments, associated, request, report, output };
275
+ return { source, manifest, pr, run, validation, artifacts, comments, associated, request, report, output };
274
276
  }
275
277
  describe('mypy_primer analysis', () => {
276
278
  let directory;
@@ -412,6 +414,34 @@ describe('mypy_primer analysis', () => {
412
414
  f.run.run_attempt = 2;
413
415
  await expect((0, mypyPrimerAnalysis_1.loadSource)(f.request, repository, f.source)).rejects.toThrow('matching');
414
416
  });
417
+ test('uses the validated PR head for follow-up runs rather than the default branch', async () => {
418
+ const f = fixture(sample, 'contributor/pyright');
419
+ f.run.event = 'workflow_run';
420
+ f.run.display_title = 'Run mypy_primer after Validation #41';
421
+ f.run.head_sha = 'b'.repeat(40);
422
+ f.run.head_repository = { full_name: repository };
423
+ f.run.head_branch = 'main';
424
+ await expect((0, mypyPrimerAnalysis_1.loadSource)(f.request, repository, f.source)).resolves.toEqual(f.source);
425
+ });
426
+ test.each(['failure', 'cancelled'])('rejects unsuccessful %s source Validation', async (conclusion) => {
427
+ const f = fixture();
428
+ f.run.event = 'workflow_run';
429
+ f.run.display_title = 'Run mypy_primer after Validation #41';
430
+ f.validation.conclusion = conclusion;
431
+ await expect((0, mypyPrimerAnalysis_1.loadSource)(f.request, repository, f.source)).rejects.toThrow('successful pull request Validation');
432
+ });
433
+ test('rejects incorrect follow-up provenance', async () => {
434
+ const f = fixture();
435
+ f.run.event = 'workflow_run';
436
+ f.run.display_title = 'Unrelated run';
437
+ await expect((0, mypyPrimerAnalysis_1.loadSource)(f.request, repository, f.source)).rejects.toThrow('source Validation run');
438
+ f.run.display_title = 'Run mypy_primer after Validation #41';
439
+ f.validation.event = 'push';
440
+ await expect((0, mypyPrimerAnalysis_1.loadSource)(f.request, repository, f.source)).rejects.toThrow('successful pull request Validation');
441
+ f.validation.event = 'pull_request';
442
+ f.validation.path = '.github/workflows/other.yml';
443
+ await expect((0, mypyPrimerAnalysis_1.loadSource)(f.request, repository, f.source)).rejects.toThrow('successful pull request Validation');
444
+ });
415
445
  test('rejects expired, duplicate, old-attempt, and oversized artifacts', async () => {
416
446
  for (const mutation of [
417
447
  (f) => (f.artifacts[0].expired = true),
@@ -902,26 +932,52 @@ describe('mypy_primer analysis', () => {
902
932
  f.report.projects[0].attribution = 'definitely-caused-by-pr';
903
933
  expect(() => (0, mypyPrimerAnalysis_1.renderReport)(f.manifest, f.report, 100)).toThrow(new Error('Invalid PR attribution for example'));
904
934
  });
905
- test('uses a short non-blocking notice only for canonical SymPy-only changes', () => {
935
+ test('keeps normal analysis for canonical SymPy-only changes', () => {
906
936
  const f = fixture(sample
907
937
  .replace(/example/g, 'sympy')
908
938
  .replace('https://github.com/sympy/project', 'https://github.com/sympy/sympy'));
909
939
  f.report.projects[0].name = 'sympy';
910
940
  expect((0, mypyPrimerAnalysis_1.renderReport)(f.manifest, f.report, 100)).toStrictEqual({
911
- body: [
912
- ...expectedReportProvenance,
913
- '**Only SymPy changed.** These differences are treated as non-blocking primer noise; no other project changed.',
914
- '',
915
- 'Recorded changes: 1 added / 1 removed diagnostic headers; 1 added / 1 removed detail lines.',
916
- '',
917
- ...expectedReportFooter,
918
- ].join('\n'),
941
+ body: expectedReport.body.replace(/example/g, 'sympy'),
919
942
  fullReport: expectedReport.fullReport.replace(/example/g, 'sympy'),
920
943
  });
921
944
  expect(() => (0, mypyPrimerAnalysis_1.renderReport)(f.manifest, { projects: [] }, 100)).toThrow('The analysis must cover every changed project exactly once');
922
945
  f.report.projects[0].explanation = '';
923
946
  expect(() => (0, mypyPrimerAnalysis_1.renderReport)(f.manifest, f.report, 100)).toThrow('Expected nonempty text');
924
947
  });
948
+ test.each(['possible-regression', 'expected-improvement'])('keeps SymPy-only type-erasure warnings visible with a %s assessment', (assessment) => {
949
+ const f = fixture([
950
+ 'sympy (https://github.com/sympy/sympy)',
951
+ '+ .../projects/sympy/test.py:1:1 - error: "assert_type" mismatch: expected "int" but received "Any" (reportAssertTypeFailure)',
952
+ '- 0 errors, 0 warnings, 0 informations',
953
+ '+ 1 error, 0 warnings, 0 informations',
954
+ ].join('\n'));
955
+ const report = {
956
+ projects: [
957
+ {
958
+ ...f.report.projects[0],
959
+ name: 'sympy',
960
+ assessment,
961
+ evidence: [
962
+ {
963
+ url: 'https://typing.python.org/en/latest/spec/assert.html',
964
+ detail: 'Type assertion specification.',
965
+ },
966
+ ],
967
+ },
968
+ ],
969
+ };
970
+ const result = (0, mypyPrimerAnalysis_1.renderReport)(f.manifest, report, 100);
971
+ expect(result.body).toContain(riskOverview);
972
+ expect(result.body).toContain('## Potential regressions');
973
+ expect(result.body).toContain('### sympy:');
974
+ expect(result.body).toContain('**Regression warning signals require review, regardless of the AI assessment:**');
975
+ expect(result.body).toContain('New assertions receive bare Any/Unknown instead of their expected type.');
976
+ expect(result.body).toContain('**Causal analysis:**');
977
+ expect(result.body).toContain('**Uncertainty / next check:**');
978
+ expect(result.body).toContain('<https://typing.python.org/en/latest/spec/assert.html>');
979
+ expect(result.body).not.toContain('non-blocking primer noise');
980
+ });
925
981
  test('keeps normal analysis for noncanonical SymPy and mixed-project changes', () => {
926
982
  const f = fixture();
927
983
  const sympy = { ...f.report.projects[0], name: 'sympy' };