easyeda-mcp-pro 1.8.0 → 1.9.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.
Files changed (72) hide show
  1. package/README.md +38 -74
  2. package/dist/circuit/circuit-ir.d.ts +6 -6
  3. package/dist/config/profiles.js +6 -6
  4. package/dist/config/profiles.js.map +1 -1
  5. package/dist/config/version.d.ts +1 -1
  6. package/dist/config/version.js +1 -1
  7. package/dist/design-rules/index.d.ts +2 -0
  8. package/dist/design-rules/index.js +1 -0
  9. package/dist/design-rules/index.js.map +1 -1
  10. package/dist/design-rules/isolation-emc-review.d.ts +73 -0
  11. package/dist/design-rules/isolation-emc-review.js +170 -0
  12. package/dist/design-rules/isolation-emc-review.js.map +1 -0
  13. package/dist/design-rules/trace-current-review.d.ts +41 -0
  14. package/dist/design-rules/trace-current-review.js +144 -0
  15. package/dist/design-rules/trace-current-review.js.map +1 -0
  16. package/dist/design-rules/trace-width.d.ts +26 -4
  17. package/dist/design-rules/trace-width.js +46 -18
  18. package/dist/design-rules/trace-width.js.map +1 -1
  19. package/dist/engineering-review/report.d.ts +119 -0
  20. package/dist/engineering-review/report.js +297 -0
  21. package/dist/engineering-review/report.js.map +1 -0
  22. package/dist/live/easyeda-smoke.js +9 -1
  23. package/dist/live/easyeda-smoke.js.map +1 -1
  24. package/dist/net-validation/datasheet-review.d.ts +69 -0
  25. package/dist/net-validation/datasheet-review.js +146 -0
  26. package/dist/net-validation/datasheet-review.js.map +1 -0
  27. package/dist/package-build-manifest.json +218 -68
  28. package/dist/pcb-constraints/manufacturing-profile-review.d.ts +51 -0
  29. package/dist/pcb-constraints/manufacturing-profile-review.js +218 -0
  30. package/dist/pcb-constraints/manufacturing-profile-review.js.map +1 -0
  31. package/dist/pcb-constraints/types.d.ts +8 -2
  32. package/dist/pcb-constraints/validation.js +157 -36
  33. package/dist/pcb-constraints/validation.js.map +1 -1
  34. package/dist/pcb-layout/differential-pair.d.ts +66 -0
  35. package/dist/pcb-layout/differential-pair.js +275 -0
  36. package/dist/pcb-layout/differential-pair.js.map +1 -0
  37. package/dist/pcb-layout/placement-evidence.d.ts +53 -0
  38. package/dist/pcb-layout/placement-evidence.js +134 -0
  39. package/dist/pcb-layout/placement-evidence.js.map +1 -0
  40. package/dist/pcb-layout/planner.js +48 -20
  41. package/dist/pcb-layout/planner.js.map +1 -1
  42. package/dist/pcb-layout/route-review.d.ts +70 -0
  43. package/dist/pcb-layout/route-review.js +182 -0
  44. package/dist/pcb-layout/route-review.js.map +1 -0
  45. package/dist/server/resources-prompts.js +4 -1
  46. package/dist/server/resources-prompts.js.map +1 -1
  47. package/dist/tools/L1_board.js +157 -41
  48. package/dist/tools/L1_board.js.map +1 -1
  49. package/dist/tools/L1_design_rules.js +194 -9
  50. package/dist/tools/L1_design_rules.js.map +1 -1
  51. package/dist/tools/L1_drc_erc.js +109 -10
  52. package/dist/tools/L1_drc_erc.js.map +1 -1
  53. package/dist/tools/L1_engineering_review.d.ts +6 -0
  54. package/dist/tools/L1_engineering_review.js +46 -0
  55. package/dist/tools/L1_engineering_review.js.map +1 -0
  56. package/dist/tools/L1_export.js +83 -1
  57. package/dist/tools/L1_export.js.map +1 -1
  58. package/dist/tools/L1_pcb_constraints.d.ts +6 -0
  59. package/dist/tools/L1_pcb_constraints.js +177 -37
  60. package/dist/tools/L1_pcb_constraints.js.map +1 -1
  61. package/dist/tools/L1_pcb_route_review.d.ts +9 -0
  62. package/dist/tools/L1_pcb_route_review.js +423 -0
  63. package/dist/tools/L1_pcb_route_review.js.map +1 -0
  64. package/dist/tools/L2_schematic_layout.d.ts +2 -2
  65. package/dist/tools/register.js +4 -0
  66. package/dist/tools/register.js.map +1 -1
  67. package/easyeda-bridge-extension.checksums.json +8 -8
  68. package/easyeda-bridge-extension.eext +0 -0
  69. package/package.json +1 -1
  70. package/skills/design-validation/SKILL.md +23 -0
  71. package/skills/design-validation/references/engineering-review.md +116 -0
  72. package/skills/easyeda-component-review/SKILL.md +11 -0
@@ -0,0 +1,144 @@
1
+ import { calculateTraceWidth } from './trace-width.js';
2
+ const THERMAL_LIMITATIONS = [
3
+ 'IPC-2221 empirical estimate, not an IPC-2152 calculation or validated thermal limit.',
4
+ 'Copper weight is nominal: finished minimum plated copper thickness can differ.',
5
+ 'Actual temperature depends on board material/thickness, copper planes, adjacent heat, airflow and duty cycle.',
6
+ 'Via transitions, plane connections and local neck-downs require separate review.',
7
+ 'Fabricator trace/space capability and electrical thermal adequacy are different checks.',
8
+ ];
9
+ const INPUT_UNITS = {
10
+ currentA: 'A',
11
+ temperatureRiseC: '°C',
12
+ copperWeightOz: 'oz/ft²',
13
+ traceWidthMm: 'mm',
14
+ neckDownWidthMm: 'mm',
15
+ manufacturerMinWidthMm: 'mm',
16
+ };
17
+ function hasCompleteModelInput(input) {
18
+ return (input.currentA !== undefined &&
19
+ input.temperatureRiseC !== undefined &&
20
+ input.layer !== undefined &&
21
+ input.copperWeightOz !== undefined);
22
+ }
23
+ function thermalFinding(estimate, narrowest) {
24
+ if (estimate === undefined) {
25
+ return {
26
+ id: 'THERMAL_ESTIMATE',
27
+ status: 'UNKNOWN',
28
+ message: 'Current, temperature rise, layer and copper weight must all be supplied.',
29
+ };
30
+ }
31
+ if (narrowest === undefined) {
32
+ return {
33
+ id: 'THERMAL_ESTIMATE',
34
+ status: 'UNKNOWN',
35
+ message: 'Only a reference width was calculated; actual routed width was not supplied.',
36
+ };
37
+ }
38
+ if (narrowest < estimate) {
39
+ return {
40
+ id: 'THERMAL_ESTIMATE',
41
+ status: 'WARNING',
42
+ message: 'Supplied width is below the IPC-2221 empirical estimate; review current path and thermal design.',
43
+ };
44
+ }
45
+ return {
46
+ id: 'THERMAL_ESTIMATE',
47
+ status: 'UNKNOWN',
48
+ message: 'Supplied width meets the empirical reference, but thermal adequacy is not verified.',
49
+ };
50
+ }
51
+ function fabricationFinding(input) {
52
+ const { traceWidthMm, neckDownWidthMm, manufacturerMinWidthMm } = input;
53
+ const narrowest = traceWidthMm === undefined
54
+ ? undefined
55
+ : Math.min(traceWidthMm, neckDownWidthMm ?? traceWidthMm);
56
+ if (manufacturerMinWidthMm === undefined || narrowest === undefined) {
57
+ return {
58
+ id: 'FABRICATION_WIDTH',
59
+ status: 'UNKNOWN',
60
+ message: 'No verified manufacturer minimum or complete routed geometry is available.',
61
+ };
62
+ }
63
+ if (narrowest < manufacturerMinWidthMm) {
64
+ return {
65
+ id: 'FABRICATION_WIDTH',
66
+ status: 'WARNING',
67
+ message: 'Supplied routed width is below the supplied fabricator trace-width minimum.',
68
+ };
69
+ }
70
+ return {
71
+ id: 'FABRICATION_WIDTH',
72
+ status: 'UNKNOWN',
73
+ message: 'The supplied trace width meets the claimed fabricator minimum, but the process was not verified.',
74
+ };
75
+ }
76
+ function validateReviewInput(input) {
77
+ for (const field of [
78
+ 'currentA',
79
+ 'temperatureRiseC',
80
+ 'copperWeightOz',
81
+ 'traceWidthMm',
82
+ 'neckDownWidthMm',
83
+ 'manufacturerMinWidthMm',
84
+ ]) {
85
+ const value = input[field];
86
+ if (value !== undefined && (!Number.isFinite(value) || value <= 0)) {
87
+ throw new Error(field + ' must be a finite positive number');
88
+ }
89
+ }
90
+ }
91
+ export function reviewTraceCurrent(input) {
92
+ validateReviewInput(input);
93
+ const estimate = hasCompleteModelInput(input)
94
+ ? calculateTraceWidth({
95
+ currentA: input.currentA,
96
+ temperatureRiseC: input.temperatureRiseC,
97
+ layer: input.layer,
98
+ copperWeightOz: input.copperWeightOz,
99
+ }).traceWidthMm
100
+ : undefined;
101
+ // Width of a single straight segment is not proof of the entire current path.
102
+ const narrowest = input.traceWidthMm === undefined
103
+ ? undefined
104
+ : Math.min(input.traceWidthMm, input.neckDownWidthMm ?? input.traceWidthMm);
105
+ const findings = [
106
+ thermalFinding(estimate, narrowest),
107
+ fabricationFinding(input),
108
+ {
109
+ id: 'ROUTE_GEOMETRY',
110
+ status: 'UNKNOWN',
111
+ message: input.neckDownWidthMm === undefined
112
+ ? 'The narrowest actual segment has not been established by live EasyEDA routing measurements.'
113
+ : 'The supplied neck-down is not verified against the complete native route.',
114
+ },
115
+ {
116
+ id: 'VIA_BOTTLENECK',
117
+ status: 'UNKNOWN',
118
+ message: 'No verified via barrel/transition geometry or parallel-current evidence is available.',
119
+ },
120
+ ];
121
+ const limitations = [
122
+ ...THERMAL_LIMITATIONS,
123
+ input.environment === 'vacuum'
124
+ ? 'Vacuum thermal conditions are not covered by this empirical lookup.'
125
+ : input.environment === 'forced-air'
126
+ ? 'Forced airflow was supplied as context but is not modeled by this lookup.'
127
+ : input.environment === undefined || input.environment === 'unspecified'
128
+ ? 'Ambient conditions were not specified.'
129
+ : 'Still-air assumptions have not been validated against the actual enclosure.',
130
+ ];
131
+ return {
132
+ status: findings.some(({ status }) => status === 'WARNING') ? 'WARNING' : 'UNKNOWN',
133
+ method: 'IPC2221_EMPIRICAL_REFERENCE',
134
+ evidence: 'caller_supplied_unverified',
135
+ source: 'IPC-2221 empirical current-versus-conductor-area equation; see IPC-2152 for thermal design guidance.',
136
+ inputs: input,
137
+ inputUnits: INPUT_UNITS,
138
+ ...(estimate === undefined ? {} : { estimatedMinimumWidthMm: estimate }),
139
+ ...(narrowest === undefined ? {} : { suppliedNarrowestWidthMm: narrowest }),
140
+ findings,
141
+ limitations,
142
+ };
143
+ }
144
+ //# sourceMappingURL=trace-current-review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-current-review.js","sourceRoot":"","sources":["../../src/design-rules/trace-current-review.ts"],"names":[],"mappings":"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"}
@@ -10,16 +10,17 @@
10
10
  * layer) conductors or 0.024 for internal conductors.
11
11
  *
12
12
  * This is an estimate, not a certified value: the curve does not model adjacent-trace
13
- * heating, via/plane proximity, forced airflow, or altitude. IPC-2152 supersedes
14
- * IPC-2221 with more conservative guidance for dense modern boards. Verify against
15
- * your fabricator's process and cross-check with IPC-2152 for safety-critical or
16
- * high-reliability current paths.
13
+ * heating, via/plane proximity, forced airflow, or altitude. IPC-2152 provides
14
+ * measured thermal guidance for a wider range of PCB conditions, not universally
15
+ * more conservative estimates. Verify against the actual fabrication process and
16
+ * thermal guidance for safety-critical and high-reliability current paths.
17
17
  *
18
18
  * @module
19
19
  */
20
20
  export type ConductorLayer = 'external' | 'internal';
21
21
  /** Standard copper thickness in mils per oz/ft² of copper weight (1oz ≈ 1.378 mils / 34.8 µm). */
22
22
  export declare const COPPER_THICKNESS_MILS_PER_OZ = 1.378;
23
+ export declare const TRACE_WIDTH_METHOD: "IPC2221_EMPIRICAL_REFERENCE";
23
24
  export interface TraceWidthInput {
24
25
  /** Required current-carrying capacity, in amps. */
25
26
  currentA: number;
@@ -38,6 +39,18 @@ export interface TraceWidthResult {
38
39
  k: number;
39
40
  source: string;
40
41
  caveat: string;
42
+ method: typeof TRACE_WIDTH_METHOD;
43
+ inputs: TraceWidthInput;
44
+ units: {
45
+ currentA: 'A';
46
+ temperatureRiseC: '°C';
47
+ copperWeightOz: 'oz/ft²';
48
+ traceWidthMm: 'mm';
49
+ traceWidthMils: 'mil';
50
+ copperThicknessMils: 'mil';
51
+ requiredAreaMils2: 'mil²';
52
+ };
53
+ limitations: string[];
41
54
  }
42
55
  /** Compute the minimum trace width for a given current, temperature rise, layer, and copper weight. */
43
56
  export declare function calculateTraceWidth(input: TraceWidthInput): TraceWidthResult;
@@ -53,6 +66,15 @@ export interface MaxCurrentResult {
53
66
  maxCurrentA: number;
54
67
  source: string;
55
68
  caveat: string;
69
+ method: typeof TRACE_WIDTH_METHOD;
70
+ inputs: MaxCurrentInput;
71
+ units: {
72
+ maxCurrentA: 'A';
73
+ traceWidthMils: 'mil';
74
+ temperatureRiseC: '°C';
75
+ copperWeightOz: 'oz/ft²';
76
+ };
77
+ limitations: string[];
56
78
  }
57
79
  /** Reverse lookup: the maximum current a given trace width can carry under the same model. */
58
80
  export declare function calculateMaxCurrent(input: MaxCurrentInput): MaxCurrentResult;
@@ -10,10 +10,10 @@
10
10
  * layer) conductors or 0.024 for internal conductors.
11
11
  *
12
12
  * This is an estimate, not a certified value: the curve does not model adjacent-trace
13
- * heating, via/plane proximity, forced airflow, or altitude. IPC-2152 supersedes
14
- * IPC-2221 with more conservative guidance for dense modern boards. Verify against
15
- * your fabricator's process and cross-check with IPC-2152 for safety-critical or
16
- * high-reliability current paths.
13
+ * heating, via/plane proximity, forced airflow, or altitude. IPC-2152 provides
14
+ * measured thermal guidance for a wider range of PCB conditions, not universally
15
+ * more conservative estimates. Verify against the actual fabrication process and
16
+ * thermal guidance for safety-critical and high-reliability current paths.
17
17
  *
18
18
  * @module
19
19
  */
@@ -24,9 +24,15 @@ const K_INTERNAL = 0.024;
24
24
  /** Standard copper thickness in mils per oz/ft² of copper weight (1oz ≈ 1.378 mils / 34.8 µm). */
25
25
  export const COPPER_THICKNESS_MILS_PER_OZ = 1.378;
26
26
  const IPC2221_SOURCE = 'IPC-2221 (formerly MIL-STD-275): I = k·ΔT^0.44·A^0.725';
27
+ export const TRACE_WIDTH_METHOD = 'IPC2221_EMPIRICAL_REFERENCE';
28
+ const TRACE_WIDTH_LIMITATIONS = [
29
+ 'Empirical IPC-2221 estimate only; not measured PCB or IPC-2152 thermal output.',
30
+ 'Nominal copper weight does not verify finished copper thickness.',
31
+ 'Copper planes, airflow, via bottlenecks, neck-downs and neighboring heat are not modeled.',
32
+ ];
27
33
  const IPC2221_CAVEAT = 'Estimate only — does not model adjacent-trace heating, via/plane proximity, or airflow. ' +
28
- 'Verify against your fabricator process; cross-check with IPC-2152 for dense or ' +
29
- 'high-reliability boards.';
34
+ 'IPC-2152 includes board stackup, copper planes, environment and thermal coupling; ' +
35
+ 'it is not uniformly more conservative. Validate the board and fabrication process.';
30
36
  function kFor(layer) {
31
37
  return layer === 'external' ? K_EXTERNAL : K_INTERNAL;
32
38
  }
@@ -34,19 +40,22 @@ function round(value, decimals) {
34
40
  const factor = 10 ** decimals;
35
41
  return Math.round(value * factor) / factor;
36
42
  }
43
+ function assertPositiveFinite(name, value) {
44
+ if (!Number.isFinite(value) || value <= 0) {
45
+ throw new Error(name + ' must be a finite positive number');
46
+ }
47
+ }
37
48
  /** Compute the minimum trace width for a given current, temperature rise, layer, and copper weight. */
38
49
  export function calculateTraceWidth(input) {
39
50
  const { currentA, temperatureRiseC, layer, copperWeightOz } = input;
40
- if (!(currentA > 0))
41
- throw new Error('currentA must be a positive number');
42
- if (!(temperatureRiseC > 0))
43
- throw new Error('temperatureRiseC must be a positive number');
44
- if (!(copperWeightOz > 0))
45
- throw new Error('copperWeightOz must be a positive number');
51
+ assertPositiveFinite('currentA', currentA);
52
+ assertPositiveFinite('temperatureRiseC', temperatureRiseC);
53
+ assertPositiveFinite('copperWeightOz', copperWeightOz);
46
54
  const k = kFor(layer);
47
55
  const areaMils2 = Math.pow(currentA / (k * Math.pow(temperatureRiseC, 0.44)), 1 / 0.725);
48
56
  const thicknessMils = copperWeightOz * COPPER_THICKNESS_MILS_PER_OZ;
49
57
  const widthMils = areaMils2 / thicknessMils;
58
+ assertPositiveFinite('computedTraceWidthMils', widthMils);
50
59
  return {
51
60
  requiredAreaMils2: round(areaMils2, 3),
52
61
  copperThicknessMils: round(thicknessMils, 3),
@@ -55,25 +64,44 @@ export function calculateTraceWidth(input) {
55
64
  k,
56
65
  source: IPC2221_SOURCE,
57
66
  caveat: IPC2221_CAVEAT,
67
+ method: TRACE_WIDTH_METHOD,
68
+ inputs: { ...input },
69
+ units: {
70
+ currentA: 'A',
71
+ temperatureRiseC: '°C',
72
+ copperWeightOz: 'oz/ft²',
73
+ traceWidthMm: 'mm',
74
+ traceWidthMils: 'mil',
75
+ copperThicknessMils: 'mil',
76
+ requiredAreaMils2: 'mil²',
77
+ },
78
+ limitations: [...TRACE_WIDTH_LIMITATIONS],
58
79
  };
59
80
  }
60
81
  /** Reverse lookup: the maximum current a given trace width can carry under the same model. */
61
82
  export function calculateMaxCurrent(input) {
62
83
  const { traceWidthMils, temperatureRiseC, layer, copperWeightOz } = input;
63
- if (!(traceWidthMils > 0))
64
- throw new Error('traceWidthMils must be a positive number');
65
- if (!(temperatureRiseC > 0))
66
- throw new Error('temperatureRiseC must be a positive number');
67
- if (!(copperWeightOz > 0))
68
- throw new Error('copperWeightOz must be a positive number');
84
+ assertPositiveFinite('traceWidthMils', traceWidthMils);
85
+ assertPositiveFinite('temperatureRiseC', temperatureRiseC);
86
+ assertPositiveFinite('copperWeightOz', copperWeightOz);
69
87
  const k = kFor(layer);
70
88
  const thicknessMils = copperWeightOz * COPPER_THICKNESS_MILS_PER_OZ;
71
89
  const areaMils2 = traceWidthMils * thicknessMils;
72
90
  const maxCurrentA = k * Math.pow(temperatureRiseC, 0.44) * Math.pow(areaMils2, 0.725);
91
+ assertPositiveFinite('computedMaxCurrentA', maxCurrentA);
73
92
  return {
74
93
  maxCurrentA: round(maxCurrentA, 3),
75
94
  source: IPC2221_SOURCE,
76
95
  caveat: IPC2221_CAVEAT,
96
+ method: TRACE_WIDTH_METHOD,
97
+ inputs: { ...input },
98
+ units: {
99
+ maxCurrentA: 'A',
100
+ traceWidthMils: 'mil',
101
+ temperatureRiseC: '°C',
102
+ copperWeightOz: 'oz/ft²',
103
+ },
104
+ limitations: [...TRACE_WIDTH_LIMITATIONS],
77
105
  };
78
106
  }
79
107
  //# sourceMappingURL=trace-width.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"trace-width.js","sourceRoot":"","sources":["../../src/design-rules/trace-width.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"trace-width.js","sourceRoot":"","sources":["../../src/design-rules/trace-width.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ import { z } from 'zod';
2
+ import type { PcbConstraintInput } from '../pcb-constraints/types.js';
3
+ /** Evidence report only; never an electrical or manufacturing sign-off. */
4
+ export declare const reviewStatusSchema: z.ZodEnum<{
5
+ UNKNOWN: "UNKNOWN";
6
+ WARNING: "WARNING";
7
+ PASS: "PASS";
8
+ FAIL: "FAIL";
9
+ NOT_APPLICABLE: "NOT_APPLICABLE";
10
+ }>;
11
+ export declare const engineeringReviewSchema: z.ZodObject<{
12
+ project_id: z.ZodString;
13
+ overall_status: z.ZodEnum<{
14
+ UNKNOWN: "UNKNOWN";
15
+ WARNING: "WARNING";
16
+ PASS: "PASS";
17
+ FAIL: "FAIL";
18
+ NOT_APPLICABLE: "NOT_APPLICABLE";
19
+ }>;
20
+ pcb_context: z.ZodEnum<{
21
+ unverified: "unverified";
22
+ observed: "observed";
23
+ }>;
24
+ runtime: z.ZodObject<{
25
+ bridge_connected: z.ZodBoolean;
26
+ registry_mismatch: z.ZodNullable<z.ZodBoolean>;
27
+ extension_version_mismatch: z.ZodNullable<z.ZodBoolean>;
28
+ }, z.core.$strip>;
29
+ groups: z.ZodObject<{
30
+ blocking: z.ZodArray<z.ZodString>;
31
+ advisories: z.ZodArray<z.ZodString>;
32
+ unknowns: z.ZodArray<z.ZodString>;
33
+ passed: z.ZodArray<z.ZodString>;
34
+ not_applicable: z.ZodArray<z.ZodString>;
35
+ }, z.core.$strip>;
36
+ source_version: z.ZodObject<{
37
+ easyeda: z.ZodNullable<z.ZodString>;
38
+ extension: z.ZodNullable<z.ZodString>;
39
+ }, z.core.$strip>;
40
+ observations: z.ZodArray<z.ZodObject<{
41
+ method: z.ZodString;
42
+ status: z.ZodEnum<{
43
+ unavailable: "unavailable";
44
+ observed: "observed";
45
+ not_run: "not_run";
46
+ }>;
47
+ guidance: z.ZodOptional<z.ZodString>;
48
+ }, z.core.$strip>>;
49
+ input_evidence: z.ZodArray<z.ZodObject<{
50
+ field: z.ZodString;
51
+ source: z.ZodString;
52
+ quality: z.ZodEnum<{
53
+ unavailable: "unavailable";
54
+ measured: "measured";
55
+ supplied: "supplied";
56
+ unverified: "unverified";
57
+ }>;
58
+ unit: z.ZodOptional<z.ZodString>;
59
+ age: z.ZodEnum<{
60
+ unverified: "unverified";
61
+ current_request: "current_request";
62
+ }>;
63
+ value: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
64
+ }, z.core.$strip>>;
65
+ findings: z.ZodArray<z.ZodObject<{
66
+ id: z.ZodString;
67
+ rule_id: z.ZodString;
68
+ rule_revision: z.ZodString;
69
+ requirement_source: z.ZodString;
70
+ scope: z.ZodString;
71
+ status: z.ZodEnum<{
72
+ UNKNOWN: "UNKNOWN";
73
+ WARNING: "WARNING";
74
+ PASS: "PASS";
75
+ FAIL: "FAIL";
76
+ NOT_APPLICABLE: "NOT_APPLICABLE";
77
+ }>;
78
+ severity: z.ZodEnum<{
79
+ info: "info";
80
+ error: "error";
81
+ warning: "warning";
82
+ }>;
83
+ message: z.ZodString;
84
+ remediation: z.ZodString;
85
+ confidence: z.ZodEnum<{
86
+ unverified: "unverified";
87
+ observed: "observed";
88
+ derived: "derived";
89
+ }>;
90
+ evidence_fields: z.ZodArray<z.ZodString>;
91
+ affected_entities: z.ZodArray<z.ZodString>;
92
+ }, z.core.$strip>>;
93
+ summary: z.ZodObject<{
94
+ PASS: z.ZodNumber;
95
+ FAIL: z.ZodNumber;
96
+ WARNING: z.ZodNumber;
97
+ UNKNOWN: z.ZodNumber;
98
+ NOT_APPLICABLE: z.ZodNumber;
99
+ }, z.core.$strip>;
100
+ human_review_required: z.ZodArray<z.ZodString>;
101
+ engineering_sign_off: z.ZodLiteral<false>;
102
+ }, z.core.$strip>;
103
+ export type EngineeringReview = z.infer<typeof engineeringReviewSchema>;
104
+ export type ReviewFinding = EngineeringReview['findings'][number];
105
+ export type ReviewObservation = EngineeringReview['observations'][number];
106
+ type ReviewBuildInput = {
107
+ projectId: string;
108
+ boardData: PcbConstraintInput;
109
+ observations: ReviewObservation[];
110
+ bridgeConnected: boolean;
111
+ registryMismatch?: boolean;
112
+ extensionVersionMismatch?: boolean;
113
+ sourceChangedDuringRead?: boolean;
114
+ easyedaVersion?: string;
115
+ extensionVersion?: string;
116
+ evidenceMode: 'native' | 'supplied';
117
+ };
118
+ export declare function buildEngineeringReview(input: ReviewBuildInput): EngineeringReview;
119
+ export {};