1.39
2 September 2026
Fixed
Changed
A handful of things that were the browser’s rather than ours, one button that had been drawing itself wrong, and a link that sent people to a page on GitHub that has never existed.
- The quiet hours fields were the browser’s own time control. It renders in whatever format the operating system prefers, ignores the theme entirely and looks nothing like anything else here. It is now ours — two scrolling columns, hour and minute, keyboard driven, in the same 24-hour clock as the sentence above it
- Long menus would not scroll. A list taller than its box grew a scrollbar and then refused to use it. Menus close when the page moves, which is right, but that listener also caught scrolling inside the open menu and treated it as the page moving. Checked both ways: with the fix a menu reaches its last row, and with the old listener put back the same gesture shuts it
- Sign out asked nothing. One click, immediate, no way back — and it sits one row under Workspace settings in the same menu. It now asks first
- A button that put its label at the top of its own box. The cause was duller and more useful: the base button style never reset link underlining, so every button that was really a link carried a hand-written patch, and it is easy to break the centring while adding one. The base style does it now and the patches are gone
- Open on GitHub could send you nowhere. It built its address from the repository name without ever asking whether that repository is connected to GitHub, so demonstration data pointed at repositories that do not exist. It now appears only for a repository with a real installation behind it. It was never wrong for a repository you connected yourself
- Uploaded pictures now appear beside members. The picture was never the problem — it uploaded, it was stored, the sidebar had been drawing it all along. The Members panel simply never asked for it
- A 404 page, on the application, this changelog and the marketing site. Three of the four ways to reach a missing page used to print the words Not found on a white screen and the fourth printed nothing. The page says the address is untraced, which is the same answer the engine gives for a commit with no author
1.38
2 September 2026
Added
Fixed
A correction first. Release 1.33 said the notification settings were “real and personal”. Four of the five were not. They saved, they reloaded, and no code anywhere ever looked at them.
- Only the report email switch was ever consulted. Alert emails, minimum severity, scan emails and the digest were written to your account on save and read by nothing. Turning Alerts off did not stop a single email. Setting the floor to High did not stop a low one. That was true when 1.33 announced them and stayed true until this release
- It is left recorded here rather than quietly edited out of 1.33. A changelog that revises what it said is worth less than one that admits it, and this is the second time this product has shipped a control that reported a state it did not have
- All four are now read on the delivery path. The test that proves it inspects the delivery records rather than the decision itself — a correct decision that the sending loop ignores is precisely the fault that was already there
- Quiet hours holds rather than drops. An alert firing inside your window is parked with the moment it should be released and sent when the window closes, carrying a line explaining why it is late. Discarding a security alert because of the hour would be a worse failure than waking somebody, and an invisible one — the message simply would not arrive
- The window is read in your time zone, not the server’s, and the release moment is fixed when the alert is parked rather than recalculated later. Changing your quiet hours cannot drag mail that is already waiting into the middle of the night
- Daily and weekly digests use the same holding mechanism with a longer wait, so a roll-up and a quiet night are one piece of code rather than two that can disagree
1.37
2 September 2026
Added
Release 1.33 replaced a two-factor switch that had never done anything with an honest “not available”, and said building it properly was its own piece of work. This is that work.
- A code from your phone on top of your password, using any authenticator you already have. Ten single-use recovery codes come with it, stored as hashes the way every other sign-in credential here is — a stolen copy of the database lets nobody in
- Nothing was pulled in to do it. Both the code arithmetic and the square you scan are written here, and neither is trusted on our word: the arithmetic is checked against the published standard’s own test values, and every square is read back by an independent decoder and compared with what went into it
- The secret does nothing until you prove you can use it. Starting enrolment stores it and enforces nothing; two-factor turns on only when you type a code that secret produces. Walking away halfway through cannot lock you out
- Every code works once. A code is valid for ninety seconds across the tolerance either side, which is long enough for somebody reading over your shoulder. The one that let you in is spent and will not let anyone else in
- Turning it off asks for your password and a working code. Somebody who has taken over a signed-in session still cannot quietly remove it
- Using a recovery code emails you to say so, and says how many are left
1.36
2 September 2026
Fixed
A search box was reported as broken. It was not broken. The browser asking for it had never been given the code that made it work, and the same was true of several other things that had been shipped and announced.
- Every page asked for
/assets/ui.js and the two stylesheets at those exact addresses, with no version attached. A browser that has fetched a file from an address once has no reason to ask again, so uploading a new build changed the file on the server and changed nothing for anyone who had already visited - What that quietly cost: the search box, the repository and period filters, the picture in the sidebar, the styling on the integrations panel and the spacing on the schema map. All of it was on the server. None of it was arriving
- It is the worst shape this kind of fault takes. Somebody arriving for the first time saw the new version and somebody who visits every day saw the old one, so it looked like the feature was broken rather than the delivery of it
- Addresses now carry the file’s modification time —
/assets/ui.js?v=1788313074. Change the file, the number changes, the browser fetches it. No build step and nothing to remember when uploading - Favicons are deliberately left out of this. Versioning those makes the tab icon flicker on every release and buys nothing
- This was worth its own release because it is not a feature. It is the reason several features you had already been told about were not there
1.35
2 September 2026
Added
The Schedules button said "Scheduling is not built. There is no job that runs a report on a timer yet." That was the last of the honest not-built notices left in the product.
- Daily, weekly or monthly, at an hour you choose, over a window you choose, for one repository or all of them, as JSON or CSV. Run now fires one immediately without disturbing the schedule it sits on
- No new scheduled job to set up. Due schedules are picked up by the same five minute pass that already reads your repositories. The cost is that a run can land up to five minutes after its hour, which the panel says rather than hides
- A scheduled report is the same artefact as one made by hand. The generator was lifted out into one file that both the application and the engine use, so there is no second implementation to drift. Checked on a report the engine produced unattended: the stored SHA-256 matches a fresh hash of the stored body
- When a run fails it says why. A schedule aimed at a window with no commits records no commits in that window, so there is nothing to attest to and shows it in red. It then waits for its normal turn rather than retrying in a loop — a schedule that silently stops producing reports is worse than one that never worked, because you find out when somebody asks for the report
- A smaller thing found on the way: the list printed stored times as though they were UTC, so a schedule set for 06:00 read back as 12:00 AM
1.34
2 September 2026
Fixed
The repository picker, the period picker and the search box all behaved like controls. They opened, they took a selection, they put a tick beside it. Then nothing happened, on four screens, because nothing was listening.
- Overview, Review, Schema and Agents were all affected. The pickers were wired to nothing at all — not wired to something broken, wired to nothing
- Filtering now runs through the address bar, so a filtered view can be kept, shared and reloaded with the picker still showing what you chose
- The repository filter went in at the one place every query already asks which repositories you are allowed to see. Thirty-nine queries, one change, and it reaches the heatmap, the risk counts, the DDL chart, the schema map and the agent scorecards without any of them needing to know it exists
- Watched moving rather than assumed: all repositories reads 842 commits in the window, one repository alone reads 80, and the card names the repository instead of claiming to cover all of them
- Search matches the title, branch, author and repository. It is escaped for
LIKE as well as for SQL, which is a distinction worth drawing — a search for “%” looks for a percent sign rather than matching everything, and one for ' OR 1=1 -- returns nothing rather than every row - Schema had no All repositories option. Once you picked one there was no way back to the whole picture
1.33
2 September 2026
Added
Fixed
Several controls in Settings accepted input, lit the save button, and reported success while doing nothing at all. One of them was worse than that.
- Default branch never saved. The field took a value, raised the save bar and answered Workspace saved, while the value went nowhere, because no column existed to hold it and nothing read it back
- Two-factor showed a switch turned on. There has never been a second factor on any account in this product. It now says not available, because a control telling you your account is protected when it is not is worse than an empty row. Building it properly is its own piece of work and it has not been done
- Profile saves. Changing the address you sign in with asks for your current password first, because an address change is an account takeover if somebody reaches an unlocked laptop
- A picture can be uploaded. It is decoded to check what it is rather than trusted by its name — a script renamed to .png is refused — then cropped square and stored in the database. Not in a folder: an uploads directory under a web root is where somebody eventually manages to serve something executable from
- Changing your password signs out every session and reissues the current one, so a password somebody else has stops working immediately
- A bug written and caught during this work, worth reporting. The first version of the password check read the stored hash from the signed-in user, which the session layer deliberately strips before handing it over. The comparison therefore ran against nothing and a wrong current password was accepted. The identical flaw made email changes impossible — same cause, opposite failure. Both read from the database now, and five cases are tested. It only surfaced because a deliberately wrong password was sent at it; read on the page, the code looked correct
- Notifications are real and personal — alert, report and scan emails, a minimum severity, a daily or weekly digest. Quiet hours are still not built and say so. Deleting a workspace is built, behind typing its name, and refuses if it is the only one left
1.32
1 September 2026
Fixed
Connect listed every unclaimed installation of the Diffport app and gave it to whoever pressed the button first. With one account that was theoretical. With two it is a way to read somebody else’s private code.
- Diffport now asks GitHub instead of guessing. GitHub answers with the installations your account can actually reach, and only those are listed and only those can be claimed. Nobody else’s installation is shown, or even named
- No token is stored. The answer GitHub gives is kept for fifteen minutes so the click that follows is covered. The token itself is used once and discarded
- The one-time code returned when you install the app is now actually checked rather than merely deleted, which is what it was doing before. Good for an hour, and it cannot be used twice
- Tested by playing the attacker. A second account with a legitimate installation of its own tries to take the first account’s six different ways — unverified, with a forged code, with somebody else’s code, verified for the wrong installation, with an expired check, and with an hour-old code. All refused, before any call to GitHub is made. With the gate removed, sixteen of the nineteen checks fail and the attacker walks off with the installation
- What this does not do: GitHub reports the installations you can reach, not the ones you administer. Somebody inside an organisation who can already read its repositories could still bind that installation to their own workspace. They gain no access to code they could not already read, so it is untidy rather than unsafe — and it is written here rather than left for somebody to find
1.31
1 September 2026
Added
Settings had a Plan panel that named a plan nobody was paying for. It is now connected to Stripe.
- No payment form exists in Diffport and no card details reach this server. Stripe hosts both the checkout and the place you go to change a card or cancel. What is stored here is a customer id, a subscription id, a status and a renewal date
- The part that receives messages from Stripe sits outside the sign-in check, because Stripe cannot log in. It is protected by a signature instead. A tampered message is refused with the subscription left untouched, one older than five minutes is refused, and a message that arrives twice is recognised and ignored rather than applied twice
- That last one is not hypothetical — Stripe retries, and applying the same message twice would extend a billing period for free
- Price, whether it is charged per person or per workspace, and the length of the trial all live in configuration. Pricing can change without a release
- Leave the keys unset and the panel says billing is not connected and names which value is missing. Nothing else in the product changes
- While in here: the sign-in and sign-up screens are the mark alone now. The word beside it is gone
1.30
1 September 2026
Added
Fixed
Time to merge and Trust scoring both carried a note explaining what they were missing. The notes were accurate. Git records when a commit was written, not when a review finished or when a pull request merged, so neither screen had anything true to show.
- Diffport now records when a pull request merged, when it closed, when the first review arrived, how many reviews there were, and whether it was a revert — taken from the pull request itself, not guessed from commit dates
- Time to merge is split by authorship, so the question it exists to answer — whether machine-written work sits longer in review — is one you can now look at rather than assume
- Trust is a function of two counted things: how much of an agent’s merged work was reverted, and how much of it was reviewed at all. It is not a feeling, and there is no hidden model in it
- A bug found while building this: the first version returned a trust score of 150. Joining to the commits inflated the sums it was built from. Rebuilt on a derived table and clamped, then watched moving properly — 100 with no reverts, 67 after one revert in three merged pull requests
- Both fill in from pull requests seen after this release. Until an agent has merged work, the screen says that in those words rather than showing a confident zero
1.29
1 September 2026
Added
Fixed
Rules have been firing and recording since they shipped. They had nowhere to go. An alert now reaches every member of the workspace by email, and each send is recorded as sent or failed rather than assumed.
- The evidence travels with the alert. Destructive count is 1 — the rule fires at > 0, not a severity badge and a link to go and find out
- Re-processing does not re-send. A firing that already exists for a pull request is not raised again, so a branch under active work does not email everyone on every commit
- A bug found while building this: every default rule was created with an empty channel list. Delivery could have been finished and still sent nothing, and the rules would have looked correct the whole time
- Slack and webhooks are not built. They say so on the Integrations screen rather than showing a channel marked connected that goes nowhere, which is what was there before
- Each delivery is a row. When something does not arrive, there is a record of whether Diffport tried
1.28
1 September 2026
Added
Line-level provenance is the thing Diffport is for, and until now it could not do it. The By file tab has been greyed out since the day it shipped, behind a note saying it needed patch storage. The note was accurate: Diffport stored what it concluded and threw away the diff it concluded from.
- Every file in every commit is now stored with its patch. Attribution could always name the commit behind a change; it can now name the line
- Each block of lines carries the commit that added it — the agent, the short SHA, and the confidence. Blocks from a commit with no signal are marked no signal and counted as untraced. They are not inferred to be human, which is the same rule everything else in the product follows
- The per-file percentages are counted from the lines themselves rather than estimated from the commit
- Bounded on purpose: 128KB of patch per file, truncated and flagged beyond that, and 300 files per commit. Binary files are recorded with no patch — the change is real and counted, there is simply nothing to attribute line by line
- This is the first thing Diffport stores that grows with your history rather than with your commit count. It is worth knowing that before it is worth having
1.27
1 September 2026
Added
The invitation email has existed since email did. The link in it pointed at a page that was never built. It now goes somewhere.
- Invite by address, as Member or Admin. Accepting creates their account, joins them at the role you chose, and signs them in. If they already have an account on that address, they enter its password and are simply added
- The token is stored as a SHA-256 hash, the same way sessions and password resets are. A database that leaks does not hand the reader a working invitation
- An invitation is bound to the address it was sent to. Forwarding the link does not work — accepting checks the signed-in account matches, refuses by name if it does not, and leaves the invitation open for the person it was meant for
- Spendable once, seven days, and revocable. Revoking kills the link immediately rather than at the next expiry sweep
- Members can be promoted, demoted and removed. The owner cannot be demoted or removed here, and you cannot change or remove yourself. A plain member cannot invite anybody, and that is checked on the server, not hidden in the interface
1.26
1 September 2026
Added
Fixed
Every report carries a line saying that re-running the hash proves nothing was altered after issue. That line was not true, because the report was never stored — it would have been regenerated at download, from data that had moved on.
- A report is now generated once, stored, and served back byte for byte. The SHA-256 printed on it matches the file you download, this year and next
- JSON and CSV, both signed the same way. PDF is refused rather than faked — it needs a rendering library the server does not have, and a broken PDF is worse than an honest no
- A report over a window with no commits is refused. There is nothing to attest to, and issuing an empty attestation is a way of lying carefully
- Preview opens the stored body, not a mock of it
- Nine invented reports have been removed from the history, along with their invented signatures and invented author. The history is now empty, because you have generated none
1.25
31 August 2026
Added
Fixed
Release 1.14 switched six controls off and said they would become real when accounts arrived. Accounts arrived. This is that promise paid.
- Alert rules can be created, edited, duplicated and deleted, with an editor built from the ten fields the engine actually evaluates and the six comparisons it supports. Nothing in that list is decorative
- The rule toggles write to the server. The switch moves at once and moves back if the server refuses — it no longer animates and then tells you nothing happened
- Workspace name, provenance thresholds and risk weights all persist. A human threshold above the AI threshold is refused, because everything between the two is what mixed means and inverting them has no meaning
- Validation appears inside the dialog, which stays open so you can fix it, rather than behind it where you would never see it
- Every write re-checks on the server that the thing being changed belongs to your workspace. Signed in as one workspace, a request naming another's rule is refused and the rule is untouched
1.24
31 August 2026
Fixed
Two screens were never wired to real data and still showed the original prototype. Settings listed three repositories that were not yours, four colleagues who do not exist, a plan you are not on, and a Slack channel marked connected that was never connected to anything.
- Settings now reads your workspace, your membership, your repositories with their true traced percentage, the real agent catalog, and the risk weights the engine actually uses
- Reports listed nine invented reports with invented SHA-256 signatures. They are gone
- Billing, integrations, notifications and workspace deletion have no feature behind them. Each now says so plainly and says what does not exist, instead of miming it
- Three controls on the Agents screen implied Diffport assigns work to agents. It does not — it reads git and reports what already happened. They have been removed rather than left as honest-looking dead ends
- A banner reading Diffport has no sign-in yet was still being shown to signed-in people on eight screens. It had stopped being true the day accounts shipped
1.23
31 August 2026
Fixed
An uncomfortable entry. Schema has rendered No schema recorded yet in live mode since it shipped, no matter how much data was behind it. Four queries had a method call sitting inside a single-quoted string, so it was never executed and the SQL was malformed. Each one threw, was caught, and returned nothing.
- The Schema page's tables, its references, the latest scan summary and the open pull request list were all affected. All four are fixed
- The scanner used to check that work reported these as correctly scoped, because the text was present in the file. It was present as literal characters inside a string, which is not the same thing as being executed
- A check now fails the build on any method call trapped inside a string literal, and every packager runs it. It was proven by reintroducing the exact bug and confirming the build was refused
- Overview's schema-change count was also wrong in the other direction — it multiplied each change by the number of commits in its pull request. It read 30 where the truth was 6
- The lesson, written down because it will happen again: a test that checks for the presence of a pattern is not a test that the pattern does anything
1.22
31 August 2026
Added
Connecting a repository read its open pull requests and nothing else. A repository with real history and a quiet pull request queue produced an empty dashboard — which reads as broken, not as nothing-open-right-now.
- Diffport now walks the default branch, resolves provenance on every commit, parses the DDL in migration files, and rebuilds the schema model when it finishes
- It paces itself: 25 commits a pass, then it puts itself back on the queue. A six-hundred-commit repository takes about two hours in the background rather than one request that dies halfway
- It stops below 200 remaining GitHub requests and resumes later, so reading history cannot starve the webhooks a repository needs to stay current
- Progress survives interruption. The page and offset live on the scan row, so a run that is killed resumes where it stopped instead of starting again
- Repositories connected before this existed can be read with Read history on the Connect screen
1.21
31 August 2026
Fixed
Added
A pull request used to be filed into a workspace derived from the repository's GitHub owner, with no reference to accounts at all. You would sign up, install on an organisation, and the engine would create a second workspace named after that organisation and put everything in it. You were not a member. You saw nothing, while the engine reported success.
- Ownership now comes from the claim: the workspace that connected the installation, and nothing else. Two accounts can hold repositories under the same GitHub owner without seeing each other
- The Connect screen lists your actual repositories rather than five invented ones, and connecting one queues its open pull requests immediately
- Connect no longer depends on GitHub's redirect.
installations/new silently drops the state parameter when the app is already installed, so the callback could never complete — Diffport now asks GitHub which installations it has and offers the unclaimed ones - A pull request arriving for an installation nobody has finished connecting is parked and retried, not failed. It processes itself the moment someone connects it
- The workspace is resolved before any GitHub call. Work that cannot be filed anywhere should not cost a request to discover that
1.20
31 August 2026
Added
Diffport can now send email: the waitlist confirmation, the welcome, the password reset and its confirmation, the invitation, the first-scan summary, an alert, an address confirmation, and the one broadcast at launch.
- Every message renders from one template set, in HTML and plain text. The text part is what people with images off and most spam filters actually read, so it is written rather than generated
- The masthead is a file on the marketing site, not markup. Replacing it changes every email, and nothing needs rebuilding
- Links are built from explicit configuration rather than from whichever host happens to be running the code — the API sends the waitlist confirmation, and its own address is
api.diffport.com - Every email overflowed a phone screen by roughly 250 pixels before it shipped.
max-width alone does not restrain a table inside a centred cell; browsers resolve it back to the preferred width - A staff-only screen renders all nine from the real templates with sample values, so the copy can be read without sending anything
1.19
31 August 2026
Added
Fixed
Every account now owns a workspace, and every query in the product is scoped to it. This sounds like plumbing. It is the difference between a demo and something you can let a second person into.
- Forty queries read across every account before this. They are scoped through one primitive, so a new one cannot quietly be written unscoped
- Joining an existing workspace is an invitation, never a side effect of signing up. The second person to register used to land inside the first person's data
- A test creates two tenants and calls every method as each, looking for the other's markers. The first version searched for names — and a heatmap and a commit count leak as numbers, carrying no name to find. It now checks the aggregates too
- Three leaks were found in production after that test passed, which is how the gap in it was discovered
- Owning a workspace is not the same as running Diffport. Staff roles are separate, so being an owner does not show you anybody else's
1.18
31 August 2026
Added
diffport.com takes email addresses now, and tells each person their true place in line. Not an inflated one — the first person to sign up is number one.
- Everyone gets a referral link. Bringing people moves you up, ties go to whoever arrived first, and the ordering is explainable in one sentence
- One confirmation email per genuinely new address. Joining twice does not send a second, so the form cannot be used to mail somebody repeatedly by typing their address
- The first 500 keep their pricing permanently. That is the promise on the page and the promise in the email, in the same words
- It is one email at launch, and there is no newsletter to unsubscribe from. Said plainly because it is unusual enough not to be believed
1.17
31 August 2026
Added
Diffport has sign-in. GitHub first, because everyone it is built for already has an account there, with email and password as the fallback for people who would rather not.
- Session tokens are stored as SHA-256 hashes, never in plaintext. A database that leaks does not hand the reader a working session
- Sign-in spends the same time on an account that does not exist as on a wrong password, so the form cannot be used to find out who has an account
- Password reset works the same way: the answer is identical whether or not the address is registered. Any difference turns the form into a way to enumerate customers
- A reset link works once, lasts an hour, and asking for a second invalidates the first. Setting a password signs out every other device
- When the database genuinely fails, reset says so rather than showing check your email and sending nothing — and it says the same thing for a registered and an unregistered address, so the failure cannot be used to enumerate either
1.16
28 August 2026
Changed
Diffport now has a brand typeface. Montreal sets every heading across the application, this changelog, and everything not yet built. Body text stays as it was — a display face is chosen for how it behaves large, and asking it to carry paragraphs is how you end up with a site that is handsome and tiring.
- Headings only,
h1 through h6, as one rule in the shared token file rather than a decision repeated per screen. New pages inherit it without anyone remembering to - It is self-hosted, not loaded from a font service. No third party learns who reads this page, and nothing on the site waits on someone else's CDN to render a title
- Shipped as woff2 — about 12KB a weight, down from 30KB as the original desktop files. It is preloaded, so headings arrive in the right face rather than snapping into it a moment after the page paints
- Montreal has two weights, 400 and 700. Three headings were set at 800 and have been brought to 700 — a browser asked for a weight a font does not have will fake it by smearing the outlines, which looks worse than the real weight it was trying to improve on
- Every character these pages actually use was checked against the font before it shipped, punctuation included. A missing glyph does not announce itself; it quietly borrows a letter from another font and hopes you do not look closely
1.15
28 August 2026
Changed
Diffport now has a settled identity. The mark is an aircraft, chosen so that port reads as a place things arrive and depart from rather than as backporting a patch — the one genuine objection to the name, answered by the icon rather than by explaining.
- The wordmark ships in a light and a dark cut, and the correct one is chosen by CSS rather than by JavaScript. It used to be one image whose source was rewritten after load, so a light-theme visitor saw the white wordmark on a white background — an invisible logo — until the script caught up
- The page no longer flashes dark before settling. The theme is resolved in the document head, before any stylesheet loads, from your stored choice or your system setting
- Every mark is now a file, not code. The application's rail logo used to be an SVG path compiled into a PHP template, so changing it meant a code release. Brand and software now ship on separate schedules
- One accent colour,
#635BFF, replaces the seven-hue palette the interface had accumulated. The mauve is gone everywhere, found by sweeping for hue rather than for known values — which caught a background glow that a search for the old colour would have walked straight past - Charts sit in greyscale and take colour on hover, so colour means something when it appears. On touch, where hover does not exist, they stay coloured — data behind a gesture is data you cannot see
1.14
27 August 2026
Changed
An unusual entry: this release removes functionality. Six controls that looked like they worked have been switched off, because they did not, and a control that lies to you is worse than one that is plainly unavailable.
- Turning an alert rule off moved the switch and changed nothing on the server. Reloading brought the rule back, still firing — and you would have walked away believing it was disabled
- Acknowledge, Snooze, Edit, Duplicate and New rule had no handler at all. They clicked and nothing happened, silently, which is the same untruth told more quietly
- All six are now visibly disabled and say why when pressed: Diffport has no sign-in yet, so nothing on this screen can be changed. What you see is exactly what the server holds
- They become real when accounts arrive. Until then the screen reports the server's state and nothing else
- Disabled has to look disabled, too — the first attempt dimmed them so far they read as missing, which is a different wrong answer
1.13
27 August 2026
Added
Rules watch every pull request as it arrives — destructive schema changes, high risk, a secret in a diff, a migration with no tests, coverage falling below a threshold, untraced commits merging. Each firing arrives with the reasoning attached, not just a verdict.
- Every firing records which field matched, which comparison, and the actual value. An alert you cannot interrogate is an alert people learn to filter
- One alert per pull request, not one per event. Four destructive operations produce one message. Four would be technically accurate and would teach you to mute the channel
- Re-processing does not re-fire. Every push to an open pull request re-runs the whole pipeline; an alert already open for that rule is left alone, so a branch under active work does not alert on every commit
- A rule referring to a field or operator the engine does not know never fires. Silence is the safe failure for a misconfigured rule — firing on everything is not
- Rules evaluate after risk scoring, never against a half-scored pull request
- Six defaults are created on the first pull request Diffport sees, and only if you have none. Edit or delete any of them
1.12
27 August 2026
Added
Diffport has never connected to your database and never will. It has no credentials, runs no queries, and holds no copy of your data. The schema you see is reconstructed entirely from the migration files in your pull requests.
- Every DDL statement is replayed in order —
CREATE TABLE defines columns, ALTER adds, drops and retypes them — building a model of what your schema is now - Each column is attributed to the commit that introduced it, so a table shows you how much of itself was machine-written and which agent wrote which field
- Replay follows migration filename order, not commit order. Files are numbered because the order they must run in is not the order they were written — backfilling an early-numbered migration is ordinary, and getting this wrong resurrects tables that were dropped
- Dropped tables and columns are kept and flagged rather than deleted. A schema that forgets what was removed cannot answer who removed it, or when
- Foreign keys are drawn only when both ends still exist, and tables are laid out by dependency depth — a table sits to the right of everything it references
- No domain groupings are invented. Diffport cannot know that a table belongs to your billing layer, so it does not pretend to
1.11
26 August 2026
Added
Diffport now reads your repositories. Install the GitHub App and every pull request that opens is resolved on its own — authorship, coverage, schema impact and risk — with no step you have to remember.
- A GitHub App with three read-only permissions and nothing else. Diffport cannot change your code, and the install screen shows you the permissions before you agree
- Pull requests are picked up as they open, and again as they change
- Every webhook is signature-verified before it is accepted; anything unsigned or mis-signed is refused and logged
- Repositories are selected individually — granting access to everything is a choice, not the default
1.10
26 August 2026
Added
The review queue is an ordering now, not a list. Every pull request carries a score from four weighted factors — data loss, security, performance, test coverage — and the highest-risk work sits at the top.
- Migration files are parsed statement by statement, so
ADD COLUMN x, DROP COLUMN y is graded as two changes at two severities rather than one blurred verdict - A destructive change with no down-migration is floored at 70. It can never read as low risk, whatever the other factors say
- A live credential found in a diff carries the same floor. A weighted sum can say how much risk; it cannot say this one thing is disqualifying, so that case is handled separately
- AI authorship is deliberately not a risk factor. It raises the review requirement, not the score — a tool that flags all machine-written code as dangerous teaches people to ignore it
1.9
26 August 2026
Added
The part that produces the answer rather than displaying one. It reads git — commit trailers, app actors, co-author lines, branch patterns, diff shape — and resolves each commit with the evidence attached.
- Every signal carries its own confidence, and the figure reported to you is the weakest link in the chain rather than the strongest
- Low-confidence signals annotate but never score. Diff shape can tell you a commit looks machine-written; it is never allowed to decide that it is
- Human is a positive attribution, not a leftover. A commit is attributed to a person on a verified signature, not on the absence of an agent signal — because absence of evidence is exactly what untraced means
- A signature never overrides an agent trailer: a person can sign a commit an agent wrote
- Ask any commit why, and it shows the evidence chain — which signals scored, which only annotated
1.8
26 August 2026
Added
A product that tells you where your code came from should be able to tell you where it came from itself. Every release from here is written down on the day it ships, in plain language, with what broke as well as what landed.
- Deep-linkable anchors on every entry, so a single change can be sent to someone directly
- Built on the same tokens as the app — one colour system, one type scale, one set of corners
- Fixes and regressions are listed alongside features rather than quietly omitted
1.7
26 August 2026
Added
A schema diagram is a commodity. One that tells you which agent added which column is not. Schema shows every table in a repository, how much of it was machine-written, and what an open pull request is about to do to it.
- Entity map grouped by domain, with foreign keys drawn between tables
- Authorship split on every table —
session_locks is 100% machine-written, memberships entirely human - Per-column origin in the inspector, naming the agent and the pull request behind each alteration
- A marker on any table with a pending change from an open pull request
1.6
22 August 2026
Added
Getting started should take a minute, and it should be obvious what you are agreeing to. The new flow states the permissions in plain language — including the one that matters most.
- Read-only by design: Diffport cannot change your code, and the install screen says so
- Pick repositories individually rather than granting access to everything
- The first scan shows its working — reading history, resolving signals, parsing DDL, scoring risk
1.5
18 August 2026
Added
The product should not require you to remember to open it. Alert rules watch for the things that actually matter and deliver to Slack, email or a webhook.
- Rules for destructive DDL from an agent, high-risk merges without human review, falling trust scores and untraced commits on main
- Severity as a coloured edge on the row, not a wall of red
- Acknowledgement is a state on the alert, not a per-person read flag — a team surface, not an inbox
1.4
14 August 2026
Added
For an auditor, a client hand-off, or a security questionnaire. Choose a scope, choose what goes in, and get a report signed against the commits it covers.
- Scope a report to a repository, a date range, or a single pull request
- PDF, JSON or CSV
- An expired share link never invalidates the attestation — the report stays verifiable, only the link lapses
1.3
8 August 2026
Added
Nine agents across eight vendors, ranked. Not on volume — on risk rate, reverts, test-coverage delta and review load.
- Claude Code, Cursor, GitHub Copilot, OpenAI Codex, Qwen Code, DeepSeek, Lovable and Replit
- Schema exposure reported separately, never folded into the score: knowing an agent is 3.1× more likely to ship risk when it touches the database is a routing decision
- Volume is deliberately not a factor. Two hundred pull requests does not make an agent trustworthy
1.2
1 August 2026
Added
Open any pull request and see who wrote each run of lines — which agent, which model, which session, and the evidence behind the verdict.
- Attribution blocks rather than per-file colouring, because a file is rarely written by one author end to end
- Every signal carries its own confidence, and the reported figure is the weakest link in the chain
- Untraced is its own state, never quietly reported as human
1.1
24 July 2026
Added
Improved
A year of machine-written commits at a glance, plus the numbers that tell you whether review is keeping up.
- Daily contribution heatmap across every connected repository
- Schema changes reaching main, split safe against destructive
- Time to merge by author type — the measurement that shows review, not generation, is the bottleneck
1.0
15 July 2026
Added
The review queue, ordered by risk rather than by date. Every pull request tagged with its true authorship and scored across data loss, security, performance and test coverage.
- Risk score with all four factors shown, never a single opaque number
- Schema impact on every pull request that touches the database layer
- AI authorship raises the review requirement, not the risk score — a tool that flags all machine-written code as dangerous teaches people to ignore it