Seattle
Account created on 11 June 2008, almost 17 years ago
#

Merge Requests

More

Recent comments

🇺🇸United States freelock Seattle

Additional fix - some missing characters in newly generated settings blocks.

🇺🇸United States freelock Seattle

> the more interesting question to answer now is, whether the current state of the MR also fixes the problem with the steps to reproduce as you described in #55.

It is working fine after your changes.

🇺🇸United States freelock Seattle

The steps I used were basically:

1. Install Drupal CMS, and install the "project" and "case study" recipes, and IEF. (also needed paragraphs and err for the tests).
2. Add an entityreference field on project type to case study with unlimited cardinality
3. Configure it to use the complex IEF widget, and allow creating new entities/reference existing entities
4. Edit a project node and add a new case study using the widget
5. Without saving yet, attempt to add another case study -- and see that the IEF form has the same details as the first case study
6. Save the project node, and you get a whitescreen.

I did have to change the config on the IEF widget -- I think to allow adding existing entities? I have them set to both allow new and existing, which was not the default.

With my patch, you get the correct case study loaded when you edit, and if you add a new entity it gives you a fresh blank form.

Configuring an ECA model to alter the IEF and disable the title field works correctly everywhere as well.

I'm on vacation this week, so won't be spending time on this until next week...

We do see this on 6+ entirely different sites. I wonder if the difference between your setup and my vanilla CMS setup is cardinality... I did debug/develop this patch on the vanilla Drupal CMS site, haven't applied it yet to the other broken sites, most of which do limit cardinalilty.

🇺🇸United States freelock Seattle

So aside from detection logic, it looks like the one substantive change in your MR commit is when adding a new item to the list, you're checking the $form_state '#ief_id' element entities and counting those, and falling back to $context['items'] if that isn't set. I'm wondering what scenario leads to that being correct -- I thought I saw some of those lazy-loaded, so I thought $context['items'] seemed more reliable... is that where you're getting null instead? I'm thinking this might be due to a difference in the field or widget config...

As for comment #50 I don't know what the goal of that is -- it looks like it's triggering validation? That doesn't appear to be required to fix the complex widget -- but maybe necessary to support models that add validation to the subform?

🇺🇸United States freelock Seattle

The results you got are exactly what we see without this patch.

Are you sure you're applying the correct MR (487), and not the old one that was already merged?

🇺🇸United States freelock Seattle

Ok, got it working for both the simple IEF widget AND the complex one. It's now checking for the specific plugin in use -- should we throw an exception if it's a different plugin? (Since we won't know how to handle it...) For the time being it's just returning unless it's the simple or complex widget.

If it's the simple widget, it works the same as before -- and I've verified that at least the test model works, it disables the title field on the IEF form, for all deltas and new ones.

For the complex widget, to get it to work I had to move the delta retrieval above the section that finds the right form to use -- the original fix worked for the first existing item in the list but not new items or any beyond the first.

Getting the $delta set above the part where the $entity_form is found fixed other deltas, but not adding new ones. Setting the $delta to the length of the EntityReferenceList (so it's always 1 bigger than the current length) made it work for new items as well.

So this is now working for me -- not sure how to set up a test for the Complex widget.

🇺🇸United States freelock Seattle

... to reach this conclusion, I spent a chunk of time debugging to find that the $delta is always set to 0 when the ECA hook handler gets called, regardless of the number of items in the field. So I went spelunking to figure out what IEF uses, and ended up here:

https://git.drupalcode.org/project/inline_entity_form/-/blob/3.x/inline_...

🇺🇸United States freelock Seattle

... and going back to the original problem, as I see it with IEF, if there is no triggering element, then the subform doesn't load at all, so ECA can't alter it.

It's a fundamental problem that the test does not properly test IEF -- instead before this update ECA is arbitrarily attaching whatever entity it sees to the form, which is exactly why it breaks IEF. The "complex" widget uses Ajax to load the inner form, and the triggering event to determine which delta to load -- if there is no delta, and you load an existing entity, it also breaks. I'm not sure if this prevents ECA from acting on it -- we might be able to create a new entity of the appropriate type to add.

🇺🇸United States freelock Seattle

Paragraphs has an entirely different method in HookHandler:

... 1 is what gets executed for IEF, where the code change is. I'm pretty sure Paragraphs uses 2 instead.

Maybe we should split this into two different tests, one for IEF, and an entirely new one for Paragraphs?

🇺🇸United States freelock Seattle

Ah, ok, thanks for the further information -- that explains why the test is checking that the title field is disabled.

But I think you're mis-understanding the test setup -- the test name is InlineEntityFormTest -- but confusingly, it is testing BOTH InlineEntityForm and Paragraph forms:

    $this->assertTrue($form['field_pages']['widget'][0]['inline_entity_form']['title']['widget'][0]['#disabled'], "The model has set the title field to be disabled.");
    $this->assertTrue($form['field_paragraphs']['widget'][0]['subform']['field_text']['widget'][0]['#disabled'], "The model has set the field_text field to be disabled.");

... the first test checks field_pages, which is set up as an entityreference field to a "page" node, the second is an entityreferencerevision field set to a Paragraph.

The second test passed before and after I changed the test -- the first was failing, because the test was not loading the IEF widget (because of the delta issue).

So I think the test has always been incorrect for the IEF field, and now it's correct (at least for testing that ECA is making the title field of the first referenced item disabled). It's just that IEF itself does not use the normal delta at all, and relies upon this special form_state property instead.

🇺🇸United States freelock Seattle

This is implemented, as both a nix run target (nix run .#config) and with a shell command in the devshell (start-config).

🇺🇸United States freelock Seattle

Ok. I've chosen to use the socket for the database server to determine whether or not the Nix runtime environment is running. If it is, the settings.nix.php file is included. If not, it's ignored.

This should allow the entire flake to happily co-exist with other dev environments such as ddev or LAMP stacks or whatever.

I would recommend having the settings.nix.php gitignore'd, it is generated at startup if it doesn't exist anyway. Otherwise when the runtime is running, drush and the site should get the necessary nix-specific values from environment variables.

🇺🇸United States freelock Seattle

Marking fixed.

🇺🇸United States freelock Seattle

Implemented in main flake.

🇺🇸United States freelock Seattle

freelock created an issue.

🇺🇸United States freelock Seattle

Ok. Without changing what is actually being tested, I updated the test to set the delta the way IEF actually sets it, so the test now passes (because it is loading the referenced entity into the form, now that the test specifies the delta).

I don't think this is a very good test though...

🇺🇸United States freelock Seattle

Hi,

Ok. So this all made me set up phpunit and figure out how to run these tests, something I've neglected up to now. Got that working, but... I don't understand this test?

It's failing because the "Title" field of the referenced content in the inline entity form is not disabled. But this doesn't make any sense -- most of our uses of inline entity form allow you to edit the title of the referenced entity, and even without the patch applied, the title is editable -- the test is checking for a "#disabled" value that appears to have no effect on the UI. It is set without the patch, but titles are still editable. With the patch, this value is not set -- and the UI is identical here.

So I think the test is invalid -- it doesn't correspond to what it claims to be testing, and what it claims to be testing is not even a relevant test.

I think the test does show that there was no entity attached to the form -- which would be correct, because the form state would not include the IEF triggering event. But we know the old code attaches the wrong entity if you are trying to add an entity using IEF.

We need a better scenario to test.

🇺🇸United States freelock Seattle

Set the PATH env variable to contain the path to the PHP environment, plus Rsync. Allowed env vars to be imported into php-fpm's environment.

🇺🇸United States freelock Seattle

Creating as "refresh-flake".

This is now fixed on the main branch.

🇺🇸United States freelock Seattle

Ok hope I did that right -- I had to merge in changes from the main dev branch and resolve a conflict before it showed mergeable. But this at least fixes the conflict with IEF. Not sure if it breaks any ECA functionality.

🇺🇸United States freelock Seattle

Given that IEFs are always broken with this active, disabling it until it actually works makes total sense to me.

That said, I just spent a little time debugging further, and I think I've at least identified the cause of the issue -- but no solution.

What I'm seeing is that during an Ajax call to refresh the form element, when opening a specific row in IEF, the $context['delta'] is always set to 0 no matter which delta you're actually trying to edit. IEF assumes that the delta is set for the row being edited, but this is not true -- pretty much ever.

It does end up correct like a stopped clock is correct twice per day -- it's correct if the first row edited is the row you're currently editing.

Here's where the delta gets set to zero:

... this is because the delta is not passed in EntityFormDisplay::buildForm to InlineEntityFormBase->form(), so $get_delta is null, and then defaults to 0 in WidgetBase->form().

Meanwhile, by the time we get to the ECA HookHandler->fieldWidgetSingleElementInlineEntityFormComplexFormAlter method, we expect to have the $context['delta'] set correctly, and the entity available in the FormState originally set up under 'eca_ief' -- but it always stores the same entity under the same 0 delta.

So I went to see how IEF determines the delta, and found this:

$delta = $form_state->getTriggeringElement()['#ief_row_delta'];

Plugging that into the ECA hook handler, seems to work! At least for existing rows. If that delta comes back NULL, and we didn't return early, you can't get a new blank form. So I've added a check for if $delta is null, and this at least makes IEF act normally.

Is there a test scenario that actually uses this ECA? I think the MR I'm adding at least fixes IEF, and I would assume would work for alters that act on existing entities -- not sure what scenario might need access to a non-existing entity.

🇺🇸United States freelock Seattle

freelock created an issue.

🇺🇸United States freelock Seattle

freelock created an issue.

🇺🇸United States freelock Seattle

freelock created an issue.

🇺🇸United States freelock Seattle

freelock created an issue.

🇺🇸United States freelock Seattle

Hi,

You're right, I get the same thing from the parent getPropValue method.

Cheers,
John

🇺🇸United States freelock Seattle

Oh sorry, looking again, we're not subclassing that method -- we're just calling it. As a private function we cannot use it -- it needs to be protected so we can call it from our subclass's getPropValue() function.

You can see our usage here: https://git.drupalcode.org/project/megamenu_sdc/-/blame/1.0.x/src/Plugin...

... we could create another copy of this code, but much easier to call existing...

🇺🇸United States freelock Seattle

Hi,

Ok, I see that method returns the result of getMenuItems(). We can definitely extend that instead, if that's the only place it gets called.

Cheers,
John

🇺🇸United States freelock Seattle

@dalemoore that's exactly what I was trying to do. It uses a plugin to get child items, which is not currently part of UI Patterns.

I've gone ahead and bundled it up into a module - MegaMenu SDC . There is a bug in UI Patterns that currently requires a patch - Cannot subclass MenuSource plugin due to private method getMenuItem() Active .

🇺🇸United States freelock Seattle

As discussed at DrupalCon, we found a different approach to solving our particular issue -- @pdureau created a MenuContentSource plugin extending the MenuContent plugin which could then provide the link content we were missing.

So our need was solvable using UI Patterns plugins instead of a preprocess function.

🇺🇸United States freelock Seattle

Just curious -- for people still affected by this, do you perhaps have ECA Form module enabled? I'm wondering if it's related to this: 🐛 ECA Form breaks complex IEF widget Active

🇺🇸United States freelock Seattle

Hi,

I'm hitting a need for something like this now, trying to create a menu_item SDC for a megamenu.

Using Menu Item Extras, you can add fields to menu_item_content entities, and then use layout builder on top-level menu items to manage the contents of each megamenu pane (as fields on the top level menu items).

We've done this without SDCs. But now trying to make an SDC, we've created a menu_menu SDC and a menu_item SDC, and placed the menu_menu SDC using UI Patterns, as a block. So far so good, we have our menu. But no menu_item_content entity.

Menu Item Extras makes use of preprocess functions to render child links as appropriate -- but these never get called when you hand off to an SDC, and I'm really struggling to figure out how to get them in there. The items do have a "below" array of child items, and each item does have an "original_link" value that returns a plugin -- not the entity, but just a plugin. That does have an id of "menu_item_content:" so what I'm currently doing is extracting that UUID, and then using Twig Tweak's "drupal_entity" to render the actual link.

I think I can get this to work -- but it feels a bit nasty and introduces other dependencies (Twig Tweak). The "drupal_entity" call goes back to the theme layer, calls the theme hook, which then needs the child SDC added to the template.

I would much rather simply call the child SDC (menu_item) from within the parent, but I don't have any access to the menu_item_content entity!

A preprocess function of some kind would allow me to add a reference to the actual entity inside the items array, and then this wouldn't have to jump out to the theme layer and back for each item.

Is there a better way to solve this? Was also thinking I could possibly decorate whatever is building the menu tree to add those references.

🇺🇸United States freelock Seattle

Would love to participate! Not a whole lot of time.

| CRM | Membership
🇺🇸United States freelock Seattle

Oh wow, looks like the code I wrote for commerce_membership (name on Drupal.org) is implemented in the site as "membership_commerce". It's not very big -- ~260 line .module file with several hooks, a service with some convenience functions, and two PriceResolver services.

It also looks like these aren't written in a portable way -- field names are hard-coded instead of looked up from config. Went ahead and pushed what I have up to Commerce Membership .

| CRM | Membership
🇺🇸United States freelock Seattle

Membership entities do require an owner, but we have used it on sites where the owner is the only user, and additional members I think used Profile entities -- at some point on a D7 site we made some custom code to allow an existing profile to be associated with a new user... we've managed membership sites for families with children that do not have email addresses or logins but still needed to be distinct (a sports academy that had open field time as well as lessons).

If Commerce License requires a user, that would be why we didn't use it...

Architecture-wise, I fully agree -- only one of our sites used Group with memberships, and having different entities for Users, Profiles (or Contact), Memberships, Membership Terms, Payment subscriptions makes a lot of sense, especially with ECA now available to build actions to sync data to whatever entities your site needs.

| CRM | Membership
🇺🇸United States freelock Seattle

As for no-cost memberships, easiest was to set the membership term to "lifetime". I don't think that is correctly built in the membership module -- I think we set a date 20 years in the future as a short-term placeholder behavior -- I haven't had a customer yet that wanted a membership that didn't expire. (We did hit the Unix Y2K/2038 bug doing this!)

| CRM | Membership
🇺🇸United States freelock Seattle

I have used Commerce Recurring for automatic renewals. I forget exactly why we didn't use Commerce License -- we had a reason at the time, but maybe whatever it was is no longer an issue. Could Commerce License be used to purchase a group membership, instead of a site role?

| CRM | Membership
🇺🇸United States freelock Seattle

I've built 3 sites using Membership module -- unfortunately none are active anymore. I did a fair amount of refactoring to make that more clear -- the current maintainer had different goals, but the overall structure can be part of the solution.

The most recent site was for a company that was selling subscription access to its services, and its customers were businesses that typically bought 5 or more seats -- they had a couple different pricing tiers based on number of logins. It was essentially a domain-specific SaaS. I ended up using both Membership and Group to make this work. And it did work, with some glue code (this was before I was a big user of ECA).

Membership provides two entity types:

- "Membership" which was a permanent entity for a particular account -- might be pending, active, expired, or in some cooldown period -- you can set different state machines to allow grace periods for renewal. So this contains the current status, along with any number of members. You can have different bundles here for different levels of access.

- "Membership Term" - this uses a special plugin so it can connect directly to external membership providers, at first. I created a general "membership_term" plugin so you could manage memberships entirely within Drupal. This entity represents the current active period, with the plugin defining details around how to handle fixed vs floating membership periods, handling pro-rating amounts for partial periods, triggering automatic renewals if connected to Commerce, and renewal notices at various points (I made a "Scheduled Message" module just for this reason, but none of our active sites still use it, we've replaced that with ECA). You make different bundles of this for different membership lengths.

I had also created a Commerce Membership module, and we did have it working, but the client pulled the plug on the whole project before we had that wrapped up -- I can find and post that code.

On this project, we used Group to enforce access. The custom code was simply keeping the various modules in sync -- sending people to buy more seats if they tried to add more users than they had in their agreement, pro-rating additional memberships so we could use the same membership term with a new quantity, making it easy to invite new users to your membership, etc. All the app's functionality was inside the group, so without group membership, authenticated users couldn't do anything other than purchase a membership and browse some help pages.

I did find myself refactoring a lot of the membership term code, and sent a bunch of patches to the maintainer, most but not all are in the Membership module.

🇺🇸United States freelock Seattle

Created new branch rebased on 2.x -- previous branch no longer applied.

🇺🇸United States freelock Seattle

freelock changed the visibility of the branch 3377609-implement-token-replacements to hidden.

🇺🇸United States freelock Seattle

It looks to me that this action plugin replaces the existing image, instead of generating a derivative image?

That's not what I'm looking for -- I want to just generate the derivative image. For content created programmatically, the derivative images don't exist until somebody visits a page that renders the specific image style you want. When posting images to social media, you might have an image style that isn't rendered when you want to send that image, and this can cause errors/failed posts.

🇺🇸United States freelock Seattle

Also check out Membership module. This module creates two custom entities: one for the actual membership, and another for the "membership term".

I built out 2 sites using this, one of them tied membership terms to commerce -- unfortunately the client pulled the plug and went an entirely different direction. That was built in Drupal 9. I do have some code in github and elsewhere to assist with this.

Membership uses state machine , which provides a nice form for transitions, and has decent support for ECA, so would be fairly easy to add/remove particular roles based on membership term start/end. We've also used this model to send reminders before a membership expires, sending only to people who have not yet renewed.

🇺🇸United States freelock Seattle

Ok, the problem is, the default branch is 8.x-1.x -- I had to manually change the target branch to 2.0.x.

🇺🇸United States freelock Seattle

freelock changed the visibility of the branch 3508587-conflict-with-ai to hidden.

🇺🇸United States freelock Seattle

freelock changed the visibility of the branch 3508587-ignore-non-http-exceptions to active.

🇺🇸United States freelock Seattle

freelock changed the visibility of the branch 3508587-ignore-non-http-exceptions to hidden.

🇺🇸United States freelock Seattle

Wow, not sure what happened with this MR -- it's a lot more than the 2 lines I changed. Trying to get an accurate branch here...

🇺🇸United States freelock Seattle

freelock changed the visibility of the branch 3508587-conflict-with-ai to active.

🇺🇸United States freelock Seattle

freelock changed the visibility of the branch 3508587-conflict-with-ai to hidden.

🇺🇸United States freelock Seattle

No, my time got taken up, probably won't be able to spend any time on this until DrupalCon or later...

🇺🇸United States freelock Seattle

Hi,

Unleash got my attention recently, as a more generic solution here. It's open source, self-hostable, plus there's a paid service that can be used... and Symfony support.

With a separate feature flag solution, flags can be enabled per environment, making it much easier to move databases around, supporting A/B testing, and a bunch of other scenarios. I'm wondering if something like this should be considered as an optional core service...

🇺🇸United States freelock Seattle

See 🐛 Whitescreen in Layout Builder when a data feed icon with argument is attached to a block Active for an example case using Views Data Export. The patch in this issue fixes that for me.

🇺🇸United States freelock Seattle

My site uses "field_image" for the image field name in Media. Before applying this patch, I could generate an image, but after saving it was lost entirely, and the media item had no thumbnail or anything.

After applying this patch, it works as expected -- after generating the image, it's properly attached to the media item.

🇺🇸United States freelock Seattle

That issue does sound very similar. One difference is that we were seeing the issue with limited cardinality, too -- although a cardinality of 6... but I'm guessing if ECA is replacing the form_state for some reason that might do it...

🇺🇸United States freelock Seattle

We are hitting this issue on a bunch of sites -- or rather 🐛 Integrity constraint violation when trying to add multiple blocks in a complex IEF field Active , which I did not think ECA had anything to do with until someone left a comment there about ECA. All of the affected sites have ECA enabled. Here's the gist of what we're doing:

1. Install IEF, ECA Form modules
2. Create a "featured block" entity reference field on a content type, e.g. "Basic Page", referencing content blocks.
3. Set the field to use the complex IEF widget
4. Create a new page, and create a new block using the IEF widget.

If you save now, everything is fine. If you edit the page and add another block, it works fine -- so long as you only ever add one block at a time.

5. If you add a second block without saving the node, it appears correct -- it adds another row to the IEF widget, and you can keep adding more.
6. But if you save, you get the Integrity Constraint Violation, duplicate entry 'xxx' for key 'node__field_uuid_value'.

This is affecting node and taxonomy term references as well as block references -- anywhere the IEF complex widget is used with multiple cardinality, if eca_form module is enabled. Doesn't matter if there's an ECA model using it.

🇺🇸United States freelock Seattle

Turns out it's a known issue of ECA - 🐛 ECA Form breaks complex IEF widget Active . Leaving this open in case the fix is better handled here in IEF.

🇺🇸United States freelock Seattle

Oh interesting, we're using ECA on the affected sites -- we're hitting this issue on at least 4 different sites, and ECA is active on all of them.

🇺🇸United States freelock Seattle

Commented in Slack #ECA channel with a link to an old blog post where I created a custom price resolver.

So what I'm wondering now is if it's possible to alter a price resolver's priority -- or have a price resolver derivative that allows a price resolver instance (or multiple instances) to get created with a specified priority. Wondering if this might be possible with a Symfony Decorator, if there's not a more Drupal-specific way?

🇺🇸United States freelock Seattle

As discussed in #ECA slack, I think we could implement a PriceResolver service with a high priority, that would return the desired price. This could then be set through an ECA plugin.

🇺🇸United States freelock Seattle

@ankondrat4 sorry to miss this, our client that we built this for hasn't been all that active. I'm not sure I'll be in here much, so I've added you with some basic roles -- if you're active on this, I can increase those, reach out to me on Slack!

🇺🇸United States freelock Seattle

Merged.

🇺🇸United States freelock Seattle

Committed, thanks!

🇺🇸United States freelock Seattle

Fixed. Thanks for the contribution!

🇺🇸United States freelock Seattle

It's not the first time I've hit circular stuff with commerce -- all the way back to Ubercart, seems like commerce events fire a lot more often than I would think necessary. My answer is idempotence -- make sure if it's called multiple times, the result is always the same.

This is why there's a quantity field in the plugin -- each time the plugin runs, if the item is already in the cart, it updates the quantity to whatever value is in that field (which accepts a token), so you if you create a token for quantity based on other products in the cart, it can always do the right thing -- set the correct quantity on one order item.

If the "right thing" is to add additional order items with the same sku, this plugin won't do that. It won't even detect if there is more than one order item on the order -- it just sets the quantity on the first matching one it finds (but you can specify elsewhere that multiple order items with the same sku should always be combined).

🇺🇸United States freelock Seattle

@nicxvan what circular logic do you see?

🇺🇸United States freelock Seattle

Merged -- not fully tested, so making an Alpha release. Any issues found should be created as new issues!

🇺🇸United States freelock Seattle

Hi,

This action requires either a sku or a purchasable entity (product variation) to add, and an order (which is what a cart is under the hood). So you do need to load an existing order/cart to pass it in.

I used this event: https://ecaguide.org/plugins/eca/commerce/events/eca_commerce_cart_entit... which provided a cart (order) and a product variation entity. I could then check details for the product, and if it matched, add a different product to the cart by sku.

It does require the commerce cart and commerce order modules to be active, and the order -- so you need to get that somehow. Loading it by entity type/id should be fine -- is the one you're loading owned by the user who's executing your model? You often need to switch users if you're trying to run from drush or cron...

Cheers,
John

🇺🇸United States freelock Seattle

Hi,

The best way to send an Easy Email programmatically is to use ECA . Both Easy Email and ECA are in Drupal CMS, so this is getting a lot more widespread use.

On the linked issue in #7, I had started a "Scheduled Message" module to do this, but we've switched over entirely to ECA.

Three of my recent Advent Calendar posts include this:

https://www.freelock.com/advent/2024/remind-customers-abandoned-carts
https://www.freelock.com/advent/2024/automatically-track-documentation-r...
https://www.freelock.com/advent/2024/send-roster-event-attendees-staff

... the gist is, create a view that collects the people you want to email. In ECA, you use a Views Query to get all of them, and send that list to a custom event (entity aware), which ECA will then call for each person on the list. From that event create a new entity of type easy_email, and the email template you want to send. You can then associate entity reference fields to your email with the views result, and use tokens in your template as appropriate.

🇺🇸United States freelock Seattle

Added new action plugin.

Note that during testing, the "Add entity to cart" event got executed multiple times (twice) -- so in my initial cut, it was adding the extra product twice.

To avoid this, I made it check the existing cart for a matching order item, and if found, it sets the quantity of that item instead of adding a new one.

This works fine for my needs. I'm not sure if there is a good way to avoid this problem otherwise.

🇺🇸United States freelock Seattle

freelock created an issue.

🇺🇸United States freelock Seattle

Similar question on the ECA queue - 💬 A honest comparison / contrast of ECA vs Rules? Active .

I Just turned most of my response into a blog post, here: https://www.freelock.com/blog/john-locke/2025-01/ask-freelock-eca-vs-rules ... would love any comments people have on that, especially from people who have used Rules recently.

Comments there are now auto-moderated by AI -- if you leave a relevant comment, it should get automatically published within 5 minutes!

@w01f I wonder if you could get a reasonable starting place on a comparison table by asking Claude or something for one...

Production build 0.71.5 2024