Skip to content
View in the app

A better way to browse. Learn more.

ernestdefoe.online

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
ernestdefoe.online

Extensions, themes & support for Flarum and Invision Community

Vibe coding for the community web. Report a bug, request a feature, or dig into the source — this is where the tools you use get built, in the open.

We do custom Bespoke Invision Community apps. If you have an idea for something you want then use the contact form to get in touch with us.
Knowledge base

Things that cost me a day, so they cost you none

Working notes from building Invision Community and Flarum applications. Mostly the failures that give no error at all — the ones where everything installs cleanly and quietly does the wrong thing.

92 articles

Invision Community 5

86 articles

Extensions and contracts

39

What each extension point is for, what it must declare, and what happens when it is wrong — which is usually nothing visible.

Languages and text

5

The string table, translation, and the places where text does not appear where you expected it to.

Theming, templates and forms

9

Theme hooks, CSS that survives both colour schemes, and building forms that do not throw on render.

Background work and scheduled tasks

5

The queue system, work that has to happen after the response, and jobs that finish without doing anything.

Data, settings and storage

11

The database layer, settings, tags, file storage, and backing up a live site.

AI features and expectations

5

What these features do, what they cost, and what buyers reasonably but wrongly assume they do.

Application structure and releases

11

The JSON files an application is made of, versioning and upgrade steps, and testing from the command line.

Realtime, chat and calls

1

WebSocket gateways, relays and the server-side pieces live features depend on — where "it works when I test it" and "it works for your members" are different claims.

Nothing matches that.

Your classifier does not learn, and everyone will assume it does

A customer asked this about an auto-tagging application, a day after installing it:

But when it begins to learn? If a user published the next untagged thread?

It is a completely reasonable question, and the answer is that it never begins to learn, because it never stops being ready. There is no warm-up. It works correctly on the very first topic and it works exactly as well on the ten thousandth. Nothing a member does changes it.

If you are building anything that classifies content with embeddings — tagging, related items, routing, triage — your users will arrive with a mental model of a system that studies their community and gradually improves. Yours almost certainly does not do that. The gap between those two models is where support tickets, bad reviews and "it stopped working" reports come from, and it is worth closing deliberately rather than hoping nobody asks.

Two things that get called the same word

Building the index is embedding each label once and storing the vector. It reads the label list, and often a sample of how each label has been used, and produces one vector per label. It is a build step. It costs API calls proportional to the number of labels, not the amount of content, and its output is static until you run it again.

Learning — what the customer meant — is a feedback loop: the system observes outcomes and adjusts. Corrections change future behaviour. Accuracy improves with use.

Almost every embedding-based classifier in the wild does the first and none of the second. The model is frozen, the label vectors are frozen, and classifying a new item is a pure function of that item and the stored vectors. Two identical topics posted a year apart get identical labels. That is a feature — it is predictable and debuggable — but it is not what "learn" means to anybody who is not the person who wrote it.

The failure this actually causes

Nobody is harmed by a system that does not improve. They are harmed by the corollary, which is much easier to miss:

A label created after the last index build has no vector, so it can never be suggested.

This is silent in the worst way. The label exists. It appears in the label picker. The classifier is enabled and visibly working — it is tagging things every day. It simply never applies that one label, and there is no error, no warning, and no log line, because from the matcher's point of view the label was never a candidate. The administrator's reasonable conclusion is that the app is ignoring their new tag, or that the AI "doesn't understand" it.

On Invision Community this is sharper than it needs to be, because there is no event fired when a tag is created. You cannot hook tag creation and rebuild automatically even if you want to. Whatever you do about this, it cannot be "detect it and fix it silently".

What to do about it

Detect the gap and say so. Comparing the label list against the stored vectors is a set difference, costs nothing, and needs no API call. If labels exist with no vector, say so on the settings screen in the terms the administrator is thinking in:

3 tags have been added since the vocabulary was last built
(Onboarding, Billing, Mobile app) and cannot be suggested
until you run Learn tags.

That single check converts your most likely support ticket into a self-service fix.

Be careful what you call the button. "Learn tags" is a good label for what it does and an actively misleading one for what it implies. Whatever you name it, put the shape of the thing next to it in one sentence: what it reads, and when it needs running again. State plainly that it is not continuous. Users do not read documentation, but they do read the sentence under the button they are about to press.

Lead with the good news, because it is genuinely good. "No learning" sounds like a limitation and is mostly the opposite. There is no cold start, no minimum corpus, no period of bad output while it settles. A brand new community with twelve topics gets the same quality as an established one. Say that, because the customer asking when it starts learning is really asking "is it working yet?"

Where the automatic behaviour actually belongs

The classification is static; the application of it should not be. Three details matter more than they look:

Do the work off the request. Classifying costs an API call and a network round trip. Posting must never wait on either — a slow or down provider would turn into "the forum won't let me post". Queue it and let the item be created immediately.

Reclassify on edit and on move, not only on create. A retitled topic is frequently a topic that is now about something else, and a topic moved between containers has often changed scope. Both are cheap to handle if your "only untagged items" guard bails before it embeds anything.

Deduplicate the queued job. Somebody editing a title five times in a minute should produce one classification, not five. Key the job on class and id.

The related trap

Do not let the classifier invent labels outside the vocabulary. Taggable::setTags() validates against the tag store and silently discards anything that is not there, so a suggestion outside the list does not error — it just fails to appear, which looks identical to the classifier having chosen nothing. Constrain the candidate set to what exists, and treat the label list as the contract.

See also: Why a similarity threshold is never enough for automatic classification, There is no event when a tag is created, and what that means for your app, and Taggable::setTags() deletes every existing tag first.



User Feedback

Recommended Comments

There are no comments to display.

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.