Your validation layer can run, pass CI, and check nothing
TLDR
Validation rule engines that cross-reference runtime document graph nodes against static spec lookup tables rely on exact key matching. If the keys used by runtime elements (e.g., lowercase pin IDs likein1) do not match the keys defined in spec tables (e.g., uppercase pin IDs like IN1), optional chaining or undefined lookups cause the rule engine to evaluate every node as compliant. Tests must assert that known-invalid inputs trigger expected findings.
| Spec Table Keys | Runtime Component Keys | Optional Chain Lookup (SPECS[id]?.pins[pinId]) | Linter Rule Result |
|---|---|---|---|
IN1 / OUT (Uppercase) | in1 / out (Lowercase) | undefined (Silent miss) | 0 Errors (False Clean Bill of Health) |
in1 / out (Matched) | in1 / out (Lowercase) | Valid Metadata Record | 100% Correct Short Detection |
Problem statement: the silent mismatched key trap
A linter rule engine verifies electrical net validity by checking pin roles on components:
// Spec Table defined with human-friendly uppercase keys
const SPECS = {
andGate: {
pins: {
IN1: { role: 'input' },
IN2: { role: 'input' },
OUT: { role: 'output' }
}
}
};
When evaluating a net for short circuits (multiple output pins tied together):
function checkBusContention(net) {
const outputs = net.pins
.map(pin => SPECS[pin.component]?.pins[pin.id]?.role)
.filter(role => role === 'output');
if (outputs.length >= 2) { reportFinding(Short Circuit: Net '${net.id}' connects multiple output pins.); } }
If the rendering kit stamps component DOM elements with lowercase pin IDs (in1, in2, out), SPECS['andGate'].pins['out'] returns undefined.
The optional chain swallows the miss, outputs evaluates to [], and the rule reports zero errors on invalid circuits.
Technical failure mode: the illusion of passing tests
This failure mode bypasses traditional unit testing:
- Syntax Tests Pass: Code is error-free and runs without throwing exceptions.
- Smoke Tests Pass: Rendering tests confirm components load and draw properly.
- Linter Tests Pass: The rule engine executes on sample inputs without crashing.
The fix & architecture: runtime key extraction & negative test assertions
1. Extract real keys directly from runtime symbols
Re-key spec tables to match exact runtime values exported by rendering kits:// REFACTORED: Spec Table re-keyed to exact runtime kit strings
const SPECS = {
andGate: {
pins: {
in1: { role: 'input' },
in2: { role: 'input' },
out: { role: 'output' }
}
}
};
2. Dev-Time warning for un-mapped keys
Log explicit warnings during development when a lookup key misses:function getPinRole(componentType, pinId) {
const compSpec = SPECS[componentType];
if (!compSpec) return null;
const pinSpec = compSpec.pins[pinId]; if (!pinSpec && process.env.NODE_ENV !== 'production') { console.warn([Linter Spec Miss] Component '${componentType}' has un-mapped pin ID '${pinId}'); }
return pinSpec?.role || null; }
3. Automated negative test cases
Write automated tests that pass known-invalid diagrams to verify that rules fire as expected:// REQUIRED: Assert known-bad input triggers rule findings!
test('Bus contention rule flags shorted outputs', () => {
const invalidDiagram = createShortedOutputsDiagram();
const findings = runLinterRules(invalidDiagram);
expect(findings).toContainEqual( expect.objectContaining({ ruleId: 'bus-contention', severity: 'error' }) ); });
Rule of thumb: A validation rule engine is only proven when a known-invalid input triggers a corresponding finding. Always include negative test cases for linter rules.