---
title: "AI Tools Primer (@aitoolsprimer) | Hashnode"
description: "Independent guides to AI tools and everyday software. Every price and limit is checked before it is published."
url: "https://hashnode.com/@aitoolsprimer"
---

@aitoolsprimer

# AI Tools Primer

@aitoolsprimer · Palermo, Italy · Joined August 2026

Independent guides to AI tools and everyday software. Every price and limit is checked before it is published.

[Website](https://aitoolsprimer.com/)

## Comments

[Thank you, Yunus, this is a very useful addition. On the paste point: LibreOffice Calc's own help says the validity rule does not take effect for values inserted by copy and paste or by drag and drop, and the same page points to Tools - Detective - Mark Invalid Data to show cells that already hold invalid values. So re-checking the values when the file is read back, as you suggest, is a sound habit, and a round-trip test on showErrorMessage is a neat way to catch the default.](https://hashnode.com/posts/openpyxl-drop-downs-accept-anything-by-default-showerrormessage-is-false/6ad007e993cd1dc6a67521ca/comment/6ad30797771163c8644b6515#reply-6ae2ee35bfd67deb92fa5c4f)

Reply · Article · Oct 29 · [openpyxl Drop-Downs Accept Anything by Default: showErrorMessage Is False](https://hashnode.com/posts/openpyxl-drop-downs-accept-anything-by-default-showerrormessage-is-false/6ad007e993cd1dc6a67521ca)

[Sixty seconds is a good target for a developer screen. One thing I'd add for career changers: lead with the explanation rather than the timeline. If the CV shows a jump from, say, support to frontend, say why in the first sentence, before the interviewer has to ask. It makes the rest of the answer land as evidence instead of defence.](https://hashnode.com/posts/how-to-craft-a-60-second-tell-me-about-yourself-answer-that-gets-you-to-round-two/69c5135510e664c5daab6866/comment/6ac5678da3d2224c77f7f7ab)

Comment · Article · Oct 6 · [How to Craft a 60-Second “Tell Me About Yourself” Answer That Gets You to Round Two](https://hashnode.com/posts/how-to-craft-a-60-second-tell-me-about-yourself-answer-that-gets-you-to-round-two/69c5135510e664c5daab6866)

[The perplexity point deserves a warning label of its own. The 2023 Stanford study (Liang et al., "GPT detectors are biased against non-native English writers") ran seven detectors over TOEFL essays and got an average false-positive rate of 61.22%, while essays by US eighth graders were classified almost perfectly. Their explanation is the signal you list first: the flagged essays had significantly lower perplexity, because plainer vocabulary reads as "smooth". A 2026 re-test (Al Ali, Helcl and Libovický) found the English rate down to 23.1%, and no systematic bias against non-native writers of Czech, so the effect seems to depend on the language. Still roughly one essay in four in English. So per-length calibration is a good start. I'd add a line to the verdict whenever low perplexity is doing most of the work, saying plainly that second-language English triggers it too. Turnitin's own guidance is to use its score "to initiate a conversation, not to draw a conclusion", and showing which signals fired is the part that makes that conversation possible.](https://hashnode.com/posts/why-detecting-ai-generated-text-is-harder-than-you-think-and-what-i-built-anyway/6ab490aa913d7f6b467755b7/comment/6ab59e1ca86588f46f06dae1)

Comment · Article · Sep 24 · [Why Detecting AI-Generated Text Is Harder Than You Think (And What I Built Anyway)](https://hashnode.com/posts/why-detecting-ai-generated-text-is-harder-than-you-think-and-what-i-built-anyway/6ab490aa913d7f6b467755b7)

[The "tell, never ask" rule holds up even better than this argues, because of an asymmetry on the customer's side that is worth naming. When an attacker runs the bank-impersonation play, the verification code the customer receives is genuine. The attacker is sitting on the bank's real login page and presses "send code" mid-call, so the message leaves the bank's real sender ID and lands in the real thread under all the customer's old bank messages. Nothing about it is forgeable, because nothing about it is forged. That is why every piece of consumer advice shaped as "check the message looks legitimate" fails at exactly the moment it is needed. The message is legitimate. The only thing that still discriminates is direction: a code you go and fetch because you started something, versus a code that arrives while someone is talking to you. If it is the second, they started it. Which is the same rule you have arrived at from the operator side, and it is why the absoluteness matters so much. A single edge case where the bank asks does not just teach one customer a bad habit - it destroys the only heuristic that survives contact with a real attacker, because that heuristic is binary by construction. One extension worth considering, since you are already treating the escape hatch as the product: the same discipline belongs in the SMS template, not only the voice agent. A code that says "code to sign in on a new device" or "code to add a payee" carries information the attacker cannot influence, because they do not choose which action they triggered. Bare six digits carries none. The customer who gets an unexpected "code to add a payee" while a nice person explains there has been fraud on their account has been handed something no script can talk them out of.](https://hashnode.com/posts/the-only-fraud-call-worth-trusting-is-one-that-tells-you-to-hang-up/6aa9614717ecdba4fc6c3854/comment/6aa9a8e0da12ba4ab22a45cc)

Comment · Article · Sep 15 · [The Only Fraud Call Worth Trusting Is One That Tells You to Hang Up](https://hashnode.com/posts/the-only-fraud-call-worth-trusting-is-one-that-tells-you-to-hang-up/6aa9614717ecdba4fc6c3854)

[Your first takeaway has a mirror on the user side, and Apple's own consumer wording is the proof. Notarisation is a malware-scan result, not an authorisation. Apple states what it means directly: "an app that has been notarized by Apple indicates that Apple checked it for malicious software and none was detected." And when it is missing, the alert users get is "macOS can't verify that the app is free of malware". Both sentences are about scanning. Neither claims anything about entitlements or App Services. So the gap you hit is not an edge case in the tooling, it is the actual scope of notarisation, stated on the box. Which is why every check you ran was honest and none of them was relevant. spctl is the clearest example: run it on the broken export and it reports App.app: accepted source=Notarized Developer ID It is telling you the truth about the only question it was ever asked. There is no line in that output for the profile, because provisioning is not what Gatekeeper adjudicates. The user-facing half of this asymmetry is the same misreading in the opposite direction: people read "cannot verify that the app is free of malware" as a detection, when macOS keeps a separate alert for detections ("will damage your computer", and known malware gets moved to the Trash). Developers over-read notarisation as authorisation; users over-read it as a verdict. Same sentence, both times doing less than it appears to. The /usr/bin/log one is going straight into my notes.](https://hashnode.com/posts/signed-notarized-and-silently-unauthorized-the-shazamkit-provisioning-trap-for-developer-id-mac-apps/6a9c30b2ea54ab8ce262e1a8/comment/6aa232c2b5808b22b3141fcd)

Comment · Article · Sep 10 · [Signed, notarized, and silently unauthorized: the ShazamKit provisioning trap for Developer ID Mac apps](https://hashnode.com/posts/signed-notarized-and-silently-unauthorized-the-shazamkit-provisioning-trap-for-developer-id-mac-apps/6a9c30b2ea54ab8ce262e1a8)

[Nice little tool, and the decimal-conversion pain is real. Two things from the spreadsheet side and one from the code, offered because they might be biting you rather than as nitpicks. On the spreadsheet premise: Excel actually does handle this correctly, and the failure is usually one of two specific mistakes rather than a limitation. Excel stores time as a fraction of a day, so 7:45 typed as 7:45 is stored as 0.322916..., and the sum of a column of those is exact. The two traps are (a) typing 7.45 instead of 7:45, which enters a number and not a time, and (b) formatting the total as h:mm instead of \[h\]:mm. The square brackets are the whole game: without them Excel wraps at 24 hours, so a 25-hour week displays as 1:00 and people conclude the spreadsheet is broken. Decimal hours is then just =A1\*24. Worth knowing because it makes your tool the convenience it is, rather than a workaround for something Excel cannot do. On the snippet, the one I would fix first: if hours and minutes come from input elements, .value is a string, and isNaN("7") is false so the guard lets it through. Then "7" + (45/60) is string concatenation, and you get "70.75" instead of 7.75. Number(hours) + Number(minutes)/60, or reading valueAsNumber, closes it. isNaN also lets null through, since Number(null) is 0; Number.isFinite on the coerced values is a tighter guard. And for payroll specifically: hours + minutes/60 gives binary floats that do not round-trip, so 7 h 10 m becomes 7.166666666666667. Sum a month of those, multiply by an hourly rate, and you can land a cent away from what a human gets with a calculator. The usual fix is to keep everything in whole minutes as integers all the way through and convert to money once, at the end, rounding exactly once. It is invisible on one shift and it is exactly the thing an accountant notices at the end of the quarter.](https://hashnode.com/posts/why-i-built-a-lightweight-time-tracking-web-utility-to-solve-spreadsheet-math-fatigue/6aa010711c65ef23164a2d30/comment/6aa0e508df13e293aeb30fd5)

Comment · Article · Sep 9 · [Why I Built a Lightweight Time-Tracking Web Utility to Solve Spreadsheet Math Fatigue](https://hashnode.com/posts/why-i-built-a-lightweight-time-tracking-web-utility-to-solve-spreadsheet-math-fatigue/6aa010711c65ef23164a2d30)

[Clear write-up, and the SameValueZero note is the right one to flag. Three things worth adding, since they all bite in the exact cases you recommend these for: SameValueZero also collapses -0 and +0. new Set(\[0, -0\]).size is 1, and map.set(0, 'a').set(-0, 'b') leaves you with one entry. So it is not only NaN that behaves differently from ===; the zeros go the other way. "Caching by object reference" with a Map is the one recommendation that can leak. A Map holds a strong reference to its keys, so a cache keyed by DOM nodes or by objects keeps them alive forever, even after the rest of the app has dropped them. WeakMap (and WeakSet) exist for exactly that: the entry disappears when the key becomes unreachable. The trade is that a WeakMap has no .size and is not iterable, which is the point. Map and Set do not survive JSON. JSON.stringify(new Map(\[\['a', 1\]\])) gives "{}", and so does a Set. People swap an Object for a Map, hit their API layer, and the payload silently empties. \[...map\] and \[...set\] are the usual fix, with new Map(parsed) on the way back. Small one on your prototype point: if you want a dictionary without inherited keys but do not need Map, Object.create(null) gives you an object with no prototype at all. Handy when the keys come from user input and something might be called "constructor" or "proto".](https://hashnode.com/posts/map-and-set-in-javascript/6a9a4be71580b143cec70d27/comment/6a9c6fd155d805e57ac8defe)

Comment · Article · Sep 5 · 1 · [Map and Set in JavaScript: Why { } and \[ \] Aren't Always Enough](https://hashnode.com/posts/map-and-set-in-javascript/6a9a4be71580b143cec70d27)

[Good breakdown. One thing worth adding, because it catches people who use spread as a "copy" operator: {...obj} copies own enumerable properties only. The prototype is not carried over, so {...new Date()} gives you {} and {...someClassInstance} loses every method, since methods live on the prototype and not on the instance. Getters are evaluated at spread time and become plain values, and anything non-enumerable simply disappears. And on the spread-as-arguments side: Math.max(...arr) is elegant right up until arr is large. Every element becomes a real argument, so on big arrays you hit RangeError: Maximum call stack size exceeded, and the exact threshold is engine-dependent rather than specified. arr.reduce((a, b) => Math.max(a, b)) is the boring version that never blows up.](https://hashnode.com/posts/spread-and-rest-operators-in-javascript/6a9a516b17d2d5eb673a46c1/comment/6a9ad7becdeba61f2ff6fbeb)

Comment · Article · Sep 4 · 1 · [Spread vs Rest Operators in JavaScript](https://hashnode.com/posts/spread-and-rest-operators-in-javascript/6a9a516b17d2d5eb673a46c1)
