babashka

sheluchin 2025-06-14T17:07:09.129329Z

Hey @borkdude I started getting some errors after upgrading 1.12.196 -> 1.12.201.

✅ 1
borkdude 2025-06-15T18:02:39.472099Z

Released a new version with the fix: https://clojurians.slack.com/archives/C015AL9QYH1/p1750010529889959

sheluchin 2025-06-14T17:07:37.310019Z

$ bb -m com.fnguy.phuzql.cli.picker
----- Error --------------------------------------------------------------------
Type:     clojure.lang.ExceptionInfo
Message:  Could not resolve symbol: taoensso.truss/try*
Data:     {:type :sci/error, :line 17, :column 1, :file "com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc", :phase "analysis"}
Location: com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:35:7
Phase:    analysis

----- Context ------------------------------------------------------------------
31:   (log/debug "Event loop started")
32:   (let [running? (atom true)]
33:     (async/go-loop []
34:       (async/<! (async/timeout resolution-ms))
35:       (enc/catching
          ^--- Could not resolve symbol: taoensso.truss/try*
36:         (sp/receive-events! event-queue env
37:           (fn [env {:keys [target] :as event}]
38:             (log/trace "Received event" event)
39:             (if-not target
40:               (log/warn "Event did not have a session target. This queue only supports events to charts." event)

----- Stack trace --------------------------------------------------------------
com.fulcrologic.statecharts.event-queue.core-async-event-loop         - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:35:7
com.fulcrologic.statecharts.event-queue.core-async-event-loop/loop    - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:35:7
clojure.core/loop                                                     - <built-in>
clojure.core/fn                                                       - <built-in>
com.fulcrologic.statecharts.event-queue.core-async-event-loop/go      - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:33:5
... (run with --debug to see elided elements)
com.fulcrologic.statecharts.event-queue.core-async-event-loop         - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:17:1
com.fnguy.phuzql.statecharts                                          - /tmp/dev_mounted_phuzql/src/com/fnguy/phuzql/statecharts.cljc:2:3
com.fnguy.phuzql.map-select-walker2                                   - /tmp/dev_mounted_phuzql/src/com/fnguy/phuzql/map_select_walker2.clj:2:3
com.fnguy.phuzql.cli.picker                                           - /tmp/dev_mounted_phuzql/src/com/fnguy/phuzql/cli/picker.clj:2:3
user                                                                  - <expr>:1:10

(py3-9_global) ✘-1 /tmp/dev_mounted_phuzql [main L|✚ 4…10] 
+13:06 $ /tmp/bb --version
babashka v1.12.196
The older version still works though.

sheluchin 2025-06-14T17:08:18.638079Z

I wonder if it's related to our last convo about Timbre https://clojurians.slack.com/archives/CLX41ASCS/p1749058086178649

borkdude 2025-06-14T17:09:09.105349Z

can you do some more bisecting, e.g. try the 200 version and see if that still worked? also a more minimal code repro would be nice

👍 1
sheluchin 2025-06-14T17:12:12.574479Z

Yeah, it's only the latest that breaks.

borkdude 2025-06-14T17:14:15.110159Z

I upgraded timbre to 6.7.0 and perhaps it changed some macro to emit code to "truss" which I never saw before in bb related code.

borkdude 2025-06-14T17:15:21.375739Z

hmm.

borkdude 2025-06-14T17:17:17.084339Z

encore seems like a high churn library

borkdude 2025-06-14T17:18:56.007079Z

taoensso/timbre uses encore (so I had to use encore macros in bb) but now encore uses truss

sheluchin 2025-06-14T17:25:37.722349Z

I could just downgrade by bb for now, not a big deal. Just thought I'd give you a heads up about the breaking change.

borkdude 2025-06-14T17:26:04.484819Z

thank you very much, fixing it now

sheluchin 2025-06-14T17:29:22.997489Z

Wonder if I should just make the jump to Telemere. Besides the point, I suppose. Thanks for taking a look.

borkdude 2025-06-14T17:31:19.554249Z

telemere doesn't work in bb btw

seancorfield 2025-06-14T17:32:58.136279Z

FWIW, part of why we moved away from timbre was the high level of churn and the interdependence between all of that maintainer's libraries.

seancorfield 2025-06-14T17:33:46.733509Z

What other logging options are there for babashka? Can it use any of the basic Java logging stuff?

borkdude 2025-06-14T17:34:35.765989Z

@seancorfield bb has clojure.tools.logging as the logging "interface" and timbre as the logging impl. I chose timbre because you don't need any config files (which is a no go for one-file scripts) and it's easy to use from clojure

borkdude 2025-06-14T17:35:03.765649Z

it has been part of bb for several years now (long before telemere)

borkdude 2025-06-14T17:36:32.804339Z

the taoensso.encore/catching this is just exposed for timbre since one of their logging macros expands into it, but incidentally it also made other libraries like mentioned in the OP work (which is a nice bonus). but the macroexpansion changed to yet another sub library

seancorfield 2025-06-14T17:39:44.917579Z

Ah, interesting... I know slf4j can be a nuisance in terms of nop/multiple deps (which is c.t.l's default) and log4j requires some minimal configuration. What about j.u.l as the implementation? Does it have reasonable defaults?

borkdude 2025-06-14T17:41:37.955999Z

I'm by no means a logging expert. In the commercial Clojure projects I've worked on, I've always encountered timbre, it wasn't even my own choice, so at the time it seemed like a good choice. Of course I could add j.u.l. but so far not a lot of people have asked for it. I won't remove timbre since that would be a major breaking change

borkdude 2025-06-14T17:49:52.966759Z

I guess for a library like in the OP it would be better to just rely on clojure.tools.logging and not bring in other logging deps

borkdude 2025-06-14T17:50:11.226919Z

I mean this one: https://github.com/fulcrologic/statecharts

borkdude 2025-06-14T17:52:39.053259Z

Here's the fix: https://github.com/babashka/babashka/pull/1830

🙌 1
sheluchin 2025-06-14T17:52:58.222029Z

Do you mean it would be better if the SC lib didn't use Timbre? Users of the lib don't really have much say about that, other than forking ofc.

borkdude 2025-06-14T17:53:43.519929Z

I mean, if I would write a library that needed logging, I'd try to rely solely on clojure.tools.logging and not bring in other deps (like encore or truss just because they provide some minor convenience around exception catching)

borkdude 2025-06-14T17:56:05.992739Z

the library doesn't even directly depend on encore, yet it uses it, which is sloppy: https://github.com/fulcrologic/statecharts/blob/b7ebeb080724dbeead94f73bcdc1963eecc531ff/deps.edn#L3

sheluchin 2025-06-14T17:56:13.016669Z

Understandable. I guess authors could have any number of reasons for choosing the stack for their libs. Perhaps in this case it's just to be more consistent with the rest of the author's related libs.

borkdude 2025-06-14T18:00:07.131499Z

@alex.sheluchin do you perhaps have the whole code of your cli? I'm trying to add some CI tests for statecharts but I don't know which namespaces it uses. Not familiar with the lib

sheluchin 2025-06-14T18:02:41.806199Z

One sec..

sheluchin 2025-06-14T18:06:48.588959Z

@borkdude I don't have the CLI pushed yet but perhaps this might be enough for your test? https://github.com/sheluchin/fnguy-examples/blob/main/examples/fulcro_statecharts/src/com/fnguy/coin_flip.cljc

borkdude 2025-06-14T18:08:32.161289Z

The test suite of statecharts unfortunately isn't able to run in bb since it loads ClojureScript, etc.

borkdude 2025-06-14T18:08:50.341709Z

I'll try to add your program as a sort of test

borkdude 2025-06-14T18:11:05.386999Z

hmm:

[com.fnguy.statecharts :as fnsc]

borkdude 2025-06-14T18:11:19.438559Z

is there some simple example I could add as a test?

sheluchin 2025-06-14T18:12:11.344139Z

That ns is just a few helper functions to simplify interacting with the statecharts.

sheluchin 2025-06-14T18:12:34.134429Z

Do you need it exposed as a top-level var or something?

borkdude 2025-06-14T18:13:06.500119Z

I just want one smoke gun test for statecharts to see if it runs in bb

borkdude 2025-06-14T18:13:10.329599Z

as a single script

borkdude 2025-06-14T18:16:00.220339Z

claude wrote this, can you check if it makes any sense?

#!/usr/bin/env bb

(require '[babashka.deps :as deps])

;; Add the dependency
(deps/add-deps '{:deps {com.fulcrologic/statecharts {:mvn/version "1.3.0"}}})

;; Require the statecharts namespace
(require '[com.fulcrologic.statecharts :as sc])

(defn smoke-test []
  "One simple test to verify fulcro-statecharts works"
  (println "🔥 Testing fulcro-statecharts in Babashka...")
  
  (try
    ;; Create a simple toggle statechart
    (let [chart-def {:id     :toggle
                     :initial :off
                     :states  {:off {:on {:TOGGLE {:target :on}}}
                              :on  {:on {:TOGGLE {:target :off}}}}}
          
          chart (sc/statechart chart-def)
          initial-state (sc/start chart)]
      
      (println "✓ Created statechart")
      (println (str "✓ Initial state: " (sc/current-state initial-state)))
      
      ;; Test transition
      (let [toggled-state (sc/trigger chart initial-state :TOGGLE)]
        (println (str "✓ After TOGGLE: " (sc/current-state toggled-state)))
        
        (if (= :on (sc/current-state toggled-state))
          (println "🎉 SUCCESS! Fulcro Statecharts works in Babashka!")
          (println "❌ FAIL: Unexpected state"))))
    
    (catch Exception e
      (println (str "❌ ERROR: " (.getMessage e))))))

;; Run the test
(smoke-test)

borkdude 2025-06-14T18:17:47.724029Z

sc/statechart
doesn't even seem to exist. But this is the kind of code I need. Just a simple example. I can't even see such an example in the README of statecharts and when looking at the test suite, I don't know even where to begin

sheluchin 2025-06-14T18:19:08.514259Z

No, that code's a bit weird. But if I add a bb.edn to my repo we can trigger that failure easily with bb -m com.fnguy.statecharts alone.

sheluchin 2025-06-14T18:19:24.618269Z

There's probably a much more minimal smoke test though. lms

borkdude 2025-06-14T18:19:52.243739Z

for starters, I could just require the main namespace and do nothing else.

sheluchin 2025-06-14T18:21:43.809169Z

I'm guessing that would be sufficient.

borkdude 2025-06-14T18:22:15.743759Z

usually that's only a good start, but a test would reveal runtime errors

borkdude 2025-06-14T18:22:28.399509Z

I'll just make this as a start, if you want to make another PR with some example, up to you

sheluchin 2025-06-14T18:23:55.141469Z

I'll add a flip-once you can call.

sheluchin 2025-06-14T18:24:20.544459Z

One a working version:

+14:23 $ /tmp/bb -m com.fnguy.coin-flip/flip-once
2025-06-14T18:24:06.556Z xps DEBUG [com.fulcrologic.statecharts.event-queue.core-async-event-loop:31] - Event loop started
2025-06-14T18:24:06.560Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:757] - Processing event on statechart => :com.fnguy.coin-flip/coin-flips
2025-06-14T18:24:06.561Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:199] - target(s) => [:state/coin]
2025-06-14T18:24:06.561Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:184] - target => :state/coin
2025-06-14T18:24:06.561Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:186] - target-element => :state/coin
2025-06-14T18:24:06.561Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:205] - (get-effective-target-states env t) => #{:state/coin}
2025-06-14T18:24:06.563Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:206] - (chart/nearest-ancestor-state statechart t) => :initial23309
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:213] - (:id (chart/find-least-common-compound-ancestor statechart (into (if tsource [tsource] []) tst
ates))) => :ROOT
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:199] - target(s) => [:state/coin]
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:184] - target => :state/coin
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:186] - target-element => :state/coin
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:368] - entry set => [#{:state/coin :state/heads} #{:state/coin} {}]
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:372] - Enter :state/coin
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:340] - Execute content of {:id :transition23310, :target [:state/heads], :type :external, :node-type 
:transition, :parent :initial23311}
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:386] - (chart/final-state? statechart s) => false
2025-06-14T18:24:06.564Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:372] - Enter :state/heads
2025-06-14T18:24:06.565Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:386] - (chart/final-state? statechart s) => false
2025-06-14T18:24:06.565Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:404] - after enter states:  => #{:state/coin :state/heads}
2025-06-14T18:24:06.565Z xps DEBUG [com.fulcrologic.statecharts.algorithms.v20150901-impl:434] - conflicting? => #{}
showing state {:wmem #:com.fulcrologic.statecharts{:history-value {}, :statechart-src :com.fnguy.coin-flip/coin-flips, :configuration #{:state/coin :state/heads}, :running? true, :macrostep-d
one? false, :initialized-states #{}, :session-id 1}}

sheluchin 2025-06-14T18:26:58.331959Z

/tmp/bb -m com.fnguy.coin-flip/flip-once gives the above but latest bb gives the error:

+14:24 $ bb -m com.fnguy.coin-flip/flip-once
----- Error --------------------------------------------------------------------
Type:     clojure.lang.ExceptionInfo
Message:  Could not resolve symbol: taoensso.truss/try*
Data:     {:type :sci/error, :line 17, :column 1, :file "com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc", :phase "analysis"}
Location: com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:35:7
Phase:    analysis

----- Context ------------------------------------------------------------------
31:   (log/debug "Event loop started")
32:   (let [running? (atom true)]
33:     (async/go-loop []
34:       (async/<! (async/timeout resolution-ms))
35:       (enc/catching
          ^--- Could not resolve symbol: taoensso.truss/try*
36:         (sp/receive-events! event-queue env
37:           (fn [env {:keys [target] :as event}]
38:             (log/trace "Received event" event)
39:             (if-not target
40:               (log/warn "Event did not have a session target. This queue only supports events to charts." event)

----- Stack trace --------------------------------------------------------------
com.fulcrologic.statecharts.event-queue.core-async-event-loop         - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:35:7
com.fulcrologic.statecharts.event-queue.core-async-event-loop/loop    - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:35:7
clojure.core/loop                                                     - <built-in>
clojure.core/fn                                                       - <built-in>
com.fulcrologic.statecharts.event-queue.core-async-event-loop/go      - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:33:5
... (run with --debug to see elided elements)
com.fulcrologic.statecharts.event-queue.core-async-event-loop         - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:17:1
com.fulcrologic.statecharts.event-queue.core-async-event-loop         - com/fulcrologic/statecharts/event_queue/core_async_event_loop.cljc:17:1
com.fnguy.statecharts                                                 - /home/alex/repos/personal-projects/fnguy-examples/examples/fulcro_statecharts/src/com/fnguy/statecharts.cljc:2:3
com.fnguy.coin-flip                                                   - /home/alex/repos/personal-projects/fnguy-examples/examples/fulcro_statecharts/src/com/fnguy/coin_flip.cljc:2:3
user                                                                  - <expr>:1:10

borkdude 2025-06-14T18:30:05.631789Z

is it possible to make it self-contained, i.e. not dependent on another namespace in your project and avoid the logging, so it can be tested against a value or so?

borkdude 2025-06-14T18:31:12.498959Z

no sweat if you don't but it would make testing easier and more robust.

sheluchin 2025-06-14T18:31:33.504069Z

I'll get back to you with a snippet a bit later

👍 1
borkdude 2025-06-14T18:31:38.593609Z

I added the require tests to this PR: https://github.com/babashka/babashka/pull/1830

borkdude 2025-06-14T18:38:31.029319Z

I merged the PR. Feel free to follow up with something later. Once master CI finishes you can test with:

bash <(curl )  --dev-build --dir /tmp

borkdude 2025-06-14T18:39:23.692869Z

I'll probably make a release for this, since it's annoying it broke again

sheluchin 2025-06-14T18:48:51.746139Z

Sounds good. Thanks again. I'll add a PR for a minimal statecharts test today or tomorrow. Just got back from a short vacation and have a few things to juggle.

borkdude 2025-06-14T19:10:51.711119Z

sure, no hurry and thanks in advance!

sheluchin 2025-06-14T19:11:34.278339Z

Do you just throw whatever code you want to try running into that statechart_test.clj file? No asserts and stuff?

borkdude 2025-06-14T19:13:15.466929Z

no, all the code are deftest + is based tests or I just straightup run the library code of existing libs

borkdude 2025-06-14T19:13:41.104029Z

only in special cases do I copy tests + adapt them a bit but with statecharts, I just don't know where to begin

borkdude 2025-06-14T19:14:14.896419Z

I'd do a smoketest myself if I saw an example in the README but it's pretty terse

sheluchin 2025-06-14T19:19:04.793839Z

Would this do?

(ns babashka.statecharts-test
  (:require
    [com.fulcrologic.statecharts :as sc]
    [com.fulcrologic.statecharts.chart :refer [statechart]]
    [com.fulcrologic.statecharts.elements :refer [state transition]]
    [com.fulcrologic.statecharts.events :refer [new-event]]
    [com.fulcrologic.statecharts.protocols :as sp]
    [com.fulcrologic.statecharts.simple :as simple]))

(def light-switch
  (statechart {:initial :off}
    (state {:id :on}
      (transition {:event :toggle, :target :off}))
    (state {:id :off}
      (transition {:event :toggle, :target :on}))))

(let [;; 1. Set up the environment and processor
      env       (simple/simple-env)
      _         (simple/register! env ::switch light-switch)
      processor (::sc/processor env)

      ;; 2. Start the machine and get initial state (s0)
      _  (println "--- Starting Light Switch Machine ---")
      s0 (sp/start! processor env ::switch {::sc/session-id 1})
      _  (println "Initial state:" (::sc/configuration s0))

      ;; 3. Send the first event, get next state (s1)
      _  (println "\nSending event: :toggle")
      s1 (sp/process-event! processor env s0 (new-event :toggle))
      _  (println "Current state:" (::sc/configuration s1))

      ;; 4. Send the second event, get final state (s2)
      _  (println "\nSending event: :toggle")
      s2 (sp/process-event! processor env s1 (new-event :toggle))]

  ;; 5. Print the final state from the last step
  (println "Current state:" (::sc/configuration s2)))

sheluchin 2025-06-14T19:19:24.048619Z

Pretty simple, just had Gemini whip it up with few small adjustments.

sheluchin 2025-06-14T19:19:44.478559Z

fails with v1.12.201

sheluchin 2025-06-14T19:21:53.252759Z

Oh, I think I misread your last message. So you would prefer a few assertions against the lib fn calls?

sheluchin 2025-06-14T19:28:14.317099Z

borkdude 2025-06-14T19:40:51.286839Z

ok let me try it

borkdude 2025-06-14T19:41:32.910019Z

works:

Ran 1 tests containing 3 assertions.
0 failures, 0 errors.
{:test 1, :pass 3, :fail 0, :error 0}

sheluchin 2025-06-14T19:42:23.279199Z

Cool. That should cover the basics to make sure the lib can run in bb, I think.

borkdude 2025-06-14T19:42:32.467059Z

thanks, I'll add it