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 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-doctor # one doctor, straight to the report
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-doctor** | 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-doctor** | Convex discipline: indexed reads, bounded collects, validated args, awaited writes, honest runtime boundaries | 15 |
47
- | **effect-v4-doctor** | Effect v4 discipline — the mechanical rules of the [kitlangton Effect skill](https://www.ui-skills.com/skills/kitlangton/effect), enforced | 10 |
48
- | **openrouter-doctor** | OpenRouter discipline: stream errors surfaced, keep-alives skipped, cancellations that stop billing | 5 |
49
- | **async-doctor** | Async and concurrency: dropped promise results, uncleared timers, fetch hygiene | 3 |
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
@@ -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-doctor's
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-doctor's sleep-in-test depends on it).
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-doctor pilot's ten patterns produce 24MB over a 979-file repo) —
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-doctor flagging imports whose
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: "async-doctor",
2
+ id: "async",
3
3
  description: "Async and concurrency discipline: fetch hygiene, promise handling, timer cleanup.",
4
4
  severity: "warning",
5
5
  category: "async",
@@ -1,5 +1,5 @@
1
1
  export const meta = {
2
- id: "convex-doctor",
2
+ id: "convex",
3
3
  description: "Convex discipline: indexed reads, bounded collects, query clocks, discarded promises, validated args, awaited writes, honest runtime boundaries.",
4
4
  severity: "warning",
5
5
  category: "convex",
@@ -1,5 +1,5 @@
1
1
  export const meta = {
2
- id: "effect-v4-doctor",
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-doctor tracks function bodies.
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: "openrouter-doctor",
2
+ id: "openrouter",
3
3
  description: "OpenRouter discipline: stream errors surfaced, keep-alives skipped, cancellations that stop billing.",
4
4
  severity: "warning",
5
5
  category: "openrouter",
@@ -1,5 +1,5 @@
1
1
  export const meta = {
2
- id: "slop-doctor",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "any-doctor",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Your agent writes the analyzer, fixtures prove it, CI reruns it forever.",
5
5
  "license": "MIT",
6
6
  "bin": {