hyperfiddle

tobias 2025-05-20T03:19:48.945029Z

I'm having trouble using pprint and with-out-str. Example: (dom/p (dom/text (with-out-str (pprint {:a 1})))) results in error: [clojure.core/*out*] is not an electric var

tobias 2025-05-20T04:03:54.109709Z

Workaround for now:

#?(:cljs
    (:require [goog.string.StringBuffer]
              [cljs.pprint :refer [pprint]]))


(defn pprint-str [x]
  (let [sb (goog.string.StringBuffer.)]
    (binding [*print-newline* true
              *print-fn* (fn [s] (.append sb s))]
      (pprint x))
    (str sb)))

Dustin Getz (Hyperfiddle) 2025-05-20T11:47:56.521509Z

yeah clojure bindings are not Electric-compatible, you need to wrap

👍 1
2025-05-20T13:25:25.897429Z

I want to use hyperfiddle.electric-forms5, but add translations to commit/discard buttons. What's a good way to do this? I don't want to change the forms5 file, as I expect new versions to roll out. Do I just hack it with JS, (set! (.-textContent commit-btn) "Commit")?

Dustin Getz (Hyperfiddle) 2025-05-20T13:53:30.840409Z

it may be possible to do override in pure css, but yes hacks are acceptable IMO

Dustin Getz (Hyperfiddle) 2025-05-20T13:54:24.712849Z

i will note the internationalization requirement

Dustin Getz (Hyperfiddle) 2025-05-20T13:56:12.539069Z

electric-forms is not in as good state as we want it to be because we had to switch workstreams for a few months – mostly we direct our roadmap based on what our customers need

2025-05-20T13:57:11.130859Z

Ok, thanks for a fast answer

Geoffrey Gaillard 2025-05-20T14:34:59.775379Z

This should work today. You can customize “Submit” and “Cancel”.

(ns ...
  (:require [hyperfiddle.electric-forms5 :refer [Form! Input! SubmitButton! DiscardButton!]]))

(Form! {::message "hello"}
  (e/fn [{:keys [::message]}]
    (e/amb
      (Input! ::message message)
      (SubmitButton! :label "Submit")
      (DiscardButton! :label "Cancel"))))

🙏 1
Dustin Getz (Hyperfiddle) 2025-05-20T13:56:59.808029Z

Reminder, I'm speaking at ReClojure (London) next week. The topic will be process supervision, differential dataflow, and user interfaces.

👍 1
🤘 10
2025-05-20T21:59:52.576229Z

I'm having trouble with the starter-app. I renamed all (afaict) the references to electric-starter-app with my directory name, but it seems the main.js file that shadow-cljs builds is corrupted. I can't open it, with emacs/`cat` /`head`

(base) baruchberger@192 bb % clj -A:dev -X dev/-main 
INFO  dev: Starting Electric compiler and server...
INFO  io.undertow: starting server: Undertow - 2.3.10.Final
INFO  org.xnio: XNIO version 3.8.8.Final
INFO  org.xnio.nio: XNIO NIO Implementation Version 3.8.8.Final
INFO  org.jboss.threads: JBoss Threads version 3.5.0.Final
shadow-cljs - server version: 2.26.2 running at 
shadow-cljs - nREPL server started on port 51774
[:dev] Configuring build.
[:dev] Compiling ...
Compiling ...
[:dev] Build completed. (200 files, 1 compiled, 0 warnings, 1,35s)
INFO  dev: 👉 
WARN  org.eclipse.jetty.server.HttpChannel: handleException /js/main.js java.io.FileNotFoundException: /Users/baruchberger/bb/resources/public/bb/js/main.js (Operation not permitted) 

2025-05-23T09:19:20.804429Z

Yeah for dev I tried to create a docker container for dev mode, manually curled the token to make it build, but couldn't yet open the server then ran out of time (or rather, got excited by the claude 4 release).

2025-05-23T09:19:58.564689Z

2025-05-23T09:21:29.400129Z

This is what bitdefender has in the history. It includes attempts I made to clear the xattr macOS file metadata and putting the files into different directories etc.

2025-05-23T09:21:56.426789Z

GT-JS Acsogenixx.284.CEC83A89 resident access to the file has been denied /Users/baruchberger/electric3-starter-app/resources/public/electric...

Dustin Getz (Hyperfiddle) 2025-05-23T11:01:21.805439Z

does it say why it flagged the file?

Dustin Getz (Hyperfiddle) 2025-05-23T11:01:31.896249Z

do other clojurescript projects build?

2025-05-23T11:02:34.307309Z

The why would be that acsogenixx detection. More information than this is not given sadly.

👀 1
2025-05-23T11:02:52.604679Z

Yes other projects build, it’s the first time I run into trouble like this.

Dustin Getz (Hyperfiddle) 2025-05-23T11:07:19.187039Z

Can you please upload the flagged file to https://www.virustotal.com/gui/home/upload and see what it says

Dustin Getz (Hyperfiddle) 2025-05-23T11:07:37.066649Z

to determine if this is a false positive based on how many engines flag it

Dustin Getz (Hyperfiddle) 2025-05-23T11:08:09.567369Z

GT-JS means generic trojan - javascript, it is not a specific signature match

Dustin Getz (Hyperfiddle) 2025-05-23T11:08:46.865879Z

also can you upload it here as an attachment, i am going to compare to results on my machine

Dustin Getz (Hyperfiddle) 2025-05-23T11:09:45.980369Z

what's weird is that our js asset does not contain auth code or servers or anything weird it's just another cljs app, so my first question is - maybe your system is compromised?

2025-05-23T11:17:42.487749Z

I also tried to send the file here but slack won't let me.

Dustin Getz (Hyperfiddle) 2025-05-23T11:19:12.119569Z

due to virus detection?

2025-05-23T11:19:54.106749Z

I don't know, could be big slack server restrictions, I would try to just send a text snippet but can't view the text in any program that lets me copy 😅

2025-05-23T11:20:20.407339Z

I can see it in the mac finder preview though, just seems like a regular shadow-cljs built main file.

Dustin Getz (Hyperfiddle) 2025-05-23T11:20:40.501419Z

drag drop it into slack as a file to use the attachment feature

2025-05-23T11:20:48.043459Z

I did, but that blocked it.

2025-05-23T11:20:58.784439Z

I guess my filesystem won't let it.

Dustin Getz (Hyperfiddle) 2025-05-23T11:21:06.124859Z

how about a gist

Dustin Getz (Hyperfiddle) 2025-05-23T11:22:08.297949Z

oh bitdefender is blocking you from viewing the content

2025-05-23T11:22:11.953239Z

Yes

2025-05-23T11:22:39.492279Z

I can view it in the finder however, I could transcribe it with ocr but it's 55kb and a small window.

2025-05-23T11:23:15.763669Z

The virus total thing has a behaviour tab which is interesting. It says it's creating files? C:\Windows\ServiceProfiles\LocalService\AppData\Local\FontCache\Fonts\Download-1.tmp

Dustin Getz (Hyperfiddle) 2025-05-23T11:26:24.830679Z

it does not look good that's for sure

Dustin Getz (Hyperfiddle) 2025-05-23T11:27:43.884449Z

but i don't see how electric-starter-app can be compromised, the file came from shadow. the most likely thing based on available evidence is that something on your system appended malicious js to the end

Dustin Getz (Hyperfiddle) 2025-05-23T11:28:12.477699Z

i still need to see if a main.js from my system produces the same alert

2025-05-23T11:28:32.081509Z

Okay, I'm trying to OCR transcribe the whole file

2025-05-23T11:28:47.854899Z

somehow finder of macOS has a preview window I can scroll in

Dustin Getz (Hyperfiddle) 2025-05-23T11:28:56.410079Z

lol

Dustin Getz (Hyperfiddle) 2025-05-23T11:29:21.093059Z

I thought you said you were on a mac mini btw?

Dustin Getz (Hyperfiddle) 2025-05-23T11:29:42.321289Z

oh, that came from the scanner tool's sandbox test machine

2025-05-23T11:29:56.252119Z

Yes

2025-05-23T12:10:12.210859Z

Hmm, I transcribed the whole thing with chatGPT which was laborious, but uploading that reconstructed file doesn't make any alarm bells go off with totalvirus.

👀 1
2025-05-23T12:14:14.677119Z

Can you reproduce? Because I just tried on my laptop where I was playing with electric on earlier and that also has it.

2025-05-23T12:16:46.176649Z

That's the file.

2025-05-23T12:23:38.617279Z

Seems like it's a false positive. But why does that not happen for other bundles. 😕

Dustin Getz (Hyperfiddle) 2025-05-23T15:23:23.709369Z

i have not attempted to repro, but i did review the file and agree i do not see malicious code ... but how does it do that stuff in the test sandbox?

Dustin Getz (Hyperfiddle) 2025-05-23T15:24:08.585969Z

is this the actual file or an OCR?

2025-05-23T15:24:45.099939Z

This is the actual file (download and see it fail the virustotal). I also don't know why that does that stuff in the test sandbox.

2025-05-23T15:26:03.456499Z

If I were to be infected and this only happens for my machines then this would be a super advanced threat, and somewhat strange to be targeting windows from a macos machine.

Dustin Getz (Hyperfiddle) 2025-05-23T15:27:13.732059Z

the windows targetting is in the secondary payload, the trojan bootstraps by just connecting to a control server and downloading the next stage

2025-05-23T15:27:34.916719Z

Ah that would make sense.

2025-05-23T15:29:43.548749Z

should I spin up a cloud machine to see if I can reproduce?

Dustin Getz (Hyperfiddle) 2025-05-23T15:31:31.654959Z

nah

Dustin Getz (Hyperfiddle) 2025-05-23T15:32:03.905499Z

there doesn't seem to be a threat here, i will continue to investigate when i have time (likely backlog until we get another report as we are traveling to reclojure tomorrow)

Dustin Getz (Hyperfiddle) 2025-05-23T15:32:25.191409Z

i am just "confused" 🙂

2025-05-23T15:32:47.781989Z

Alright, thanks for having a look anyway. Safe travels to ReClojure!

Dustin Getz (Hyperfiddle) 2025-05-23T15:32:50.936199Z

ty for the reports and diagnosing

2025-05-23T15:33:03.225679Z

sure thing

Dustin Getz (Hyperfiddle) 2025-05-20T22:03:23.576579Z

could there be a unix permissions issue? e.g. you accidentally cloned with root or something?

2025-05-20T22:03:27.204009Z

Things I've tried: • removing .cpcache .shadow-cljs and trying again • doing all with sudo • seeing if there's anything special about my filesystem, can't find anything, other files in the resources dir open

Dustin Getz (Hyperfiddle) 2025-05-20T22:03:38.621759Z

try fresh clone in new directory

2025-05-20T22:04:23.704169Z

I've also tried that, but I'll try it with nothing renamed and (meaning electric-starter-app -> something else)

2025-05-20T22:05:48.103949Z

(base) baruchberger@192 ~ % git clone 
Cloning into 'electric3-starter-app'...
remote: Enumerating objects: 305, done.
remote: Counting objects: 100% (197/197), done.
remote: Compressing objects: 100% (128/128), done.
remote: Total 305 (delta 81), reused 92 (delta 36), pack-reused 108 (from 1)
Receiving objects: 100% (305/305), 262.36 KiB | 18.74 MiB/s, done.
Resolving deltas: 100% (108/108), done.
(base) baruchberger@192 ~ % cd electric3-starter-app 
(base) baruchberger@192 electric3-starter-app % 
(base) baruchberger@192 electric3-starter-app % clj -A:dev -X dev/-main                                      
Downloading: com/hyperfiddle/electric/v3-alpha-SNAPSHOT/maven-metadata.xml from clojars
Downloading: com/hyperfiddle/hyperfiddle-contrib/v0-alpha-SNAPSHOT/maven-metadata.xml from clojars
Downloading: com/hyperfiddle/hyperfiddle-contrib/v0-alpha-SNAPSHOT/maven-metadata.xml from clojars
Downloading: com/hyperfiddle/electric/v3-alpha-SNAPSHOT/maven-metadata.xml from clojars
INFO  dev: Starting Electric compiler and server...
INFO  io.undertow: starting server: Undertow - 2.3.10.Final
INFO  org.xnio: XNIO version 3.8.8.Final
INFO  org.xnio.nio: XNIO NIO Implementation Version 3.8.8.Final
INFO  org.jboss.threads: JBoss Threads version 3.5.0.Final
shadow-cljs - server version: 2.26.2 running at 
shadow-cljs - nREPL server started on port 54108
[:dev] Configuring build.
[:dev] Compiling ...
Please sign up or login to activate:  
Compiling ...
:hyperfiddle.electric.shadow-cljs.hooks3/recompile-clj hyperfiddle.electric3
:hyperfiddle.electric.shadow-cljs.hooks3/recompile-clj hyperfiddle.electric-css3
:hyperfiddle.electric.shadow-cljs.hooks3/recompile-clj hyperfiddle.electric-dom3-props
:hyperfiddle.electric.shadow-cljs.hooks3/recompile-clj hyperfiddle.electric-dom3
:hyperfiddle.electric.shadow-cljs.hooks3/recompile-clj electric-starter-app.main
[:dev] Build completed. (200 files, 199 compiled, 0 warnings, 12,61s)
INFO  dev: 👉 
WARN  org.eclipse.jetty.server.HttpChannel: handleException /js/main.js java.io.FileNotFoundException: /Users/baruchberger/electric3-starter-app/resources/public/electric_starter_app/js/main.js (Operation not permitted)
WARN  org.eclipse.jetty.server.HttpChannel: handleException /js/main.js java.io.FileNotFoundException: /Users/baruchberger/electric3-starter-app/resources/public/electric_starter_app/js/main.js (Operation not permitted)
Same problem

2025-05-20T22:06:28.174859Z

(base) baruchberger@192 electric3-starter-app % cat resources/public/electric_starter_app/index.css
@import url('');

* {
    box-sizing: border-box;
}

body {
    font-family: 'Open Sans', Arial, Verdana, sans-serif;
    background-color: rgb(248 250 252);
}
(base) baruchberger@192 electric3-starter-app % cat resources/public/electric_starter_app/js/main.js 
cat: resources/public/electric_starter_app/js/main.js: Operation not permitted

Dustin Getz (Hyperfiddle) 2025-05-20T22:07:13.037909Z

it looks like a system permission issue to me, MacOS has some weird security stuff happening in certain folders that i've seen cause issues like this

2025-05-20T22:07:33.887839Z

Hmm yes, but why only for the main file.

👀 1
2025-05-20T22:08:08.178049Z

(base) baruchberger@192 electric3-starter-app % head -n 5 resources/public/electric_starter_app/js/cljs-runtime/electric_starter_app.main.js
goog.provide('electric_starter_app.main');
electric_starter_app.main.Main = (function() {
var electric_starter_app$main$Main = null;
var electric_starter_app$main$Main__0 = (function (){
return cljs.core.PersistentHashMap.fromArrays([1],[hyperfiddle.electric.impl.runtime3.ctor(new cljs.core.Keyword("electric-starter-app.main","Main","electric-starter-app.main/Main",1906897109),(0))]);

Dustin Getz (Hyperfiddle) 2025-05-20T22:08:11.753019Z

ls -al ?

Dustin Getz (Hyperfiddle) 2025-05-20T22:08:29.249619Z

are you in a container?

2025-05-20T22:08:43.067299Z

(base) baruchberger@192 electric3-starter-app % ls -al resources/public/electric_starter_app/js 
total 128
drwxr-xr-x@   5 baruchberger  staff    160 May 21 00:05 .
drwxr-xr-x    6 baruchberger  staff    192 May 21 00:05 ..
drwxr-xr-x@ 403 baruchberger  staff  12896 May 21 00:05 cljs-runtime
-rw-r--r--@   1 baruchberger  staff  55103 May 21 00:05 main.js
-rw-r--r--@   1 baruchberger  staff   6037 May 21 00:05 manifest.edn
Not in a container

Dustin Getz (Hyperfiddle) 2025-05-20T22:09:14.480479Z

did it ever work previously?

2025-05-20T22:09:40.546909Z

Hmm, I've used the starter app a couple of times on my macbook a week or 2 back.

2025-05-20T22:10:03.367459Z

This is on my mac mini, I believe I've run electric 2 on it a long time ago. Not sure.

2025-05-20T22:13:11.703089Z

was the first electric thing I did, a week or 2/3 back, streaming LLM responses into a https://milkdown.dev/docs/guide/using-crepe editor. Challenging to get to know both electric and electric JS interop, but pretty results quick.

2025-05-21T07:47:52.944189Z

It seems this is caused by the licensing strategy electric v3 has. Interestingly grep can inspect the file, but cat can't. I think the code responsible for writing the main.js file might be in the dev hook?

Dustin Getz (Hyperfiddle) 2025-05-21T10:41:06.695809Z

but you said it works on your other computer?

2025-05-21T10:41:18.919159Z

Yes

2025-05-21T10:41:42.673389Z

But that was with a slightly older electric-starter-app codebase iirc

Dustin Getz (Hyperfiddle) 2025-05-21T10:45:47.512459Z

main.js is written by shadow, not us. electric hot code reloading is implemented as a shadow hook but the actual compilation is performed by shadow

2025-05-21T10:46:42.706309Z

I've had a talk with Thomas this morning: https://clojurians.slack.com/archives/C6N245JGG/p1747811285609769

Dustin Getz (Hyperfiddle) 2025-05-21T10:48:34.148499Z

like thomas, i think you have a system issue, i think you should try on another computer. you can also clone inside a docker container if you don't have access to another computer. many people (100s) have successfully ran the starter app

Dustin Getz (Hyperfiddle) 2025-05-21T10:49:45.313449Z

the purpose of the shadow hook is to reload the clj namespaces when shadow reloads cljs namespaces, otherwise your electric app will desync

2025-05-21T10:51:21.609769Z

Okay, I don't know what I could have done to my system that is out of order. But I'll try the container version, thanks!

Dustin Getz (Hyperfiddle) 2025-05-21T10:51:48.184199Z

as thomas and I both said, macos has insane and obtuse security mechanisms on the file system

Dustin Getz (Hyperfiddle) 2025-05-21T10:54:17.951849Z

they have also changed over the years, is your mac mini up to date?

2025-05-21T10:54:56.054809Z

Yeah, I believe you. Tried a bunch of suggestions wrt mac file protections and they all don't work out or show what's wrong. If even LLM's are stumped I'm sure it's obtuse.

2025-05-21T10:55:20.964469Z

Yeah it's 15.5

👀 1
2025-05-22T15:50:19.814859Z

Found the culprit, BitDefender.

👀 1
2025-05-22T15:50:24.442829Z

Works in docker though, but that's not the dev version. Trying to get that to work by adjusting the dockerfile.

Dustin Getz (Hyperfiddle) 2025-05-22T23:00:26.035939Z

by try in docker, i meant use a generic image, apt-get install git, apt-get install clojure, git clone

Dustin Getz (Hyperfiddle) 2025-05-22T23:00:51.730319Z

Do you have any additional info about the BitDefender issue? I want to make a note of it

cjmurphy 2025-05-20T22:25:46.181869Z

Can anyone help with a standard reactive query against Rama for V.3? This is the error I'm getting:

clojure.lang.ExceptionInfo: Value: missionary.core$relieve$fn__11209@1c7129bf {:v #function[missionary.core/relieve/fn--11209], :hyperfiddle.electric.impl.runtime3/unserializable true}
Using this code:
(defn proxy-callback [f]
  (fn [new _diff _old]
    (f new)))

(defn make-reactive-query [path pstate]
  (->> (m/observe
         (fn [!]
           (! nil)
           (let [cp (r/foreign-proxy-async path pstate {:callback-fn (proxy-callback !)})]
             #(.close @cp))))
    (m/relieve {})))
Which comes from this great project: https://github.com/jeans11/demo-rama-electric, which is now 2 years old.

cjmurphy 2025-05-23T15:22:25.183319Z

I tried the three things you mentioned, but this was always the result:

ETL-ing Item
{:item-id "CARROTSALAD00000",
 :org-id "164J0XYOR0OP335J",
 :neat-item
 {:id "CARROTSALAD00000",
  :price 239,
  :description "Bombay Carrot Salad",
  :kind :item.kind/product,
  :heading-id "SALADS0000000000"}}
{:new 4,
 :_diff
 #object[com.rpl.rama.diffs.NewValueDiff 0x764edee0 "NewValueDiff[[{:id \"CARROTSALAD00000\", :price 239, :description \"Bombay Carrot Salad\", :heading-id \"SALADS0000000000\", :kind :item.kind/product} {:id \"FALAFELSALAD0000\", :price 420, :description \"Falafel Salad\", :heading-id \"SALADS0000000000\", :kind :item.kind/product} {:id \"GARDENSALAD00000\", :price 235, :description \"Acme Garden Salad\", :heading-id \"SALADS0000000000\", :kind :item.kind/product} {:id \"SALADS0000000000\", :price nil, :description \"Salads\", :heading-id nil, :kind :item.kind/heading}]]"],
 :_old 4}
One only is being put into the *item-depot and thus gets ETL-ed into $$org->items and yet the diff is a NewValueDiff of all 4 dishes.

cjmurphy 2025-05-23T15:24:36.894269Z

This is what happens at the log "ETL-ing Item":

(r/local-transform> [(path/keypath *org-id *item-id)
                         #_(path/submap (keys *neat-item))
                         (m->multi-path *neat-item)
                         #_(path/termval *neat-item)] $$org->items)
It shows 2 of the suggestions being tried.

cjmurphy 2025-05-23T15:26:16.459049Z

This is the proxy path:

[(path/keypath id) (path/subselect path/MAP-VALS (path/submap [:id :price :description :heading-id :kind]))]

noonian 2025-05-20T23:47:01.891229Z

I have this working in my project but I am away from a computer atm. I'll post a snippet when I'm back in an hour or so

1
noonian 2025-05-21T01:02:35.619809Z

Ok, this is what I am currently using. It's pretty similar to the old one, but I don't give it an initial value of nil.

(defn proxy-flow
  "Usage: (e/join (e/flow->incseq (proxy-flow (keypath key) pstate)))"
  [path pstate]
  #?(:clj
     (-> (m/observe
           (fn [!]
             (let [cp-ps (r/foreign-proxy-async path pstate
                           {:callback-fn
                            (fn [new _diff _old]
                              (! new))})]
               (fn cleanup [arg]
                 (r/close! @cp-ps)))))
         (m/relieve))))
And this is how I use it (`deps/pstates` is a map of pstates declared with e/declare and dynamically bound in electric at app startup)
(e/defn ReactiveProxy [path pstate-name]
  (e/server
    (e/join (e/flow->incseq (proxy-flow path (get deps/pstates pstate-name))))))
The trick for me with v3 was discovering e/flow-incseq and learning about incseqs. I kind of had this working with e/input and a nil initial value, but I wanted to get rid of the nil initial value if the thing it's proxying is never nil. Feedback from the electric team is very welcome on the approach here as I've only gleaned info on incseq's from this slack

Dustin Getz (Hyperfiddle) 2025-05-21T11:03:10.269189Z

@cjmurphy i think your error is caused by the call site

henrik 2025-05-21T14:33:20.111599Z

The unserializable is almost certainly the middle argument of the callback function, diff, which is an object that won’t serialize without additional work.

henrik 2025-05-21T14:35:47.274349Z

If you emit new, as in Jed’s example, the error should disappear. In both cases, I would recommend closing the proxy with a .thenComposeAsyncor .whenCompleteAsync or similar to avoid locking up any threads in case it doesn’t deref in a timely manner.

cjmurphy 2025-05-21T16:20:21.597529Z

I had a few things to sort out (getting away from files being .clj to .cljc, where I'm comfortable that Electric and Missionary are comfortable, then using Rama's subselect on end of the path to be returning a vector rather than one element). I believe not using the e/join was my main problem, and the cause of the serialisation error message. I'm now using @noonian’s way exactly, so can confirm that works for me. Thanks also Dustin and @henrik - I'll get to trying out closing the proxy a bit later...

cjmurphy 2025-05-22T22:36:27.174739Z

The domain is products per organisation (say menu of a restaurant). The problem I ended up with is that every time a product is added all products are broadcast! Claude suggested this was the problem: ResyncDiff happens when query paths are too complex for incremental diffing.

cjmurphy 2025-05-22T22:37:38.401329Z

Anyway that's a Rama issue...

henrik 2025-05-23T05:38:04.009619Z

That’s probably Claude hallucinating. I don’t know how complex your paths are, but I’ve never run into that problem. I have run into the problem when there’s been other issues however: the connection to Rama is interrupted (eg. because of network issues). Since diffs are pushed straight through from write, it’s not inconceivable that it could occur if you’re doing coarse grained transforms on the pstate. Also, I don’t think Electric will care if you’re only returning new either way. By the way, it’s probably a good idea to guard the emit with (when-not (instance? DestroyedDiff diff) …).

cjmurphy 2025-05-23T05:47:33.048689Z

I've made the path this simple: [(path/keypath id) (path/subselect path/MAP-VALS)] . It used to be this [(path/keypath id) (path/subselect path/MAP-VALS (path/view transform-item))] but I'm doing the transform on the browser client now. I agree on the hallucinating - the docs seem confident any path will work. I'm getting more than ResyncDiff. Now seeing NewValueDiff. But the problem with it is it contains that whole menu, when all I'm doing from the UI is changing the price of one dish. And I can see one depot event and I'm not sure what could be wrong with the ETL.

henrik 2025-05-23T05:49:45.789829Z

When you write the map, are you updating the entire map in place? NewValueDiff suggests that it’s been written wholesale, rather than manipulated with eg. submap.

cjmurphy 2025-05-23T05:51:28.641519Z

I'm not using submap no. This is the ETL update:

(r/local-transform> [(path/keypath *org-id *item-id) (path/termval *neat-item)] $$org->items)

cjmurphy 2025-05-23T05:54:57.676719Z

And this is $$org->items:

(r/declare-pstate s $$org->items
      (r/map-schema String
        (r/map-schema String
          (r/fixed-keys-schema
            {:id String
             :price Long
             :description String
             :kind clojure.lang.Keyword
             :heading-id String})
          {:subindex? true})))

👍 1
henrik 2025-05-23T05:58:18.169349Z

Well, if you’re termvaling an entire item, rather than writing eg. the price only with say (keypath *org-id *item-id :price), that would explain why you’re seeing NewValueDiffs at the leaf nodes, but not for the entire thing, since you are walking down via specific keys.

henrik 2025-05-23T05:58:58.086389Z

Rama does no diffing; the diffs emitted are entirely based on the semantics of the transform that updated them.

henrik 2025-05-23T06:03:05.694499Z

Apart from looking at the granularity of your updates, try being more specific in your proxy path, eg.: [(path/keypath id) (path/subselect path/MAP-VALS (submap [:id :price …])] and see what happens. I don’t know for sure that this makes a difference, but it might.

👍 1
cjmurphy 2025-05-23T06:03:15.679339Z

I'll do a more detailed intro-item that looks at every key and only changes the minimum then, and see the results. Thanks for your input here.

👍 1
henrik 2025-05-23T06:10:13.049469Z

You can allow updating arbitrary parts of the map with some transform like (submap (keys *neat-item)) (termval *neat-item). This would allow *neat-item to contain only a subset of fields in the map and leave the rest of the fields alone. If that’s still too coarse, you can unfold it into a multi-path:

(defn m->multi-path
  [m]
  (apply multi-path (mapv (fn [[k v]] [(keypath k) (termval v)]) m)))
Though I’m not sure if this produces finer-grained diffs than submap.