Changelog
Complete version history of the SPERT® Suite.
v2.6.1October 9, 2026
Fixed
- The “Skip to main content” link no longer peeks out as a thin blue strip at the top left of every page. It stays hidden until you press Tab, as intended.
v2.6.0October 9, 2026
New Features
- A new “I Want Training” tile in the Support section leads to a short form for requesting training. William W. Davis offers affordable live virtual training on the SPERT® Suite for individuals and teams, starting with a free consultation about your training needs, objectives, and any scheduling or budget constraints.
Accessibility
- Every tile’s link text, such as “Map Your Releases”, now meets the WCAG AA contrast minimum in both light and dark mode. Where a tile’s color fell short, its link text is now slightly darker in light mode or slightly lighter in dark mode; the colored bar at the top of each tile is unchanged. A new test checks every tile, including any added later.
Changed
- The “I Found a Bug” tile and form are retired. Please report problems through Contact Me; the old /bug-report address now takes you there.
v2.5.43October 9, 2026
Connect AI
- When an AI chatbot connected to SPERT® Scheduler tries to add, change or remove dependencies in a scenario whose dependency mode is off, it is now told where that setting is, so it can tell you: in the browser tab where you connected the AI, select the scenario by its name, then turn on its “Dependencies” switch, in the summary panel above the activity list, on the same row as “Parkinson’s Law”. It is also told to have you close any other tab of the project in that browser and reload this one, how to reconnect the tab if it shows a “Connect AI” button, to ask you for a new session code if the browser no longer holds the connection, that a locked scenario must be unlocked first, and to wait a few seconds after you confirm before trying again. Until now it was told only to ask you to turn the setting on, without saying where.
- When the chatbot needs your project but none is available from SPERT Scheduler, it is now told what is missing: Read Mode is on, but no project is available. It is told to ask you to keep the project open in the browser tab where you connected the AI — pressing “Connect AI” there if the tab shows that button, and giving it a new session code if the browser no longer holds the connection — then to try again a few seconds later, and, if that keeps happening, to ask you to look in that browser’s console for a message beginning “[AI] Snapshot”. Until now it asked you to open SPERT Scheduler with Read Mode enabled, although Read Mode was already on whenever this happened.
- Only the explanations change: the same requests are refused as before, with the same error codes. New tests check the full wording of every refusal changed here. The AI service now reports its version as 1.13.1.
v2.5.42October 5, 2026
Legal
- New editions of three legal documents are published: Terms of Service 1.3, Privacy Policy 1.3 and AI Privacy Notice 2.2, all effective October 5, 2026. The AI Connectivity Consent Notice is unchanged and stays at version 2.1.
- The Privacy Policy now spells out several things the service already did: the database backups (daily backups kept for up to 98 days and point-in-time recovery data kept for up to 7 days, both in the United States), the request information our web host receives whenever a page loads, operational logs kept for 30 days, project sharing and invitation emails, and messages sent through this site’s contact form. It names the service providers behind those — Vercel, Resend and Formspree — and notes that a record is kept of which edition of the Terms and Privacy Policy you accepted.
- Cloud Storage and Connect AI data are stored at rest in the United States. The Terms and the Privacy Policy now say so, and commit to giving notice by updating them before that location changes.
- The AI Privacy Notice now states exactly how long Connect AI relay data lasts: it expires seven days after your last activity, is deleted sooner when you disconnect or sign out, and copies may remain in database backups until those expire. It also states that the Read Mode snapshot can be read only by the relay server, never from a web browser.
- The Terms now let you enter the email address of someone you are inviting to collaborate, an exception the earlier wording did not make, and say that any backups the Operator keeps are for its own disaster recovery and give you no right to have data restored. The AI Privacy Notice is now incorporated into the Terms by reference, alongside the Privacy Policy.
- Unlike the September editions, these need your agreement again: each app that offers sign-in will ask you to accept the new Terms and Privacy Policy once that app is updated.
v2.5.41September 25, 2026
Connect AI
- An AI chatbot connected to SPERT® Scheduler can now create and update activities that use Beta-PERT, the distribution Scheduler 0.72.0 added. Every Scheduler tool that takes a distribution accepts it — creating or updating one activity, or many at once. The chatbot still never picks Beta-PERT on its own: it uses it when you ask for it. Before this release the service refused a request naming Beta-PERT, cleanly, without changing anything.
- The shared definition that this site’s AI service and SPERT Scheduler are both built against now lists Beta-PERT, and the two copies were checked identical. A new test confirms each of the five Scheduler tools accepts Beta-PERT and still refuses a value no version knows. The AI service now reports its version as 1.13.0.
v2.5.40September 17, 2026
Infrastructure
- MyScrumBudget projects: no change to what the rules allow. MyScrumBudget 0.42.0 made tile colour, archiving and dashboard order personal — each person’s choice is now saved in their own settings rather than on the shared project — so the app no longer writes those three fields to a project. The rules keep accepting them on purpose: projects saved by earlier versions still carry them, and removing them from the rules first would stop those projects from being overwritten by an upload from local storage and leave the old values impossible to clear. A planned cleanup will remove the stored values first, and only then retire the three fields from the rules.
- Two new checks in the rules test suite hold that in place. One fails if the three fields are removed from the rules while projects still store them; the other fails if an editor still running an earlier version of MyScrumBudget could no longer change a shared project’s colour or archived state.
- The only changes to the deployed ruleset are comments. Those that described what MyScrumBudget writes now say which versions they describe, and five references to line numbers in the ruleset now name the rule they point at instead, because nothing checked them and three had already drifted.
v2.5.39September 14, 2026
Security
- SPERT Story Map projects: a new project may now only contain the fields the app actually uses. Until now the create path was the one project surface in the suite with no field allowlist, so a crafted request could add arbitrary fields to a brand-new project document. Updates have been guarded since 2.5.17; creates now match.
- The Story Map client was fixed and deployed FIRST, in its v0.53.7 release, and only then did this rule land. Rules are global and take effect within seconds, while the client is a static bundle that can sit in an open tab — so tightening the rule first would have broken Duplicate for anyone still running the older client. The reverse order is the whole reason this shipped as two releases rather than one.
- Story Map v0.53.7 also stopped writing two internal bookkeeping fields into cloud storage at create, and made replacing a project keep any that an older client already stored. That second half is what repairs projects made with Duplicate before the fix, which could not be replaced by an import at all.
v2.5.38September 13, 2026
Security
- MyScrumBudget projects: the cost-snapshot field is owner-only. A project can now carry the labor rates, holidays and discount rate it was costed with, so every collaborator sees the same figures instead of pricing the project with their own rate card. Only the project owner may write it — an editor who could change it would silently alter the basis on which somebody else's project is costed.
- The field is added to the MyScrumBudget project allowlist ahead of the app release that writes it, because the ruleset has to permit a field before the app can send it.
v2.5.37September 13, 2026
Legal
- New editions of all four legal documents are published: Terms of Service 1.2, Privacy Policy 1.2, AI Privacy Notice 2.1 and AI Connectivity Consent Notice 2.1, all effective September 13, 2026. Every one of them now names famousdavis, LLC as the operator of this site and the apps.
- Each document carries a Change of Operator section recording that the SPERT® Suite business transferred to that company on September 12, 2026, and stating what the transfer did not change: not what the apps collect, not where it is stored, not who processes it, not how long it is kept, and not any right you hold. Cloud Storage data stayed in the same Firebase project under the same access controls throughout, and was not moved or disclosed to anyone as part of the transfer. Posting the Privacy Policy is the notice of the transfer its own Business Transfers section calls for.
- ⚠️ Copyright in the software did not transfer. It is held by William W. Davis, MSPM, PMP personally and licensed to the company, and the Terms now say so in their own right. The footer’s copyright line, the credit shown in each app, and the copyright notice in every source file all still name him and are correct as they stand.
- The Terms gained a short section defining who the word “Operator” covers, because after the transfer there are two parties rather than one. In the provisions that disclaim warranties, limit liability or provide for indemnification, it covers the company and William W. Davis individually. Everywhere else — in particular the content, feedback and AI licences you grant — it means the company alone, so those grants run to the company and not to an individual.
- No new consent is required, and the Connect AI consent dialogs are unchanged and will not be shown again on account of this. Their wording and the data handling behind them were not affected by the transfer, so the consent version they record is deliberately unchanged.
- This site’s footer now reads “Operated by famousdavis, LLC” beneath the legal links. The apps’ own footers are unchanged.
v2.5.36September 13, 2026
Legal
- The licence file now names famousdavis, LLC as the owner of the SPERT® trademarks. The SPERT® Suite business — the spertsuite.com website, the hosting it runs on, and the SPERT®, Statistical PERT® and Estimation Made Easy® marks — transferred to that company on September 12, 2026. The licence’s trademark clause still named the previous owner while the newly published Terms of Service named the company, so two published legal documents disagreed about who owns the marks.
- ⚠️ Copyright in the software did not transfer, and the licence still says so. It is held by William W. Davis, MSPM, PMP personally and licensed to the company. The clauses requiring his name to be kept as the author, and withholding his name from promotional use, are unchanged — as are the copyright notices in every source file, the credit shown in each app, and the copyright line in this site’s footer. Two different names now appear in the licence and both are correct: the company operates the service, the individual owns the code.
- Nothing you may do with this software changed. It is still the GNU General Public License v3 with the same additional terms — the code is free to take, change and share, a modified version must still be released under a different name, and credit to the original author must still travel with it.
- The licence is one file copied byte-for-byte into eight repositories, each of which pins a checksum of it, so changing it in one place alone fails the other seven at once. All eight were updated in the same pass and are released separately. The checksum guard was confirmed to still catch both ways this can go wrong — a repository left on the old checksum, and a copy edited in place instead of recopied — by breaking it each way and watching it fail.
v2.5.35September 12, 2026
Security
- On a shared MyScrumBudget project, anyone invited as an editor could rewrite four record-keeping fields on a project owned by somebody else. These are not the project’s content — they are the fields that record where a project came from, when it was created, which version of the data format it uses, and a log of the changes made to it. An editor could clear that change log completely in a single action, leaving nothing on the server to show it had happened. Only the project’s owner can change these four now.
- Measured against the live rules before the fix: all four were writable by a non-owner editor. Fourteen editor seats across four shared projects were affected, and one account holds editor access on three of the four.
- ⚠️ This was not a new fault and nothing in a recent release caused it. It is being fixed on its own, ahead of other planned MyScrumBudget work, so that a security fix does not wait on anything else.
- ⚠️ Dashboard ordering is deliberately left as it was. Each person can drag their projects into a preferred order, but that order is stored on the project itself rather than against the person who chose it. Restricting it to owners would mean anyone invited to even one shared project could no longer reorder their own dashboard at all — the entire reordering action would be refused, and the app does not currently notice such a refusal. That is a genuine problem of its own, but the repair belongs in the app rather than in these rules, and it has been recorded as separate work rather than folded in here.
- The change is covered by new tests that were first confirmed to fail against the unfixed rules, so they demonstrate the fault rather than merely describing it. They also hold in place the things that must keep working: an editor saving ordinary project content, and an editor reordering their dashboard. Writing the same protection for the other six apps is now a mechanical follow-on, and is deliberately not part of this release.
v2.5.34September 12, 2026
Fixed
- Invitation claiming had been failing for every Microsoft sign-in, across all seven apps. Firebase records a Microsoft account’s email as unverified, because Microsoft’s sign-in token carries no verified-email flag for Firebase to copy, and the shared claim function refused any unverified email. A student who signed in with a university Microsoft account and clicked an invite link was told the link did not match their account. The email matched. It was never compared. Measured on September 12, 2026 in the live user export: all ten Microsoft accounts unverified, all eleven Google accounts verified, no exceptions and no account on both providers.
- The claim function now accepts a Microsoft sign-in with an unverified email, and still refuses every other unverified identity — an email-and-password account, an anonymous one, or a Google account that reports unverified. The decision keys on the provider used for this particular sign-in, not on the list of providers linked to the account, so an account holding both is judged by whichever it signed in with.
- ⚠️ The refusal message had told the caller to “use a Microsoft work or school account” — measurably the case that was failing. It now reads: “Your account’s email address could not be verified, so invitations can’t be accepted. Please sign in with Google or Microsoft.”
- ⚠️ This release on its own changes nothing a student can see, and that is deliberate. All seven apps still decline to call the function while the account’s email is unverified — a client-side courtesy that suppressed console noise and was never the policy — so the Microsoft path stays closed until each app is changed to call the function unconditionally and let it decide. MyScrumBudget goes first. The function is also deployed by hand, separately from this site, so merging this release does not put it into production; the owner authorises that step.
- The tests now model a real sign-in token, which always names its provider. The two new cases are one token shape differing only in the provider string, so the refusal of a password identity is attributable to the provider and not to a claim the test forgot to include. A third case pins that a token with no provider claim at all — a shape no real token has — is refused rather than crashing.
v2.5.33September 3, 2026
Infrastructure
- A check in the release gate had been quietly skipping itself, in exactly the situation releases are normally prepared in. The gate confirms that each project’s internal notes file declares the same version number as everything else, so those notes cannot drift out of date unnoticed. That check skips when the notes file is not present — which is correct on the automated build server, where the file is deliberately excluded from the repository and genuinely is not there.
- ⚠️ The same absence had a second, unrelated cause, and the check could not tell the two apart. When a release is prepared in a separate working copy — which is how these releases are normally prepared — the tooling that creates that copy leaves excluded files behind. The check saw a missing file, assumed the build-server reason, and skipped. It printed a skip line and the gate went green, so nothing looked wrong. The check that exists to stop the notes drifting was itself absent from every release prepared the usual way.
- The two reasons are now told apart. On the build server it skips as before. Otherwise it looks for the notes file in the main working copy and reads it from there, so the check runs even when the release is being prepared elsewhere. If it still cannot be found, that is now a failure rather than a skip: a check that cannot run should say so instead of passing quietly.
- ⚠️ This is the same shape as the problem the notes file itself once had — it sat thirteen releases out of date because the tool meant to notice it could not see it. A skip and a pass look identical from the outside unless the reason is stated, which is why the failure branch was chosen over a warning.
- The change lives in the release script that is deliberately identical in every project in the suite, so each project takes the same corrected copy rather than growing its own variant. Worth noting for anyone auditing the nine: only four of them actually switch this check on, and the other five declare it as an empty list, so for those the fix is preventive rather than closing a live gap.
v2.5.32September 3, 2026
Infrastructure
- A step in the release checklist was enforced by nothing, in every project in the suite. After a release is merged, the local copy of the project is supposed to be brought back into line with the copy on the server. Merging advances the server; it does not touch the local copy. If the local one is left behind, every report still reads as though the release arrived everywhere, and the next release is built on the wrong starting point.
- ⚠️ Two mechanisms that look like they should have covered it could not, and that pair is why it survived rather than merely going unnoticed. The release gate runs before a release is merged, so the condition it would be checking does not exist yet. The automated checking cannot see it either, because it is a fact about the machine doing the release rather than about the project, and a fresh automated copy has no view of anyone’s working copy. Nothing the suite already had was pointed at it.
- Two checks now cover the two moments. Before a release, the gate refuses to proceed if the local copy is behind the server, so a release is never cut on a stale base; being ahead is normal and is not reported, since that is what the release itself is. After a release, a new command compares three sources — the local copy, the local record of the server, and the server’s own answer — and reports which one disagrees. Three rather than two, because the first two can be stale together and agree with each other while both are wrong.
- ⚠️ The pre-release check deliberately does not require a clean working copy, and must not start to. It runs partway through a release, after the version and changelog edits and before they are committed, so uncommitted work is expected at that exact moment. Requiring cleanliness there would fail every release. That check belongs to the post-release command, where it is correct.
- Both compare fingerprints rather than reading a command’s own message. The step had once been reported as done from the tail of a command whose informative line had been trimmed away, and a message saying everything was already current cannot distinguish a real check with nothing to do from no check at all. Running a command is not the same as checking its effect.
- A fetch failure fails the pre-release check rather than skipping it, because the comparison reads a remote-tracking ref and a swallowed error would compare a stale ref with itself, agree, and read as a pass. Both checks self-skip under automated checking, where the checkout is shallow and detached and the question is meaningless.
v2.5.31August 27, 2026
Infrastructure
- The error the new pre-flight tool found last release is fixed, and it turned out to be a different error than it first appeared. The entry did not merely point at the wrong file: it named two functions that live in two different files, and it named the second one for a job it does not do. That second function is what puts cleared fields back as explicit deletions — which is a separate column’s business, and that column already records it. The duplicate was removed rather than moved, and the entry now names the two things that genuinely determine the answer, both with addresses the tool can check.
- The count of files being watched went from eleven to thirteen as a result. ⚠️ That is worth being precise about, because a number moving is usually bad news here: earlier corrections were the same population being counted wrongly. This one is a larger population, counted correctly — the record now points at two real files it had been silently failing to mention. More to watch, not a worse count of the same thing.
- Fixing it created a second problem, which is fixed in the same release. That one real error was the only evidence the tool worked; repairing it would have left a check that has never once been seen to fail, which is indistinguishable from one that cannot fail. So the tool now proves itself: a test builds a small throwaway repository with two commits, points the checker at a name that exists in the later commit but not the earlier one, and requires it to object — then moves the pin forward and requires it to stop objecting. That proof needs nothing outside this repository, so it runs everywhere, including where the other apps are not present.
- Only with that in place was the check added to the release gate. It now reports how much it actually examined on every run, passing or failing — because on a machine without the other apps checked out it examines nothing at all, and a pass that does not say so is the precise failure this whole line of work has been about. The gate’s own configuration records that limit, so it is visible to someone reading it rather than only to someone running it.
v2.5.30August 27, 2026
Infrastructure
- Seven of the columns in the cloud-permissions record are copies of what another app looked like on a particular day, and nothing here could tell you whether they had since gone wrong. A new pre-flight tool reads those other apps directly and reports two separate things: how many changes each cited file has seen since it was last read, and whether the specific function each entry names still exists at the exact commit it was read from.
- The two answers are kept apart on purpose. Being out of date is not the same as being wrong — a file can have changed many times and the record still be exactly right, and two of the four currently behind are known to be correct. The first number is a prompt to go and look, nothing more. The second is the one that can actually be false.
- It found one. An entry pointing at the Forecaster names a function in a file that does not contain it, and never did — the function lives in a neighbouring file. That is a genuine error in the record rather than a fault in the tool, and it is reported rather than quietly worked around.
- One target cannot be placed at all, because the record names the file without saying where it lives. That is reported as unresolved rather than dropped, and the tool deliberately does not go looking for it by name: guessing would make the summary tidier while making it less true, and the right fix is to correct the record. Reporting it also keeps it visible — a dropped entry looks exactly like a clean one.
- The tool prints the rows, not just the totals. Three plausible-but-wrong ways of writing it produce exactly the same totals as the correct one and differ only in the rows they fail to print, so the summary line alone cannot tell you which you are running. It also states which of its green results are meaningless: a shared licence header means certain common words are found in every file it inspects, so only a red result carries information.
v2.5.29August 27, 2026
Infrastructure
- The record of what each app may save to the cloud has nineteen columns, and they are not all worth the same. Some are held to reality by a check that would fail if they went wrong. Others are copies of what an app looked like on a particular day, and nothing here can tell you they have since gone stale. Reading the file, there was no way to tell which was which. Every column now has to say, and the answer is checked rather than merely written down.
- Seven of the nineteen are the expensive kind: statements about another app’s code that nothing in this repository can test. Each now records what would make it out of date — a field being added to the app, a function being renamed — so the next person to look knows what to look for rather than having to re-read everything. The other columns must name the specific check that holds them, and that name is verified to point at something that actually exists. A label claiming a check that is not there is the same defect this record was built to stop making about other people’s code.
- The labels are enforced by the type system, which forces every column to carry one. A type cannot force a label to be true, though — a record calling all nineteen columns the same thing would pass — so the seven expensive ones are pinned by name as well, and mislabelling any one of them now fails and says which.
- A single flag saying whether an app keeps its ownership field separate from its member list is now required rather than optional. Twelve of the thirteen entries were answering “no” by saying nothing, which is indistinguishable from never having considered the question — and a fourteenth entry could have been added without its author ever meeting it, producing a test failure pointing at entirely the wrong thing. Getting it wrong was always loud. Leaving it out was silent. It cannot be left out now.
v2.5.28August 27, 2026
Infrastructure
- The suite keeps a written record of which fields each app is permitted to save to the cloud, alongside the security rules that actually enforce it. Nothing compared the two. The record could say one thing and the rules do another, and every check in the repository would still pass — so a rule quietly widened to permit a field nobody had declared went unnoticed by design. This release adds the comparison.
- It reads the rules directly and works out, for each app and each kind of save, the exact set of fields that rule permits — following the named lists where they are used and reading the inline ones where they are not. Any disagreement is reported as a line naming the app, the operation, the rule it came from, and which fields are on which side. A count on its own could not tell you which of the two was wrong, so it reports the rows rather than a total.
- It also refuses to ignore anything. Every permission list in the rules must either be claimed by an entry in the record or be written down as a deliberate exception with a reason — there is exactly one of those today, and it is covered by a separate suite of its own. That means a new permission list added without a matching entry now fails, which nothing previously checked.
- Deliberately keyed to the rule’s own address — which collection, which operation — rather than to a line number. An earlier version keyed on line numbers and, when a single line was added above the rules, produced nineteen alarming reports about apps that had not changed. The real problem was one line. It now reports nothing at all for a move that changes no permissions, and the existing line-number check still catches the move itself.
- This runs with the ordinary checks rather than the ones needing a database emulator, because it only reads files. That puts it on every release rather than on the ones where somebody remembered to run the slower suite.
v2.5.27August 27, 2026
Infrastructure
- A note in the security rules gave the wrong reason why one app’s missing field never seemed to cause trouble. It said that a field left deliberately empty is not counted when the rules check which fields a save contains. That has now been measured directly against the rules engine, with a control in each direction, and it is false: an explicitly empty field is still a field that is present, and the save is rejected exactly as it would be carrying any other value.
- So those saves were being rejected after all, for the six weeks between the field shipping and the rules being widened to allow it. What actually separated that case from the similar one recorded beside it was not the value written but whether the app said anything: one raised a sync error and was noticed within days, the other raised nothing and was never noticed at all. The note now says that, and carries the measurement with it, so the old explanation is not reached for again the next time someone asks why a silent failure was silent.
- The same wrong explanation appeared twice in the security rules and twice more in MyScrumBudget, one of those on a page that app shows to its own users. All four have now been corrected.
- The line references the rules test data keeps into the security rules were updated to follow the edit above, and every one of them re-checked to confirm it still lands on the rule it names.
v2.5.26August 24, 2026
Fixed
- When you invite someone to a project, or accept an invitation to one, the behind-the-scenes service records the time the project last changed. It was writing that time in a format the apps do not use — and it was writing the same one to every app, regardless of what that app actually stores. For the Cumulative Flow Diagram app the mismatch was not cosmetic: opening the project list after someone was added would fail to draw the row, because the app tried to read a date and found something it could not interpret. Both services now write the time in the same plain text format the apps themselves use.
- The Forecaster had a quieter version of the same problem. It reads the date, keeps it, and writes it back the next time you save — and on the way back out the date was being flattened into a shape nothing can read afterwards. Once one save had happened the original time was gone for good. The date is now converted to the standard format as soon as it is read, so what is written back is always something the app can read again.
Infrastructure
- One time format across the whole suite, instead of four. Projects are stored in the cloud by seven different apps, and between them they were recording “last updated” in four different ways: plain text, a number, a database-specific timestamp object, and — in one case — an unfinished placeholder that was never filled in. They all now agree on plain text, which is the only one of the four that survives being saved to your own browser and read back, and the only one that sorts correctly as text.
- A note in the security rules said that the invitation service disagreed with the apps about this format, and was harmless for now. That stopped being true with this release, so it has been removed rather than reworded — a corrected version would have been a fresh claim about other repositories with nothing in place to catch it going stale, which is the problem the note itself was an example of.
- The record of which fields carry special write instructions has been corrected in two places, not one. One entry disappears from the count because the only such field on it was the one changed here; a second entry keeps its place on the strength of a different field, but the mention of the changed field had to go. Correcting only the count would have left the second claim false in the file whose entire purpose is that its claims can be checked.
v2.5.25August 24, 2026
Infrastructure
- The record of which fields each app writes has been re-scoped, and the disagreement noted last release is settled. One entry claimed an app both does and does not write the same key. Neither half was wrong on its own: the two neighbouring fields were simply counting different things, one looking at every way the app can write to that collection and the other at a single routine save. The wider of the two now counts every write path, which is what the narrower one was always compared against.
- The other field, the one that records the smallest write an app makes, has deliberately not been changed to match. A largest-of is well behaved when you widen what it covers; a smallest-of is not, because it collapses to whatever the tiniest write in the whole app happens to be, and then it no longer tests anything. Instead each entry now names the specific write it was measured against, because the honest answer differs from app to app: for some it is a routine save, for one it is a rule the app has to satisfy rather than any code, and for another it is a deliberate decision about what to leave out. A previous attempt to state one rule covering all of them was wrong for five.
- While re-scoping it, every entry claiming an app writes the whole of its permitted field list was checked against the app itself, two of them field by field and the rest by sampling the least likely fields. All of them held. The comments that had gone out of date were corrected in the same pass, including one that named the wrong function as the widest writer.
v2.5.24August 24, 2026
Infrastructure
- A note, and nothing else. Alongside the record of which fields each app deletes, this repository keeps a record of which fields each app writes. The second one has not been re-checked against the apps yet, and doing it in the same release as the first would have been a mistake — both records feed the same tests, so if anything had gone wrong there would have been no way to tell which of the two changes caused it.
- That decision is now written down where the next person to pick the work up will find it, together with the thing that has to be sorted out first: the two records disagree with each other about whether the list of collaborators counts as a field the app writes. One app’s entry says yes, another’s says no. Both have been shipped that way for a while and neither is causing a problem, but they cannot both be the rule, and that needs settling before the record is re-checked rather than discovered halfway through.
v2.5.23August 24, 2026
Infrastructure
- Nothing in this release changes what the apps do. It corrects a record that was wrong, and adds two checks that go off if it ever goes wrong the same way again.
- Each app keeps a list of who may work on a project. When someone is removed, the app does not overwrite that list — it sends a specific instruction to delete just that one person’s entry, so that two people removing different collaborators at the same time cannot undo each other. All seven apps do it exactly this way.
- This repository keeps a written record of which fields each app deletes like that, and a test reads the record to decide what to check. The record said only two of the seven apps ever delete anything. It was written that way in a release that added the lists for those two apps and filled in a blank for the other eleven entries without going and looking. So for five of the seven apps the test had nothing to check, and it did not complain, because a check that was never created and a check that passed look exactly alike from the outside.
- The record has now been re-derived by reading all seven apps’ own source code, and the five missing entries are filled in. The test that had been covering two deletion paths now covers all seven, and all seven pass — the rules were always accepting these deletions correctly, so nothing was broken for anyone. What was broken was the evidence that they were.
- Two new checks were added so this cannot recur quietly. The first says that every app holding a collaborator list must declare that it deletes from it — that is true of all seven today, and it would have failed on the day the record was written. The second catches the mirror-image mistake: an entry can be recorded against a part of the rules the test is unable to exercise, where it would again sit there checking nothing. Four of the thirteen entries are in that position today, all of them correctly blank, and the check makes sure it stays that way.
- A third gap was closed in the test itself. It confirmed a deletion by looking for the field afterwards and finding it gone — but a field that was never there in the first place is also gone, and the two are indistinguishable. It now also confirms the field was present before the deletion, and that confirmation deliberately sits in the part of the suite that checks the test’s own setup, so that a problem with the setup cannot be mistaken for a problem with the rules.
- Finally, a note explains why a related record was considered and deliberately not created — including the reason that decides it, which is that it could not have been filled in correctly from where the reading is done. Writing the reason down means the idea does not have to be worked through from scratch a third time.
v2.5.22August 24, 2026
Infrastructure
- Nothing in this release changes what the apps do. It adds checks around a question that was asked, measured and answered "no problem" — so that if the answer ever changes, something says so.
- The rules deciding what may be saved to each app’s records work by listing the field names that are allowed and refusing anything else. Alongside ordinary saves, which send a value, the database also accepts saves that send an instruction instead — "add this item to that list", "add one to that number", "put the current time here". The database works the instruction out on its own side. The question was whether the rules can still see which field is being written when the save arrives in that form. If they could not, every one of those permitted-field lists could be walked straight around by anyone who sent instructions rather than values, and none of them would have been protecting anything.
- They can see it. Eight outcomes were written down in advance and all eight came out as predicted, against the real rules, on two different days by two different people working separately. There is no hole here and no rule was changed.
- What the release adds is the alarm. The rules ask their question in two different ways depending on whether a record is being created or edited, and there are three kinds of instruction a save can carry, so six refusals are now checked — every combination of the two and the three. Alongside them sit two acceptances, and those matter more than they look: a database that quietly discarded the instruction would also have accepted the save, and an accepted save proves nothing on its own. So both acceptances read the saved record back afterwards and confirm the value actually arrived.
- They are deliberately not repeated for each of the lists. Doing that would have produced twenty checks covering one of the three kinds of instruction and none of the other two — more cases, less of the thing that could actually vary. Where a save is refused, it is refused for naming a field that is not permitted, and a field that is not permitted is not permitted anywhere. The part that does vary got the coverage.
- There are fourteen of these permitted-field lists. Thirteen are checked together in one place; the fourteenth keeps its own separate set of checks, because it is the one that silently rejected every saved snapshot in the Gantt app for seven days and its checks were written around that. Two matching cases were added there so that no list in the rules is left without one. They are labelled in place as being there for completeness rather than because they prove anything the other six do not — otherwise someone finds them in six months, works out that they add nothing, and removes them.
- One correction. A note recording where one of these lists came from named three places in the Cumulative Flow app that write to it and left out a fourth, which had been writing to it since long before the note was made. The missing name was added. The note’s date and version stamp were deliberately left alone: the field list it records was read correctly at the time, only the list of names was short, and re-stamping it would have made a statement at the top of that same file — that everything in it was read on one particular day — untrue for that one entry.
v2.5.21August 22, 2026
Infrastructure
- Nothing in this release changes what the apps do. It removes a false statement from the top of the shared release-checking script, and adds two explanations that were missing beside it.
- The script that checks a release before it ships is deliberately the same file in all nine projects. The note at the top of it said there was no automated checking anywhere in the suite — that a green tick on a proposed change meant only that a preview copy of the site had been built, and that nothing ran the tests. That has not been true since the script existed. Automated checking runs on every one of the nine projects, on every proposed change and on every merge, and what it runs is this very script.
- The statement did not go out of date. It was untrue on the day it was written: the same set of edits that added the script also switched the automated checking on, so the file contradicted a change sitting beside it. That distinction decides the remedy, which is why it is recorded here. A statement that decays can be helped by writing down when it was made; a statement that was never true cannot. What went wrong was that a claim about the projects was written into an explanation without being checked against them — and an explanation is read as background rather than as an assertion somebody has to verify.
- The cost of leaving it was small each time and unbounded in total. Anyone reading the note would discount a real signal, or repeat work that had already been checked: a sensible-looking pause resting on a false premise, which produces no error and simply spends a round trip.
- Two explanations were added while the file was open. The first records that automated checking and a check run by hand are complementary rather than ranked. The automated one works from a clean copy, so it catches anything that quietly depends on a file existing only on the author’s own machine; but it also has less of the project to look at, so certain checks step aside there and only a hand-run finds what those cover.
- The second explains how the code-style step is judged. That step compares the number of reported issues against an agreed figure instead of reading pass or fail, and it does so for opposite reasons in different projects: in most of them the step reports failure at the agreed figure, so reading pass-or-fail would be too strict; in one it reports success at the agreed figure, so reading pass-or-fail would be too lenient and would let new issues through unnoticed. One mechanism, two reasons. The note also warns that the figure counts every kind of issue rather than the one kind a project set it for, and that when it reaches zero the setting must be removed rather than set to zero — at zero the tool prints no count at all, and the step then fails asking for a number that was never printed.
- Four notes in other projects pointed at this file by line number, and adding lines to the top moved all of them. They now name the part of the script they mean instead of a position in it. A stale line number is worse than a missing one: it lands on real code, so a reader who follows it finds something plausible and concludes the reference was sound. One of the four was written the day before this release and had already gone stale by the time it shipped, which is the argument in miniature.
- Predictions were recorded before anything was measured, and reported against afterwards. That the change would add twenty-four lines and touch nothing but comments held exactly, although the predicted split between lines added and lines removed was two out, because two unchanged lines had been counted as replaced. That no project’s checks would fail because of the change held. And that the false statement was not repeated in wording of its own anywhere else held — but only on the second attempt, because the first search returned nothing at all, including the nine copies it was certain to find, which showed the search was broken rather than the projects clean.
v2.5.20August 21, 2026
Infrastructure
- Nothing in this release changes what the apps do. It corrects a date on this page, and adds the check that would have caught it.
- The previous release was dated August 20. It was written at three minutes past one in the morning on August 21, so the date was a day early — carried forward from the release before it rather than mistyped. Nothing on this site computes from these dates, so the cost was cosmetic. The way it happened is not, because the usual remedy is a line on a release checklist, and a checklist line is exactly the kind of control that quietly stops being followed.
- A check now compares the newest entry on this page against the moment its own change was recorded, and refuses a date that is not the same calendar day. It refuses a date one day early and one day late alike — a check catching only one direction would miss half the mistake. It also refuses a misspelled month, because the tool used to read the date accepts "Augustt" and "Auggust" as August without complaint; the date must now be written back exactly as it was given.
- The check runs only on the machine where the release is written, and that is a limitation rather than an oversight. Merging a change to this site discards the record of which timezone its author was in, so afterwards the correct local date genuinely cannot be recovered — no setting brings it back. Running the check on the build servers instead would compare a date written in one timezone against a clock keeping another. That reasoning is recorded beside the check itself, so anyone tempted to switch it on later reads why it cannot work rather than assuming nobody tried.
- Separately, a maintenance script comparing the database rules against their one surviving copy printed a nonsense location when pointed at a local file: it appended a filename to a path that already ended in one. Both of its reporting modes now describe their source correctly.
- Five things were confirmed against a recorded prediction before this shipped: that the check fails on the very date it was built for and stops failing only once that date is corrected; that it fails one day early and one day late; that the misspelling test catches what the date test cannot, with the date test confirmed to pass the same misspelling; that the check steps aside and names its reason on a build server, outside a repository, and with the version-control tool missing entirely — each of those three produced for real rather than simulated; and that the script fix changed only the reporting mode that was wrong, leaving the other byte-for-byte identical.
v2.5.19August 21, 2026
Infrastructure
- Nothing in this release changes what the apps do. It puts a scheduled check on a second copy of the database rules that had been quietly falling out of date.
- The rules deciding who may read and write each project live in one place. A second copy is kept inside the Scheduler project, because a test there reads it to confirm that every setting the app saves is actually one the rules permit — a real guard, and the whole reason that copy exists. But nothing was watching the copy itself. It has fallen behind three times now, and every time the only reason anyone found out was a person comparing the two files by hand.
- A check now makes that comparison automatically, every six hours and again whenever the rules themselves are edited — so the person creating the gap hears about it rather than someone else discovering it later. It ignores the explanatory comments in both files deliberately. The two are meant to carry different notes, and that difference already accounts for roughly three hundred lines; counting it would bury the thirty-four that actually matter.
- This release reports the gap rather than closing it. The copy is currently behind by the two limits added in the previous release, so the check is expected to read red until a separate change to the Scheduler project brings it back in line. That is said plainly here, because a check that is red the day it arrives is exactly the kind that gets ignored instead of fixed.
- Five things were confirmed before this shipped, each against a recorded prediction: that it reports the real gap and gets the same answer as the standard comparison tool; that it stays silent on two files whose notes differ but whose rules agree; that editing a comment alone does not set it off; that the step which makes it ignore only the right comments is doing work, even though removing it appears to change nothing today; and that it fails loudly rather than quietly passing when it cannot read the other file at all.
v2.5.18August 20, 2026
Infrastructure
- Nothing in this release changes what the apps do. It repairs the notes that explain the database rules, and adds a check so the same decay cannot set in again unnoticed.
- The database rules for all seven apps live in one place, and their comments explain themselves by pointing at the app code that writes each collection. That app code lives in separate projects. Until now those notes pointed at specific line numbers — and a line number in someone else's project stops being true the moment that project is edited for any unrelated reason. One recent change to a single file moved every note aimed below it by forty-eight lines, all at once and with no warning. The worst case found was a note off by a hundred and thirty-five lines: it named a line that no longer had anything to do with what the note described.
- Every one of those notes now names the function it means instead of a line number. A function keeps its name across edits, and if someone does rename it the reference breaks loudly and gets fixed, rather than quietly pointing at the wrong code and misleading whoever reads it next.
- A new check refuses to let a line number aimed at a file this project does not contain be added again. It works by asking whether the file named actually exists here, so notes pointing within this project — which are checked separately and are genuinely useful — keep working untouched. Both halves were confirmed: adding a note of the bad kind makes the check fail and names it; adding one of the good kind does not.
- Two notes also claimed a safeguard in the AHP app did not exist. It was built the day before this release, so the claim had gone stale; a third copy of the same claim was found during the sweep. All three now describe the safeguard, and record the two gaps it does not cover so no one reads more assurance into it than is there.
v2.5.17August 20, 2026
Security
- Two of the seven apps — SPERT® Forecaster and SPERT® AHP — let anyone with access to a project save any piece of information they liked into it. Access itself was never in question: you still had to be a member of the project, and only an owner could change who could see it or who owned it. But once you were in, nothing limited what could be stored alongside the real data. The other five apps have had that limit since May; these two were missed at the time.
- Each of the two now has a list of exactly the information it uses, and the database refuses anything outside it. Nothing about who may open, change, share or delete a project has changed — only what may be kept inside one. Nothing was exploited; this closes a gap rather than repairing damage.
- Getting this wrong in the other direction is the real hazard, and it is worth saying how it was avoided. A list that is too short produces no error message: it makes every save fail silently, for every user, immediately. So each list was built by reading every place its app writes to the database — five places in Forecaster and thirteen in AHP, five of them written in a form that an ordinary search for the usual save commands does not find at all. The tests confirming that a normal save still works were written and run BEFORE the new limits went in, so the release rests on a recorded before-and-after rather than on an assurance.
- One piece of information in AHP came close to being left out. The setting controlling what participants see on the Results tab never appears by name in the code that saves it — it travels through a general-purpose routine that forwards whatever it is handed, so searching for it finds only a type definition and a default value. Had it been omitted, every change to that setting would have failed silently. It is on the list, and the reason it looks absent is now recorded beside it.
- Confirmed by removing a single permitted item from one of the two new lists and checking that exactly the two affected tests failed, on that one app, while the other twelve lists and every other test carried on passing — then restoring the file and verifying it was byte-for-byte unchanged.
Changed
- The database rules file described its own release process incorrectly. It said it was a copy of what had been pasted into the Firebase console by hand, which stopped being true in August: the repository is now the original, and the live database follows it automatically whenever a change is merged. That description has been corrected, and so has a second note claiming one app was the only one missing the limits described above — it was not, which is what this release is about.
v2.5.16August 20, 2026
Security
- The rules governing the shared database keep twelve separate lists of which pieces of information each app is allowed to save. Until now only one of those lists was tested. A mistake in any of the other eleven — a list that no longer matches what its app actually writes — would have stopped that app saving, silently and every time, with nothing anywhere reporting a problem. That is not a hypothetical: it is exactly what happened to the twelfth list in the previous release, and it went unnoticed for seven days.
- All eleven are now covered. For each one, the tests confirm that a save carrying every permitted piece of information is accepted, that the smaller save an app makes when optional details are absent is also accepted, and that a save carrying anything unrecognised is still refused — on each operation the rule governs, since saving a new item and changing an existing one are separate rules that can fail independently. The tests also confirm that permission to save was not widened along the way: someone who is not a member of a project still cannot write to it, and a collaborator still cannot promote themselves to owner.
- The list of what each app writes was read from the apps themselves and recorded here alongside the exact function it came from, the version, and the commit — so a later review can tell how old that reading is rather than merely that it is a copy. At the time of reading, every one of the twelve matched.
- What this does and does not do is worth being plain about. It catches a rule tightened past what an app already saves. It cannot catch the reverse — an app adding something new that the rules were never told about, which is what caused the previous release’s fault. Closing that half requires checks inside the apps and is not something this release claims to have done.
- Confirmed by removing a single permitted item from one of the twelve lists and checking that exactly the three affected tests failed, on precisely that one list, while the other eleven and every other test carried on passing — then restoring the file and verifying it was byte-for-byte unchanged.
v2.5.15August 20, 2026
Fixed
- Saving a chart snapshot in GanttApp™ failed for anyone using cloud storage who had set a status date, and failed without saying so. The rules governing the shared database list which pieces of information a snapshot is allowed to carry. The status date, added to GanttApp in August, was never added to that list, so the database refused the snapshot outright. Nothing told the user — the snapshot simply never appeared, every time, for as long as a status date was set. Snapshots taken without a status date were unaffected, as was anyone working in local storage rather than the cloud.
- The status date is now on the list, so those snapshots save. A new automated test saves a snapshot carrying every piece of information the app actually writes, including the status date, and separately confirms that a snapshot carrying anything unrecognised is still refused. Testing only the second half is what allowed this to happen: the rules were checked for what they should block and never for what they must allow.
v2.5.14August 19, 2026
Security
- The check that protects cloud project data now runs automatically. It was added in the previous release but had to be started by hand, so nothing actually forced it to run — a safeguard that depends on someone remembering is not a safeguard. It is now part of the release gate, running both on a developer’s machine and on every proposed change, and a release cannot complete while it fails.
- The check refuses to be skipped. It needs a Java runtime in order to start a local copy of the database, and where none is found it stops the release and explains why, rather than passing quietly. A check that does nothing when its dependencies are missing looks exactly like a check that passed, and that is the failure being designed out.
- Confirmed to work by deliberately reintroducing the original fault in one collection and watching the gate fail on precisely that collection and nothing else, before restoring it. The gate was never trusted on the strength of a green run alone.
v2.5.13August 19, 2026
Security
- A signed-in user of any SPERT® Suite app could retrieve every project stored in cloud storage, including projects never shared with them. The rules governing the shared database allowed opening an individual project only to its members, and that check was correct and always worked. But the separate rule governing how a whole collection is listed asked only whether the request came from someone signed in. Anyone querying the database directly, rather than through one of the apps, would have received every project it held. All seven apps that share the database were affected. Projects kept in a browser’s local storage are never sent to the database and were never exposed.
- The listing rules now apply the same membership test that opening always applied, so the database enforces it regardless of which program asks. Each rule is shaped to the request its own app actually makes, so no app needed changing — two of the seven deliberately record ownership differently from the other five, and a single uniform rule would have quietly stopped those two from loading anything.
- A new automated test suite runs the real rules against a local copy of the database and checks both directions: that a request for another person’s projects is refused, and that each app’s own request still returns its own projects, down to the individual documents. Checking only the first half would have let a rule that blocks everyone pass as a success. The suite was confirmed to fail against the previous rules before it was trusted.
- The reasoning that produced the original rule was written into the rules file itself, and it was mistaken — it claimed the database could not check membership during a listing, which it can. That comment has been replaced with the correction and the evidence, so the same conclusion is not reached again.
v2.5.12August 2, 2026
Licensing
- The additional conditions attached to this project’s licence have been revised, and two new ones added. What the licence permits is unchanged — anyone may still use, study, modify and share this software freely. What changed is the set of conditions that travel alongside it, and each of the six now follows the wording of the standard licence itself rather than paraphrasing it. That matters more than it sounds: the standard licence lets a recipient delete any added condition that strays outside the short list it allows, so a condition worded too ambitiously protects nothing at all.
- The first new condition says the author’s name may not be used to endorse or promote a product built from this software without permission. Nothing else in the licence covered this. The project’s trademarks are protected whether the licence mentions them or not, but a personal name has no such protection — and because another condition requires that name to stay in the source code, anyone forking the project already has it in hand.
- The second new condition applies to anyone who resells this software with a warranty or a support contract of their own. If those promises create a liability that lands on the original author, the reseller has to cover it. The standard licence already permits a reseller to make such promises; this simply makes clear that the promises are theirs to stand behind.
- The condition covering on-screen credit was rewritten. It previously required any modified version with a user interface to display a notice. It now requires that where such a version already displays legal notices, the original author’s name is preserved among them. The standard licence allows a project to require that existing notices be kept, not that new ones be created, and the earlier wording asked for more than that — which would have let a recipient strike the condition out entirely.
- Two smaller changes. A modified version may no longer misrepresent where this software came from. And the trademark condition now states plainly that referring to this project by name, in order to say honestly what a fork was derived from, is not itself prohibited — provided it does not suggest this project endorses the result. No change to how the application works.
v2.5.11July 31, 2026
Licensing
- Every file of source code in this project now carries the copyright and licence notice, and 71 of them were either missing it or carrying an incomplete version. Most of the gap was in the server-side code that handles collaboration invitations and the AI connection — 43 files that were written after the notices were added everywhere else, and so never received them.
- Twenty-two files carried a shortened notice that named the licence but left out the line saying where to read it. That line is the part the licence actually requires: this software is released under terms that add four conditions to the standard licence, and a source file carrying those conditions has to either state them or say where they are found. A file that stops at the licence name points a recipient nowhere.
- A new automated check now refuses a release if any source file is missing the notice, including files that have not yet been committed, and including the security rules file that has no other check on it at all. Every way the check could fail was deliberately triggered and confirmed to be caught before it was trusted.
v2.5.10July 31, 2026
Release process
- The release checks can now be told about every copy of a changelog a project keeps, rather than just one. Six of the nine SPERT® Suite repositories keep the same history in two or three places at once — a file alongside the source, a served copy the app actually reads, and in some cases a third copy built into the app itself. Until now the checks looked at one of them, so a release could pass while the others were left behind.
- This mattered most where the served copy is the one on screen. In SPERT® Story Map the app fetches that copy at the moment a reader opens the version history, which means the file the checks were watching was the one nobody ever saw. Had the two drifted apart, the app would have shown the stale one and every check would still have reported success.
- Each new check was deliberately broken before being trusted: a copy was altered, an entry was removed, and a file was deleted, and the checks were confirmed to fail in each case before the change was accepted.
v2.5.9July 31, 2026
Release process
- The automated checks introduced in the previous release now run on the exact version of Node.js each repository pins, rather than on whichever recent version the build service happens to offer. Every repository already recorded its required version in a small file alongside the code; that file is now what the checks read. Two repositories that were missing the file have been given one.
- This closes a gap rather than repairing a visible fault. The checks had been passing on a newer version than the one declared, so a problem specific to the declared version could have gone unreported. One companion repository deliberately holds back from the newest release of Node.js to avoid a known fault in it, and the checks as written would have quietly ignored that instruction.
v2.5.8July 30, 2026
Release process
- Every proposed change to this site is now checked automatically before it can be merged: the linter, a type check, a production build, the Cloud Functions test suite, and a check that the version number agrees everywhere it appears. This is the first automated checking this repository has ever had — previously a green checkmark meant only that a preview had been built.
- This site is the last of the nine SPERT® Suite repositories to receive the same release gate. All nine now run an identical script, with only their own configuration file differing.
- The versioning rule written down here since v2.4.0 — that package.json, the lockfile, the version the footer displays, and the changelog must all be bumped together — is now enforced rather than remembered. All four surfaces are checked, and a release cannot ship with any of them out of step.
Shared documents
- Added automatic checks for the documents this site publishes on behalf of the whole suite. The Terms of Service and Privacy Policy PDFs are linked directly by all eight other SPERT apps, and the AI Privacy and AI Consent notices are reached through permanent short links. Renaming or removing any of them would have broken those links in every app at once, with nothing anywhere reporting an error. Their presence is now verified on every test run, along with every short link that points at them.
- The license file kept here is the master copy that all nine repositories share. Its exact content is now verified against the same fingerprint the other eight check against, so the master and its copies can no longer drift apart unnoticed.
Connect AI
- The shared definition that this site’s AI service and SPERT Scheduler are both built against is now verified automatically in both places. Keeping the two copies identical had always been a written rule with a helper command, but that command only displayed a fingerprint for a person to compare by eye — nothing failed if the two ever drifted apart. Both halves now check the same fingerprint on every test run, so a one-sided change fails immediately instead of surfacing later as a rejected request.
v2.5.7July 29, 2026
Legal
- The license now reserves the SPERT® brand explicitly. A new Trademark Reservation clause names "SPERT", "Statistical PERT" and "Estimation Made Easy" as trademarks registered with the USPTO, and "GanttApp" and "MyScrumBudget" as unregistered common-law marks, and grants no right to use any of them — whether alone, combined with other words such as "SPERT Suite", or as a logo.
- Previously the license said nothing at all about the brand, which left room to argue that the freedom to redistribute and modify the code carried the name along with it. That was never the intent.
- A companion clause now requires any modified version to be renamed so that it cannot be confused with those marks. Between them the two new clauses draw the line the license always meant to draw: the code is free to take, change and redistribute, the author attribution has to travel with it, and the brand stays behind.
- The existing Attribution Preservation and UI Notice Preservation clauses are unchanged, and the GNU GPL v3 text itself is untouched — verified byte-for-byte against the previous release. Both additions sit in the ADDITIONAL TERMS section and fall inside the categories GPL v3 Section 7 permits, which is what stops a downstream recipient from simply deleting them.
- The ADDITIONAL TERMS heading now cites Section 7 rather than Section 7(b), because the terms draw on 7(b) for attribution, 7(c) for renaming modified versions, and 7(e) for the trademark reservation.
Infrastructure
- This repository is now the canonical source for the suite-wide license, and the same file is being copied into all eight sibling app repositories. The only difference permitted between copies is the project repository URL on line 4.
- An audit of all nine repositories found just one exact copy of the license before this release. Two apps shipped a summary and a link in place of the full GNU GPL v3 text, one was missing a section of it, five still carried the retired "Statistical PERT® Software Suite" name, and six carried an older and weaker wording of the additional terms. Each is being corrected in its own patch release.
v2.5.6July 29, 2026
Security
- Updated the site framework to pick up nine published security advisories.
- Patched a file-disclosure advisory in the stylesheet build tool.
- Patched a denial-of-service advisory in a pattern-matching library used by the linter.
Dependencies
- Tightened two dependency ranges so routine installs can no longer pull in versions that have not completed review.
- Routine maintenance only — nothing changes in the site or the apps.
v2.5.5July 28, 2026
Fixed
- Corrected the grammar in the "you’ve been added to a project" email, which read "added you as a editor" instead of "an editor".
v2.5.4July 28, 2026
Dependencies
- Updated the email delivery library and the email template renderer used to send SPERT® Suite invitations.
- Invitation emails were confirmed to render identically before and after the change, down to the byte.
- Routine maintenance only — nothing changes in the site or the apps.
v2.5.3July 28, 2026
Dependencies
- Updated the server-side linter to ESLint 10.4.1.
- Routine maintenance only — nothing changes in the site or the apps.
v2.5.2July 27, 2026
Dependencies
- Moved the server-side linter to ESLint 10, bringing it in line with the rest of the SPERT® Suite. It was the last piece still on ESLint 8.
- Retired an unmaintained style configuration that had been holding the linter back, along with two dependencies it required.
- Routine maintenance only — nothing changes in the site or the apps.
v2.5.1July 27, 2026
Security
- Patched a denial-of-service advisory in a pattern-matching library used throughout the server-side build and test tooling.
Dependencies
- Updated the server-side test toolchain to Jest 30.
- Updated firebase-admin to 13.10, React to 19.2.6, TypeScript ESLint to 8.60, and ts-jest to 29.4.11.
- Routine maintenance only — nothing changes in the site or the apps.
v2.5.0July 26, 2026
Legal
- Updated the Terms of Service and the Privacy Policy to Version 1.1.
- Account deletion is now described accurately: deletion is requested through the contact form or by email and is carried out by the Operator, and both documents now state plainly that the apps do not yet offer a self-service account-deletion control.
- The Privacy Policy now commits to completing a deletion request within 30 days under normal circumstances.
- The Privacy Policy now calls out up front that turning on Read Mode uploads a copy of your open project even if you otherwise keep your data in local browser storage only.
- The Terms of Service now reflect that some apps offer AI Connectivity in read-only form, where no permission grants an AI assistant the ability to change your content.
- Reissued the SPERT® AI Privacy Notice and AI Connectivity Consent Notice with page numbering. The wording is unchanged — both remain Version 2.0.
Fixed
- Corrected a broken link in the Privacy Policy, which pointed at an address for the AI Privacy Notice that did not resolve. Copies of the older document already downloaded will now reach the notice as well.
v2.4.0July 26, 2026
Legal
- Updated the SPERT® AI Privacy Notice to Version 2.0, published at /ai-privacy.
- Updated the SPERT® AI Connectivity Consent Notice to Version 2.0, published at /ai-consent-notice.
- Both notices now cover every application offering Connect AI — SPERT® Story Map and SPERT® Scheduler (write and read) and SPERT® Forecaster (read-only) — including a table of the modes each application offers.
- Clarified that enabling Read Mode uploads a copy of the open project even when an application is configured for local storage only, and added guidance for users connecting AI on behalf of an employer or organization.
v2.1.2June 28, 2026
Dependencies
- Adopted Node.js 24 runtime.
v2.1.1June 28, 2026
Security
- Updated the underlying framework and build tooling to address security advisories.
Dependencies
- Adopted TypeScript 6.0.3.
- Updated React, Tailwind CSS, and related build dependencies.
v2.1.0June 12, 2026
Legal
- Updated Terms of Service and Privacy Policy to v06-12-2026 ahead of the upcoming AI Connectivity ("Connect AI") feature.
- Published the SPERT® AI Privacy Notice v1.0 at the permanent URL /ai-privacy and added an "AI Privacy Notice" link to the footer legal links.
- Published the SPERT® AI Connectivity Consent Notice v1.0 at /ai-consent-notice (background reference document; publicly accessible but not linked in navigation).
v2.0.5May 3, 2026
Accessibility
- Added `autoComplete="name"` and `autoComplete="email"` to the shared form shell so Chrome stops flagging the autocomplete-attribute warning on the Contact, I Found a Bug, and I Have a Request forms — and so password managers and browser autofill recognize the user-name and user-email fields correctly.
v2.0.2May 1, 2026
Changed
- Replaced the generic "Open App →" call-to-action on each of the six tool tiles with action-oriented, tool-specific CTAs: SPERT® Story Map → "Map Your Release"; SPERT® Forecaster → "Forecast Your Release"; GanttApp™ → "Build Your Timeline"; SPERT® Scheduler → "Schedule Your Project"; SPERT® CFD → "Analyze Your Flow"; MyScrumBudget™ → "Plan Your Budget".
v2.0.1May 1, 2026
Changed
- Tightened hero headline to "Give stakeholders forecasts you can defend." — sized down (text-lg/xl, semibold) so it no longer competes with the "SPERT® Suite" brand title and capped at max-w-3xl with text-balance for cleaner wrapping on smaller laptop displays.
- Split hero subhead into two sentences (em-dash removed), clarified "delivery" as "product delivery," and added text-balance for cleaner wrapping.
- Italicized the "No sign-up required to get started!" line and added an exclamation mark for warmth.
- Refined three tile descriptions: SPERT® Story Map → "Map and size your release scope before the first sprint begins."; SPERT® Scheduler → "Build and maintain a project schedule that accounts for uncertainty."; MyScrumBudget™ → "Plan and reforecast your budget for any project, any team."
v2.0.0May 1, 2026
Changed
- Rewrote hero copy: new headline ("Give stakeholders forecasts you can defend — not single-point guesses.") and subhead emphasizing defensibility and user judgment over feature description.
- Rewrote all six tool tile descriptions to be outcome-first and action-oriented — answering "when would I use this?" instead of describing the underlying technique.
- Trimmed homepage intro to a single "No sign-up required to get started." line below the subhead.
Versioning
- Switched from MAJOR.MINOR to full semver (MAJOR.MINOR.PATCH) starting with this release.
v1.8May 1, 2026
Added
- Branded favicon for the browser tab and a small brand mark in the header beside "SPERT® Suite"; a charcoal dark-mode variant ships alongside the navy original.
Changed
- App tile colors realigned to each app’s official favicon palette: Scheduler orange (#f75b2b), Story Map indigo (#4f46e5), CFD purple (#7c3aed), GanttApp™ teal (#0891b2), MyScrumBudget™ green (#16a34a). Forecaster blue (#0070f3) unchanged.
v1.7April 5, 2026
Legal
- Updated Terms of Service and Privacy Policy to v04-05-2026
- Added SPERT® AHP to list of covered apps
- Updated effective date to April 5, 2026
v1.6March 31, 2026
Legal
- Updated Terms of Service and Privacy Policy to v03-31-2026
- Updated canonical legal document URLs from spert-landing.vercel.app to spertsuite.com
- Added License link to footer (links to GitHub LICENSE file)
v1.5March 30, 2026
Improvements
- Updated all app tile URLs to use the new spertsuite.com subdomains (storymap, forecaster, ganttapp, scheduler, cfd, myscrumbudget)
v1.4March 30, 2026
Rebranding
- Renamed main title from "Statistical PERT®" to "SPERT® Suite"
v1.3March 16, 2026
New Features
- Added "I Have a Request" form for feature ideas and improvement suggestions (Formspree integration)
- Added "I Found a Bug" form for bug reports across all SPERT web apps (Formspree integration)
- Added "Support" section on the homepage grouping Contact Me, I Have a Request, and I Found a Bug tiles
- Both new forms include an optional multi-select checkbox for specifying which app(s) the submission relates to
Improvements
- Extracted shared FormPageShell component to eliminate duplication across all three form pages
- Added category field to app data for separating main apps from support tiles
v1.2.3March 11, 2026
Infrastructure
- Pinned Vercel deployment target to Node.js 22 LTS ahead of Node 20 EOL (April 30, 2026)
- Added engines field to package.json requiring Node >= 22
- Added .nvmrc for consistent Node version across environments
- Updated @types/node from ^20 to ^22
v1.2.2March 11, 2026
Improvements
- Extracted shared form input styling constant to reduce duplication in contact form
Dependencies
- Updated react and react-dom to 19.2.4
- Updated devDependencies to latest compatible versions (tailwindcss 4.2, eslint 9.39)
v1.2.1March 11, 2026
Improvements
- Extracted reusable Header and Footer components to reduce duplication across pages
- Centralized app version constant in src/config.ts
- Fixed duplicate ThemeMode type definition
- Fixed pre-existing lint error in useTheme hook (replaced useState mounted pattern with useSyncExternalStore)
- Updated README with correct app names and URLs
- Upgraded @types/react-dom and typescript to latest stable versions
Security
- Added HTTP security headers (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy)
- Patched transitive dependency vulnerabilities (minimatch, ajv) via npm audit fix
v1.2March 11, 2026
New Features
- Added Terms of Service and Privacy Policy as canonical PDFs served from this site
- Added legal document links (Terms of Service, Privacy Policy) to footer on all pages
v1.1.3March 10, 2026
Changes
- Renamed "CFD Laboratory" tile to "SPERT® CFD"
- Added changelog page with version history
- Footer version number now links to changelog
v1.1.2March 10, 2026
Changes
- Renamed "SPERT® Release Forecaster" tile to "SPERT® Forecaster"
- Updated SPERT Forecaster URL to spert-forecaster.vercel.app
v1.1.1March 10, 2026
Changes
- Updated intro blurb to remove local-only data claim for cloud storage compatibility
v1.1March 10, 2026
New Features
- Added SPERT® Story Map tile (agile user story mapping for release planning)
v1.0March 8, 2026
New Features
- Initial release with five app tiles: SPERT® Release Forecaster, GanttApp™, SPERT® Scheduler, CFD Laboratory, MyScrumBudget™
- Contact Me tile with Formspree-powered contact form
- Dark/light/system theme toggle with anti-flash script
- Responsive tile grid (1 column mobile, 2 tablet, 3 desktop)
- Branded header with blue gradient and "Estimation Made Easy®" tagline