@rulemetric/local 0.12.1 → 0.12.3

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.
@@ -0,0 +1,110 @@
1
+ -- 00205 — an unattended file writer may only write to a project's canonical
2
+ -- checkout.
3
+ --
4
+ -- THE DEFECT, found 2026-08-24 by releasing the staleness backlog and LOOKING at
5
+ -- what became eligible rather than assuming.
6
+ --
7
+ -- `enqueue_auto_accept_suggestions` groups by `instruction_suggestions.project_path`
8
+ -- verbatim. It has never asked whether that path is a checkout, let alone THE
9
+ -- checkout. While the catalog-skill backlog was stale that was invisible: the
10
+ -- pool held two paths. The moment the backlog was released, the producer's match
11
+ -- set was 13 paths, of which exactly TWO are canonical checkouts:
12
+ --
13
+ -- /Users/nickyeager 14 skills HOME DIRECTORY
14
+ -- /private/var/folders/dn/.../T 3 skills temp directory
15
+ -- /Users/nickyeager/Code/agents/momento-mori/apps/cli 7 skills the dead path from 00186
16
+ -- …/tinyworlds/.worktrees/image-blast-m4, -m6, -m7 13 skills worktrees
17
+ -- /Users/kylechalmers/Development 2 skills a parent of two workspaces
18
+ --
19
+ -- `/Users/nickyeager` is the one that matters most: `acceptSkill` writes under
20
+ -- `<projectPath>/.claude/skills/`, so the home directory means `~/.claude/skills/`
21
+ -- — the GLOBAL skills directory, loaded into every session of every project. An
22
+ -- unattended loop would have installed 14 skills globally and reported success.
23
+ --
24
+ -- 00202 cannot catch any of these. Its question is "is this path on disk", and
25
+ -- all of them are. This is the same defect as 00202's — a producer aiming at a
26
+ -- path nobody validated — wearing a different hat.
27
+ --
28
+ -- THE RULE, and it is not new. `public.project_canonical_checkouts` (00186) is
29
+ -- the single authority for which path IS a project, and CLAUDE.md's invariant is
30
+ -- that it must never be re-derived. `enqueue_instruction_training` has been
31
+ -- gated on it since 00188, whose comment records the identical failure: "the
32
+ -- project-level activity join in 00174 let every subpath of an active repo
33
+ -- through, and apps/cli collected 6 undead trials that way". Auto-accept — which
34
+ -- writes FILES rather than nominating trials — was never given the same gate.
35
+ -- It is the site that needed it most.
36
+ --
37
+ -- CONSEQUENCE, stated rather than buried: this blocks the external user
38
+ -- entirely, because none of his three paths is a canonical checkout. That is the
39
+ -- correct default for an unattended writer (better to write nowhere than into a
40
+ -- directory holding two unrelated workspaces), but it means his skill lane moves
41
+ -- from "dead via is_stale" to "dead via this gate", and the real fix is that his
42
+ -- checkouts are not registered in `project_checkouts`. Tracked separately; do not
43
+ -- widen this gate to paper over it.
44
+
45
+ create or replace function public.enqueue_auto_accept_suggestions()
46
+ returns integer
47
+ language plpgsql
48
+ security definer
49
+ set search_path = public
50
+ as $$
51
+ declare
52
+ queued integer;
53
+ begin
54
+ with eligible as (
55
+ select s.user_id, s.project_path
56
+ from instruction_suggestions s
57
+ join profiles p on p.id = s.user_id
58
+ join instructions i on i.id = s.instruction_id
59
+ left join projects proj on proj.id = s.project_id
60
+ where
61
+ s.kind = 'add'
62
+ and (s.score >= 0.8 or i.frontmatter->>'source' = 'insights')
63
+ and i.type in ('instruction', 'skill')
64
+ and i.archived = false
65
+ and s.accepted_at is null
66
+ and s.dismissed_at is null
67
+ -- Nobody answering is not a refusal (00203).
68
+ and (s.declined_at is null or s.declined_reason = 'surface_budget')
69
+ and s.is_stale = false
70
+ and coalesce(
71
+ proj.metadata->>'autoAcceptSuggestions',
72
+ p.auto_accept_suggestions::text
73
+ ) = 'true'
74
+ -- WHERE an unattended writer may write: the project's canonical checkout,
75
+ -- and nowhere else. Not a home directory, not a temp directory, not a
76
+ -- worktree, not a subdirectory somebody once opened a session in. Read
77
+ -- from the view, never re-derived (00186, and CLAUDE.md's invariant).
78
+ and exists (
79
+ select 1 from public.project_canonical_checkouts c
80
+ where c.path = s.project_path
81
+ )
82
+ -- The worker said this directory is not there (00202).
83
+ and not public.project_path_recently_missing(s.user_id, s.project_path)
84
+ and not exists (
85
+ select 1 from agent_jobs j
86
+ where j.task_kind = 'cron_auto_accept_suggestions'
87
+ and j.status in ('pending', 'claimed', 'running')
88
+ and j.payload->>'projectPath' = s.project_path
89
+ and j.user_id = s.user_id
90
+ )
91
+ group by s.user_id, s.project_path
92
+ ),
93
+ ins as (
94
+ insert into agent_jobs (user_id, task_kind, status, payload, dedupe_key)
95
+ select e.user_id,
96
+ 'cron_auto_accept_suggestions',
97
+ 'pending',
98
+ jsonb_build_object('projectPath', e.project_path),
99
+ 'auto-accept:' || e.user_id::text || ':' || e.project_path
100
+ from eligible e
101
+ returning 1
102
+ )
103
+ select count(*)::int into queued from ins;
104
+
105
+ return queued;
106
+ end;
107
+ $$;
108
+
109
+ comment on function public.enqueue_auto_accept_suggestions() is
110
+ 'Hourly producer for cron_auto_accept_suggestions. Requires a consented ADD proposal that is high-confidence or insights-authored, of an auto-adoptable type (00197), not declined by MEASUREMENT (00203), on a path that IS the project canonical checkout (00205 — releasing the staleness backlog revealed the match set was 13 paths of which 2 were checkouts; the others were a HOME directory, a temp directory, three worktrees and the dead apps/cli path, and acceptSkill would have written 14 skills into ~/.claude/skills/ globally), and that a worker has not reported missing from disk in 24h (00202).';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulemetric/local",
3
- "version": "0.12.1",
3
+ "version": "0.12.3",
4
4
  "description": "RuleMetric local-mode runtime: bundled API server, web dashboard, and database migrations for fully local (zero cloud contact) deployments. Installed on demand by `rulemetric local up` — not meant to be used directly.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -28,7 +28,7 @@
28
28
  "postgres": "^3.4.0",
29
29
  "resend": "^4.0.0",
30
30
  "zod": "^3.24.0",
31
- "@rulemetric/skills-registry": "0.12.1"
31
+ "@rulemetric/skills-registry": "0.12.3"
32
32
  },
33
33
  "devDependencies": {
34
34
  "esbuild": "^0.25.0",