any-doctor 0.1.1 → 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.
- package/README.md +6 -6
- package/bin/analysis-host.js +1 -1
- package/bin/certify.js +1 -1
- package/bin/engine.js +1 -1
- package/bin/mask.js +1 -1
- package/docs/plans/finding-lifecycle/design.md +39 -0
- package/doctors/{async-doctor.mjs → async.mjs} +1 -1
- package/doctors/{convex-doctor.mjs → convex.mjs} +1 -1
- package/doctors/{effect-v4-doctor.mjs → effect-v4-kitlangton.mjs} +2 -2
- package/doctors/{openrouter-doctor.mjs → openrouter.mjs} +1 -1
- package/doctors/{slop-doctor.mjs → slop.mjs} +1 -1
- package/package.json +1 -1
- /package/doctors/{async-doctor.fixtures.mjs → async.fixtures.mjs} +0 -0
- /package/doctors/{convex-doctor.fixtures.mjs → convex.fixtures.mjs} +0 -0
- /package/doctors/{effect-v4-doctor.fixtures.mjs → effect-v4-kitlangton.fixtures.mjs} +0 -0
- /package/doctors/{openrouter-doctor.fixtures.mjs → openrouter.fixtures.mjs} +0 -0
- /package/doctors/{slop-doctor.fixtures.mjs → slop.fixtures.mjs} +0 -0
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ each with impact, why, fix, and the honest blind spots. `enter` copies a
|
|
|
32
32
|
fix prompt for your agent.
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
|
-
npx any-doctor@latest run slop
|
|
35
|
+
npx any-doctor@latest run slop # one doctor, straight to the report
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
Non-terminals and CI never see a prompt — output is stable and pipeable
|
|
@@ -42,11 +42,11 @@ Non-terminals and CI never see a prompt — output is stable and pipeable
|
|
|
42
42
|
|
|
43
43
|
| Doctor | Discipline | Checks |
|
|
44
44
|
|---|---|---:|
|
|
45
|
-
| **slop
|
|
46
|
-
| **convex
|
|
47
|
-
| **effect-v4-
|
|
48
|
-
| **openrouter
|
|
49
|
-
| **async
|
|
45
|
+
| **slop** | The recurring failures of LLM-written code: identical helpers copied across modules, dead exports, unread bindings, hostname-sniffed environments, careless substring matching, collapsed boolean states | 8 |
|
|
46
|
+
| **convex** | Convex discipline: indexed reads, bounded collects, validated args, awaited writes, honest runtime boundaries | 15 |
|
|
47
|
+
| **effect-v4-kitlangton** | Effect v4 discipline — the mechanical rules of the [kitlangton Effect skill](https://www.ui-skills.com/skills/kitlangton/effect), enforced | 10 |
|
|
48
|
+
| **openrouter** | OpenRouter discipline: stream errors surfaced, keep-alives skipped, cancellations that stop billing | 5 |
|
|
49
|
+
| **async** | Async and concurrency: dropped promise results, uncleared timers, fetch hygiene | 3 |
|
|
50
50
|
|
|
51
51
|
Checks ship positive and innocent-lookalike fixtures. `verify` compares an
|
|
52
52
|
exact multiset of rule/file/line and optional column, then runs shared innocent
|
package/bin/analysis-host.js
CHANGED
|
@@ -9,7 +9,7 @@ const modelCache = new Map();
|
|
|
9
9
|
const callsCache = new Map();
|
|
10
10
|
const spansCache = new Map();
|
|
11
11
|
// Test seam: the model cache is keyed by mtime+size for the process
|
|
12
|
-
// lifetime; tests bust it between cases. Invisible to slop
|
|
12
|
+
// lifetime; tests bust it between cases. Invisible to slop's
|
|
13
13
|
// default run (test-file consumers are the documented narrowing).
|
|
14
14
|
export function clearAnalysisCache() {
|
|
15
15
|
modelCache.clear();
|
package/bin/certify.js
CHANGED
|
@@ -161,7 +161,7 @@ export async function certify(mod, fixtures) {
|
|
|
161
161
|
}
|
|
162
162
|
// Verify always lists everything (includeTestsFor): the sandbox is
|
|
163
163
|
// the doctor's own world — a seed named *.test.ts is deliberate
|
|
164
|
-
// test data (effect-v4-
|
|
164
|
+
// test data (effect-v4-kitlangton's sleep-in-test depends on it).
|
|
165
165
|
const result = await inSandbox(fixture.seed, (tmp) => runOnce(tmp, mod, { includeTests: true }));
|
|
166
166
|
const diff = contract.compareFindings(fixture.expected, result.findings);
|
|
167
167
|
const row = { name: fixture.name, ok: diff.missing.length === 0 && diff.unexpected.length === 0, ...diff };
|
package/bin/engine.js
CHANGED
|
@@ -90,7 +90,7 @@ export function resolveAstGrepBinary() {
|
|
|
90
90
|
return cachedBinary;
|
|
91
91
|
}
|
|
92
92
|
// One batched query over a real repo emits tens of megabytes of JSON (the
|
|
93
|
-
// async
|
|
93
|
+
// async pilot's ten patterns produce 24MB over a 979-file repo) —
|
|
94
94
|
// spawnSync's 1MB default truncates that mid-array, and the crash reads as
|
|
95
95
|
// an ast-grep bug instead of a buffer bug. The ceiling exists so a runaway
|
|
96
96
|
// pattern (matching near-every node of a monorepo) fails loudly here
|
package/bin/mask.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
//
|
|
6
6
|
// Regex literals must be masked because they may contain quote
|
|
7
7
|
// characters: an unmasked /["']/ opens a phantom string that swallows
|
|
8
|
-
// every line after it (found by slop
|
|
8
|
+
// every line after it (found by slop flagging imports whose
|
|
9
9
|
// type-position uses had been masked out of existence).
|
|
10
10
|
//
|
|
11
11
|
// Two host-side consumers share it: ctx.files.readMasked (the sdk — what
|
|
@@ -88,6 +88,45 @@ changed doctor can support an explicit detector comparison, not a code-fix claim
|
|
|
88
88
|
Expired detailed history must be identified as unavailable, not reconstructed as
|
|
89
89
|
complete from summary counters.
|
|
90
90
|
|
|
91
|
+
## Doctor identity across authors and renames (planned, M3)
|
|
92
|
+
|
|
93
|
+
Decisions crossing trust boundaries — committed project records shared
|
|
94
|
+
through Git — need doctor identity that is unique across authors and
|
|
95
|
+
stable across display renames. Two mechanisms, both visible, both
|
|
96
|
+
authored; no hidden self-asserted IDs:
|
|
97
|
+
|
|
98
|
+
- **Namespace/id.** A doctor's full key is `namespace/id` when it
|
|
99
|
+
declares a `namespace` (kebab-case author or origin), bare `id`
|
|
100
|
+
otherwise. Bundled doctors stay bare forever — the curated first-party
|
|
101
|
+
pack — so the 0.1.2 rename never churns again; third-party doctors
|
|
102
|
+
MUST declare a namespace, making `alice/convex` and `bob/convex`
|
|
103
|
+
distinct by construction while keys stay human-readable (surfaces may
|
|
104
|
+
show the friendly id; machine surfaces carry the full key). A copy
|
|
105
|
+
that keeps the same namespace/id is honestly the same doctor; a fork
|
|
106
|
+
that changes meaning diverges through provenance (revision/digest).
|
|
107
|
+
Self-generated UUIDs are ruled out: they travel with file copies,
|
|
108
|
+
producing invisible collisions — worse than name collisions because
|
|
109
|
+
nobody can read the key. The doctor identity key never drops its
|
|
110
|
+
namespace component: matching decisions on code evidence alone would
|
|
111
|
+
let one doctor's decision suppress another doctor's finding at the
|
|
112
|
+
same location — the cross-doctor suppression the identity layer
|
|
113
|
+
exists to prevent.
|
|
114
|
+
- **`supersedes` for renames.** Renaming is a semantic event only the
|
|
115
|
+
doctor's owner can assert: `supersedes: "convex-doctor"` (old full
|
|
116
|
+
key). On load, the state layer migrates decisions from superseded
|
|
117
|
+
keys to the new ones, gated on provenance continuity — revision or
|
|
118
|
+
program digest must still match; a rename combined with a meaning
|
|
119
|
+
change resurfaces decisions for reassessment rather than silently
|
|
120
|
+
carrying. This is the explicit, authored version of "identity
|
|
121
|
+
survives renames": no invisible magic, and the migration is visible
|
|
122
|
+
in state.
|
|
123
|
+
|
|
124
|
+
Both land with M3 (they are load-bearing only once decisions are
|
|
125
|
+
committed and shared); the doctor contract and the authoring skill
|
|
126
|
+
teach the declaration from day one so authored doctors arrive
|
|
127
|
+
namespaced. The 0.1.1→0.1.2 bundled rename churns once, deliberately,
|
|
128
|
+
while exposure is near zero; `supersedes` is not retrofitted for it.
|
|
129
|
+
|
|
91
130
|
## Team convergence
|
|
92
131
|
|
|
93
132
|
For the same source, compatible doctors/engines, configuration, and committed
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const meta = {
|
|
2
|
-
id: "effect-v4-
|
|
2
|
+
id: "effect-v4-kitlangton",
|
|
3
3
|
description: "Effect v4 discipline: typed errors over hand-rolled tags, Config over direct env reads, named Effect.fn, deterministic generators, validated boundaries, no casts that silence the type system. The mechanical rules of the kitlangton Effect skill, enforced.",
|
|
4
4
|
severity: "warning",
|
|
5
5
|
category: "effect",
|
|
@@ -312,7 +312,7 @@ function checkSchemaClass(ctx, file, lines) {
|
|
|
312
312
|
|
|
313
313
|
// Two shapes: the Data.TaggedError class-builder (any usage), and any class
|
|
314
314
|
// declaring its own _tag member - the body is brace-tracked from the class
|
|
315
|
-
// line the same way convex
|
|
315
|
+
// line the same way convex tracks function bodies.
|
|
316
316
|
function checkTaggedError(ctx, file, lines) {
|
|
317
317
|
for (let i = 0; i < lines.length; i++) {
|
|
318
318
|
if (/\bData\.TaggedError\b/.test(lines[i])) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const meta = {
|
|
2
|
-
id: "slop
|
|
2
|
+
id: "slop",
|
|
3
3
|
description: "LLM slop discipline: duplicated helpers, dead exports and unread bindings, hostname-sniffed environments, careless text matching, collapsed boolean states. Born from 1,368 Bugbot findings across 182 reviewed PRs.",
|
|
4
4
|
severity: "warning",
|
|
5
5
|
category: "slop",
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|