本文へ移動
cccskills
無料GitHub で公開

bugs-to-grafema-capabilities

Fires after fixing any non-trivial bug or regression. Asks: could the graph have caught this as a guarantee? Pairs with reflection-in-and-on-action — picks up after "earliest catchable signal" and asks the next question: was that signal expressible in graph? Triggers: (1) after any non-trivial bug fix is verified working, (2) after a regression report (something used to work, broke), (3) during step 6 (knowledge extraction) of the workflow, (4) when reflection-on-action surfaces a "would have been catchable" signal. Outcome is a triage decision (graph-reachable? rule expressible? rule sound?) and either a draft Linear issue + guarantee proposal, or a recorded "graph capability gap" note. Never auto-creates guarantees.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md9.4 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Bugs → Grafema capabilities

Why this skill

Grafema's core thesis: AI should query the graph, not read code. A bug that was structurally visible — wrong call ordering, missing edge, dead branch, type mismatch — but never queried for is a missed guarantee. Every such bug is a chance to convert one-time pain into permanent CI protection.

Without this skill the loop breaks: bug fixed → moved on → next session repeats the same class. With this skill: bug fixed → pattern extracted → guarantee proposed → next sibling caught before merge.

Anchored to project vision (CLAUDE.md): "If reading code gives better results than querying Grafema — that's a product gap, not a workflow choice." A bug we caught by reading is exactly such a gap, until proven otherwise.

Pair with reflection-in-and-on-action

reflection-in-and-on-action ends a fix with three questions: predicted vs actual, earliest catchable signal, reusable pattern. Read those answers, then run THIS skill on the second one.

If reflection said "no clear earliest signal" → record that and stop. Don't force a rule on a non-structural bug. That's an honest "not graph material" outcome, not a failure.

If reflection said "the signal was X visible at code-shape level" → continue below.

Triggers (fire post-fix, NOT mid-fix)

  • Any non-trivial bug fix has been verified working (build green, test passes, e2e confirms)
  • A regression report just got resolved (something used to work, broke, was fixed)
  • Step 6 of workflow — knowledge extraction — and the session contained at least one bug fix
  • When reflection-in-and-on-action produces an "earliest catchable signal" and the signal is structural

DO NOT fire mid-fix. Premise reflection during the fix; capability reflection after. Mixing them blurs both.

Procedure

Step 1 — Triage scope: is the bug graph-reachable?

Stop and skip if:

  • Bug is in a language Grafema doesn't analyze. Currently the orchestrator self-analyzes JS/TS/Haskell/Rust/Python/Go/Java/Kotlin/Swift/ObjC/BEAM. Check spawn_analysis! in packages/grafema-orchestrator/src/main.rs for the live list — anything else is out of reach.
  • Bug is in build/CI/infrastructure (cargo flags, GitHub Actions, environment variables)
  • Bug is environmental: timing, network, OS-level race, file-system contention
  • Bug requires concrete runtime values (specific user input, specific data shapes only seen in prod)

Continue if the bug shape is structural: wrong call, missing edge, ordering of operations, scope/lifetime, type mismatch, dead code, resource lifecycle, dispatch-target mismatch, dependency cycle.

Step 2 — Generalize the bug into TWO patterns

Forget the specific lines. Sketch:

  1. Narrow pattern — captures THIS bug exactly. E.g. "function holding pool lock A then calling B which acquires A again."
  2. Broader pattern — variants that share the same failure mode. E.g. "any function holding a finite-resource handle, then calling into a function that re-acquires the same resource type."

Both matter. Narrow tests viability of the rule; broad tests its value. A guarantee that fires only on the original bug location is solving the past, not the future.

Step 3 — Express in Datalog (or surface why you can't)

Map the pattern to graph primitives:

  • Nodes: FUNCTION, METHOD, MODULE, CALL, BRANCH, VARIABLE, PARAMETER, CLASS, ISSUE, METRIC
  • Edges: CONTAINS, CALLS, ASSIGNED_FROM, GUARDED_WRITE, OBSERVES, DEPENDS_ON, INSTANCE_OF, PASSES_ARGUMENT
  • Numeric: lt, gt, lte, gte on attributes (line, count)
  • Negation: \+ for "no edge of type X"

If the rule needs concepts that don't exist as nodes/edges yet — STOP. Record the gap. A graph capability gap is more valuable than the rule itself, because it points to product work, not just lint work. Examples of capability gaps caught this way:

  • "Need a RECEIVER_CALL edge to detect a().b() chain receivers" (resolved Apr 2026)
  • "Need cross-file call traversal via CALLS to detect dispatch-into-pool patterns" (open)

Step 4 — Validate empirically (NON-NEGOTIABLE)

Write the Datalog. Run it. Three measurements:

  1. TP on origin — does it fire on the specific function/file the bug lived in? If not, your model of the bug is wrong. Refine.
  2. TP elsewhere — does it fire on at least 2 other locations? Inspect each. Are they real bugs you didn't know about, near-bugs, or false positives?
  3. FP rate — manually classify all hits. A guarantee with >20% FP is worse than no guarantee — it desensitizes everyone to checks. Either tighten or abandon.

Pair with break-new-abstractions-before-adopting: sample widely. If you have <3 distinct true-positive hits, the rule isn't load-bearing yet. Don't propose it.

Step 5 — Propose, don't auto-create

A graph guarantee gets wired into grafema check and CI — it's a product decision. Present:

  • The Datalog rule (final form)
  • Validation evidence: TP count with file:line refs, FP count with reasoning
  • Originating bug (commit SHA, Linear issue if any)
  • Draft Linear issue: REG-* (Reginaflow team) or RFD-* (RFDB team), labeled Improvement or Bug, version v0.2 or later

User decides. If green-lit:

  1. mcp__grafema__create_guarantee — writes to .grafema/guarantees.yaml
  2. File the Linear issue
  3. Reference the originating bug commit in the guarantee description

Step 6 — If not green-lit or fails Step 4

Record outcome in _ai/gaps.md (graph capability gap) or in memory (rule too noisy / pattern not structural). This is not a failure — it's calibration data for the next round. Pattern of repeated "not structural" outcomes in some domain → that domain may be inherently runtime-only and shouldn't be litigated again.

Worked example — 2026-04-28 orchestrator deadlock

Bug: acquire_all() held the pool's only worker; stream_and_resolve_single_worker then called pool.acquire() on the same depleted pool; drop(handles) was unreachable. Deterministic deadlock.

Step 1 — Graph-reachable? Yes. Code lives in packages/grafema-orchestrator/src/main.rs, in-graph (1052 CALL nodes confirmed).

Step 2 — Patterns:

  • Narrow: function calls acquire_all() then a later call to a function that internally calls pool.acquire()
  • Broad: any function holding a resource at finite-pool capacity, then dispatching to code that re-enters the same pool

Step 3 — Datalog draft:

violation(FnName, L1, L2) :-
  node(Fn, "FUNCTION"), attr(Fn, "name", FnName),
  edge(Fn, C1, "CONTAINS"), node(C1, "CALL"), attr(C1, "name", "acquire_all"), attr(C1, "line", L1),
  edge(Fn, C2, "CONTAINS"), node(C2, "CALL"), attr(C2, "name", "acquire"), attr(C2, "line", L2),
  lt(L1, L2).

Step 4 — Validation: Zero results. Initial diagnosis (and _ai/gaps.md entry) wrongly blamed missing analyzer; real cause: pool.acquire() is in plugin.rs::stream_and_resolve_single_worker, not in main.rs. Cross-file via CALLS edge required.

Step 5 — Outcome: No guarantee proposed. Recorded as graph capability gap: "cross-file call traversal for dispatch-into-pool patterns". Adding it depends on whether RFDB Datalog handles transitive CALLS efficiently — open product question.

Lesson: the validation step itself produced more value than the rule would have. The premature _ai/gaps.md entry blaming missing analyzer would have been pushed without Step 4.

Anti-patterns

  • Auto-creating guarantees on first match. No empirical sample → high FP risk → CI noise → desensitization. Always Step 4.
  • Skipping for "small" bugs. Small bugs are exactly where guarantees pay off — cheap to add, easy to validate.
  • Forcing a rule when the pattern isn't structural. "It just feels like the graph should catch this" — if you can't translate to nodes+edges, it can't, and that's fine.
  • Filing the task without validation. A task to add a rule that doesn't fire even on the origin location is a false promise.
  • Reusing the bug-fix patch as the rule. Patches reference specific lines; rules describe shapes. The skill is in the abstraction step, not the copying step.

Connection to other skills

  • reflection-in-and-on-action — predecessor; this skill consumes the "earliest catchable signal" answer
  • break-new-abstractions-before-adopting — Step 4 borrows the "sample widely, ≥3 cases" bar
  • extract-knowledge — Step 5 outcomes (rule, gap, or "not structural") are session-level findings worth saving regardless of whether a guarantee was proposed
  • materialize-only-what-queries-need — sister principle for the graph: don't add edges/attrs for hypothetical rules; only add them when a concrete rule needs them

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Fix Elixir/Erlang AST processing bugs in Grafema beam-analyzer. Use when: (1) Elixir parser returns MODULE node but 0 functions/calls — body nesting issue, (2) Erlang parser crashes with "cannot convert list to string" on OTP 26+ — location format changed from integer to keyword list, (3) pipe operator |> creates spurious CALL nodes instead of desugared function calls — clause ordering bug, (4) multi-module .ex files return only the first module — missing __block__ handler, (5) installing Erlang/Elixir on macOS with outdated Xcode/Clang.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Fix Playwright automation failures against code-server (VS Code in browser). Use when: (1) trust dialog blocks all clicks — "monaco-dialog-modal-block intercepts pointer events", (2) button:has-text() finds wrong buttons behind modal dialog, (3) keyboard shortcuts don't work — Meta vs Control inconsistency, (4) VS Code extension activity bar icon not found by aria-label, (5) panels show placeholder text despite extension being "Connected". Covers trust dialog dismissal, keyboard shortcut hybrid mode, extension panel selectors, and database connection verification for Grafema extension.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Systematic methodology for achieving 100% backward dataflow reachability in a new language. Create gauntlet fixture, write trace, diagnose gaps, fix analyzer/algorithm, iterate to 100%. Language-agnostic process. Use when: (1) adding a new language to Grafema, (2) auditing dataflow coverage for existing language, (3) user says "/dataflow-gauntlet".

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Fix docker exec hanging when starting background processes (servers, daemons) inside containers. Use when: (1) docker exec never returns despite using & or nohup, (2) background server started in container causes docker exec to hang indefinitely, (3) env_startup_command in SWE-bench or similar frameworks times out, (4) setsid/disown needed for proper process detachment in Docker. Root cause: docker exec tracks ALL processes in the exec session, not just the top-level PID.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Fix Node.js CLI tools crashing inside Docker containers when host-installed node_modules require a newer Node version than the container provides. Use when: (1) "SyntaxError: Invalid regular expression flags" with /v flag in string-width or similar packages, (2) node_modules installed on host with Node 20+ but container has Node 18, (3) `npm install` with file: protocol creates symlinks that break inside Docker, (4) pnpm workspace packages become broken symlinks in containers. Covers version detection, Node binary mounting, and npm install strategies for cross-version compatibility.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Fix intermittent `{:no_translation, :unicode, :latin1}` crashes in Elixir escript daemons that use length-prefixed framed IPC on stdin/stdout. Use when: (1) daemon worker crashes only on some input files, usually ones with non-ASCII bytes (kanji, cyrillic, emoji); (2) error surfaces as `Protocol error` from daemon's error branch or as garbled frame-length bytes seen by the orchestrator/client side; (3) standalone one-shot mode works fine on the same input but multi-request daemon mode fails; (4) `IO.binread(:stdio, N)` returns `{:error, {:no_translation, :unicode, :latin1}}` despite the "bin" prefix suggesting it should be encoding-agnostic. Root cause is the escript default `:standard_io` encoding — it's `:unicode`, and `IO.binread` still routes through the io_server, which translates bytes to codepoints and errors when raw binary frames contain invalid UTF-8 sequences.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Disentinel のスキルをすべて見る

このスキルの問題を報告する