@eviano/tribunal 0.1.2

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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -0
  3. package/dist/analyzers/assertionFreeTest.d.ts +12 -0
  4. package/dist/analyzers/assertionFreeTest.js +316 -0
  5. package/dist/analyzers/assertionFreeTest.js.map +1 -0
  6. package/dist/analyzers/claimReconciliation.d.ts +3 -0
  7. package/dist/analyzers/claimReconciliation.js +190 -0
  8. package/dist/analyzers/claimReconciliation.js.map +1 -0
  9. package/dist/analyzers/defaults.d.ts +8 -0
  10. package/dist/analyzers/defaults.js +82 -0
  11. package/dist/analyzers/defaults.js.map +1 -0
  12. package/dist/analyzers/exports.d.ts +12 -0
  13. package/dist/analyzers/exports.js +84 -0
  14. package/dist/analyzers/exports.js.map +1 -0
  15. package/dist/analyzers/hallucinatedSymbol.d.ts +22 -0
  16. package/dist/analyzers/hallucinatedSymbol.js +233 -0
  17. package/dist/analyzers/hallucinatedSymbol.js.map +1 -0
  18. package/dist/analyzers/index.d.ts +9 -0
  19. package/dist/analyzers/index.js +9 -0
  20. package/dist/analyzers/index.js.map +1 -0
  21. package/dist/claims.d.ts +15 -0
  22. package/dist/claims.js +32 -0
  23. package/dist/claims.js.map +1 -0
  24. package/dist/cli.d.ts +2 -0
  25. package/dist/cli.js +116 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/diff/gitDiff.d.ts +19 -0
  28. package/dist/diff/gitDiff.js +64 -0
  29. package/dist/diff/gitDiff.js.map +1 -0
  30. package/dist/diff/parseUnifiedDiff.d.ts +9 -0
  31. package/dist/diff/parseUnifiedDiff.js +63 -0
  32. package/dist/diff/parseUnifiedDiff.js.map +1 -0
  33. package/dist/index.d.ts +16 -0
  34. package/dist/index.js +25 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/report/render.d.ts +10 -0
  37. package/dist/report/render.js +70 -0
  38. package/dist/report/render.js.map +1 -0
  39. package/dist/types.d.ts +71 -0
  40. package/dist/types.js +8 -0
  41. package/dist/types.js.map +1 -0
  42. package/package.json +61 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tribunal contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,169 @@
1
+ # ⚖️ Tribunal
2
+
3
+ **A deterministic, no-LLM-in-the-loop CI gate that catches the defects coding agents ship** — tests
4
+ that assert nothing, references to symbols that don't exist, and PR claims that contradict what the
5
+ diff actually did.
6
+
7
+ Agents now write both the change *and* a persuasive PR description optimized to sound done. Reviewers
8
+ anchor on the prose and rubber-stamp. Tribunal is the deterministic safety net for that failure mode —
9
+ not another stochastic reviewer that can be prompt-injected or hallucinate an approval.
10
+
11
+ > **Status: pre-alpha (M0).** The first analyzer — `assertion-free-test` — and the full
12
+ > diff → verdict → exit-code pipeline are working and tested. See [docs/SPEC.md](docs/SPEC.md) for the
13
+ > architecture and roadmap.
14
+
15
+ ## The Trust Contract
16
+
17
+ Tribunal is only useful if a paranoid platform team will let it block a build. That requires hard
18
+ guarantees, not vibes:
19
+
20
+ 1. **No LLM is ever in the verification path.** The thing that flips a build red is always
21
+ deterministic code. (A model may *propose* a claim to check; it may never *adjudicate* one.)
22
+ 2. **Three verdicts:** 🟢 `PASS` · 🟡 `UNVERIFIED` · 🔴 `CONTRADICTED`.
23
+ 3. **The build is gated ONLY on `CONTRADICTED`,** and only with `--hard-fail`. Absence of a
24
+ contradiction never blocks; `UNVERIFIED` never blocks.
25
+ 4. **`CONTRADICTED` is a syntactic certainty, never a guess.** If a contradiction can't be *proven*
26
+ from the AST, the verdict degrades to `UNVERIFIED` — never a false red. We would rather miss a real
27
+ defect than block a correct PR.
28
+ 5. **Reporter-first.** Default mode is a non-blocking PR comment. Teams earn trust in the signal before
29
+ it can break their build.
30
+
31
+ ## Quickstart
32
+
33
+ ```bash
34
+ npm install
35
+ npm test # run the suite
36
+ npm run check -- check --help
37
+ ```
38
+
39
+ Run it against your working changes (report-only):
40
+
41
+ ```bash
42
+ npm run check -- check # diff working tree vs HEAD
43
+ npm run check -- check --base main --head HEAD
44
+ npm run check -- check --diff some.patch # analyze a unified diff file
45
+ npm run check -- check --format json
46
+ ```
47
+
48
+ Make it block a build (opt-in, gates only on 🔴 CONTRADICTED):
49
+
50
+ ```bash
51
+ npm run check -- check --base main --head HEAD --hard-fail
52
+ ```
53
+
54
+ ## Use it in CI (GitHub Action)
55
+
56
+ Tribunal ships a reusable composite action that runs on a PR, posts a **sticky comment** with the
57
+ report, and (optionally) fails the build — gating **only** on 🔴 CONTRADICTED.
58
+
59
+ ```yaml
60
+ # .github/workflows/tribunal.yml
61
+ name: Tribunal
62
+ on: pull_request
63
+ permissions:
64
+ contents: read
65
+ pull-requests: write
66
+ jobs:
67
+ tribunal:
68
+ runs-on: ubuntu-latest
69
+ steps:
70
+ - uses: actions/checkout@v4
71
+ with: { fetch-depth: 0 }
72
+ - uses: eviano/tribunal@v1
73
+ with:
74
+ base: ${{ github.event.pull_request.base.sha }}
75
+ head: ${{ github.event.pull_request.head.sha }}
76
+ hard-fail: 'false' # start in report-only; flip to 'true' once you trust the signal
77
+ ```
78
+
79
+ This repo dogfoods its own action — see [.github/workflows/tribunal.yml](.github/workflows/tribunal.yml).
80
+
81
+ ## What M0 catches: `assertion-free-test`
82
+
83
+ A test the PR added or changed that **can never fail** because it asserts nothing:
84
+
85
+ ```ts
86
+ it('validates the input', () => {
87
+ const result = validate(payload); // 🔴 CONTRADICTED: no assertion — this test can never fail
88
+ });
89
+ ```
90
+
91
+ - 🟢 **PASS** — an assertion is reachable (directly, or via a local helper Tribunal can follow).
92
+ - 🟡 **UNVERIFIED** — no assertion found, but the test calls an external helper that *might* assert.
93
+ Loud, never blocking.
94
+ - 🔴 **CONTRADICTED** — a syntactic certainty: the body is empty, has no calls at all, or only calls
95
+ local helpers that themselves cannot assert.
96
+
97
+ It understands `expect`, `assert`/`node:assert` (incl. named imports like `strictEqual`), chai
98
+ (`.should`, `chai.expect`), `sinon.assert.*`, Deno std `assert*`, and AVA/`node:test` context
99
+ assertions (`t.is`, `t.deepEqual`, …). Skipped tests (`it.skip`, `it.todo`) are ignored. Only tests
100
+ **touched by the diff** are evaluated.
101
+
102
+ ## What M1 adds: `hallucinated-symbol`
103
+
104
+ Imports the PR added that reference something that doesn't exist:
105
+
106
+ ```ts
107
+ import { parseConifg } from './config'; // 🔴 CONTRADICTED: './config' has no export named 'parseConifg'
108
+ import { helper } from './utils/missing'; // 🔴 CONTRADICTED: path resolves to no file
109
+ import { Client } from 'some-sdk'; // 🟡 UNVERIFIED: package not installed (dependency check is separate)
110
+ ```
111
+
112
+ It resolves modules the way the target repo's own `tsconfig.json` does, follows local `export *`
113
+ re-exports, and degrades to 🟡 UNVERIFIED whenever exports can't be statically enumerated (CJS,
114
+ unresolvable re-exports). Default imports are never flagged (interop synthesizes a default). Scope for
115
+ M1 is imports; full identifier/call resolution is a later increment.
116
+
117
+ ## What M3 adds: `claim-reconciliation`
118
+
119
+ Verifies the agent's **own claims** against the diff — deterministically. Claims are declared in a
120
+ machine-readable block (parsing, never NLU), so an unrecognized claim degrades to 🟡 UNVERIFIED and can
121
+ never become a false 🔴 CONTRADICTED:
122
+
123
+ ````md
124
+ ```tribunal
125
+ added-test
126
+ no-public-api-change
127
+ ```
128
+ ````
129
+
130
+ - `added-test` → 🟢 PASS if the diff adds a test with a reachable assertion; 🔴 CONTRADICTED if it adds
131
+ no test at all; 🟡 UNVERIFIED if a test was added but its assertion can't be detected.
132
+ - `no-public-api-change` → compares the exported-symbol set between base and head; 🔴 CONTRADICTED on any
133
+ added/removed export, 🟡 UNVERIFIED when there's no base ref or a module re-exports via `export *`.
134
+ - `no-default-flip` → compares literal default parameter values between base and head (scope to one with
135
+ `no-default-flip: paramName`); 🔴 CONTRADICTED when a default silently changed.
136
+
137
+ Pass claims with `--claims <file>` (a claims file) or `--pr-body <file>` (reads only the fenced block).
138
+ Adding a new claim is one entry in the verifier registry.
139
+
140
+ ## Benchmark — the moat-proof
141
+
142
+ Tribunal is only safe as a hard-fail gate if it almost never false-fires. That's measured, not
143
+ asserted:
144
+
145
+ ```bash
146
+ npm run bench
147
+ # cases=16 TP=9 TN=7 FP=0 FN=0
148
+ # recall=100.0% precision=100.0% false-positive=0.0%
149
+ ```
150
+
151
+ The [`bench/`](bench/) corpus is deliberately adversarial on the clean side (big refactors carrying a
152
+ `no-public-api-change` claim, tests that assert through helpers) so the **false-positive rate** means
153
+ something. It runs in CI via `test/bench.test.ts` and is the regression guard for the Trust Contract.
154
+ The public MSR'26 PR-MCI labeled set (974 PRs) plugs in alongside the seed corpus — see
155
+ [bench/README.md](bench/README.md).
156
+
157
+ ## Roadmap
158
+
159
+ | Milestone | Scope |
160
+ |-----------|-------|
161
+ | **M0** ✅ | scaffold + `assertion-free-test` + pipeline + tests |
162
+ | **M1** ✅ | `hallucinated-symbol` — import resolution (nonexistent named exports & relative paths) |
163
+ | **M2** ✅ | PR-comment reporter as a GitHub Action |
164
+ | **M3** ✅ | claim-reconciliation: `added-test`, `no-public-api-change`, `no-default-flip` (pluggable registry) |
165
+ | **M4** ✅ | benchmark harness + adversarial seed corpus + CI guard (currently **0% false-positive**); MSR'26 PR-MCI set pluggable |
166
+
167
+ ## License
168
+
169
+ MIT
@@ -0,0 +1,12 @@
1
+ import ts from 'typescript';
2
+ import type { Analyzer, Finding } from '../types.js';
3
+ declare function isTestFile(path: string): boolean;
4
+ declare function scriptKindFor(path: string): ts.ScriptKind;
5
+ declare function analyzeFile(sf: ts.SourceFile, path: string, addedLines: Set<number>): Finding[];
6
+ export declare const assertionFreeTest: Analyzer;
7
+ export declare const __test__: {
8
+ analyzeFile: typeof analyzeFile;
9
+ isTestFile: typeof isTestFile;
10
+ scriptKindFor: typeof scriptKindFor;
11
+ };
12
+ export {};
@@ -0,0 +1,316 @@
1
+ import ts from 'typescript';
2
+ /**
3
+ * `assertion-free-test` — flags tests the PR added/changed that contain NO assertion and therefore can
4
+ * never fail. This is a marquee agent defect: "I added tests" where the test does setup and asserts
5
+ * nothing.
6
+ *
7
+ * Trust Contract (docs/SPEC.md §3):
8
+ * - PASS : an assertion is reachable from the test body (directly or via a resolvable local helper).
9
+ * - CONTRADICTED : a SYNTACTIC CERTAINTY that no assertion can occur — the body is empty, or it contains
10
+ * zero function calls, or every call resolves to a local helper that also cannot assert.
11
+ * - UNVERIFIED : no assertion found, but the body calls something external/unresolvable that COULD
12
+ * assert indirectly. We never guess PASS and never guess CONTRADICTED here.
13
+ */
14
+ const TEST_FILE_RE = /(^|[./\\])(test|spec)\.[cm]?[jt]sx?$/i;
15
+ const TEST_DIR_RE = /(^|[/\\])(__tests__|tests?)[/\\]/i;
16
+ const SOURCE_EXT_RE = /\.[cm]?[jt]sx?$/i;
17
+ function isTestFile(path) {
18
+ return TEST_FILE_RE.test(path) || (TEST_DIR_RE.test(path) && SOURCE_EXT_RE.test(path));
19
+ }
20
+ /** Test-defining call roots. `Deno` covers `Deno.test(...)`. */
21
+ const TEST_ROOTS = new Set(['it', 'test', 'fit', 'Deno']);
22
+ /** Modifiers that mean the test does not run, so its lack of assertions is not a defect. */
23
+ const SKIP_MODIFIERS = new Set(['skip', 'todo']);
24
+ /** AVA / node:test context-object assertion methods (`t.is`, `t.deepEqual`, ...). */
25
+ const CTX_ASSERTIONS = new Set([
26
+ 'is', 'not', 'deepEqual', 'notDeepEqual', 'like', 'true', 'false', 'truthy', 'falsy',
27
+ 'assert', 'pass', 'fail', 'throws', 'throwsAsync', 'notThrows', 'notThrowsAsync',
28
+ 'regex', 'notRegex', 'snapshot',
29
+ ]);
30
+ /** Walk a callee chain to its root identifier, noting any `.skip`/`.todo` modifier on the way. */
31
+ function calleeInfo(expr) {
32
+ let hasSkip = false;
33
+ let node = expr;
34
+ while (true) {
35
+ if (ts.isCallExpression(node)) {
36
+ node = node.expression;
37
+ }
38
+ else if (ts.isPropertyAccessExpression(node)) {
39
+ if (SKIP_MODIFIERS.has(node.name.text))
40
+ hasSkip = true;
41
+ node = node.expression;
42
+ }
43
+ else if (ts.isElementAccessExpression(node)) {
44
+ node = node.expression;
45
+ }
46
+ else {
47
+ break;
48
+ }
49
+ }
50
+ return { root: ts.isIdentifier(node) ? node.text : undefined, hasSkip };
51
+ }
52
+ /** Find the function/arrow argument that is the test body (the last function-like argument). */
53
+ function testBodyFn(call) {
54
+ for (let i = call.arguments.length - 1; i >= 0; i--) {
55
+ const a = call.arguments[i];
56
+ if (ts.isArrowFunction(a) || ts.isFunctionExpression(a))
57
+ return a;
58
+ }
59
+ return undefined;
60
+ }
61
+ /** First string-literal argument, used as the human-readable test name. */
62
+ function testName(call) {
63
+ const a = call.arguments[0];
64
+ if (a && (ts.isStringLiteral(a) || ts.isNoSubstitutionTemplateLiteral(a)))
65
+ return a.text;
66
+ return undefined;
67
+ }
68
+ /** Build the per-file assertion vocabulary from imports plus globals (`expect`, `assert`). */
69
+ function collectVocab(sf) {
70
+ const ids = new Set(['expect', 'assert']);
71
+ const memberRoots = new Set(['assert', 'sinon', 'chai', 'expect']);
72
+ sf.forEachChild((node) => {
73
+ if (!ts.isImportDeclaration(node) || !node.importClause)
74
+ return;
75
+ if (!ts.isStringLiteral(node.moduleSpecifier))
76
+ return;
77
+ const mod = node.moduleSpecifier.text;
78
+ const fromAssertModule = /assert/i.test(mod);
79
+ const considerBinding = (name) => {
80
+ if (name === 'expect' || name === 'should' || /^assert/i.test(name) || fromAssertModule) {
81
+ ids.add(name);
82
+ }
83
+ if (name === 'chai' || name === 'sinon' || name === 'expect' || name === 'assert') {
84
+ memberRoots.add(name);
85
+ }
86
+ };
87
+ const clause = node.importClause;
88
+ if (clause.name)
89
+ considerBinding(clause.name.text); // default import
90
+ const nb = clause.namedBindings;
91
+ if (nb) {
92
+ if (ts.isNamespaceImport(nb)) {
93
+ memberRoots.add(nb.name.text); // import * as assert / chai
94
+ }
95
+ else if (ts.isNamedImports(nb)) {
96
+ nb.elements.forEach((e) => considerBinding(e.name.text));
97
+ }
98
+ }
99
+ });
100
+ return { ids, memberRoots };
101
+ }
102
+ /** Leftmost root identifier of a (possibly chained) expression. */
103
+ function rootIdentifier(expr) {
104
+ let node = expr;
105
+ while (ts.isPropertyAccessExpression(node) ||
106
+ ts.isElementAccessExpression(node) ||
107
+ ts.isCallExpression(node) ||
108
+ ts.isNonNullExpression(node)) {
109
+ node = node.expression;
110
+ }
111
+ return ts.isIdentifier(node) ? node : undefined;
112
+ }
113
+ function isAssertionCallee(callee, vocab, ctxParam) {
114
+ if (ts.isIdentifier(callee))
115
+ return vocab.ids.has(callee.text);
116
+ if (ts.isPropertyAccessExpression(callee)) {
117
+ const root = rootIdentifier(callee);
118
+ if (root) {
119
+ if (vocab.memberRoots.has(root.text))
120
+ return true;
121
+ if (ctxParam && root.text === ctxParam && CTX_ASSERTIONS.has(callee.name.text))
122
+ return true;
123
+ }
124
+ }
125
+ return false;
126
+ }
127
+ /** Local module-scope helpers: name → body node, so we can follow `helper()` calls one or more levels. */
128
+ function collectHelpers(sf) {
129
+ const helpers = new Map();
130
+ sf.forEachChild((node) => {
131
+ if (ts.isFunctionDeclaration(node) && node.name && node.body) {
132
+ helpers.set(node.name.text, node.body);
133
+ }
134
+ else if (ts.isVariableStatement(node)) {
135
+ for (const d of node.declarationList.declarations) {
136
+ if (ts.isIdentifier(d.name) &&
137
+ d.initializer &&
138
+ (ts.isArrowFunction(d.initializer) || ts.isFunctionExpression(d.initializer))) {
139
+ helpers.set(d.name.text, d.initializer.body);
140
+ }
141
+ }
142
+ }
143
+ });
144
+ return helpers;
145
+ }
146
+ const MAX_HELPER_DEPTH = 4;
147
+ function analyzeBody(body, vocab, ctxParam, helpers, visited, depth) {
148
+ let hasAssertion = false;
149
+ let callCount = 0;
150
+ let hasUnresolved = false;
151
+ const visit = (node) => {
152
+ if (hasAssertion)
153
+ return;
154
+ // chai BDD: `result.should.equal(x)` — the assertion signal is the `.should` property.
155
+ if (ts.isPropertyAccessExpression(node) && node.name.text === 'should') {
156
+ hasAssertion = true;
157
+ return;
158
+ }
159
+ if (ts.isCallExpression(node)) {
160
+ callCount++;
161
+ if (isAssertionCallee(node.expression, vocab, ctxParam)) {
162
+ hasAssertion = true;
163
+ return;
164
+ }
165
+ const callee = node.expression;
166
+ const localName = ts.isIdentifier(callee) ? callee.text : undefined;
167
+ if (localName && helpers.has(localName)) {
168
+ if (!visited.has(localName) && depth < MAX_HELPER_DEPTH) {
169
+ visited.add(localName);
170
+ const sub = analyzeBody(helpers.get(localName), vocab, undefined, helpers, visited, depth + 1);
171
+ if (sub.hasAssertion) {
172
+ hasAssertion = true;
173
+ return;
174
+ }
175
+ if (sub.hasUnresolved)
176
+ hasUnresolved = true;
177
+ // else: a fully-resolved helper that cannot assert — contributes a call but nothing asserting.
178
+ }
179
+ else {
180
+ hasUnresolved = true; // recursion limit / cycle — stay safe.
181
+ }
182
+ }
183
+ else {
184
+ hasUnresolved = true; // external/unknown call could assert indirectly.
185
+ }
186
+ }
187
+ ts.forEachChild(node, visit);
188
+ };
189
+ visit(body);
190
+ return { hasAssertion, callCount, hasUnresolved };
191
+ }
192
+ function statementCount(body) {
193
+ if (ts.isBlock(body))
194
+ return body.statements.length;
195
+ return 1; // expression-bodied arrow
196
+ }
197
+ function ctxParamName(fn) {
198
+ const p = fn.parameters[0];
199
+ if (p && ts.isIdentifier(p.name))
200
+ return p.name.text;
201
+ return undefined;
202
+ }
203
+ function scriptKindFor(path) {
204
+ if (/\.tsx$/i.test(path))
205
+ return ts.ScriptKind.TSX;
206
+ if (/\.jsx$/i.test(path))
207
+ return ts.ScriptKind.JSX;
208
+ if (/\.[cm]?ts$/i.test(path))
209
+ return ts.ScriptKind.TS;
210
+ return ts.ScriptKind.JS;
211
+ }
212
+ /** Inclusive overlap test between a node's [start,end] line range and the diff's added lines. */
213
+ function isTouched(addedLines, startLine, endLine) {
214
+ if (addedLines.size === 0)
215
+ return false;
216
+ for (let l = startLine; l <= endLine; l++) {
217
+ if (addedLines.has(l))
218
+ return true;
219
+ }
220
+ return false;
221
+ }
222
+ function analyzeFile(sf, path, addedLines) {
223
+ const findings = [];
224
+ const vocab = collectVocab(sf);
225
+ const helpers = collectHelpers(sf);
226
+ const visit = (node) => {
227
+ if (ts.isCallExpression(node)) {
228
+ const info = calleeInfo(node.expression);
229
+ if (info.root && TEST_ROOTS.has(info.root) && !info.hasSkip) {
230
+ const fn = testBodyFn(node);
231
+ if (fn) {
232
+ const startLine = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
233
+ const endLine = sf.getLineAndCharacterOfPosition(node.getEnd()).line + 1;
234
+ if (isTouched(addedLines, startLine, endLine)) {
235
+ findings.push(evaluateTest(node, fn, sf, path, vocab, helpers, startLine, endLine));
236
+ }
237
+ // Don't descend into the test body looking for nested tests — tests don't nest meaningfully.
238
+ return;
239
+ }
240
+ }
241
+ }
242
+ ts.forEachChild(node, visit);
243
+ };
244
+ visit(sf);
245
+ return findings;
246
+ }
247
+ function evaluateTest(call, fn, sf, path, vocab, helpers, startLine, endLine) {
248
+ const name = testName(call);
249
+ const label = name ? `"${name}"` : 'this test';
250
+ const ctxParam = ctxParamName(fn);
251
+ const analysis = analyzeBody(fn.body, vocab, ctxParam, helpers, new Set(), 0);
252
+ let verdict;
253
+ let title;
254
+ let detail;
255
+ if (analysis.hasAssertion) {
256
+ verdict = 'PASS';
257
+ title = 'Test asserts';
258
+ detail = `${label} contains at least one assertion.`;
259
+ }
260
+ else if (statementCount(fn.body) === 0) {
261
+ verdict = 'CONTRADICTED';
262
+ title = 'Test body is empty';
263
+ detail = `${label} has an empty body and asserts nothing — it can never fail.`;
264
+ }
265
+ else if (analysis.callCount === 0) {
266
+ verdict = 'CONTRADICTED';
267
+ title = 'Test asserts nothing';
268
+ detail = `${label} has no assertions and calls nothing that could assert — it can never fail.`;
269
+ }
270
+ else if (analysis.hasUnresolved) {
271
+ verdict = 'UNVERIFIED';
272
+ title = 'No assertion found';
273
+ detail =
274
+ `No assertion was detected in ${label}, but it calls a function Tribunal cannot resolve ` +
275
+ `(an external/imported helper) that may assert. Verify manually.`;
276
+ }
277
+ else {
278
+ verdict = 'CONTRADICTED';
279
+ title = 'Test asserts nothing';
280
+ detail =
281
+ `${label} only calls local helpers that contain no assertions — it can never fail.`;
282
+ }
283
+ return {
284
+ analyzer: 'assertion-free-test',
285
+ verdict,
286
+ file: path,
287
+ line: startLine,
288
+ endLine,
289
+ title,
290
+ detail,
291
+ };
292
+ }
293
+ export const assertionFreeTest = {
294
+ id: 'assertion-free-test',
295
+ title: 'Assertion-free tests',
296
+ description: 'Flags tests the PR added or changed that contain no assertion and therefore can never fail.',
297
+ kind: 'claim-independent',
298
+ run(ctx) {
299
+ const findings = [];
300
+ for (const f of ctx.changedFiles) {
301
+ if (f.status === 'deleted')
302
+ continue;
303
+ if (!isTestFile(f.path))
304
+ continue;
305
+ const src = ctx.readFile(f.path);
306
+ if (src == null)
307
+ continue;
308
+ const sf = ts.createSourceFile(f.path, src, ts.ScriptTarget.Latest, true, scriptKindFor(f.path));
309
+ findings.push(...analyzeFile(sf, f.path, f.addedLines));
310
+ }
311
+ return findings;
312
+ },
313
+ };
314
+ // Exposed for unit tests that drive a single source string directly.
315
+ export const __test__ = { analyzeFile, isTestFile, scriptKindFor };
316
+ //# sourceMappingURL=assertionFreeTest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertionFreeTest.js","sourceRoot":"","sources":["../../src/analyzers/assertionFreeTest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Analyzer } from '../types.js';
2
+ export declare const recognizedClaims: string[];
3
+ export declare const claimReconciliation: Analyzer;