<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hacker News: geokon</title><link>https://news.ycombinator.com/user?id=geokon</link><description>Hacker News RSS</description><docs>https://hnrss.org/</docs><generator>hnrss v2.1.1</generator><lastBuildDate>Mon, 17 Aug 2026 07:08:48 +0000</lastBuildDate><atom:link href="https://hnrss.org/user?id=geokon" rel="self" type="application/rss+xml"></atom:link><item><title><![CDATA[New comment by geokon in "Low-Tech Ceramic Water Filter"]]></title><description><![CDATA[
<p>I wonder if you could achieve the same effect more easily/consistently using cement. It's basically how aquifers "filter" water. Limestone is naturally permeable unlike fired clay.. were you need to control the porosity. I'd imagine cement mixtures are much easier to handle and you can make arbitrary shapes (higher surface area and higher hydraulic pressure to increase the flow rate)</p>
]]></description><pubDate>Mon, 17 Aug 2026 01:06:23 +0000</pubDate><link>https://news.ycombinator.com/item?id=49325491</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=49325491</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49325491</guid></item><item><title><![CDATA[New comment by geokon in "A spectre is haunting Unicode"]]></title><description><![CDATA[
<p>> Either they are translated to Chinese so you should be able to search with Chinese, or they aren't and you should search with Japanese.<p>The point is that when they look identical most of the time, you have no idea which language "mode" the text is in.<p>Tokyo is 東京 in both languages. They're not visually distinguishable. Maybe in a long list some particular characters are written slightly differently, but you'd have to really inspect the list and hope that distinguishing characters show up.<p>From the outside this may look weird, but to people that are around Chinese characters having multiple ways to write a character is just a normal fact of life. They look different in classical writing, seal scripts and cursive scripts. Trades people will also use shorthands. You have analogous situations with Simplified and Traditional Character - where some characters are simplified to fewer strokes and others are not. But as a reader you don't really care if it's 吃/喫 or 臺灣/台灣/台湾. There is basically no situation where you want to find 吃 but not 喫.<p>I get the desire to preserve native Japanese forms of the Chinese characters. But that seems like something mostly resolved with a font<p>If you want to mix Chinese and Japanese characters, then you are left having to mix fonts - which is a bit ugly I guess. It's not the most ergonomic solution, but this is the edge case. Most of the time you want different forms to search the same. If you search 臺灣 and your word processor skipped 台灣, then you'd be rightfully annoyed.</p>
]]></description><pubDate>Sun, 16 Aug 2026 14:12:27 +0000</pubDate><link>https://news.ycombinator.com/item?id=49320275</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=49320275</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49320275</guid></item><item><title><![CDATA[New comment by geokon in "A spectre is haunting Unicode"]]></title><description><![CDATA[
<p>Do you feel similarly about french and english? It could work but would be a little weird and annoyong to switch language modes<p>I think you underestimate the similarities. For instance Japanese names are not translated to Chinese. Theyre just read with Chinese pronunciations. So Chinese will regularly interact with Japanese content (im guess it happens the other way around too, but i dont have the personal experience)</p>
]]></description><pubDate>Sun, 16 Aug 2026 09:24:40 +0000</pubDate><link>https://news.ycombinator.com/item?id=49318373</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=49318373</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49318373</guid></item><item><title><![CDATA[New comment by geokon in "Grok 4.6"]]></title><description><![CDATA[
<p>Out of curiosity why isn't this stuff handled by a secondary "monitor" agent that's specifically trained on what's okay and not okay? I'd think it'd be a pass-no-pass classifier and wouldn't degrade the performance of the main LLM.<p>Would the concern be that with sophisticated obfuscated input you could try to get ROT13 Klingon instructions on how to build a bomb - and that could fool the monitor?</p>
]]></description><pubDate>Thu, 13 Aug 2026 10:21:56 +0000</pubDate><link>https://news.ycombinator.com/item?id=49283877</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=49283877</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49283877</guid></item><item><title><![CDATA[New comment by geokon in "Jolt: Clojure compiler implemented with Chez Scheme"]]></title><description><![CDATA[
<p>> I don't recall ever writing my own protocol, record, or struct.<p>I'm honestly extremely surprised. Protocols seem sort of essential if you want two different "things" to exhibit the same behavior.<p>The whole set of immutable datastructures are fundamentally backed by them (well they use Java Interfaces but its fundamentally the same). Not entirely sure how youd implement them without Protocols<p>Theyre also sort of essential if you want plug-in backends for any part of your codebase.<p>Im curious what your go-to is currently? Do you just write multimethods and dispatch on the inferred input type?</p>
]]></description><pubDate>Thu, 13 Aug 2026 03:35:38 +0000</pubDate><link>https://news.ycombinator.com/item?id=49281510</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=49281510</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49281510</guid></item><item><title><![CDATA[New comment by geokon in "Jolt: Clojure compiler implemented with Chez Scheme"]]></title><description><![CDATA[
<p>I spent a couple of days digging in to Janet and what surprised me was how even though at a surface level it resembles Clojure, under the hood its actually quite radically different.<p>It has a lot of very interesting ideas going on, though ultimately i didnt end up using it (i need my persistent datastructures and seq col abstractions)<p>It feels very minimal and scheme-y and very different from anything ive used before. Definitely worth exploring</p>
]]></description><pubDate>Wed, 12 Aug 2026 08:19:45 +0000</pubDate><link>https://news.ycombinator.com/item?id=49269296</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=49269296</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49269296</guid></item><item><title><![CDATA[New comment by geokon in "Less Coffee, Better Sleep"]]></title><description><![CDATA[
<p>I don't have any severe sleep problems, but I can relate to this issue. I find reading fiction helps. It's kind of difficult to dream about an interesting problem or a project, so the way I perceive the problem is that my brain doesn't slip into a narrative free-associative state. But if I can get myself to think about something "dreamable" then it's a different story. A book works b/c you already need to engage your imagination quite a bit as you read anyway</p>
]]></description><pubDate>Mon, 03 Aug 2026 10:40:25 +0000</pubDate><link>https://news.ycombinator.com/item?id=49153912</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=49153912</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49153912</guid></item><item><title><![CDATA[New comment by geokon in "EU Fines Google $1.02B for Favoring Its Own Services"]]></title><description><![CDATA[
<p>I think this is a larger web-standards problem.<p>There is no standard clickable "link" for physical locations. There is no URL-equivalent you can send to someone, they click it, it open up their map viewer of choice. You can send Lat Lon coordinates and then have the recipient copy and paste them. It generally works though there isn't a standard format and no service will make it clickable like an email address, so the whole process remains clunky.<p>When you "Share" a location in Google Maps or OSMand, you get back a URL link to their service and not an service agnostic "link" to the geographic location.</p>
]]></description><pubDate>Mon, 27 Jul 2026 07:53:56 +0000</pubDate><link>https://news.ycombinator.com/item?id=49066377</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=49066377</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=49066377</guid></item><item><title><![CDATA[New comment by geokon in "Incremental – A library for incremental computations"]]></title><description><![CDATA[
<p>Where is it actually explained how it works..?<p>Usually these kinds of systems either don't scale dynamically or have caching issues. The first example, a spreadsheet, is "easy" because there are a fixed amount of cells to track. A GUI can be a lot harder (imagine sub windows and sub-sub windows dynamically popping up and tracking some redundant and some unique "computations". Entities can appear and then be removed at random). Though the wording carefully says "constructing views" so maybe it doesn't handle dynamism</p>
]]></description><pubDate>Tue, 21 Jul 2026 08:40:14 +0000</pubDate><link>https://news.ycombinator.com/item?id=48989667</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=48989667</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48989667</guid></item><item><title><![CDATA[New comment by geokon in "Sealed tomb filled with paintings and inscriptions discovered in Egypt"]]></title><description><![CDATA[
<p>A cemetery that charges an entrance fee..</p>
]]></description><pubDate>Mon, 20 Jul 2026 14:33:57 +0000</pubDate><link>https://news.ycombinator.com/item?id=48979458</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=48979458</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48979458</guid></item><item><title><![CDATA[New comment by geokon in "Sealed tomb filled with paintings and inscriptions discovered in Egypt"]]></title><description><![CDATA[
<p>Thanks :)</p>
]]></description><pubDate>Mon, 20 Jul 2026 10:07:17 +0000</pubDate><link>https://news.ycombinator.com/item?id=48976638</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=48976638</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48976638</guid></item><item><title><![CDATA[New comment by geokon in "Sealed tomb filled with paintings and inscriptions discovered in Egypt"]]></title><description><![CDATA[
<p>In Paris they use the corpse of their heroes like Voltaire and Napoleon to flease tourists of their Euros<p>Using a tomb to expand our knowledge of the ancient world seems like small potatoes in comparison. Overton window is already far off</p>
]]></description><pubDate>Mon, 20 Jul 2026 08:58:34 +0000</pubDate><link>https://news.ycombinator.com/item?id=48976067</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=48976067</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48976067</guid></item><item><title><![CDATA[New comment by geokon in "The Kimi K3 Moment"]]></title><description><![CDATA[
<p>are there any "open source" efforts to do distillation? Like some place one can submit one's anonymized chat logs? So they can be pooled and used as an open training set (similar to OpenCrawl)</p>
]]></description><pubDate>Sun, 19 Jul 2026 08:38:42 +0000</pubDate><link>https://news.ycombinator.com/item?id=48966080</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=48966080</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48966080</guid></item><item><title><![CDATA[New comment by geokon in "Biff.graph: structure your Clojure codebase as a queryable graph"]]></title><description><![CDATA[
<p>Sorry for the delay, I've been thinking about how to respond :)<p>> For me it is.<p>if you can have a running example I'd love to see it<p>> I want some good guidelines<p>Yeah, I totally understand. I don't have a very clear mental model myself as of yet.<p>> try to pack related entities into their own nested collections<p>I'd try to just be wary of trying to map OO concepts to Pathom. I get the impulse, but my gut feeling is that this won't be fruitful or will make things muddled.<p>> you can make bridges between that resolver<p>tbh I haven't had to really use bridges. The few times I did, I then rearchitected till they disappeared. I do sometimes have different ns's using keys from each other though .. which feels wrong. No clear picture here yet.<p>My mental model at the moment is a bit fuzzy but goes like this:<p>Pathom is fundamentally a web of resolvers. The resolvers are best thought of as functions that can only be run once. This is the fundamental constraint you're working under - but you get a bunch of benefits - and I wouldn't try to fight this fundamental paradigm<p>1.<p>How do we deal with resolvers that conceptually have the same I/O keys? Say we have two resolvers:<p><pre><code>    :filename -> [readFileJPG] -> :image
    :filename -> [readFilePNG] -> :image
</code></pre>
(I'm going to use this much simpler example b/c it's sufficient to illustrate the problems)<p>You have two choices/branches. Pathom can't make that choice for you:<p>In your systems either the provider has to decide:<p><pre><code>    :filenameJPG -> [readFileJPG] -> :image
    :filenamePNG -> [readFilePNG] -> :image
</code></pre>
.. or the consumer has to decide:<p><pre><code>    :filename -> [readFileJPG] -> :imageJPG
    :filename -> [readFilePNG] -> :imagePNG
</code></pre>
I think this is the part where you really have to think hard about who knows which branch should be taken. Who knows you need a fat db request or a skinny one. Is that the part providing the :id and whatnot, or is it the one receiving the result of the db query?<p>But bear in mind that Pathom is a "compile time" tool in a sense. If it's something determined from a db query.. then it's not part of the program control flow and needs to be decide at "runtime". It's not a Pathom problem! It has to happen inside the resolver code and it can't be part of the web of resolvers.<p>In that previous :fat-pack example, the equivalents would been :id-FAT (provider) or :customers/phone_number-FAT (consumer)<p>2.<p>Okay, but say I have readFileJPG and readFilePNG provided by some library/module/ns. I can't modify it's I/O keys. Then hopefully the keys are namespaced:<p><pre><code>    ::jpg/filename -> [jpg/readFile] -> ::jpg/imageJPG
    ::png/filename -> [png/readFile] -> ::png/imagePNG
</code></pre>
Now you can bridge keys either on one side or the other, effectively re-creating either a provider or consumer driver flow. But you can't bridge both sides, cus then you're back to the original problem<p>3.<p>Okay, but say I have a pipeline that is filetype-agnostic and for some reason :filename are coming in from "outside" (maybe user is typing it into a text box) and the output really just wants :image keys for some subsequent processing. What are your options?<p>- let the provider/upstream decide: The :filename is coming in from somewhere, but it know the file type a priori. So it can supply a flag that the resolvers require - ex: :is-jpg , :is-png<p><pre><code>    ::filename + :is-jpg -> [jpg/readFile] -> :image
    ::filename + :is-png -> [png/readFile] -> :image
</code></pre>
- let the consumer/downstream decide: nested outputs {:jpg [:image]}<p><pre><code>    ::filename -> [jpg/readFile] -> {:jpg [:image]}
    ::filename -> [png/readFile] -> {:png [:image]}

</code></pre>
Both options leave a bad taste the mouth.<p>- The first feels fragile (you live in fear of it taking a wrong branch), esp if you have "default no-flag" case like in your db request example.<p>- The second creates a packed thing that needs to be unpacked. (this is what I showed with :fat-pack). I actually think this is the worse solution b/c it breaks composability. The packed space is completely isolated from the wider soup of keys, which can severely limit what you can do (as I'll illustrate).<p>EDIT: Part 6 I show the better solution for the consumer<p>4.<p>The second solution also conceptually clashes with another tool in the toolbelt. Nested inputs and outputs have a fundamental, completely unrelated, different usecase. They allow you to create a mini-context in which you can re-execute your Pathom resolvers. So if you have two images in your application, you can read them both in. These two transformation can co-exist:<p><pre><code>    {:profile-pic [:filename]} => {:profile-pic [:image]}
    {:background-pic [:filename]} => {:background-pic [:image]}
</code></pre>
You can of course create mini-contexts arbitrarily if you want. The downside of these nested mini-contexts is that they are aggressively isolated and completely oblivious of the larger world, so you need to shove in all the keys you may use. If you have a resolver somewhere else that processes the image:<p><pre><code>    :image + :username -> [addUsernameOverlay] -> :image-with-username
</code></pre>
Then you'll need to jam all the necessary keys in to the mini-context:<p><pre><code>     {:profile-pic [:filename :username]} => {:profile-pic [:image-with-username]}
</code></pre>
5.<p>So for the consumer side solution:<p><pre><code>    ::filename -> [jpg/readFile] -> {:jpg [:image]}
</code></pre>
You're a bit screwed. You've lost the natural extensibility of Pathom. You now CANNOT do<p><pre><code>    ::filename + ::username => :image-with-username [XXXX - doesn't work!]
</code></pre>
Nor can you do<p><pre><code>    ::filename + ::username => {:jpg [:image-with-username]}
</code></pre>
One hack is to have jpg/readFile pack the :jpg container (ie. forward the :username into it)<p><pre><code>    ::filename + :username -> [jpg/readFile] -> {:jpg [:image + :username]}
</code></pre>
This makes the second call work, but this is a bit gross.. B/c now the jpg/readFile resolver <i>requires</i> a :username that it actually doesn't use. The resolver is now coupled to downstream requirements. Eww<p>6.<p>After chewing it over, I think the best solution is to pack everything when possible:<p><pre><code>    {:jpg [:filename]} -> [jpg/readfile] -> {:jpg [:image]}
</code></pre>
Now the jpg/readfile resolver doesn't take a :filename, but instead takes a :jpg as {:jpg [:filename]} and unpacks it. Here.. I think technically only consumer must know the type.. But now you can add the username transparently and this transformation works without jpg/readfile needing to forward anything.<p><pre><code>    {:jpg [:filename + :username]} -> {:jpg [:image-with-username]}
</code></pre>
The downside is that you may end up having to shove in a lot of variables in to the mini-context. If it's all using resolvers from a library/ns that are kinda doing an isolated set of stuff then this can be very viable though!<p>When to create these mini-contexts is not something I have a clear mental model for. It's related to the fundamental downstream output</p>
]]></description><pubDate>Thu, 16 Jul 2026 06:54:56 +0000</pubDate><link>https://news.ycombinator.com/item?id=48931164</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=48931164</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48931164</guid></item><item><title><![CDATA[New comment by geokon in "Biff.graph: structure your Clojure codebase as a queryable graph"]]></title><description><![CDATA[
<p>Okay - actual code is good :))<p>But I can't replicate the behavior. Here is the code:<p><a href="https://github.com/kxygk/ednless/blob/master/pathom-prectest.clj" rel="nofollow">https://github.com/kxygk/ednless/blob/master/pathom-prectest...</a><p>I didn't know what jdbc was so I just plugged in dummy values - but I think I'm matching your logic one2one<p>Let me know if you can tweak it to have the weird results trigger<p>At a high level I'd say a couple of things stand out.<p>- Your resolvers take in an id and return an id.. That sets off a bunch of alarm bells for me. I wouldn't ever do that. There is no good reason to have that, even if the values are identical (if the values change then that's even more dangerous). I can't point to exactly what will go wrong, but you're exacerbating the problem of having multiple resolvers providing an input. Worse yet, in this example you are guaranteed that they are all running. So where is it going to take the ID from..? I don't even know<p>- The :fat-key isn't doing anything here. If you wanted to do the nested request, it'd be a solid way to guarantee the fat branch is always taken:<p><pre><code>    (pco/defresolver get-user-with-customer
      [{:users/keys [id]}]
      {::pco/output [{:fat-pack [:users/id
                                 :users/email
                                 :users/customer_id
                                 :customers/id
                                 :customers/billing_number
                                 :customers/phone_number]}]}
      (println "get-user-with-customer FAT triggered")
      {:fat-pack {:users/id                 66
                  :users/email              "66@66.com"
                  :users/customer_id        id
                  :customers/id             id
                  :customers/billing_number 666
                  :customers/phone_number   6666}})

    (def env
      (pci/register [get-user
                     get-customer
                     get-user-with-customer
                     user-customer-bridge]))

    (p.eql/process env
                   {:users/id 1000}
                   [{:fat-pack [:customers/phone_number
                                :users/email]}])
    ;;{:fat-pack {:customers/phone_number 6666, :users/email "66@66.com"}}
</code></pre>
I think you can see you get the same results, but there is no way for it to go wrong. Admittedly here I have the EQL request "unpacking" it, but it can also be unpacked transparently from a different resolver using nested inputs.<p><pre><code>    (pco/defresolver fat-eater
      [{:keys [fat-pack]}]
      {::pco/input[{:fat-pack [:users/id
                               :users/email
                               :users/customer_id
                               :customers/id
                               :customers/billing_number
                               :customers/phone_number]}]
       ::pco/output [:response]}
      (println "fat-eater triggered")
      {:response (str "yum, just ate: "
                      (:users/id fat-pack))})

    (def env
      (pci/register [get-user
                     get-customer
                     get-user-with-customer
                     user-customer-bridge
                     fat-eater]))

    (p.eql/process env
                   {:users/id 1000}
                   [:response])
    ;; {:response "yum, just ate: 66"}
</code></pre>
This is very explicit and about equivalent to your original thought of "why not just have explicit imperative function calls". The consumer (the `fat-eater` or the user making the EQL request) knows a priori that he wants the fat call.<p>EDIT: At the bottom of the .clj I added a bunch of other tests for the pipeline branching (the A->B->C thing)<p>- Adding an XXX resolver to override step B worked when "forced" with an extra <i>input</i> key.<p>- Adding an YYY resolver to override step B by <i>outputting</i> an extra key ends up <i>always</i> overriding B (whether you request the new dummy output key or not!)<p>I'm guessing here.. but it's probably b/c YYY has the same input requirements as B, but YYY outputs two keys instead of one - so it's preferred.<p>In a way both seem useful. The first lets you use a flag to select when you take a branch. The second make you always override the branch</p>
]]></description><pubDate>Wed, 15 Jul 2026 06:19:31 +0000</pubDate><link>https://news.ycombinator.com/item?id=48916916</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=48916916</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48916916</guid></item><item><title><![CDATA[New comment by geokon in "Biff.graph: structure your Clojure codebase as a queryable graph"]]></title><description><![CDATA[
<p>It doesn't seem petty at all. These are the fundamental primitives of how you want to decouple and organize code. You have to look at them through small examples.<p>In the first case, the situation looks largely the same. I mean you can either uses the same nested inputs strategy but have a special key that triggers the fat-query resolver. Something like :employed-user-id.<p>The other alternative is using nested outputs. You have the resolver returned a keyed bundle. Something like  {:fat-request [:users/email :company/phone_number]}. The downstream resolver then consumers a :fat-request and unpacks it using nested inputs.<p>As for the second example. I'm a little confused on some of the specifics. Writing out the resolver mappings more explicitly.. I'm inferring this is what's going on:<p>- GetUser - :users/id -> :users/email :company/id<p>- GetCompany - :company/id -> :company/phone_number<p>- GetUserWithCompany - :users/id -> :users/email :company/phone_number (<- this is a shortcircuit bypassing :company/id)<p>From this I can see why the first request triggers number 3. You could of course make the third resolver return a bundled output which may simplify things.<p>The second request.. I get a bit confused here.<p>1. I'm a bit confused about the bridge. Maybe there's a typo? Or are you saying `customer` is some completely separate namespace that's interfering with the behavior? In the text you seem to imply you're aliasing company/id and user/id.. but that would be a bit crazy :)<p>2. You then say "and use the cached result to get the rest of the data". So you have cached resolvers and there is memory from previous requests?<p>Is it internally, after the first request, remembering the :company/id associated with this :users/id? So it triggers the first two resolvers instead of the third one (but why was the :company/phone_number and users/email not in the cache?)<p>> Imagine working with 12 people and having hundreds of tables.<p>Yeah, I think at this point in time there is no sense of best-practices or common programming patterns. From reading the docs and issues, I don't even get the sense Pathom's author has a good sense of how best to hook things up. So we're in the `goto` era of using Pathom and you can end up with a messy web of resolvers. Playing around with the system.. I'm left feeling like there is some emergent logic and ways to organize code. But maybe there are corner cases where it all breaks down and you start to miss imperative programming. My gut reaction is that if I see two separate paths on the same inputs/outputs .. then I'm immediately thinking - "can I redesign my system to avoid this?"<p>As a simple thought experiment. Say you want to inject stuff in to a pipeline (So some  A -> B -> C -> D becomes A -> B -> ZZ -> D). Pathom's author suggests using the Priority attribute. <a href="https://pathom3.wsscode.com/docs/resolvers/#prioritization" rel="nofollow">https://pathom3.wsscode.com/docs/resolvers/#prioritization</a><p>But you have other alternatives...<p>- You can also add a dummy key :take-zz-branch. You have resolverC that takes :B and you have resolverZZ that takes :B and :take-zz-branch. Precedence rules .. should ..  make it take the branch (unless it for some reason requires fewer inputs?).<p>- You can make resolverZZ <i>output</i> some dummy key :zz-was-run. If you request :zz-was-run then I think it should also take the branch? (or maybe it runs both branches).<p>Maybe there are other methods I've not considered. But at this point I'm not clear which method is best!</p>
]]></description><pubDate>Tue, 14 Jul 2026 03:56:38 +0000</pubDate><link>https://news.ycombinator.com/item?id=48902134</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=48902134</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48902134</guid></item><item><title><![CDATA[New comment by geokon in "Biff.graph: structure your Clojure codebase as a queryable graph"]]></title><description><![CDATA[
<p>great example.<p>Some of this is out of my bailiwick, but on a high level I agree with you. I think your intuition is right. If you have behavior that's dependent on priority, this is a code-smell. It feels like you're just sort of #yolo'ing and hoping the right resolver is called. So far.. In these situations I usually pause and reconsider my architecture. There are probably several solutions here.<p>(Do bear in mind that I'm still learning the Pathom kungfu here, so I can't guarantee these are the best solutions..)<p>1.<p>So in your example the first step in isolating the behavior would be to re-think of it as three keys<p>- ::employee-ID<p>- ::company-ID<p>- ::employee-company-id-pair<p>and make more resolvers<p>- ::employee-ID -> ::employee<p>- ::company-ID -> ::company<p>- ::employee-ID + ::company-ID -> ::employee-company-ID-pair<p>- ::employee-company-ID-pair -> ::employee-company-pair<p>You can then just request an ::employee-company-pair and it should be disambigious. The problem is that you've now have a dense pair that doesn't hook back up with the rest of your resolvers. But this can be addressed with ...<p>2.<p>isolating behavior using "nested inputs/outputs". They allow you to go from a soup of keys to a narrow subset<p>Again:<p>- ::employee-ID<p>- ::company-ID<p>- ::employee-company-id-pair<p>first you can just have the original three 1-to-1 resolvers<p>- ::employee-ID -> ::employee<p>- ::company-ID -> ::company<p>- ::employee-company-ID-pair -> ::employee + ::company<p>At this point, as you illustrated, you have a bit of a priority issue.
With a ::employee-ID and ::company-ID keys it's unclear which path is taken.<p>The trick is to now use nested input to disambiguate things.<p>You make a resolver that returns the results wrapped in a key (nested output):<p>- ::employee-ID + ::company-ID -> {::packed-request [::employee-company-ID-pair]}<p>The "consumer" resolver that only wants that efficient db call has on input a ::packed-request and just "unpacks" the request using nested inputs. Furthermore on input it will directly requests {::packed-request [::employee ::company]} and the engine handles the ::employee-company-ID-pair -> ::employee + ::company conversion. This nested input scope (ie. the inside of ::packed-request) doesn't have ::employee-ID and ::company-ID keys, so the request is always unambiguous.<p>The Pathom docs could be a bit more clear on this. They just show the basics and unfortunately don't walk through these tricks. But you can be explicit about both input and output map shapes and the engine uses these to do conversions. This allows you to narrow the set of inputs. So here one resolver outputs a {:packed-request [::employee-company-ID-pair]} and another takes a {::packed-request [::employee ::company]} - and the conversion is implicit. The engine finds only one resolver that returns a ::packed-request and it sees that it internally it will have a ::employee-company-ID-pair key. It then looks for a path from ::employee-company-ID-pair to the requested ::employee + ::company pair and it finds the corresponding resolver(s). Sometimes you need to forward other keys into this inner context, but you just provide them in parallel to the ::employee-company-ID-pair - it's all explicit.<p>I'll admit.. this looks weird. As I said elsewhere.. it's a real paradigm shift in how to think about and organize code. But I find after some adjustment it's actually worked really nicely for me so far.</p>
]]></description><pubDate>Mon, 13 Jul 2026 06:47:27 +0000</pubDate><link>https://news.ycombinator.com/item?id=48888799</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=48888799</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48888799</guid></item><item><title><![CDATA[New comment by geokon in "Biff.graph: structure your Clojure codebase as a queryable graph"]]></title><description><![CDATA[
<p>I'll be honest, I work in a very different area (scientific computing) so my code is a lot more exploratory and I don't ever deal with DB access for instance. If you have a very stable interface and clear objectives then coupling isn't really a concern b/c there won't be anything to refactor and extend.<p>> avoiding intermediate keys at all can be helpful for performance, and graph querying encourages people to break their queries into small, atomic units that can fire in any order<p>EDIT: Reading the other comments, I realize here query is a DB query and not a EQL query.. so nevermind :)<p>I'm a bit fuzzy on what you're saying, but I think you may be misunderstanding an aspect (I could be wrong here). You typically have one complex top-level query and the engine builds the sequence/graph of resolvers that need to be run to derive the requested query. In that graph key values can be reused and branches can be run in parallel. You don't run a series of small queries and manually build up anything.<p>In my limited experience the order in which the resolvers are run is pretty clear (unless they're independent branches of the graph being run concurrently) and if you have a non-branching pipeline there isn't really any incentive to break it up. From a performance perspective I'm guessing you mean in terms of DB access? Because calling a series of functions or a series of resolvers is going to be quite similar performance wise - though you have some engine and destructuring overhead (can be significant in tight loop situations).<p>> Is that exceptionally harder to do with regular functions though?<p>It's hard to make a general statement here b/c it really depends on how you've set up your functions. But yes, generally if you are just playing with functions it can be harder to plug in a different "backend" or step in the middle unless you've somehow planned for it. Is it very hard? Generally not super difficult - but you generally need to refactor code to make it happen and explicitly handle the branching logic - so the code usually gets uglier<p>If you want to do a mock or try injecting some step, with resolvers you can do that without touching your code</p>
]]></description><pubDate>Mon, 13 Jul 2026 03:05:35 +0000</pubDate><link>https://news.ycombinator.com/item?id=48887372</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=48887372</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48887372</guid></item><item><title><![CDATA[New comment by geokon in "Biff.graph: structure your Clojure codebase as a queryable graph"]]></title><description><![CDATA[
<p>that I understand. providing that compatibility guarantee is extra work for you<p>It's always nice talking to you about these things. Thanks again :)</p>
]]></description><pubDate>Mon, 13 Jul 2026 02:33:53 +0000</pubDate><link>https://news.ycombinator.com/item?id=48887174</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=48887174</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48887174</guid></item><item><title><![CDATA[New comment by geokon in "Biff.graph: structure your Clojure codebase as a queryable graph"]]></title><description><![CDATA[
<p>Lots of great thoughts<p>As for function memoization, I previously tried this workflow and after scratching my head about it, I think it's just not possible to make it scale properly (in the sense of making a library of resolvers/functions where you don't know how they'll be used exactly). The memoized function has no way to know how often it's called. It can be called 2 times, or 2000 times. So it's unclear how large its cache should be and there isn't a clear mechanism for when to flush the cache. I couldn't find a good mechanism to safely use it. In the Pathom model .. as far as I understand you just don't need to worry about that since the outputs are "cached" in the context of a query (or an inner input) and discarded when you're "out of context".<p>Since often you have many similar requests it can make sense to add a layer of memoization a the top level to remember the last request (cache of size 1) but otherwise it should scale okay. Though I'm sure it's not difficult to create pathological cases where it probably doesn't work and you end up recomputing stuff.<p>I think caching is an unresolved problem</p>
]]></description><pubDate>Sun, 12 Jul 2026 15:08:54 +0000</pubDate><link>https://news.ycombinator.com/item?id=48881774</link><dc:creator>geokon</dc:creator><comments>https://news.ycombinator.com/item?id=48881774</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=48881774</guid></item></channel></rss>