<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ReadyStack</title>
    <description>The latest articles on DEV Community by ReadyStack (@readystack).</description>
    <link>https://dev.to/readystack</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4051807%2Fe35a4b6b-9160-456b-a481-b0fdf7b2a4d5.png</url>
      <title>DEV Community: ReadyStack</title>
      <link>https://dev.to/readystack</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/readystack"/>
    <language>en</language>
    <item>
      <title>57 small VS Code linters for regulation deadlines (CRA, cert 47-day cap, K8s removed APIs)</title>
      <dc:creator>ReadyStack</dc:creator>
      <pubDate>Sat, 19 Sep 2026 00:10:00 +0000</pubDate>
      <link>https://dev.to/readystack/57-small-vs-code-linters-for-regulation-deadlines-cra-cert-47-day-cap-k8s-removed-apis-409j</link>
      <guid>https://dev.to/readystack/57-small-vs-code-linters-for-regulation-deadlines-cra-cert-47-day-cap-k8s-removed-apis-409j</guid>
      <description>&lt;p&gt;I kept losing days to things that were true last year: a Kubernetes manifest that still says &lt;code&gt;extensions/v1beta1&lt;/code&gt;, a TLS cert plan written for 398 days when the cap is now 47, a Python project that ships without PEP 639 licence metadata, an SBOM that misses the fields the EU Cyber Resilience Act (reporting since 2026-09-11) expects.&lt;/p&gt;

&lt;p&gt;So I built small, single-purpose linters that check the file open in your editor against the rule as it stands today, with the source of the rule (the statute or spec) on every finding. Each one is a separate VS Code extension (also on Open VSX for Cursor, as an npm CLI, and as a Docker image), with the same &lt;code&gt;rules.json&lt;/code&gt; driving all forms.&lt;/p&gt;

&lt;p&gt;The file open in the editor is free: no key, no counter, no limit. Sweeping a whole workspace and writing a dated report asks for a licence ($29 once, 7-day trial, 7-day refund). Source is public: &lt;a href="https://github.com/jmshinhwa/readystack-themes" rel="noopener noreferrer"&gt;readystack-themes&lt;/a&gt; (the extensions) and &lt;a href="https://github.com/jmshinhwa/readystack-mcp" rel="noopener noreferrer"&gt;readystack-mcp&lt;/a&gt; (the same checks as MCP servers for AI agents).&lt;/p&gt;

&lt;p&gt;Catalogue with a free web version of every check: &lt;a href="https://getreadystack.com/" rel="noopener noreferrer"&gt;getreadystack.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Things I would genuinely like feedback on: which rules are wrong or stale (each finding cites its basis, so it should be easy to point at), and which deadlines you have to track that nothing checks yet.&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>devops</category>
      <category>compliance</category>
      <category>opensource</category>
    </item>
    <item>
      <title>IR35 Deemed Employer Cost Check 2026/27</title>
      <dc:creator>ReadyStack</dc:creator>
      <pubDate>Fri, 18 Sep 2026 07:32:42 +0000</pubDate>
      <link>https://dev.to/readystack/ir35-deemed-employer-cost-check-202627-3de1</link>
      <guid>https://dev.to/readystack/ir35-deemed-employer-cost-check-202627-3de1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmq8730f9uv8fiykipi99.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmq8730f9uv8fiykipi99.jpg" alt="IR35 Deemed Employer Cost Check 2026/27" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;£65,665.60 — UK recruitment agency fee-payers, one £500-a-day contractor, four assessable years at £16,416.40 each. That is the run, straight off the free web page:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Deemed direct payment (PAYE base)&lt;/td&gt;
&lt;td&gt;£110,000.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Employer NI at 15% — your cost, on top&lt;/td&gt;
&lt;td&gt;£15,866.40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apprenticeship Levy at 0.5%&lt;/td&gt;
&lt;td&gt;£550.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Employment Allowance relief available&lt;/td&gt;
&lt;td&gt;£0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost on top of the agreed rate, per year&lt;/td&gt;
&lt;td&gt;£16,416.40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;True cost per day&lt;/td&gt;
&lt;td&gt;£574.62&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Outside the set-off if status is overturned, over four years&lt;/td&gt;
&lt;td&gt;£65,665.60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s.61T deadline to answer the dispute&lt;/td&gt;
&lt;td&gt;2026-10-15&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Inputs: £500 a day, 220 days engaged, no VAT inside the invoiced amount, £0 direct materials, annual pay bill over £3m, determination disputed, four years HMRC can assess, representations received 1 September 2026.&lt;/p&gt;

&lt;p&gt;Eight figures out, and the £65,665.60 is not the tax bill. It is only the slice of the tax bill that the off-payroll set-off rules refuse to hand back, totalled across the four years.&lt;/p&gt;

&lt;p&gt;Since 6 April 2024 HMRC has been able to offset tax already paid by a contractor's personal service company against the PAYE liability of the deemed employer. For income tax and employee National Insurance it works. But the legislation permits set-off of income tax and employee NICs only. Arrears of employer NICs, and the Apprenticeship Levy where it is due, sit outside the mechanism entirely. They stay with the fee-payer, in full, for every year HMRC can assess.&lt;/p&gt;

&lt;p&gt;Here is where the £16,416.40 a year comes from. The deemed direct payment — the PAYE base Chapter 10 ITEPA 2003 defines — is £110,000. Employer secondary Class 1 National Insurance for 2026/27 runs at 15% above a secondary threshold of £5,000 a year, which is £96 a week and frozen until 2030/31. Across 44 working weeks that threshold shelters £4,224, so the agency owes 15% of £105,776: £15,866.40. An agency with an annual pay bill over £3m adds the Apprenticeship Levy at 0.5% of the deemed payment, another £550.&lt;/p&gt;

&lt;p&gt;That £16,416.40 sits on top of the agreed rate, not inside it. A deemed employer cannot lawfully deduct employer NI or the Levy from the contractor's rate to recover it. So the £500-a-day contractor is a £574.62-a-day contractor, and the margin the agency priced the placement on was never there.&lt;/p&gt;

&lt;p&gt;Then there is the line most spreadsheets get wrong in the other direction. The Employment Allowance is £10,500 in 2026/27, and it cannot be set against payments to deemed employees. Payroll templates and chatbots apply it anyway, because it applies everywhere else in the same payroll. On this engagement the relief available is £0.&lt;/p&gt;

&lt;p&gt;Under section 61T ITEPA 2003, when a worker makes representations against a Status Determination Statement, the client has 45 days beginning with the day the representations are received to either confirm the conclusion with reasons or issue a new SDS. Miss that and the client itself is treated as the deemed employer. Representations received on 1 September 2026 must be answered by 15 October 2026. That date is not on any calendar until somebody puts it there.&lt;/p&gt;

&lt;p&gt;HMRC's CEST tool answers one question — inside or outside — and returns a status. It never returns a pound figure, it does not apply employer NI or the Levy, and it is silent on how much of an overturned determination you will actually eat.&lt;/p&gt;

&lt;p&gt;IR35 Deemed Employer Cost Check 2026/27 is a browser extension and a free web page sharing one engine. Eight inputs in, eight figures out — the table above is the whole of it. All eight are free, unlimited, and nothing you type leaves your machine.&lt;/p&gt;

&lt;p&gt;The paid layer sits on a different axis, not a bigger number. For $60 the key exports the liability schedule as a .csv you own and sets a browser alarm on the s.61T date. For comparison, a per-contract IR35 status review from a UK contractor accountant is quoted at £200 to £800 in September 2026 price guides — it comes back with a status, not a liability.&lt;/p&gt;




&lt;p&gt;Free in your browser (the same rules): &lt;a href="https://getreadystack.com/tools/ir35-deemed-employer-cost-2026" rel="noopener noreferrer"&gt;https://getreadystack.com/tools/ir35-deemed-employer-cost-2026&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Licence ($60, once, 7-day refund): &lt;a href="https://buy.polar.sh/polar_cl_85nmF80S9an8JjdqDlt3HwlrADTiMF4pAC8cK3Hhjmm" rel="noopener noreferrer"&gt;https://buy.polar.sh/polar_cl_85nmF80S9an8JjdqDlt3HwlrADTiMF4pAC8cK3Hhjmm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>chromeextension</category>
      <category>browserextension</category>
      <category>productivity</category>
    </item>
    <item>
      <title>SPF &amp; DMARC Record Lint</title>
      <dc:creator>ReadyStack</dc:creator>
      <pubDate>Thu, 17 Sep 2026 07:32:30 +0000</pubDate>
      <link>https://dev.to/readystack/spf-dmarc-record-lint-32m2</link>
      <guid>https://dev.to/readystack/spf-dmarc-record-lint-32m2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F714bkhlbonveo3pl5p0s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F714bkhlbonveo3pl5p0s.jpg" alt="Six email-auth faults in one zone file" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Six findings in one four-record zone file — for the platform engineer who keeps DNS in git and adds a sending vendor every quarter. The result first, the explanation afterwards:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_fixtures/dirty.zone — 15 checks — 6 findings (4 errors, 2 warnings)
ERROR  L5  spf_lookup_limit  SPF record needs 11 DNS lookups — the limit is 10 (RFC 7208 §4.6.4). Receivers return PermError and treat the domain as having no SPF at all.
ERROR  L5  spf_ptr           The 'ptr' mechanism is deprecated and must not be published (RFC 7208 §5.5).
ERROR  L6  spf_pass_all      '+all' passes SPF for every sender on the internet — the same as publishing no SPF.
WARN   L7  dmarc_p_none      'p=none' only asks for reports; nothing that fails alignment is blocked.
WARN   L7  dmarc_no_rua      No 'rua=' tag, so no aggregate reports are ever sent.
ERROR  L8  dkim_p_empty      Empty 'p=' means the key is revoked — every signature from this selector fails.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The zone is plain: one SPF record for the mail host, one for a legacy sender, one DMARC record, one DKIM selector. Every line is valid. BIND loads it, &lt;code&gt;dig&lt;/code&gt; prints it back exactly as written, and a language model asked to review it will say it looks fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 5 is the expensive one.&lt;/strong&gt; RFC 7208 §4.6.4 caps SPF evaluation at ten DNS lookups — &lt;code&gt;include&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;mx&lt;/code&gt;, &lt;code&gt;ptr&lt;/code&gt;, &lt;code&gt;exists&lt;/code&gt; and &lt;code&gt;redirect=&lt;/code&gt; each cost at least one, and every &lt;code&gt;include:&lt;/code&gt; resolves to a record that can spend more. At lookup eleven the receiver stops and returns PermError, and most receivers treat PermError like a domain with no SPF record. If DMARC was passing on SPF alignment alone, DMARC fails with it. Nothing in the editor or the deploy log turns red, and the record stays live until somebody notices invoices landing in spam.&lt;/p&gt;

&lt;p&gt;Eight includes, an &lt;code&gt;a:&lt;/code&gt;, an &lt;code&gt;mx&lt;/code&gt; and a &lt;code&gt;ptr:&lt;/code&gt; is eleven. Nobody adds eleven at once: you add the fourth vendor, then the sixth, then the eighth, and the record crosses the line on an ordinary Tuesday. The &lt;code&gt;ptr:&lt;/code&gt; should not be there either — §5.5 deprecated it, receivers may ignore it, and it costs a lookup per candidate host.&lt;/p&gt;

&lt;p&gt;Line 6 authorises every host on the internet to send as the domain: &lt;code&gt;+all&lt;/code&gt; is the protection of publishing nothing with the paperwork of publishing something. Line 7 is monitoring with the monitor unplugged — &lt;code&gt;p=none&lt;/code&gt; blocks nothing, and with no &lt;code&gt;rua=&lt;/code&gt; no aggregate report is ever sent, so there is no data to move off it with. Line 8 is a DKIM selector whose public key has been revoked to an empty &lt;code&gt;p=&lt;/code&gt;: every signature made with it fails.&lt;/p&gt;

&lt;p&gt;Fix those six and the same zone returns zero findings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the free checkers do not catch it
&lt;/h2&gt;

&lt;p&gt;Because they resolve. Every online SPF tool takes a domain name, queries DNS, and answers about the record already live — which is exactly the record already costing you mail. The one you want checked is in a pull request, on a domain that does not resolve yet, behind a Terraform variable. A chatbot will count your include: chain by guessing.&lt;/p&gt;

&lt;p&gt;SPF &amp;amp; DMARC Record Lint reads &lt;code&gt;v=spf1&lt;/code&gt;, &lt;code&gt;v=DMARC1&lt;/code&gt; and &lt;code&gt;v=DKIM1&lt;/code&gt; strings wherever you actually write them — BIND zone files, &lt;code&gt;aws_route53_record&lt;/code&gt; and &lt;code&gt;cloudflare_record&lt;/code&gt; blocks, Kubernetes and Ansible YAML, &lt;code&gt;.env&lt;/code&gt; files, docs — and runs 15 checks on each one: seven for SPF, five for DMARC, three for DKIM. Findings land on the line in the Problems panel with the RFC section and the edit that fixes them. No DNS queries, no network, no account, no telemetry.&lt;/p&gt;

&lt;p&gt;The file in front of you is checked in full, by all 15 rules, free and forever, with nothing timed or watermarked. The licence key is a different axis: sweeping every zone, Terraform and YAML file in the workspace in one pass, and keeping one dated Markdown audit report you can attach to the change ticket. $29 once, one key per person or CI seat, 7-day full refund — against the $50–$150 an hour a freelance deliverability specialist bills, most of the first hour going on reading the records you already have.&lt;/p&gt;




&lt;p&gt;Free in your browser (the same rules): &lt;a href="https://getreadystack.com/tools/spf-dmarc-record-lint" rel="noopener noreferrer"&gt;https://getreadystack.com/tools/spf-dmarc-record-lint&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Licence ($29, once, 7-day refund): &lt;a href="https://buy.polar.sh/polar_cl_lTz1ceauyoB7vrNgatSTcYZd8Oyia1VfFLlxg3fcI1A" rel="noopener noreferrer"&gt;https://buy.polar.sh/polar_cl_lTz1ceauyoB7vrNgatSTcYZd8Oyia1VfFLlxg3fcI1A&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>devtools</category>
      <category>linter</category>
    </item>
    <item>
      <title>CRAN Policy Submission Lint</title>
      <dc:creator>ReadyStack</dc:creator>
      <pubDate>Wed, 16 Sep 2026 07:32:34 +0000</pubDate>
      <link>https://dev.to/readystack/cran-policy-submission-lint-1o4c</link>
      <guid>https://dev.to/readystack/cran-policy-submission-lint-1o4c</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh9zwyd0q6st7g5av41se.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh9zwyd0q6st7g5av41se.jpg" alt="CRAN Policy Submission Lint" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Eight lines - a licence string, a version number, a Description opening, a library() call, an unrestored par(), a write to ~/, a ::: and a stray T - are all it takes for CRAN to send an R maintainer's first submission back into the queue.&lt;/p&gt;

&lt;p&gt;None of the eight is a bug. The package installs, the tests pass, R CMD check --as-cran is quiet about every one of them. They are policy: prose in the CRAN Repository Policy and Writing R Extensions that a volunteer reviewer applies by reading. That is the layer no tool in the standard R toolchain reads for you, and it is the layer that decides whether your tarball is accepted this week or next month.&lt;/p&gt;

&lt;p&gt;Here is the split. R CMD check computes: an argument you documented but did not declare, an example that errors, an import you forgot. A reviewer judges: a Description opening with "This package provides", which the policy asks you not to do; License: MIT, which CRAN refuses without "+ file LICENSE" and a two-line LICENSE file beside it; library(dplyr) in R/, which a package may not do because attaching changes the user's search path; par(mfrow = c(1, 2)) never put back with on.exit(). All documented rules, none computable the way check works.&lt;/p&gt;

&lt;p&gt;CRAN Policy Submission Lint encodes 25 of those rules and runs them on the file you have open. Ten cover DESCRIPTION: Title in title case with no trailing period, a Description that is a real sentence and does not begin with the package name, a licence string CRAN accepts, exactly one person() carrying role = "cre", no four-component or .9000 development version, no example.com placeholder address, a Date field neither in the future nor over a month stale, and packages declared under Imports rather than Depends. One covers NAMESPACE: exportPattern(), which ships your internals as public API. Fourteen cover R sources: library() and require(), install.packages(), setwd(), options()/par()/Sys.setenv() with no on.exit(), writes to ~/ instead of tempdir(), T and F, print() and cat() where message() belongs, \dontrun{}, non-ASCII characters, &amp;lt;&amp;lt;- and assign() to .GlobalEnv, installed.packages(), set.seed() inside a function, ::: into another package, and source() at package level.&lt;/p&gt;

&lt;p&gt;The sample package that ships with the extension is one DESCRIPTION, one NAMESPACE and one R file. Run it through and you get 28 findings - 18 errors and 10 warnings - which is every one of the 25 rules firing at least once. Run the corrected version of the same three files and you get zero. That is the whole demonstration: same engine, same three files, 28 to 0.&lt;/p&gt;

&lt;p&gt;R that an assistant drafts looks like R from scripts, because scripts are what it learned from - and a script may call library(), may setwd(), may use T. A package may not. Those three are also the cheapest things in the world to fix, once someone points at the line.&lt;/p&gt;

&lt;p&gt;The cost of not pointing at it is a round trip. CRAN's reviewers are volunteers and submissions queue; a published package that fails gets an email with a dated archival deadline - a named day, after which it leaves the repository and every reverse dependency breaks. A freelance R developer in North America bills $50 to $100 an hour (Upwork, 2026); the rework is not the expensive part, the wait is.&lt;/p&gt;

&lt;p&gt;Checking the file you have open is free and uncapped, in VS Code and in the browser tool, which runs the identical engine with nothing uploaded. The licence covers a different axis: sweeping every file in the package at once and writing a dated report you keep, commit beside the tarball, or paste into your submission comments.&lt;/p&gt;




&lt;p&gt;Free in your browser (the same rules): &lt;a href="https://getreadystack.com/tools/cran-policy-submission-lint" rel="noopener noreferrer"&gt;https://getreadystack.com/tools/cran-policy-submission-lint&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Licence ($29, once, 7-day refund): &lt;a href="https://buy.polar.sh/polar_cl_3p5QJlCGs0PUdsfxchdv4o2Jyr2C8Op4waTgt0xQNDs" rel="noopener noreferrer"&gt;https://buy.polar.sh/polar_cl_3p5QJlCGs0PUdsfxchdv4o2Jyr2C8Op4waTgt0xQNDs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>devtools</category>
      <category>linter</category>
    </item>
    <item>
      <title>CGS Threshold Check — the £600,000 rule that started 29 July 2026</title>
      <dc:creator>ReadyStack</dc:creator>
      <pubDate>Tue, 15 Sep 2026 08:11:50 +0000</pubDate>
      <link>https://dev.to/readystack/cgs-threshold-check-the-ps600000-rule-that-started-29-july-2026-2157</link>
      <guid>https://dev.to/readystack/cgs-threshold-check-the-ps600000-rule-that-started-29-july-2026-2157</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyt14kdaa25fnoebf579i.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyt14kdaa25fnoebf579i.jpg" alt="CGS Threshold Check — the £600,000 rule that started 29 July 2026" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A £400,000 office bought on 30 September 2026 owes nothing to the Capital Goods Scheme — and the UK finance manager who files that VAT return has just saved nine annual adjustments worth £28,800.&lt;/p&gt;

&lt;p&gt;That number comes from Revenue and Customs Brief 7 (2026). From 29 July 2026 the capital expenditure threshold for land, buildings and civil engineering works rose from £250,000 to £600,000, excluding VAT. The new limit applies to land acquired on or after that date, and to buildings and civil engineering works acquired, constructed, refurbished, fitted out, altered or extended on or after it. Computers and computer equipment acquired on or after 29 July 2026 left the scheme entirely. Ships, boats and aircraft are unchanged.&lt;/p&gt;

&lt;p&gt;Two things make this expensive.&lt;/p&gt;

&lt;p&gt;The first is that the change is not retrospective in the direction people assume. An item already a capital item under the old threshold stays in the scheme to the end of its adjustment period. So a warehouse bought on 28 July 2026 for £400,000 is in for ten intervals, and a near-identical one bought on 30 September 2026 is out. One day of difference on the completion statement, ten years of difference on the VAT return.&lt;/p&gt;

&lt;p&gt;The second is that every free answer still quotes the old figure. Type the question into a chatbot and it returns £250,000, the number in almost every page ever written about the scheme. The failure is silent: nobody gets an error, the business simply starts making adjustments it does not owe, or keeps ten years of records for an asset that left the scheme the day it was bought.&lt;/p&gt;

&lt;p&gt;CGS Threshold Check is a browser extension plus a free web page running the identical code. You give it seven things: the kind of capital item, the spend excluding VAT, the date it was acquired or the work was done, the input VAT charged, taxable use in the first interval, taxable use in this interval, and the date this interval ends.&lt;/p&gt;

&lt;p&gt;It returns seven. Which limit applies and why. In the scheme or out. Which interval you are in, out of how many. The adjustment for this interval. Which way the money moves — repay to HMRC or reclaim. What is still at stake if taxable use stays where it is. And the date the final adjustment falls.&lt;/p&gt;

&lt;p&gt;Worked through: an office, £400,000 excluding VAT, acquired 28 July 2026, £80,000 of input VAT, 100% taxable use in the first interval, 60% now, interval ending 31 March 2028. The old £250,000 limit binds it, so it is in for ten intervals. You are in interval 2. The adjustment is £80,000 divided by ten, multiplied by the forty point drop in taxable use: repay £3,200 to HMRC. Another £25,600 is still at stake across the remaining intervals, and the last adjustment falls on 31 March 2036.&lt;/p&gt;

&lt;p&gt;Now change one field. Move the acquisition date to 30 September 2026. The limit becomes £600,000, £400,000 is under it, and every other line drops to zero. That £3,200 plus £25,600 — £28,800 across intervals two to ten — is money that would have gone to HMRC on the strength of a threshold that no longer applied.&lt;/p&gt;

&lt;p&gt;The check is free, unlimited, with no key and no sign-up, in the popup and on the web page. The paid version exists on a different axis: it exports the whole interval schedule as .csv so it can sit in the working papers, and it sets reminders so each interval end reaches you before the return is filed. A UK VAT specialist bills roughly £150 to £300 an hour, and a written opinion on one capital item runs to several hours.&lt;/p&gt;

&lt;p&gt;Install it unpacked in Chrome or Edge, or open the web page and type the completion date. The date is the whole answer.&lt;/p&gt;




&lt;p&gt;Free in your browser (the same rules): &lt;a href="https://getreadystack.com/tools/cgs-threshold-check-2026" rel="noopener noreferrer"&gt;https://getreadystack.com/tools/cgs-threshold-check-2026&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Licence ($60, once, 7-day refund): &lt;a href="https://buy.polar.sh/polar_cl_DXX3bq3ADU6ptiv04a8nPAfZM6esWciIyUsgh0Uu3EX" rel="noopener noreferrer"&gt;https://buy.polar.sh/polar_cl_DXX3bq3ADU6ptiv04a8nPAfZM6esWciIyUsgh0Uu3EX&lt;/a&gt;&lt;/p&gt;

</description>
      <category>chromeextension</category>
      <category>browserextension</category>
      <category>productivity</category>
    </item>
    <item>
      <title>CRA 24/72/14 Reporting Lint (Article 14)</title>
      <dc:creator>ReadyStack</dc:creator>
      <pubDate>Mon, 14 Sep 2026 07:30:49 +0000</pubDate>
      <link>https://dev.to/readystack/cra-247214-reporting-lint-article-14-4ojk</link>
      <guid>https://dev.to/readystack/cra-247214-reporting-lint-article-14-4ojk</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwqn44umm240nwvj7rqmt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwqn44umm240nwvj7rqmt.jpg" alt="Five lines in your SECURITY.md that EU Article 14 now rejects" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Five lines in the average SECURITY.md now fail EU Cyber Resilience Act Article 14 — and for any maintainer shipping software into the Union, 11 September 2026 was the day that stopped being theoretical.&lt;/p&gt;

&lt;p&gt;That date is the one people get wrong. The Cyber Resilience Act is usually filed under "December 2027", and that is true of most of it. It is not true of the reporting obligation. From 11 September 2026, a manufacturer who becomes aware of an &lt;strong&gt;actively exploited vulnerability&lt;/strong&gt; in their product, or of a &lt;strong&gt;severe incident&lt;/strong&gt; affecting its security, owes three filings on a clock measured in hours — and it applies to products that were already on the market.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;24 hours&lt;/strong&gt; from awareness: an early warning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;72 hours&lt;/strong&gt; from awareness: a notification, with severity, impact and any corrective measure already applied.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;14 days&lt;/strong&gt; after a corrective measure is available: the final report. (For a severe incident, one month after the notification.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They go to &lt;strong&gt;ENISA&lt;/strong&gt; and to the &lt;strong&gt;CSIRT designated as coordinator&lt;/strong&gt; for your main establishment in the Union, filed through the single reporting platform.&lt;/p&gt;

&lt;p&gt;Now open your own SECURITY.md. Most of them were written years before this existed, and they fail in the same five places:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;line 10  [error] wrong_start_date_2027
      Wrong start date. The reporting obligation already applies;
      December 2027 is when the remaining obligations follow.
      fix: Correct the date to 11 September 2026 for reporting.  (CRA Art. 71(2))

line 11  [error] wrong_recipient
      Wrong recipient on the Article 14 path. This report does not go there.
      fix: Route the report to the coordinating CSIRT and ENISA.  (CRA Art. 14(1))

line 13  [error] gdpr_clock_confusion
      Two different 72-hour clocks are being treated as one.
      fix: Split the runbook into two paths.  (CRA Art. 14 vs GDPR Art. 33)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The GDPR confusion is the expensive one. Article 33 of the GDPR also says 72 hours, which makes it feel like the same obligation with the same runbook. It is not. Different trigger, different recipient, different content — and one incident can start both clocks at the same moment. A runbook that routes an actively exploited vulnerability to a data protection supervisory authority has notified the wrong body and still owes ENISA a report that is now late.&lt;/p&gt;

&lt;p&gt;The fourth failure is quieter: a response window measured in days sitting next to an obligation measured in hours. "We acknowledge reports within 5 business days" is a perfectly good disclosure promise, but a reader — including the on-call engineer at 3am — will take the slower number as the operative one. Keep the promise, state the 24/72/14 clock separately, and say which governs.&lt;/p&gt;

&lt;p&gt;The fifth is arithmetic. Article 13(8) expects a declared support period, and plenty of repositories still carry &lt;code&gt;supported until 2026-06-30&lt;/code&gt; in a release that is very much still installed. A date that has already passed is not a support period; it is a disclosure that the product is unsupported.&lt;/p&gt;

&lt;p&gt;I wrote &lt;strong&gt;CRA 24/72/14 Reporting Lint&lt;/strong&gt;, a VS Code extension, to check exactly this. Eighteen rules, run entirely offline, reading the Markdown file you have open: the three clock steps, the recipients, the two triggers, the single point of contact, the coordinated disclosure policy, the SBOM reference, the support period end date and whether it has lapsed or falls short of five years. Every finding names the article it comes from and the line to write instead.&lt;/p&gt;

&lt;p&gt;There is a free web version of the same engine — literally the same file, inlined into the page — so you can paste a policy and see the findings without installing anything: &lt;a href="https://getreadystack.com/t/cra-24-72-14-reporting-lint/" rel="noopener noreferrer"&gt;https://getreadystack.com/t/cra-24-72-14-reporting-lint/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The limits are worth stating plainly. This is a linter for a document, not a legal opinion and not a conformity assessment. It will tell you that your runbook never names a CSIRT. It cannot tell you whether your product is in scope, which class it falls into, or whether a given vulnerability is being actively exploited. Open-source stewards carry a lighter duty under Article 24, and the rules here flag the manufacturer path.&lt;/p&gt;

&lt;p&gt;But the mechanical errors — the wrong date, the wrong recipient, the borrowed GDPR runbook, the lapsed support period — are the ones a reviewer finds in the first five minutes, and they are the ones you can fix this afternoon.&lt;/p&gt;

&lt;p&gt;Regulation (EU) 2024/2847, Articles 13, 14 and 16; Annex I Part II; Annex II.&lt;/p&gt;




&lt;p&gt;Free in your browser (the same rules): &lt;a href="https://getreadystack.com/tools/cra-24-72-14-reporting-lint" rel="noopener noreferrer"&gt;https://getreadystack.com/tools/cra-24-72-14-reporting-lint&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Licence ($29, once, 7-day refund): &lt;a href="https://buy.polar.sh/polar_cl_zmN08yKAf6Qz5WMiSQO9V9MxIRQN87VQEfurn03M3KT" rel="noopener noreferrer"&gt;https://buy.polar.sh/polar_cl_zmN08yKAf6Qz5WMiSQO9V9MxIRQN87VQEfurn03M3KT&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>devtools</category>
      <category>linter</category>
    </item>
    <item>
      <title>EAA Form Lint: WCAG 2.2 AA for HTML</title>
      <dc:creator>ReadyStack</dc:creator>
      <pubDate>Sun, 13 Sep 2026 07:30:35 +0000</pubDate>
      <link>https://dev.to/readystack/eaa-form-lint-wcag-22-aa-for-html-b1i</link>
      <guid>https://dev.to/readystack/eaa-form-lint-wcag-22-aa-for-html-b1i</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiztm88efofvci149hg8v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiztm88efofvci149hg8v.jpg" alt="EAA Form Lint: WCAG 2.2 AA for HTML" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A 70-line signup form, generated in a single prompt, fails 28 WCAG 2.2 Level AA checks across 15 success criteria - and the frontend developer shipping it into Germany or Ireland usually learns this from a market surveillance letter rather than from the editor.&lt;/p&gt;

&lt;p&gt;I kept that form as a test fixture so the number is reproducible: 24 errors, 4 warnings, 28 findings. The repaired version of the same page returns 0.&lt;/p&gt;

&lt;p&gt;The interesting part is not the total. It is which criteria the generated markup breaks. Six of the 28 findings sit under the four success criteria that WCAG 2.2 added: 2.5.7 Dragging Movements, 2.5.8 Target Size (Minimum), 3.3.7 Redundant Entry and 3.3.8 Accessible Authentication. Models learned forms from a decade of WCAG 2.1-era code, so they reproduce the habits 2.2 turned into failures.&lt;/p&gt;

&lt;p&gt;Four lines from that form, each a house style you will recognise:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="password" autocomplete="off" onpaste="return false"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Two failures of 3.3.8 on one line. A password field that refuses paste and hides itself from password managers forces the user to retype a 20-character secret by hand. The fix is to delete the handler and write autocomplete="current-password".&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input type="email" name="confirm_email" placeholder="Confirm email address"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Three findings. The placeholder is doing the job of a label (3.3.2), there is no autocomplete token (1.3.5), and the field asks for something the user already typed (3.3.7).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="submit" onclick="submitForm()"&amp;gt;Create account&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;2.1.1. It looks like a button and the keyboard cannot reach it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button class="icon-btn" style="width:20px;height:20px"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Two more: a 20px target where 2.5.8 asks for 24 by 24 CSS pixels, and an icon with no accessible name (4.1.2).&lt;/p&gt;

&lt;p&gt;None of this is exotic. All of it is machine-checkable from the template text, before the page is rendered, the point: browser audit panels score a page you already deployed, and most of them still test WCAG 2.1. On the four criteria that matter most for generated forms, they stay quiet.&lt;/p&gt;

&lt;p&gt;Why now: the European Accessibility Act, Directive (EU) 2019/882, has applied to new consumer-facing e-commerce, banking, ticketing and e-book services since 28 June 2025. Enforcement runs through national market surveillance bodies, against the live service, and the technical yardstick they point at is EN 301 549, which carries the WCAG criteria. The remedy is not a fine; it is an order to fix or withdraw, with a deadline attached.&lt;/p&gt;

&lt;p&gt;The linter is 18 rules over the template text. Each finding names the line, the success criterion, and the one-line fix. It runs in VS Code on the file you have open, and the same engine file runs in the browser on a free page, so you can paste a template without installing anything. That tier is complete on its own: every rule, every line, no key, no limit, no watermark.&lt;/p&gt;

&lt;p&gt;The licensed tier does a different job rather than more of the same one. It scans every template in the workspace in a single pass and writes a dated evidence file you keep - one row per finding, per file, mapped to its criterion. That artefact is what an accessibility statement rests on, and what a client asks for.&lt;/p&gt;

&lt;p&gt;One honest limit: this reads markup, not a rendered page. It cannot judge colour contrast or visual reading order, and it will never tell you that you conform. It finds the part a machine can find, which happens to be the part generated code gets wrong.&lt;/p&gt;

&lt;p&gt;For comparison, a WCAG audit from an accessibility vendor starts around $2,500 for a single signup flow and answers for the day it was run.&lt;/p&gt;




&lt;p&gt;Free in your browser (the same rules): &lt;a href="https://getreadystack.com/tools/eaa-form-lint-wcag22" rel="noopener noreferrer"&gt;https://getreadystack.com/tools/eaa-form-lint-wcag22&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Licence ($29, once, 7-day refund): &lt;a href="https://buy.polar.sh/polar_cl_O5AMXCnn3ZETWE939bA4zjzmM0KqLt9Yp76Xm2x1Pa1" rel="noopener noreferrer"&gt;https://buy.polar.sh/polar_cl_O5AMXCnn3ZETWE939bA4zjzmM0KqLt9Yp76Xm2x1Pa1&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>devtools</category>
      <category>linter</category>
    </item>
    <item>
      <title>MCP 2026 Migration Lint</title>
      <dc:creator>ReadyStack</dc:creator>
      <pubDate>Sat, 12 Sep 2026 07:32:29 +0000</pubDate>
      <link>https://dev.to/readystack/mcp-2026-migration-lint-4k2c</link>
      <guid>https://dev.to/readystack/mcp-2026-migration-lint-4k2c</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhl67yvpai3tnd8mcdb7b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhl67yvpai3tnd8mcdb7b.jpg" alt="MCP 2026 Migration Lint" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Six lines that a US platform team's MCP server still ships stopped being protocol on 28 July 2026 - and the server still starts up clean.&lt;/p&gt;

&lt;p&gt;That is the whole trap. The &lt;code&gt;2026-07-28&lt;/code&gt; revision of the Model Context Protocol did not rename those calls or soften them into warnings. It &lt;strong&gt;removed&lt;/strong&gt; them. A server written against &lt;code&gt;2025-06-18&lt;/code&gt; or &lt;code&gt;2025-11-25&lt;/code&gt; keeps answering old clients perfectly, and breaks the first morning a client upgrades. Nothing goes red in your editor, because none of it is a syntax error.&lt;/p&gt;

&lt;p&gt;Here is what a working server looked like in June, and what each line is now:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Still in your repo&lt;/th&gt;
&lt;th&gt;What 2026-07-28 says&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;InitializeRequestSchema&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;removed - implement &lt;code&gt;server/discover&lt;/code&gt;; version rides in &lt;code&gt;_meta&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Mcp-Session-Id&lt;/code&gt; header&lt;/td&gt;
&lt;td&gt;removed - mint your own handle, pass it as a tool argument&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PingRequestSchema&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;removed - nothing replaces it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;resources/subscribe&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;replaced by &lt;code&gt;subscriptions/listen&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;roots/list&lt;/code&gt; (server-initiated)&lt;/td&gt;
&lt;td&gt;replaced by &lt;code&gt;InputRequiredResult&lt;/code&gt; (MRTR)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;McpError(-32002)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;McpError(-32602)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The second trap is that your assistant cannot help you find them. It was trained before 28 July 2026. Ask it for an MCP server today and it will write &lt;code&gt;InitializeRequestSchema&lt;/code&gt;, &lt;code&gt;"type": "sse"&lt;/code&gt; and &lt;code&gt;-32002&lt;/code&gt;, and if you ask whether that is current it will tell you yes. The tool that produced the debt is not the tool that clears it.&lt;/p&gt;

&lt;p&gt;And the config files carry their own version of this. &lt;code&gt;"type": "sse"&lt;/code&gt; is the HTTP+SSE transport, deprecated since protocol &lt;code&gt;2025-03-26&lt;/code&gt; and now formally Deprecated under the new feature-lifecycle policy, which sets a minimum twelve-month window before removal. Roots, Sampling and Logging entered that same window on 28 July 2026 - so the earliest they can disappear is 28 July 2027. That is your migration budget, and it is already six weeks spent.&lt;/p&gt;

&lt;p&gt;MCP 2026 Migration Lint is 27 rules that read the file you have open - &lt;code&gt;.vscode/mcp.json&lt;/code&gt;, &lt;code&gt;.mcp.json&lt;/code&gt;, &lt;code&gt;claude_desktop_config.json&lt;/code&gt;, &lt;code&gt;.cursor/mcp.json&lt;/code&gt;, or JS/TS/Python server source - and put a line number, the change it comes from, and the replacement on each finding. It runs offline; nothing is uploaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"github"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sse"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Mcp-Session-Id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"abc123"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"GITHUB_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ghp_9f2k1JqR7sT4vW0xYz"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four findings on those eight lines: the key &lt;code&gt;mcpServers&lt;/code&gt; shows nothing in VS Code, which reads &lt;code&gt;servers&lt;/code&gt;; &lt;code&gt;"type": "sse"&lt;/code&gt; is the deprecated transport; &lt;code&gt;Mcp-Session-Id&lt;/code&gt; was removed outright; and the token is a literal credential in a file that usually gets committed.&lt;/p&gt;

&lt;p&gt;The file you have open is free - all 27 rules, no key, no account. Doing it by hand instead means reading the changelog and mapping every removal across every file yourself; freelance senior software engineers publish an average of $101 an hour. The paid tier does not give better answers, it changes the scale: the whole repository in one pass, an exported report, and CI output so a removed RPC cannot be merged back in. $29 once, seven-day full refund.&lt;/p&gt;




&lt;p&gt;Free in your browser (the same rules): &lt;a href="https://getreadystack.com/tools/mcp-2026-migration-lint" rel="noopener noreferrer"&gt;https://getreadystack.com/tools/mcp-2026-migration-lint&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Licence ($29, once, 7-day refund): &lt;a href="https://buy.polar.sh/polar_cl_oDjtHoT9LT11eZ3znaYEtjljb5fL8onpd7R0j3VkVqB" rel="noopener noreferrer"&gt;https://buy.polar.sh/polar_cl_oDjtHoT9LT11eZ3znaYEtjljb5fL8onpd7R0j3VkVqB&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>devtools</category>
      <category>linter</category>
    </item>
    <item>
      <title>AI Crawler Rules - robots.txt Audit for AI Search</title>
      <dc:creator>ReadyStack</dc:creator>
      <pubDate>Fri, 11 Sep 2026 07:30:38 +0000</pubDate>
      <link>https://dev.to/readystack/ai-crawler-rules-robotstxt-audit-for-ai-search-19gi</link>
      <guid>https://dev.to/readystack/ai-crawler-rules-robotstxt-audit-for-ai-search-19gi</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdfmovcurb7e95onjvgrm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdfmovcurb7e95onjvgrm.jpg" alt="The robots.txt line that quietly deletes you from ChatGPT" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Six lines in this robots.txt do nothing the author intended - for SEO consultants and publishers auditing a client site.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;robots.txt
  1  ERROR  No crawler answers to this name - the real token has no hyphen
  4  ERROR  Retired token. Claude-Web and anthropic-ai were replaced by ClaudeBot in 2024
  5  ERROR  Disallow: * is not a valid path value
  7  WARN   Google-Extended is a control token, not a crawler
 10  ERROR  Google stopped honouring noindex in robots.txt on 1 September 2019
 11  ERROR  Sitemap must be an absolute URL including scheme and host.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those findings come from an eleven-line file whose every line reads like an instruction: &lt;code&gt;User-agent: GPT-Bot&lt;/code&gt;, &lt;code&gt;Disallow: *&lt;/code&gt;, &lt;code&gt;Noindex: /private&lt;/code&gt;, &lt;code&gt;Sitemap: /sitemap.xml&lt;/code&gt;. Not one of them is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The names are wrong
&lt;/h2&gt;

&lt;p&gt;There is no crawler called &lt;code&gt;GPT-Bot&lt;/code&gt;. The real token is &lt;code&gt;GPTBot&lt;/code&gt;, with no hyphen. &lt;code&gt;Claude-Web&lt;/code&gt; was real once and was retired in 2024, when Anthropic consolidated on &lt;code&gt;ClaudeBot&lt;/code&gt;. robots.txt ignores unknown user-agent tokens silently: no warning, no error, no log line. The file looks correct and blocks nothing.&lt;/p&gt;

&lt;p&gt;Assistants produce these names because the crawler names changed after their training data was collected - which is why you cannot ask a chatbot to write the file that governs chatbots.&lt;/p&gt;

&lt;h2&gt;
  
  
  Training and citation are two different taps
&lt;/h2&gt;

&lt;p&gt;Blocking a training crawler and blocking a citation crawler look identical in the file, and do opposite things to your business:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User-agent: GPTBot          # training  - your text feeds a future model
User-agent: OAI-SearchBot   # citation  - your link appears inside ChatGPT answers
User-agent: ChatGPT-User    # a reader asked ChatGPT to open your page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;GPTBot&lt;/code&gt; trains. &lt;code&gt;OAI-SearchBot&lt;/code&gt; is how ChatGPT finds and cites you. Anthropic splits the same way: &lt;code&gt;ClaudeBot&lt;/code&gt; trains, &lt;code&gt;Claude-SearchBot&lt;/code&gt; cites, &lt;code&gt;Claude-User&lt;/code&gt; fetches when a person asks.&lt;/p&gt;

&lt;p&gt;So someone who pastes "block the AI bots" and disallows the whole family keeps the training exposure they were worried about on the crawlers they missed, and deletes themselves from the surfaces that were sending readers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google-Extended does not do what its name suggests
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Google-Extended&lt;/code&gt; is not a crawler but a control token - you will never see it as a request in your logs. Google documents that it only opts content out of Gemini model training and grounding, that it does not affect inclusion in Google Search, and that it is not a ranking signal. AI Overviews are served from &lt;code&gt;Googlebot&lt;/code&gt;. So blocking it does nothing about AI Overviews; the only way out is to block &lt;code&gt;Googlebot&lt;/code&gt;, which removes you from Google Search entirely. &lt;code&gt;Applebot-Extended&lt;/code&gt; is the same shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wildcard group is not a base layer
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;User-agent: *&lt;/code&gt; is not inherited. A named group replaces it rather than merging with it, so adding a group for &lt;code&gt;GPTBot&lt;/code&gt; makes that crawler ignore every rule under the wildcard. And &lt;code&gt;Crawl-delay&lt;/code&gt; is not a fix: Googlebot ignores it, though Bing and several AI crawlers honour it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check it instead of trusting it
&lt;/h2&gt;

&lt;p&gt;I built the check into the editor: &lt;strong&gt;AI Crawler Rules for robots.txt&lt;/strong&gt;, a VS Code extension that reads the file line by line and says what each line actually controls. It carries nineteen rules, six of them hard errors, with every token taken from the vendors' own crawler documentation. There is a free web version too.&lt;/p&gt;

&lt;p&gt;Checking the open file is free and complete: every rule runs, every finding is shown, nothing is hidden or watermarked. A licence is $29 once and adds a different job rather than more of the same one - scanning every &lt;code&gt;robots.txt&lt;/code&gt; in a workspace, exporting the report for a client, failing CI when an error appears, and re-checking on save. A freelance technical SEO consultant bills roughly $100-150 an hour, and an AI-crawler robots.txt review is a one-to-two hour job per site.&lt;/p&gt;

&lt;p&gt;Open your own &lt;code&gt;robots.txt&lt;/code&gt; and search it for a hyphen in &lt;code&gt;GPT-Bot&lt;/code&gt;, and for the word &lt;code&gt;Claude-Web&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;Free in your browser (the same rules): &lt;a href="https://getreadystack.com/tools/robots-txt-ai-crawler-audit" rel="noopener noreferrer"&gt;https://getreadystack.com/tools/robots-txt-ai-crawler-audit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Licence ($29, once, 7-day refund): &lt;a href="https://buy.polar.sh/polar_cl_I8R8AzowzmASHy45ujvewcvtcl4wBBfC2Fe7r3fZwpr" rel="noopener noreferrer"&gt;https://buy.polar.sh/polar_cl_I8R8AzowzmASHy45ujvewcvtcl4wBBfC2Fe7r3fZwpr&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>devtools</category>
      <category>linter</category>
    </item>
    <item>
      <title>Porting Excel PMT to the browser: two traps that only show up in money</title>
      <dc:creator>ReadyStack</dc:creator>
      <pubDate>Thu, 30 Jul 2026 04:45:23 +0000</pubDate>
      <link>https://dev.to/readystack/porting-excel-pmt-to-the-browser-two-traps-that-only-show-up-in-money-g0p</link>
      <guid>https://dev.to/readystack/porting-excel-pmt-to-the-browser-two-traps-that-only-show-up-in-money-g0p</guid>
      <description>&lt;p&gt;We put a loan calculator on a landing page — no backend, no request, the visitor types four or five numbers and the answer appears. The whole thing is one small function. It still took two attempts, because both bugs are invisible until the output happens to be money.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trap 1: PMT divides by zero at 0%
&lt;/h2&gt;

&lt;p&gt;Excel's &lt;code&gt;PMT(rate, nper, pv, fv, type)&lt;/code&gt; is a closed-form annuity payment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pmt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nper&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pv&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;fv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;nper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// &amp;lt;- the branch people forget&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nper&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pv&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;fv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drop the &lt;code&gt;rate === 0&lt;/code&gt; line and the general formula gives you &lt;code&gt;(f - 1) === 0&lt;/code&gt; in the denominator, so a 0% promotional loan — the exact case a dealer advertises — returns &lt;code&gt;Infinity&lt;/code&gt; or &lt;code&gt;NaN&lt;/code&gt;. Excel has that branch. If you transcribe only the algebra from a finance textbook, you don't.&lt;/p&gt;

&lt;p&gt;A second detail: the sign. &lt;code&gt;pmt&lt;/code&gt; returns a negative number for a positive present value, because Excel models money leaving you. If you pass the balance in as &lt;code&gt;-balance&lt;/code&gt; you get a positive payment back and the rest of your arithmetic reads normally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trap 2: Excel's ROUND and JavaScript's Math.round disagree
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Math.round&lt;/code&gt; in JavaScript is half-up toward positive infinity: &lt;code&gt;Math.round(-2.5) === -2&lt;/code&gt;. Excel's &lt;code&gt;ROUND&lt;/code&gt; is half away from zero: &lt;code&gt;ROUND(-2.5, 0)&lt;/code&gt; is &lt;code&gt;-3&lt;/code&gt;. On a page that shows a savings figure, that is a cent of difference between the browser and the spreadsheet the user downloads — and a cent is enough for someone to conclude one of the two is broken.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;excelRound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;fl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;fl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;fl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why bother with parity at all
&lt;/h2&gt;

&lt;p&gt;Because the spreadsheet is the product and the page is the demo. If the two disagree by a cent, the demo has told the visitor not to trust the product.&lt;/p&gt;

&lt;p&gt;The live version is a car-refinance calculator. It runs 5 of the spreadsheet's 9 inputs and 2 of its 6 results, in the page, with the same formulas — the numbers you type never leave your browser. Two outputs are worth having even if you never download anything: how much the monthly payment actually drops, and how many months it takes for the closing costs to pay for themselves. On the default numbers that is $80.24 and 2.3 months.&lt;/p&gt;

&lt;p&gt;Poke at it here: &lt;a href="https://getreadystack.com/g/WXNNSESB" rel="noopener noreferrer"&gt;car refinance calculator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The input that decides the whole answer, by the way, is the payoff balance — and the figure in your lender's app usually isn't it. Call and ask for the payoff.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>excel</category>
      <category>math</category>
    </item>
  </channel>
</rss>
