Longtail Forge Update: Making the Browser Stop Guessing
Longtail Forge Update · September 5–18, 2026

There is a particular kind of software bug I dislike because it can sit quietly for months: two parts of the application agree about what a piece of data probably looks like, nobody actually checks, and everything works until one odd value arrives and proves the agreement was imaginary.
A lot of this Longtail Forge update has been about replacing those imaginary agreements with real ones.
That sounds like TypeScript work, because a lot of it is TypeScript work. But the useful part is not “the compiler is happier.” The useful part is that the browser is becoming much more explicit about what it receives, what it is allowed to assume, and what it should refuse to use when those assumptions are not true.
That work has touched time entries, Notes, and user administration. It has also caught a few places where the first attempted fix would have changed existing behavior just to make the type checker stop complaining. Those changes were backed out. That distinction matters more to me than getting another diagnostic count to zero.
The short version
- The Time Entry dialog now validates the shape of records it receives instead of merely trusting that an array contains the right kind of data.
- Notes is getting clearer typed records for linked context without breaking older field spellings or existing behavior.
- The Add User and Edit User flows now know much more precisely which controls and records they are working with.
- Several review findings exposed places where a type declaration was stronger than the runtime checks underneath it. Those checks now match the claims.
- Tests caught attempted “cleanup” changes that would have silently altered behavior, so the contracts stayed intact instead of being weakened to satisfy the compiler.
- None of this means the private preview has suddenly become a public launch. It is still a private technical preview, and invitations remain deliberately gated.
The type checker is useful when it tells me something I did not already know
There are two ways to do a TypeScript cleanup.
The first is to make the red squiggles disappear.
The second is to use the red squiggles as evidence that the program is being vague about something important, then figure out whether the vagueness is harmless or whether it is hiding a real assumption.
I want the second one.
Longtail Forge still has a lot of browser-side JavaScript that grew before the current type contracts were as explicit as they are now. The current work is gradually tightening those boundaries instead of stopping everything for a giant rewrite. That means taking one real workflow at a time — opening a time entry, adding a user, editing a user, linking a Note to another record — and following the data all the way through.
The Time Entry dialog is a good example. The browser loads an entry, fills the controls, lets you edit it, reads the values back, and sends the save request. That sounds simple until you realize every step has to agree on things like which client and project are selected, what kind of value a tag picker returns, whether an ID is really text, and what comes back after the save.
Making that whole round trip explicit uncovered an actual missing guard around an unresolved client. It also forced the save path to distinguish between a checked record and “whatever happened to come back from the request.”
That is the kind of TypeScript work I care about. Not because a number went down. Because an assumption became visible before a user had to discover it.
Technical discovery & auditing
The public page doesn’t tell you much about the machinery behind it. Raymond Tec audits inherited and long-running projects to uncover the plugins, integrations, data, dependencies, and old decisions that determine what the next change will really involve.
A type is only useful if the data earned it
One of the more useful review findings came after the first Time Entry work was already passing.
The browser had a normalized time-entry type saying a set of fields were strings. The server really does produce those fields as strings. So far, so good.
The problem was the browser-side normalizer was not actually proving that before it handed the records to the rest of the page. It checked that the response was an array and then copied the values through. In other words, the type declaration was telling the truth about the normal producer, but the runtime boundary was still trusting the wire format more than the type suggested.
That is subtle. It is also exactly the kind of subtlety that makes “we typed it” sound more reassuring than it should.
The repair was not to coerce whatever arrived into text and hope for the best. The browser now checks the fields the server contract says should be text and refuses malformed rows that cannot satisfy that contract. Good rows keep flowing through unchanged. Bad rows do not get dressed up to look valid.
The same review found two other useful corrections. The tag picker already had a published contract; an earlier note incorrectly said it did not, so the code and the test that had locked in that explanation were corrected to use the contract that was already there.
The save callback also did not need its response stripped down. It needed the response narrowed before the existing spread, preserving extra fields while proving the part Longtail Forge depends on.
This is one of those areas where “make the types stricter” can be the wrong instruction. The better instruction is “make the claim match reality.” Sometimes reality is stricter. Sometimes reality is broader. The important thing is that the code and the runtime behavior agree.
User administration is a bad place for vague assumptions
The same cleanup is moving through User Administration, starting with the Add User flow and then the Edit User dialog.
That page handles account lookup, workspace scope, roles, memberships, sessions, and permission-dependent controls. Treating every DOM lookup as a generic “Element or maybe null” leaves a lot of room for the browser code to guess what it has in its hands.
The Add User work now identifies the actual control types where they are acquired, while still preserving the places where a control really is optional.
That distinction sounds fussy until you consider the alternative. If I make every control “required” too early, one missing optional element can kill the entire page before the existing error handling gets a chance to explain what happened. If I leave everything vague, the code can dereference the wrong kind of element or quietly accept an unexpected record.
The goal is neither “trust everything” nor “throw immediately.” It is to be precise at the point where the page actually needs precision.
That work also uncovered a weird little browser detail: the DOM definition for an element’s hidden property can be boolean or a special string value. Longtail Forge uses it as a boolean on this page, so the code now states that explicitly instead of relying on an inference that happened to work.
The Edit User work carried the same idea farther. The user list is now typed only after records have passed the existing checked readers, so the compiler can verify the path from response to rendered user. A membership renderer also had to admit that null is a real input when the dialog closes, rather than forcing the caller to pretend otherwise.
More importantly, an intermediate edit tried to make a focus call “safer” with optional chaining. It looked harmless. It was not.
That would have changed a missing required control from a visible failure into a silent no-op. The existing behavior was restored, and the test now protects that decision.
There is a larger point hiding in that tiny example: defensive programming is not always adding more question marks. Sometimes a silent failure is worse than a loud one because it leaves the interface half-working and gives you less evidence about what broke.
Custom application development
Off-the-shelf software is great when your business works the way the software expects. When it doesn’t, Raymond Tec builds focused internal tools, dashboards, portals, plugins, and custom applications around the work that actually needs to happen.
The tests are being taught what not to let me get away with
The testing work around these changes is not just “run the suite and hope it turns green.”
For several of these slices, the checks deliberately break a small rule and verify that the guardrail catches it. If a test claims a required record must be validated, the break harness removes or weakens that validation and expects the test to fail. If the test still passes, the test is not protecting what it says it protects.
That process has found its own mistakes.
One attempted break was inert because replacing a record check with simple truthiness did not actually change the behavior for the data the test supplied. Instead of declaring victory, the test case was expanded so the difference became real.
Another assertion had been written around the first typed cluster on the User Administration page and became too specific once the second cluster was typed. The assertion was changed to protect the underlying rule rather than the historical count.
There was even a line-ending problem in two shared files caused by an edit path that rewrote LF lines as CRLF on Windows. The first check missed it because the shell pipeline hid the carriage returns. The files had to be inspected byte-by-byte to prove what happened and restore them without changing the actual code.
None of these are features. You will not see a “better mutation harness” button in the sidebar.
But I would much rather find out that a test is lying while I am deliberately trying to break it than after I have trusted it through three releases.
Reliable automation
Automation is wonderful until it quietly stops working three Tuesdays ago. Raymond Tec builds integrations with logging, monitoring, and failure handling in mind so the boring work stays automated without becoming mysterious.
So, what will anybody actually notice?
Probably less than the amount of work would suggest, which is fine.
The immediate benefit is not a new module. It is that some of the older browser code is getting much clearer about the data and controls it depends on.
Time-entry editing should be less willing to operate on malformed records. User administration should be less dependent on vague DOM assumptions. Notes can keep accepting the legacy field spellings it actually supports without turning every input into an untyped bucket. And the test suite is doing a better job of refusing changes that make the type checker happy by quietly changing behavior.
Over time, the bigger benefit is maintenance. Future changes now have more specific information about what is allowed. That does not make bugs impossible; it narrows the ambiguity they can hide inside.
For self-hosters, that is especially useful because the product eventually has to be maintainable outside my development environment. A system that only stays coherent because the person who wrote it remembers every unwritten assumption is not really ready to hand to somebody else.
Where things stand now
Longtail Forge is still in active development and still being used privately. The limited friends-and-family internet preview is technically deployed, but invitations remain blocked behind the readiness review. This round of browser-contract work does not change that status.
The roadmap also still separates the current 0.33.33 work from the planned Support Tickets module in 0.34. Support Tickets is not shipped.
The current 0.33.33 plan is concerned with the public demo’s analytics, privacy, and durable interest capture. The important word there is “plan.” Nonessential analytics and interest capture are supposed to stay disabled until the external data boundaries, consent, retention, and review path are actually decided and documented. Mailing-list signup and feedback are also meant to live outside the resettable demo database.
I like that order. Measure less until the rules are clear, not collect everything first and write the privacy explanation later.
There is still a lot of browser modernization ahead. But the useful change in this stretch is that the work is increasingly about proving the boundary instead of decorating the assumption.
That is slower than adding a cast and moving on.
It is also the point.
Want the deeper trail? The Longtail Forge Changelog keeps the detailed release history, the Roadmap shows what is planned next, and you can subscribe for future Longtail Forge updates if you would rather have the next one come to you.
