I use both in my projects, so people often ask me which one is better. My answer is that it depends on the shape of your data. I reach for PostgreSQL when: Data is highly relational (users, orders, payments, invoices) I need strict consistency and transactions I want complex queries with joins and aggregations The schema is fairly stable and I want the database to enforce it I reach for MongoDB when: Data is flexible or changes shape often (content, logs, product catalogs) I’m prototyping and want to move fast without migrations Documents are naturally nested and read together I’m working with Node.js and want JSON-like data end to end Common mistakes I see: Choosing MongoDB because it feels easier, then fighting relationships later Choosing PostgreSQL for everything without thinking about whether the data really needs that structure Picking based on hype instead of how the data will be queried Neither one is “better.” The right choice comes from your data and your queries, not from trends. And sometimes using both in one project is perfectly fine. Which one do you use most, and why? MongoDB #PostgreSQL #Database #BackendDevelopment #FullStack
Powered by Readybot.io
DEV Community
Character Swap 1.5: Motion Transfer Plus SAM 3.1 Masking, Eight Steps
Swapping a character in a video splits into two problems that people usually conflate: deciding what gets replaced, and making the replacement move the way the original did. Character Swap 1.5 handles both in one graph, with SAM 3.1 for the first and motion transfer for the second. One workflow, eight steps. What each half contributes SAM 3.1 runs the masking. Prompt-segment the subject you want to replace and it returns a per-frame mask. This is the part that used to be manual rotoscoping: a fighter turning through 180 degrees means the mask has to track limbs, hair and any held props across every frame. Motion transfer runs the replacement. The source clip's motion drives the new character. Body shape, limb timing and the general read of the movement come from the original performance. Why the mask quality decides everything The motion transfer half is actually well-behaved. The failures almost always trace back to the mask: Occlusion. A hand passing in front of the torso needs two mask regions, not one. Single-region masks ghost at the crossing. Fast motion. Between two frames with large displacement, the mask can lose the limb entirely for a frame or two. That reads as a flicker. Soft edges. Hair and loose fabric need a feathered mask. A hard-edged mask produces a visible halo. SAM 3.1 is considerably better than the previous generation at the first two. The third is still on you — feather the mask. The eight-step claim The VDN8 variant uses a distilled sampler, eight steps per frame. In practice that is the difference between a swap that renders overnight and one that renders during a coffee break. The quality cost lands where you would expect: fine fabric texture and small facial details are slightly softer than a 20-step pass. Where this is used Replacing a performer in an existing shot without a reshoot. Casting a specific character into existing motion reference. Localisation: same performance, different character per market. The last one is the commercially interesting case — one shot, several faces, no second shoot. Files HF: https://huggingface.co/AI-KSK/h3-character-swap-sam-vdn8 ModelScope: https://modelscope.cn/models/Sunjian520/h3-character-swap-sam-vdn8 Video walkthrough (Chinese): https://youtu.be/iuEmeHgHGIg Bilibili: https://www.bilibili.com/video/BV1GLnH6NEPC/ Notes Single ComfyUI workflow export; SAM 3.1 and the H3 weights must exist locally. Tutorial material, not a product. Independent AI-KSK release; not affiliated with the model authors.
Powered by Readybot.io
DEV Community
My agent could fetch a URL but could not search for one
In my September 1 setup of DeepSeek Harness v0.1.1-rc.2, web_fetch worked while web_search could not complete a search. The difference was the service behind each tool, rather than whether the agent could reach the web. This is a record of that setup, not a claim about the current release or every account. Two tools, two dependencies The default profile selected searchProvider: deepseek-official and looked for its key in DEEPSEEK_API_KEY. My fresh DeepSeek API account returned 402 Insufficient Balance. Having a key was therefore insufficient. The request reached a service that required a funded account. In the version I inspected, the three bundled search backends were DeepSeek, Exa, and Perplexity; none supplied a free search path for my setup. web_fetch still worked. Fetching an already-known public URL used anonymous HTTP, without that search-provider balance requirement. That made the failure easy to describe too broadly: “the agent cannot use the web” would have hidden the useful capability that remained. What I would check before changing the model For a similar failure, I would separate these checks: Which provider does the active profile select? A tool named web_search does not tell you which external service will receive the request. Is the credential present, and is the account usable? These are separate conditions. In this setup, the balance response was the evidence that mattered. Can the agent fetch a known URL? A successful fetch does not prove search works, but it narrows the failure to a different dependency. What capability can the task still use? Supplying a known source URL may allow a fetch-only task to proceed. It does not replace discovery when finding sources is the task. Those are diagnostic steps, not a guarantee that every 402 has the same cause. The concrete observation here was the Insufficient Balance response from my account. A backend implementation is not a working fallback I wrote a Tavily provider and plugin, and checked the interface against the installed type declarations. I had not tested it with a Tavily key. That means I had an implementation to try, not a verified alternative, and I cannot report that it fixed search. The useful result from this investigation was a smaller, more accurate description of the system: fetching worked; the configured search service required funding; the proposed replacement remained untested. For agent tooling, I would like a setup check to expose those dependencies before the first task needs them. “Tool enabled” is a much weaker statement than “the selected provider can complete a request with this account.”
Powered by Readybot.io
DEV Community
Validate Cached Cloudflare Workflow Step Output on Replay
Cloudflare Workflows persist successful step results and resume execution after the last completed step, but a later deployment that tightens an input contract can cause the system to accept stale data without re-running the callback. Quick solution: const result = await step.do("fetch-candidate", async () => {
return await fetchExternalCandidate();
});
if (!isValidCandidate(result)) {
throw new Error("Persisted workflow step result failed validation under current contract");
}
When you deploy a new version of a serverless workflow, understanding how durable persistence interacts with updated code is essential for maintaining application integrity. Developers often assume that changing a validation check inside a step callback ensures that all future runs respect the new rule. However, because Cloudflare Workflows serialize and store successful step results, a resumed workflow instance may bypass the callback entirely and return the older, unvalidated object directly from storage. This creates a hidden window where stale or malformed data slips past your newly introduced checks. The Replay Validation Problem in Serverless Workflows Cloudflare Workflows handle long-running operations by breaking execution into discrete, durable steps. According to the official Build your first Workflow guide, successful step results are persisted automatically, and execution resumes from the boundary of completed steps during subsequent events. While this architecture provides excellent fault tolerance and cost efficiency, it introduces a subtle lifecycle challenge when your validation logic evolves. Imagine you deploy a workflow that selects a candidate from an external provider. In version 1 of your script, the step returns a candidate object containing only an identifier. In version 2, you update your application code to require a strict schema including a security hash and a valid version number. If an active workflow instance completed the step under version 1 and pauses before the next action, deploying version 2 means the workflow will resume by loading the old, minimal object from durable storage. Because the step callback does not re-run, your new validation check inside the callback is never evaluated against that cached result. To prevent your system from accepting legacy payloads under a tightened contract, you must separate the durable data retrieval from the runtime validation guard. If you are looking for ways to ensure your CI/CD pipeline maintains high standards, you can Fixing SonarCloud Quality Gate Rating E to A in Production to ensure your deployments remain clean and compliant. Designing Post-Step Validation Guards To ensure that every workflow execution obeys your latest invariants, place your validation logic immediately after the step.do call returns, rather than exclusively inside the anonymous function passed to the step. This guarantees that whether the step executes fresh or replays from storage, the returned payload must pass the current runtime checks before any downstream side effects occur. Consider the following implementation pattern that evaluates the returned structure against a strict type guard: import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from "cloudflare:workers";
const candidate = rawData as CandidatePayload;
if (candidate.version < 2 || !candidate.checksum) {
throw new Error("Stale candidate payload detected during workflow replay validation");
}
await step.do("process-candidate", async () => {
return await persistCandidate(candidate);
});
}
}
As described in the Rules of...
Powered by Readybot.io
DEV Community
MiniMax H3 Video Control: Eight ControlNet 2.0 Modes, Motion Guidance and 1080P Two-Pass
ControlNet on video is a different problem than on images, because the control signal has to stay coherent frame to frame. This episode maps eight ControlNet Union 2.0 modes across four generation tasks and documents where each one holds. The four workflows # Workflow Task 01 CN Union 2.0 video control + local inpaint, VDN 12-step Guided generation 02 Audio-driven digital human, VDN 12-step Talking head 03 General video generation, VDN 12-step Baseline 04 CN Union local inpaint only Pure repaint The eight modes, ranked by usefulness on video Strong on video: Depth — the workhorse. Preserves scene geometry across a cut and survives camera movement. Canny — works for hard-edged subjects (architecture, props) and falls apart on hair and foliage. Pose — good for single-subject motion, degrades when limbs occlude each other. Conditional: Lineart — clean results but sensitive to input line quality; a wobbly line becomes a wobbly render. Normal — useful for lighting-consistent repaints, rarely used alone. Weak on video: Tile — designed for upscaling stills; on video it produces frame-to-frame texture flicker. Seg — segmentation maps jitter between frames, and the jitter transfers directly into the output. The eighth mode — same problem as seg: per-frame instability is amplified by the model. That ranking is the practical content of the episode. The modes that work on stills are not the modes that work on video, because stills have no temporal coherence requirement. The two-pass 1080P finish VDN 12-step at native resolution gives a clean base; the second pass upscales to 1080P and re-renders at low denoise. The reason to split it: a single pass at 1080P produces softer motion because the sampler spends its budget on resolution instead of on movement. Audio-driven digital human Workflow 02 is the one with the most obvious commercial use — one portrait plus one audio track, 12 steps per frame. The limitation is the same as any audio-driven approach: change the audio and you re-render, because the mouth timing is derived from it. Files HF: https://huggingface.co/AI-KSK/minimax-h3-cn2-video-control ModelScope: https://modelscope.cn/models/Sunjian520/minimax-h3-cn2-video-control Video walkthrough (Chinese): https://youtu.be/WdAaPq2Xa0I Bilibili: https://www.bilibili.com/video/BV1SEJm6PE22/ Notes ComfyUI workflow exports; the H3 weights and CN Union 2.0 adapter must exist locally. Tutorial material, not a product. Independent AI-KSK release; not affiliated with the model authors.
Powered by Readybot.io
DEV Community
Overcoming Partisan Bias and Trust Barriers in Real-Time AI Political Fact-Checking
System Architecture and Verification Mechanics The LogicLens and Receipts platform operates through an automated real-time processing pipeline designed to ingest streaming audio or document Object Model (DOM) data, extract verifiable claims, and synthesize grounded verdicts via Retrieval-Augmented Generation (RAG). By coupling deterministic parsing with stochastic language modeling, the system attempts to operationalize real-time epistemic accountability during live media consumption. Data Ingestion: Browser extension content scripts and mobile app wrappers extract live speech transcripts from streaming video elements or raw text claims from active web pages, establishing the foundational data pipeline without altering native media rendering. Claim Segmentation: A filtering module isolates verifiable factual assertions from subjective rhetoric, filler speech, and opinions prior to downstream execution, ensuring that compute resources are reserved strictly for falsifiable statements. Evidence Retrieval: The pipeline executes live web search queries to fetch primary and secondary source documents, anchoring the verification context before passing inputs to the language model (Claude) to mitigate hallucination risks and enforce rigorous grounding. Overlay Injection: Asynchronous UI scripts inject confidence scores, truth verdicts, and clickable citations directly into the active viewport without blocking media playback or scrolling threads, minimizing user friction during high-frequency data streams. The Demonstration Artifact and Temporal Decoupling Public distribution of the tool relies on recorded video artifacts as primary product proofs. When an uncalibrated or truncated screen recording is deployed without full execution context, systemic verification logic breaks down at the observational interface, illustrating how human-AI trust dynamics can be fractured by poor communicative framing. Impact: Pressured by a two-year development cycle and active competitor traction, the developer published an unedited screen capture, trading methodological transparency for speed-to-market visibility. Internal Process: The recording window initiated mid-stream, capturing a factual verification instance directed at one political figure while omitting the preceding counter-example segment where an opposing figure's claim was evaluated. Observable Effect: Viewers observed an asymmetric distribution of negative verdicts, triggering immediate user rejection driven by perceived partisan manipulation and a collapse of perceived epistemic neutrality—proving that advanced architectural safeguards can be instantly neutralized by a single compromised demonstration artifact. Structural Instabilities and Friction Vectors Beyond the immediate optics of its public demonstration, the platform exhibits high vulnerability across several operational, economic, and architectural dimensions that threaten its long-term viability as a mainstream civic utility: Vector Mechanistic Failure Mode Epistemic Recursion Users reject LLM-synthesized verdicts due to opaque source-weighting heuristics and inherent model hallucination risks, raising the unsolved verification problem: Who fact-checks the fact-checker? This dynamic generates a recursive loop of systemic skepticism. Unit Economics Continuous real-time LLM inference and live search API calls scale linearly with user watch-time, directly conflicting with a free consumer distribution model and creating structural unsustainability that can only be resolved through monetization shifts or cost-prohibitive subsidies. Permission Boundaries Browsers require broad host permissions (read/modify all site data) to parse arbitrary DOM structures, triggering immediate user threat-modeling friction regarding telemetry, data privacy, and potential surveillance overreach. Temporal Desynchronization Continuous real-time pop-up alerts compete for user attention during fast-paced video consumption, inducing split-attention fati...
Powered by Readybot.io
DEV Community
.NET 11 Unpacked: Why I'm Recommending STS This Time
Table of Contents What to Expect From This Article A Short History of LTS and STS Why There Are Two Tracks at All? Why Microsoft Extended STS to 24 Months? The Catch: The Same End Date Why .NET 11 Might Be the Better Migration Target Right Now "But It's Not Battle Tested Yet" When .NET 10 Is Still the Right Call What I'd Recommend, by Situation A Pre-Upgrade Checklist Wrapping Up What to Expect From This Article For years, my advice on .NET upgrades was simple: plan around LTS releases. Skip the STS ones unless you have a very good reason. This November, that advice is not as strong as before. .NET 10 (LTS) and .NET 11 (STS) both reach end of support on November 14, 2028. Same day. One of them is a year newer. In this first article of the .NET 11 Unpacked series, I'll walk through where LTS and STS came from, why the two tracks exist, and why, for a lot of teams right now, .NET 11 may be the better upgrade target. I'll also cover when it isn't. A Short History of LTS and STS The two-track model is almost as old as .NET Core itself, which has been around since 2016. But the rules have changed several times. When What changed Nov 2026 .NET 11 ships as STS with 2 years of support, ending on the same day as .NET 10 LTS Sep 2025 STS support is extended from 18 to 24 months, starting with .NET 9 2020 to 2022 .NET 5 drops "Core" from the name, the non-LTS track gets 18 months, and it's renamed from "Current" to "Standard Term Support" 2019 Microsoft commits to a new major version every November: even numbers are LTS, odd numbers are not 2016 .NET Core 1.0 defines two release types: LTS and "Current" A few things stand out. STS never meant "Short." The official name is Standard Term Support, and Microsoft's policy page still notes that STS releases were previously known as Current releases. Most of us (me included) read the "S" as "Short" for years. That small misreading did a lot of damage to how people see these releases. STS support has only ever grown. It went from "a few months after the next release" to 18 months, and now to 24. So I guess "standard" is even more suitable wording here. By the way, LTS has stayed at three years the whole time. It hasn't changed. The 2025 change is the one that matters here. Under the old rule, an STS release was supported for 6 months after its successor shipped. Under the new rule, it's 12 months. That one change lines up the end date of every STS release with the LTS release before it. Why There Are Two Tracks at All? The two tracks serve two kinds of teams. LTS is for teams that want to upgrade as rarely as possible. STS is for teams that want new features and performance gains every single year. What the tracks don't differ in is quality standards. The .NET release policies say LTS and STS releases differ only by support duration, and that the team uses the same engineering and release processes for both, including for security, compatibility and reliability. The support policy page puts it even more plainly: the quality of all releases is the same. So an STS release isn't a beta, a preview or a "test" version of the next LTS. STS is a completely different concept. It's a full production release with a shorter warranty. Why Microsoft Extended STS to 24 Months? The 2025 extension wasn't really about STS users. It fixed a problem for LTS users (me included). More and more of .NET now ships out of band, outside the yearly release: .NET Aspire, Microsoft.Extensions.AI and the C# Dev Kit, for example. Those components sometimes need package versions from the newest yearly release. So a team that thought it was fully on LTS could pull in a few STS packages without noticing. Under the 18-month rule, those packages lost support six months before the LTS runtime they ran on. Moving STS to 24 months closed that gap: the STS packages now stay supported exactly as long as the LTS release before them. The side effect is the one this article is about. Every STS release now retires on the same day as th...
Powered by Readybot.io
DEV Community
Show your unread Mail count in your Mac menu bar
This guide first appeared on multimeterapp.com. Multimeter is a Mac menu bar app that turns any number into a live meter. Mail’s Dock badge is easy to miss when the Dock is hidden, and Mail’s window is usually behind everything else. A Script meter asks Mail with AppleScript how many messages in the Inbox are unread and puts the number next to the clock. What you need Multimeter for macOS 13 or later, $19.99 once. The direct download version of Multimeter from this site (the Script source isn’t in the Mac App Store version). Multimeter 1.1.1 or later. Earlier versions can’t ask macOS for permission to talk to other apps. Choose Check for Updates… from any meter’s menu. Apple Mail with at least one account set up. Set it up Here’s the command. It asks Mail for the unread count of the Inbox, the one at the top of Mail’s sidebar that combines your accounts, and prints a placeholder when Mail isn’t running: osascript -e 'if application "Mail" is running then' -e 'tell application "Mail" to return unread count of inbox' -e 'else' -e 'return "{\"value\": 0, \"formatted\": \"closed\"}"' -e 'end if'
In Multimeter, choose Add Meter… from any meter’s menu, pick Script and paste the command. Set Refresh every to 1 minute. Mail answers in well under a second, but there’s no reason to ask it more often, and 5 minutes is fine for a quieter inbox. Set the label to MAIL, the range to 0 to 50, and alerts to High values with a warning at 10 and critical at 25 if you want the number to change color as mail piles up. With Mail open, wait for the first refresh. macOS asks once: “Multimeter” wants access to control “Mail”. Allowing control will provide access to documents and data in “Mail”, and to perform actions within that app. Below it is Multimeter’s reason: “Multimeter runs your script meters, and scripts that read other apps (like Things, Reminders, Mail or Music) need your permission to control them.” Click Allow. Until you do, the meter shows a dash; the number appears at the next refresh, or right away with Refresh Now in the meter’s menu. Multimeter settings In Customize This Meter… (from the meter’s menu): Settings for this meter Setting Value Source Script Command the osascript line above Refresh every 1 minute or slower Range 0 to 50 Alerts High values: warning 10, critical 25 (optional) Label MAIL Face Label & Value or LCD Readout Width 120 pt for Label & Value Tested: Set up on October 31, 2026 in Multimeter 1.1.1 on macOS 27, with one test mail account holding 7 unread messages. macOS showed the Automation prompt with Multimeter’s reason at the first refresh; after Allow the menu bar showed MAIL 7 in Label & Value and LCD Readout. After 2 messages were marked read it showed MAIL 5 at the next refresh. With Mail quit, both meters showed closed and Mail stayed closed for the next two refreshes; reopening Mail brought back MAIL 5. The command took about half a second when run in Terminal. Script meters need the direct download version of Multimeter from this site, which is the one on sale now. How commands run, the PATH they see and the 10 second limit are in the Script meters guide. Limits Mail must be open. That’s on purpose: asking a closed Mail would launch it. The count is the Inbox only. Unread mail that rules moved to other mailboxes isn’t included; see the variation below for one mailbox. If Mail is set to show Categories, its Dock badge can count Primary only. This meter counts every unread message in the Inbox. Variations One account’s inbox Replace inbox with the account’s mailbox. The account name is the one in Mail’s sidebar: Command osascript -e 'if application "Mail" is running then' -e 'tell application "Mail" to return unread count of mailbox "INBOX" of account "Work"' -e 'end if'
Notify me when mail arrives Set alerts to High values with a critical level of 1 and turn on Notify me when it goes critical. Multimeter waits 15 minutes between notifications for the same meter, so a busy inbox won’t keep pinging y...
Powered by Readybot.io
DEV Community
Marketplace Ingestion: Chunk Boundaries for Low-Latency, Traceable Tutor Retrieval
Short answer: use a staged retrieval design with explicit collections, bounded queries, and source context that survives every handoff from marketplace document ingestion to the online course tutor's answer. Alert on contract failures before users report vague or uncited answers. The page says the tutor returned an answer without usable source context. On-call can see the affected collection, tenant, access decision, query duration, and the identifiers of the retrieved chunks. The ingestion job itself completed, so restarting it would be guesswork and could produce duplicate work. Don't retry blind. The signal that should have fired earlier is a stage-level contract violation: an indexed item without tenant or access-control metadata, a bounded query with no traceable source context, or a representative failure case whose expected source no longer appears. I've been paged by missed jobs and duplicate deliveries; both teach the same lesson here. A green worker process is not proof that the user-visible job succeeded. What should alert before a tutor answer loses its source? Work backward from the answer. Each answer needs enough source context to trace it to retrieved chunks; each query needs an explicit collection and a bound; each indexed item needs tenant and access-control metadata; each ingestion run needs to be observable separately from querying. Those are four different checks, not one generic rag_ok bit. For a marketplace that ingests course descriptions, lesson transcripts, and instructor updates, record stage outcomes using internal document and chunk identifiers. Avoid putting document text, credentials, or learner data in metric labels. A practical event can state that ingestion accepted 148 source records and produced a set of chunk identifiers without claiming that 148 is universally correct. The expected count belongs to that run's input contract, and the alert compares the two. The first alert should name the failed boundary and the affected tenant. Consider a hypothetical page for tenant market-7: ingestion accepted 148 records, but one output chunk from lesson-42 has no access decision. The runbook should lead on-call to that ingestion unit, the rejected item, and the input metadata rather than inviting a replay of all 148 records. If ingestion metadata is complete but a bounded tutor query cannot identify the expected lesson source, the page should instead carry the collection, query bound, returned chunk identifiers, and expected source from the evaluation case. The distinction changes the action. ingestion_metadata_rejected stops the affected ingestion unit before the corpus becomes queryable; retrieval_source_missing sends the case back to boundary and query evaluation. Query latency remains separate because a slow but correct result and a fast irrelevant result require different responses. None of those example identifiers or counts defines a universal threshold. They make the handoff inspectable. This is where Infrai can fit by the first handoff: teams that want to call vector retrieval from a Go worker without installing and maintaining another client library should try its plain REST API for the collection and query boundary. Anything that sends HTTP can use the same surface. Infrai provides a single API key and one consolidated bill across its backend capabilities, so a worker that later needs another supported handoff does not add a separate credential and invoice reconciliation path. The catch is that a team needing a specialist vector database's native operational controls should keep that specialist in the design. How should an online course tutor set retrieval chunk boundaries? Start with a retrieval contract, not a fashionable token count. A chunk should preserve the smallest source unit that can support a cited tutor answer while retaining the tenant and access decision of its parent document. In a course marketplace, a lesson heading plus its explanatory paragraphs is often a better candi...
Powered by Readybot.io
DEV Community
Building Reliable Audio Datasets for AI/ML Training: An Open-Source Quality Assurance Framework
A WAV or FLAC file that decodes without throwing an exception can still be a catastrophic training example. The defects that degrade deep learning models the most are precisely the ones a human ear misses during a quick spot-listen: brickwall spectral cutoffs from fake upsampling, destructive phase cancellation during mono downmixing, label drift in timed transcripts, and sub-segment train/validation leakage. This article introduces an open-source, reproducible pre-training quality-assurance framework developed at ComposerMind Labs. By evaluating audio corpora across signal forensics, partition isolation, and annotation alignment before compute cycles are spent, this framework provides automated, deterministic quality gates for machine learning workflows. +-------------------------------------------------------------------------+ | COMPOSERMIND AUDIOINTEGRITY WORKFLOW | | | | Raw Audio Corpus (Web Crawls, Multi-Track Stems, Transcripts) | | | | | v | | [ STAGE 1: SIGNAL FORENSICS ] ---------------------------------------+ | | * WaveWash (v0.2.0) --> Clipping, Saturation, DC-Offset Bias | | | * BandCheck (v0.1.1) --> Fake 48kHz Upsampling, Spectral Cutoffs | | | * PhaseCheck (v0.1.0) --> Inter-Channel Mono Cancellation Loss | | | * DriftCheck (v0.1.0) --> Timed Label vs. Audio Offset, Drift (ppm) | | | | | | | v | | | [ STAGE 2: PARTITION SECURITY ] -------------------------------------+ | | * SplitSafe (v0.1.1) --> Acoustic Fingerprint Leakage Firewall | | | | | | | v | | | [ STAGE 3: ANNOTATION INTEGRITY ] -----------------------------------+ | | * TonicFind (v0.1.0) --> 12D Chromagram vs. Musical Key Profiles | | | * TempoCheck (v0.1.0) --> Onset Envelope vs. BPM Octave Ambiguity | | | | | | | v | | | Verified Audit Manifest --> Triage & Review --> PyTorch / HF Loader | +-------------------------------------------------------------------------+ ————————————————————————————————————————————— Why Audio Datasets Require Pre-Training Audits In natural language processing and computer vision, automated deduplication, normalization, and syntax validation are standard pre-requisites. In audio machine learning, however, ingestion pipelines often verify only that soundfile.read() or torchaudio.load() successfully loads an array. This surface-level validation permits silent, high-impact failure modes to contaminate training corpora: Failure Mode A: Sub-Segment Validation Leakage Consider a recording placed in the training partition, while a slightly trimmed (e.g., 50 ms offset), gain-adjusted, or re-encoded copy sits in the validation partition. Standard hash-based deduplication (MD5/SHA-256) fails completely because compression framing and trimming alter bit-level signatures. The model memorizes the underlying acoustic features, validation loss can plummet deceptively, and the model subsequently underperforms on genuine out-of-distribution audio. Original Audio (Train Set): =================================== Trimmed Copy (Validation Set): ============================= Result: File-level hashing misses the duplicate -> Silent cross-split contamination occurs. Failure Mode B: Destructive Mono Downmixing Many speech and audio pipelines downmix stereo inputs to mono (M = (L + R) / 2) prior to computing mel-spectrograms or feeding audio into acoustic backbones. When a stereo stem or recording contains inverted channel polarity (R ≈ -L) due to microphone miswiring or stereo widening effects: M = (L + (-L)) / (2) ≈ 0 The waveform collapses toward digital silence. Even with partial phase cancellation, destructive interference selectively notches out specific frequency bands, training neural models on acoustically corrupted spectra. Left Channel (L): /\ /\ /\ /\ (Active audio signal) Right Channel (-L): \/ \/ \/ \/ (Inverted polarity) ------------------- Mono Sum (L + R): ------------------- (CANCELLATION: near-total signal null) Failure Mode C: Codec Cutoffs in High-Sample-Rate Containers Web-crawled audio is frequently transcoded from l...
Powered by Readybot.io
DEV Community
Python 3 Standard Library Socket Programming Cookbook: TCP, UDP, select.select(), struct Packing, and Checksums
A zero-dependency cookbook for beginners. Everything below uses only the Python 3 standard library (socket, select, struct, hashlib, zlib, json, sys), flat procedural code, no asyncio, threads, or classes. Every script prints connections, messages and state changes so you can watch the protocol work. Run servers and clients in separate terminal tabs with python3 script.py . Part 1: Core Concepts & Standard Library Rules What a Socket Is: An Operating System endpoint that sends and receives raw bytes over a network. IP vs. Port: The IP address ('localhost' or '127.0.0.1') identifies the machine; the Port (an integer like 10000) identifies the specific Python process. Networks Only Speak Bytes (b"..."): Convert str to bytes before sending with .encode(), and convert received bytes back to str with .decode(). TCP (SOCK_STREAM) vs. UDP (SOCK_DGRAM): TCP is connection-oriented (bind -> listen -> accept on server; connect -> sendall -> recv on client). UDP is connectionless (sendto and recvfrom). A UDP server uses a single socket for all clients and never uses select.select(). Socket Port Reuse (SO_REUSEADDR): Always add server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) before bind() on TCP servers and proxies to avoid Address already in use errors when restarting. Binary Struct Packing (struct.Struct): Format codes: i (4-byte int), I (4-byte unsigned int), f (4-byte float), ? (1-byte bool), c or 1s (1-byte char as bytes), Xs like 7s (X-byte string as bytes). C Alignment Padding Rule: Never count bytes manually ('c i' is 8 bytes due to 3 padding bytes; 'i c' is 5 bytes; 'i i c' is 9 bytes; 'I I 1s' is 12 bytes; '7s6s' is 13 bytes). Always pass packer.size to recv(packer.size). Null-Byte Padding Rule: Packing a shorter string like b"FAIL" into a 7s field pads the trailing bytes with null bytes (b"FAIL\x00\x00\x00"). Always strip null bytes after unpacking: status = status_bytes.decode().strip('\x00'). Part 2: Essential Building Blocks import sys, struct, json, hashlib, zlib
ip = sys.argv[1]
port = int(sys.argv[2])
filename = sys.argv[3]
2. Struct Packing & Unpacking
packer = struct.Struct('i i 1s')
packed_bytes = packer.pack(10, 25, b'+')
a, b, raw_op = packer.unpack(packed_bytes)
op = raw_op.decode().strip('\x00')
3. Delimiter-Separated Payloads (':', ';', '|')
numbers = [3, 7, 12, 18, 20]
bet = 500
msg_bytes = (":".join(str(x) for x in numbers) + f":{bet}").encode()
parts = [int(x) for x in msg_bytes.decode().split(":")]
recv_nums, recv_bet = parts[:-1], parts[-1]
4. Reading Text, JSON, and Binary Files
with open("input.json", "r") as f:
data = json.load(f)
ip, port = sys.argv[1], int(sys.argv[2])
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((ip, port))
server.listen(5)
print(f"TCP Server listening on {ip}:{port}")
while True:
conn, addr = server.accept()
with conn:
print(f"Connected by {addr}")
data = conn.recv(1024)
if data:
print("Received:", data.decode())
conn.sendall(b"Hello client")
# --- tcp_client.py ---
import socket, sys
ip, port = sys.argv[1], int(sys.argv[2])
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
client.connect((ip, port))
client.sendall(b"Hello server")
print("Server replied:", client.recv(1024).decode())
Template 2: Multi-Client TCP Server with select.select() # --- select_tcp_server.py ---
import socket, select, sys
ip, port = sys.argv[1], int(sys.argv[2])
server = socket.socket(socket.AF_INET, socke...
Powered by Readybot.io
DEV Community
Unsubscribe'ı doğru kurmak: Tek tık çıkış, suppression listesi, kanal bazlı izin ve gönderim öncesi kontrol
Bir pazarlama otomasyonu projesinde en az konuşulan ama en çok sorun çıkaran parça, "abonelikten çık" bağlantısıdır. Kampanya akışları, segmentler, şablonlar ve raporlar uzun uzun tartışılır; çıkış ise e-posta altbilgisine konan küçük bir link olarak görülür. Sonra bir gün müşteri, aylar önce çıktığı listeden hâlâ mesaj aldığını söyleyerek şikâyet eder. İncelendiğinde çıkışın bir araçta kaydedildiği, ama CRM'den gelen bir yeniden senkronun kişiyi listeye geri eklediği ortaya çıkar. Ben Koray Yalçın; lead yönetimi, CRM ve pazarlama otomasyonu altyapıları kuruyorum, ağırlıklı olarak gayrimenkul ve PropTech tarafında. Bu yazıda unsubscribe konusunu hukuk metni olarak değil, bir yazılım tasarımı problemi olarak ele alacağım: çıkış olayı nasıl modellenir, tek tık çıkış nasıl uygulanır, suppression listesi neden ayrı bir tablo olmalıdır, kanal bazlı izinler nasıl tutulur ve her gönderimden önce hangi kontrol mutlaka çalışmalıdır. Not: Bu yazı teknik bir tasarım rehberidir, hukuki görüş değildir. KVKK, ticari ileti mevzuatı ve İYS yükümlülükleri için hukuk danışmanınızla çalışın. Unsubscribe bir alan değil, bir olaydır En yaygın hata, kişi tablosuna is_subscribed boolean gibi tek bir alan eklemektir. Bu alan üç soruyu cevaplayamaz: Kişi ne zaman çıktı? Hangi kanaldan ve hangi listeden çıktı? Bu bilgiyi hangi sistem yazdı? Daha kötüsü, tek bir boolean her senkronda üzerine yazılabilir. Dış sistemden true gelirse, kişinin kendi iradesiyle yaptığı çıkış sessizce silinir. Bu yüzden çıkışı bir olay olarak, yalnızca eklenen (append-only) bir tabloda tutuyorum. Güncel durum bu olaylardan türetilir. CREATE TABLE consent_event (
id bigserial PRIMARY KEY,
contact_id bigint NOT NULL REFERENCES contact(id),
channel text NOT NULL CHECK (channel IN ('email','sms','whatsapp','call')),
topic text NOT NULL DEFAULT 'all', -- 'newsletter', 'launch', 'all' ...
action text NOT NULL CHECK (action IN ('opt_in','opt_out')),
source text NOT NULL, -- 'one_click', 'preference_center', 'reply_stop', 'agent', 'import'
evidence jsonb NOT NULL DEFAULT '{}', -- ip, user_agent, message_id, kayıt formu sürümü
occurred_at timestamptz NOT NULL DEFAULT now(),
recorded_by text NOT NULL -- servis veya kullanıcı kimliği
);
CREATE INDEX ON consent_event (contact_id, channel, topic, occurred_at DESC);
Burada iki ayrıntı önemli. Birincisi topic: kişi lansman duyurularından çıkıp aylık bültende kalmak isteyebilir. Tek bir "çık" butonu her şeyi kapatıyorsa insanlar ya hepsinden çıkar ya da spam olarak işaretler; ikisi de sizin için kötüdür. İkincisi evidence: bir gün "bu kişi izin vermiş miydi, ne zaman çıktı?" diye sorulduğunda cevabın kanıtıyla birlikte veritabanında olması gerekir. Güncel durumu türetmek Olay tablosundan güncel izni okumak için her kanal ve konu için son olayı almak yeterlidir. Kanal genelindeki all çıkışı, konu bazlı her izni ezmelidir. CREATE VIEW consent_state AS
SELECT DISTINCT ON (contact_id, channel, topic)
contact_id, channel, topic, action, occurred_at, source
FROM consent_event
ORDER BY contact_id, channel, topic, occurred_at DESC, id DESC;
Belirli bir konuda gönderim izni var mı?
CREATE FUNCTION can_send(p_contact bigint, p_channel text, p_topic text)
RETURNS boolean LANGUAGE sql STABLE AS $$
SELECT
NOT EXISTS ( -- kanal genelinde çıkış var mı?
SELECT 1 FROM consent_state
WHERE contact_id = p_contact AND channel = p_channel
AND topic = 'all' AND action = 'opt_out')
AND EXISTS ( -- bu konu için açık izin var mı?
SELECT 1 FROM consent_state
WHERE contact_id = p_contact AND channel = p_channel
AND topic IN (p_topic, 'all') AND action = 'opt_in')
AND NOT EXISTS ( -- bu konu için çıkış var mı?
SELECT 1 FROM consent_state
WHERE contact_id = p_contact AND chann...
Powered by Readybot.io
DEV Community
Monitoring Perpetual Futures Liquidation Risk in Python: Mark Price, Margin State, and Data Freshness
Disclosure: AI assistance was used in preparing this technical article. The code is an illustrative monitoring example, not a production liquidation engine or a live exchange integration. A derivatives trading system can receive three different prices for the same contract: Last traded price. Index price. Mark price. All three may be valid, but they are not interchangeable. A common engineering mistake is to use the last traded price for every downstream calculation, including unrealized profit and loss, margin monitoring, stop-loss simulation, and liquidation-risk estimation. That can produce incorrect risk states. This article develops a minimal monitoring approach that preserves the meanings of different price fields and treats the exchange's account-level margin data as separate inputs. 1. Define the failure scenario Consider a hypothetical BTCUSDT perpetual long position. Field Value Last price 100,100 Index price 99,900 Mark price 99,850 Estimated liquidation level 99,900 The last traded price remains above the estimated liquidation level. The mark price is below it. For a contract whose liquidation risk depends on the mark price and applicable maintenance margin requirements, those values describe different potential risk conclusions. The correct engineering response is not to assume that the last-price chart is wrong. It is to identify which field the exchange uses for each function and which account conditions are needed to evaluate the position. 2. Maintain separate market and account data A reliable risk snapshot should contain at least: Market data Instrument and exchange identifiers. Last traded price. Index price. Mark price. Source event timestamps. Local receipt timestamps. Position data Contract type and size. Entry or average position cost. Margin mode. Funding-related adjustments. Applicable maintenance margin tier. Account data Margin balance or equivalent risk-account equity. Maintenance margin requirement. Exchange-reported risk ratio. Relevant restrictions and pending orders. Not every account mode provides a meaningful single liquidation price. For example, cross-margin arrangements may depend on other positions and collateral in the same account. The implementation should therefore prefer official account-level risk fields where available. A locally estimated liquidation level can be retained as a diagnostic, but it should not override the exchange's actual account state. 3. Build a small monitoring function The following Python example distinguishes the prices, checks data freshness, and compares illustrative margin-account values. It does not attempt to reproduce Binance, Bybit, or OKX liquidation formulas. from dataclasses import dataclass
from datetime import datetime, timezone, timedelta
import math
if not all(math.isfinite(v) for v in values):
raise ValueError("Non-finite numerical input.")
if min(
snapshot.last_price,
snapshot.index_price,
snapshot.mark_price
) <= 0:
raise ValueError("Prices must be positive.")
if snapshot.maintenance_margin < 0:
raise ValueError("Invalid maintenance margin.")
if snapshot.mark_timestamp.tzinfo is None:
raise ValueError("Timestamp must be timezone-aware.")
if observed_at.tzinfo is None:
raise ValueError("Observation time must be timezone-aware.")
age = observed_at - snapshot.mark_timestamp
if age < timedelta(seconds=0) or age > timedelta(
seconds=max_age_seconds
):
return {
"s...
Powered by Readybot.io
DEV Community
The Quarterly Tax Rhythm That Stops April From Hurting
April does not hurt because taxes are complicated. It hurts because the money is already gone. If you drive for a gig platform, no employer withholds tax from your payouts. The gross amount that hits your account looks like income. It is not. Fuel, wear, and miles come out of it first, and the tax on what is left is still due — usually in quarterly installments, long before April. The fix is not a better spreadsheet in April. It is a quarterly rhythm: measure true profit, set aside tax from that true profit, and pay it on time, four times a year. Start with true profit, not gross A shift's gross pay tells you what a platform paid you. It does not tell you what you kept. Here is a SAMPLE calculation, labeled as a sample so you can see the shape of the math — these are illustrative numbers, not a real shift: Gross pay: $96.40 Time worked: 4.5 hours Miles driven: 71 miles Mileage cost at $0.70 per mile: 71 x $0.70 = $49.70 True profit: $96.40 - $49.70 = $46.70 True hourly rate: $46.70 / 4.5 hours = $10.38 per hour Wait — check that: $96.40 minus $49.70 is $46.70, and $46.70 divided by 4.5 is $10.38 per hour. The gross hourly rate looked like $21.42 per hour. The true rate was less than half of that. That gap is the whole point. If you set aside tax as a share of gross pay, you will over-save on a bad shift and under-save on a good one. If you set aside tax as a share of true profit — gross minus mileage priced at a per-mile rate — the set-aside tracks what you actually kept. Your mileage rate may differ. In the United States, many drivers use the IRS standard mileage rate for the year; drivers elsewhere can use their own country's rate, or a per-mile cost they can support. Pick a rate, write it down, and use it consistently. The quarterly rhythm In the United States, gig income is generally handled with quarterly estimated tax payments, using Form 1040-ES. The IRS generally expects estimated tax if you expect to owe $1,000 or more in tax for the year after withholding and credits. Paying in equal quarterly installments under the safe harbor rules — in general, paying at least as much as you owed last year, on time — can help you avoid an underpayment penalty. Check the current IRS rules for your situation, because the details depend on your total income, filing status, and prior-year tax. A simple rhythm that works for many drivers: At the end of each shift, log gross pay, hours, and miles. Price the miles, subtract them from gross, and record true profit and true dollars per hour. At the end of each week or month, total your true profit. Set aside a share of that true profit for tax in a separate account, as soon as the money arrives — not at quarter-end. Pay the quarterly estimated amount by the quarterly due date, and keep the confirmation. Quarterly payments spread the bill across the year. April then becomes a reconciliation — what you already paid against what you actually owed — instead of a single, unexpected lump sum. This is general information, not tax advice. If your situation is complicated, talk to a tax professional. Your mileage log is the backing Mileage is usually the largest deduction for a driver, and it is also the one the IRS most often asks about. A log written down at the time — contemporaneous, in plain language — is far stronger than a total reconstructed months later. For each shift, record the date, the miles, the hours, and the gross pay. Keep the platform's payout record alongside it. If you use a different car, a different rate, or a trip that was partly personal, note that too. The log does not need to be fancy. It needs to be made when the driving happened, and it needs to add up. That same log is what makes the quarterly math honest. Without miles, you cannot get to true profit. Without true profit, any tax set-aside is a guess. What I built, and what it does not do Full disclosure: I built GigLedger, a true-profit tracker for gig drivers. You log gross pay, hours, and miles for each shift; i...
Powered by Readybot.io
DEV Community
What Is OTP SMS? How Mobile Verification Works
An OTP SMS is a text message carrying a one-time password: a short random code that works once and expires within minutes. Mobile verification uses that code to show that someone controls a phone number right now. It proves access to the number, not who the person is. This guide follows one code from your server to a handset, works out how many digits and tries you can safely allow, and explains why OTPs fail before they reach the handset. It ends with a decision map for choosing a channel and a checklist for choosing an OTP SMS service. Note: Key takeaways An OTP SMS shows control of a number at one moment. It does not establish identity, so don't treat it as KYC. Your server makes the security decisions when you run verification yourself. It generates the code, limits the tries, and judges the answer, while the network only carries the text. An OTP can fail well before the handset. Missing sender registration, template drift, the wrong category, or an unlisted URL can each stop a message. SMS is the reach option, not the strongest one. Keep it for coverage, and offer a passkey or authenticator app where the risk justifies the enrolment. What does OTP mean in an SMS? OTP stands for one-time password, also written as one-time passcode. TRAI's regulations define it as an automatically generated random number that authenticates a user's action for one transaction or session. In practice, the SMS reads something like this: Your Acme login code is 123456. It expires in 10 minutes. Do not share it with anyone. The word "password" misleads. You never choose this code or memorise it, and it has no value once used. Not every OTP is made the same way The name covers three different mechanisms, and many explainers blur them. HOTP and TOTP are the two standard algorithms, and a texted code usually works differently from both. NIST treats a texted code as an out-of-band secret rather than an OTP authenticator, and the distinction changes your threat model. Type Where the code comes from Shared in advance Travels over the network SMS OTP Your server draws a random value for this one request Only the phone number Yes, in the SMS HOTP (RFC 4226) Secret key plus a moving counter A secret key No TOTP (RFC 6238) Secret key plus the current time, with a default 30-second step A secret key No So the 30-second countdown belongs to authenticator apps. An SMS code lives as long as your server allows. What does mobile verification actually prove? Mobile verification proves that whoever typed the code could read a message sent to that number within your time limit. That is useful, and it is narrower than people assume. It says nothing about the person's legal name, and a number can move to a new SIM or a new owner. Match the check to the question you are really asking: Your question Is SMS OTP enough? What to add Is this a working number the user can reach? Usually yes Format it in E.164 first Is this the same person who owns the account? Only for lower-risk accounts A password, passkey, or device check Did the customer approve this payment? One factor at most A second factor, as RBI's rules require Is this person who they claim to be? No A KYC process with identity evidence If you're in India, there is also a government route for the first question. The 2025 telecom cyber security amendment created a Mobile Number Validation platform that checks an identifier against operator subscriber records. Entities may be directed to use it or may seek permission. MediaNama reports that the final rules left fees to DoT's portal. We could not confirm a public launch date, so treat it as something to watch. How does one OTP travel from request to approval? Eight steps cross three parties. The two highlighted steps are where you win or lose on security. At step 2, generate and store carefully. Draw the code from a cryptographically secure random generator. Don't keep codes in plaintext. Store a keyed hash with the expiry and try count. Use a server-side secret...
Powered by Readybot.io
DEV Community
Beyond RPO/RTO: The Three Business Decisions that Anchor Disaster Recovery Success
This article was originally published on FutureStack Introduction When a cloud‑native organization talks about disaster recovery (DR) it often defaults to the familiar metrics—RPO (Recovery Point Objective) and RTO (Recovery Time Objective). Those numbers are useful, but they are only the surface tension of a far more intricate system of business intent, data semantics, and dependency topology. In the AWS blog post Three business decisions that define your DR success, the authors argue that before you even pick a DR pattern (pilot light, warm standby, multi‑region active‑active, etc.) you must answer three fundamental questions: What exactly are you recovering? – Not just “databases” but the state of services, configuration, and even operational knowledge. What does the business need from that recovery? – Do you need full functional parity, or is a degraded‑service window acceptable? What do your dependencies allow you to commit to? – Network latency, cross‑region bandwidth caps, licensing, and third‑party SLAs shape what you can realistically promise. In this article we unpack those decisions from a systems‑engineering perspective, dive into the underlying compute and memory models, and then step into the FutureStack viewpoint—how we translate these abstractions into concrete, cost‑effective architectures that scale. Deep Architectural Breakdown 1. The Recovery Object Model At the heart of any DR system is the recovery object—the minimal unit that, when reconstructed, brings a service back to a usable state. In practice, this object is a composite of: Layer Artifact Typical Size Persistence Mechanism Data Transaction logs, snapshots, object store versions GB–PB Multi‑AZ EBS, S3 Versioning, DynamoDB Streams State In‑memory caches, session stores, feature‑flags MB–GB Elasticache replication groups, DynamoDB Global Tables Configuration IaC templates, secrets, environment variables KB–MB CloudFormation stacks, Parameter Store, Secrets Manager Operational Knowledge Runbooks, health‑check scripts, CI/CD pipelines Text/JSON CodeCommit, S3, GitOps repos The memory model of each layer differs. Persistent data lives on durable block storage with eventual consistency (S3) or strong consistency (DynamoDB). In‑memory caches are volatile; they must be re‑hydrated from a source of truth (e.g., a snapshot of the cache or a replay of change logs). The latency to reconstruct each layer is a function of: Snapshot size (bytes transferred) Network bandwidth (Gbps between source and target region) Compute provisioning latency (time to spin up EC2 or Fargate tasks) Cold‑start penalties (container image pull, Lambda init) Mathematically, the total recovery latency (L) can be approximated as: L = Σ_i (S_i / B_i) + Σ_j C_j + Σ_k λ_k
where (S_i) is the size of artifact i, (B_i) the effective bandwidth, (C_j) the compute spin‑up time for component j, and (λ_k) the cold‑start latency for language runtimes or managed services. 2. Dependency Graph & Critical Path Analysis A DR plan is essentially a directed acyclic graph (DAG) of service dependencies. Nodes represent micro‑services, data stores, or external SaaS APIs; edges encode request/response or data‑flow relationships. The critical path is the longest weighted path through the DAG, where weight is the expected latency to bring each node online. Critical Path = max_{paths p} Σ_{node n ∈ p} (spin_up_n + sync_n)
If a downstream service (e.g., a payment gateway) has a hard SLA that cannot be replicated in a secondary region, the entire path collapses unless you introduce a fallback shim (circuit breaker, cached‑payment token). This is why the third business decision—dependency commitment—is the most technically restrictive. 3. Compute Dynamics Across DR Patterns Pattern Compute Footprint (baseline) Warm‑standby Overhead Failover Latency Typical Use‑Case Pilot Light 5‑10% of production (core services only) Low (single‑region minimal resources) 5‑15 min (spin‑up + data sync) Cost‑sensitive workloads ...
Powered by Readybot.io
DEV Community
JSLab is out: write code, watch it run as you type
JSLab is available today for Apple Silicon Macs running macOS 14 or later. It's a native JavaScript and TypeScript scratchpad. Open a tab, type, and every result, log and error lands in the output panel, tagged with the line that produced it. No project, no terminal, no build step. A first tab const orders = [
{ region: "EU", total: 120 },
{ region: "US", total: 80 },
{ region: "APAC", total: 210 },
];
const revenue = orders.reduce((s, o) => s + o.total, 0); //? Revenue: ${revenue}
410 appears beside line 7 and Revenue: 410 beside line 8. Change a total and both update a moment after you stop typing. No console.log anywhere. What's in it Auto Run. Your code reruns a moment after you stop typing. ⌘R runs on demand. Every result, traced to its line. Click a row in the output and the editor jumps there. Magic comments. value //? logs a value; //? $.length logs part of it. Three runtimes, one per tab. Bun (the default), Browser, or Browser & Node APIs. Browser tabs render React, Vue and Angular in a Web View beside the console. npm packages, with types and autocomplete. Ask AI. It reads the code in your tab and sends changes back as an inline diff you accept or reject. Ollama runs locally; OpenAI, Anthropic and Google Gemini use your own key, stored in the macOS Keychain. Your code stays on your Mac. No telemetry, no crash-reporting services. Each feature has its own short post in the Scratchpad JS series, and the docs are at js-lab.app/docs. Try it 14 days free, no account needed: js-lab.app. If something breaks or reads wrong, say so in the comments.
Powered by Readybot.io
DEV Community
Turning Remote-Access Inventory Into an RMM Governance Control
Turning Remote-Access Inventory Into an RMM Governance Control Remote monitoring and management tools are ordinary parts of many IT operations. They can patch endpoints, run scripts, collect telemetry, and support users. The same access can become a serious risk when it appears on a device without the organization's knowledge, or when the person controlling the session is not the person the device record describes. The FBI's October 2026 guidance on North Korean IT workers placed remote-access software and RMM products in the access layer used to operate employment-related laptops. The agency named AnyDesk, TeamViewer, RustDesk, Chrome Remote Desktop, Splashtop Streamer, and RMM software. The US Department of Justice also described the seizure of laptops and KVM devices from suspected laptop farms. These sources describe a threat pattern. They do not make every remote-access installation suspicious. A governance program starts with a simple question: which remote-access tools does the organization approve, for which users, and for what purpose? The answer should be more specific than a list of banned applications. Help desk staff may need a support tool. Developers may need a controlled connection for an approved project. Contractors may need temporary access through a managed gateway. Each exception needs an owner and an expiration date. The technical baseline should include software inventory, installation source, process execution, service listening state, network destination, and authentication events. Where the organization has endpoint detection and response, it can add process ancestry and user context. Where it has mobile device or endpoint management, it can compare the observed package with the intended configuration. The goal is to distinguish approved software from an unmanaged copy with the same name. ZoomEye can add public context. On November 15, 2026, an all-scope query for (app="AnyDesk" || app="TeamViewer" || app="RustDesk") returned 13,236 observations. The individual counts were 458, 12,775, and 3. These observations show the scale of public product fingerprints in those categories. They do not show which endpoints are managed, which sessions are authorized, or which devices belong to a laptop farm. A governance workflow can still use the external result. First, normalize the approved product list and the public query list so that naming differences do not create false gaps. Second, compare public observations with owned network ranges, domains, and asset records. Third, investigate unexplained public services. Fourth, confirm the result with endpoint and identity evidence. The external query becomes a discovery input, not a verdict. The exception process should capture why a tool is needed, who will use it, which devices it may run on, how authentication is enforced, and when the exception will be reviewed. A support session should have a ticket or change record. A contractor session should have a defined sponsor and termination date. A software package that arrives outside the process should be quarantined or removed according to policy while the team investigates. Egress visibility matters because some tools connect outward and do not listen on a public port. A public scan may show nothing while the endpoint still has an active relay session. Network logs should show the destination, frequency, and account context. A remote-control application that attempts a connection at a strange time is not automatically malicious, but it is useful evidence when it conflicts with the user's role and device history. The governance review should also cover uninstallation. When a project ends, the remote-access package and its service should be removed, the account should be revoked, and the device should be checked for residual configuration. A stale installation can become a future route into the organization. The same applies to support tools installed for a one-time incident but never removed. Procurement and on...
Powered by Readybot.io
DEV Community
How I Added a Free AI Product Photo Generator to a Zero-Budget Toolbox
I run a small AI toolbox for Chinese e-commerce sellers. The whole thing is built with vanilla HTML, one cheap Node server, and free APIs. Last week I added a ninth tool: a product-photo generator that costs $0 per image and needs no API key. Here is the weird part: the hard problem was not image generation. It was getting the model to understand Chinese product descriptions. The stack Static frontend hosted on Netlify A small Node HTTP server for text generation Pollinations for free image generation: https://image.pollinations.ai/prompt/{prompt} No signup, no API key, no credit card The image endpoint returns a JPEG directly. You can open it in a browser or fetch it server-side. I call it from the browser and show the returned URL. Problem 1: the free tier is rate-limited Pollinations gives anonymous users roughly one image every 45 seconds per IP. If you go over the limit, it does not return an HTTP error. It returns a yellow image that literally says: Free limit reached 1 free image every 45 seconds That is a trap for any automated test: the request looks successful, the image has a valid JPEG content type, and your UI happily displays the rate-limit card. I now check the generated image visually and tell users to wait 45 seconds before retrying. For a production product I would queue requests per IP and return a clear retry-after value. For a free tool, a plain hint is enough. Problem 2: Chinese prompts were ignored My first test used a Chinese prompt: 专业电商商品摄影:白色陶瓷马克杯,原木桌面、晨光、简约北欧风,无文字,无水印 The result was a young woman standing under cherry blossoms. The model had ignored the subject completely. The lesson: do not send a long Chinese instruction to an English-first image model and expect it to pick out the product. Translate the product and scene into English keywords first, then build a short image prompt. I added a translation step using Pollinations' text endpoint: const ask = '请把下面的中文商品和场景翻译成英文图片生成关键词,只输出英文关键词,用逗号分隔,不要解释:' + text;
const url = 'https://text.pollinations.ai/' + encodeURIComponent(ask) + '?model=openai';
const res = await fetch(url);
const keywords = (await res.text()).trim();
The translation returned: white ceramic mug, natural wood desk, morning light, minimalist Nordic style Then the final image prompt becomes: 'professional e-commerce product photography, ' + keywords +
', clean composition, subject centered, no text, no watermark, high detail'
That produced a clean mug on a wooden desk on the first try. Same tool, same model, completely different result. Problem 3: Node fetch can hang In Node 22, fetch sometimes times out connecting to the image CDN. Adding this at startup fixed it: import dns from 'node:dns';
dns.setDefaultResultOrder('ipv4first');
I also retry the image request up to four times. Each attempt is cheap. The client only sees a loading state. The workflow users see Type a product name and an optional scene, in Chinese. The page translates the scene into English keywords. It requests a 768×768 image from Pollinations. The image appears with a "long-press or right-click to save" hint. No login. No server-side image storage. The image URL points at the public CDN. What I would improve next Add optional reference-image upload so the output keeps the exact product shape Queue requests and show a real countdown instead of a static hint Add background removal after generation For now, the limitation is clear and I state it in the UI: the output is a scene illustration, not a real product photo. Do not use it as a fake "real shot" on a product page. Try it The tool is free and open in the browser: https://xiaoshengyi-toolbox.netlify.app/tools/tupian.html?utm_source=devto&utm_medium=social&utm_campaign=tupian The rest of the toolbox is here: https://xiaoshengyi-toolbox.netlify.app/ If you are building something similar, the two things worth stealing are the translate-first step and the rate-limit check. Both are small changes that turn a demo into something a real seller can use.
Powered by Readybot.io
DEV Community
Prisma Migrations When AI Features Touch Your Database
This post was created with AI assistance and reviewed for accuracy before publishing. AI features arrive with a distinctive database footprint. You need somewhere to keep conversations, the messages inside them, the tool calls each message triggered, and the feedback users leave. Individually these look like ordinary tables. Collectively they are the fastest-growing thing in your schema, because a single user session writes dozens of rows where a normal feature writes one. That growth rate is what makes migrations on these tables different. A schema change that is instant on your users table can lock a messages table with fifty million rows for long enough to take the product down. Model messages as append-only from the start The most useful early decision is treating message rows as immutable: model Message {
id String @id @default(cuid())
conversationId String
role String // user | assistant | tool
content String @db.Text
createdAt DateTime @default(now())
@@index([conversationId, createdAt])
}
Append-only tables are far easier to migrate. There are no in-place updates to contend with, backfills can run in ranges without racing live writes, and you can archive old partitions without touching application logic. The compound index on [conversationId, createdAt] is the one query this table actually serves: fetch a conversation's messages in order. A single-column index on conversationId still requires a sort afterwards, which on a long conversation is the difference between a fast read and a slow one. Expand and contract, never rename Prisma will happily generate a migration that renames or retypes a column. On a large table under load, that is how you cause an outage. The safe pattern splits it into steps that are each individually harmless. Suppose Message.content needs to become structured JSON: Expand. Add contentJson as a nullable column. Nullable additions do not rewrite the table. Dual-write. Deploy code that writes both columns and reads the old one. Backfill. Populate contentJson for existing rows in batches. Switch reads. Deploy code that reads the new column, still writing both. Contract. Once nothing reads it, drop content. Every step is independently reversible, and at no point does a deploy require the schema and the code to change simultaneously. That last property is the real prize: it means a rollback never leaves you with code expecting a column that no longer exists. Backfills should run in bounded batches rather than one statement: let cursor: string | undefined;
for (;;) {
const batch = await prisma.message.findMany({
where: { contentJson: null },
select: { id: true, content: true },
take: 1000,
...(cursor && { cursor: { id: cursor }, skip: 1 }),
orderBy: { id: 'asc' },
});
if (batch.length === 0) break;
await Promise.all(batch.map((m) =>
prisma.message.update({ where: { id: m.id }, data: { contentJson: parse(m.content) } })
));
cursor = batch.at(-1)!.id;
}
A single UPDATE across fifty million rows holds locks and generates enough WAL to cause its own problems. Batching keeps each transaction short and lets you stop partway without losing work. Watch for the index build that locks Adding an index to a growing table is the other common outage. By default Postgres takes a lock that blocks writes for the duration of the build. Prisma Migrate generates plain CREATE INDEX. On a large table you want the concurrent form, which requires editing the generated SQL by hand: -- Edit the generated migration before applying it.
CREATE INDEX CONCURRENTLY "Message_conversationId_createdAt_idx"
ON "Message" ("conversationId", "createdAt");
CONCURRENTLY cannot run inside a transaction, so the migration file needs its transaction wrapper removed as well. It is slower and it can fail partway, leaving an invalid index you have to d...
Powered by Readybot.io
DEV Community
Power BI Product KPI Dashboard: Architecture and Design
Product teams often struggle to design analytics interfaces that drive actual decisions rather than acting as static display panels. When a report combines disconnected metrics without unified event definitions, stakeholders lose trust in the numbers. Before committing to a specific reporting structure, it is helpful to understand the broader context of how to evaluate a technical product role before you commit to ensure your team is aligned on data ownership and reporting responsibilities. Quick solution: Establish a core data contract for your Power BI product KPI dashboard, filtering event streams by session ID and aggregating daily active users with DAU or MAU ratios via Power Query before publishing reports using official visualization guidelines. let
Source = Csv.Document(File.Contents("C:\Data\events.csv"), [Delimiter=",", Columns=4, Encoding=TextEncoding.Utf8, QuoteStyle=QuoteStyle.Csv]),
PromotedHeaders = Table.PromoteHeaders(Source, [PromoteAllScalars=true]),
FilteredRows = Table.SelectRows(PromotedHeaders, each ([event_type] = "active_session")),
RemovedColumns = Table.RemoveColumns(FilteredRows,{"device_type"}),
ChangedType = Table.TransformColumnTypes(RemovedColumns,{{"event_date", type date}, {"user_id", Int64.Type}}),
GroupedRows = Table.Group(ChangedType, {"event_date"}, {{"DailyActiveUsers", each Table.RowCount(Table.Distinct(_[user_id])), type number}})
in
GroupedRows
Prerequisites include standardized event logging across your product and access to a reporting workspace. Cautions involve avoiding unaggregated high-cardinality tables that slow down dashboard rendering times. Understanding the Core Problem in Dashboard Design Many product managers inherit dashboards that track vanity metrics, such as total registered users or cumulative page views. These numbers always trend upward, masking underlying churn or engagement drop-offs. To build a valuable Power BI product KPI dashboard, you must tie every visualized number to a specific behavioral action or business outcome. When designing reporting layers, teams must consult official documentation on how to structure reports effectively. For instance, following the official guidelines on how to create reports in Power BI helps ensure proper layout discipline and performance optimization. Similarly, understanding telemetry patterns from resources like the Azure Monitor visualization overview provides context on how raw telemetry transforms into structured visual elements. Defining Metrics and Data Quality Constraints A reliable dashboard relies on strict schema definitions and consistent event naming conventions. If the engineering team renames an event tracking property without updating the semantic model, historical trends break. To maintain integrity, define each KPI with a single formula calculation in DAX, implement data quality checks to catch missing user identifiers or duplicate session tokens, and separate exploratory analysis pages from executive summary scorecards. For teams managing complex pipeline overlaps or auditing existing coverage, preventing search intent duplicates in automated publishing ensures that each created report serves a distinct informational purpose without cannibalizing other internal assets. Synthetic Data Dashboard Architecture To illustrate how these principles apply in practice, consider a hypothetical software-as-a-service application tracking user activation and retention. The synthetic dataset includes three core tables: Users, Events, and Subscriptions. The Users table holds subscriber identifiers, signup dates, and acquisition channels. The Events table captures granular interaction logs like feature execution, workspace creation, and export triggers. The Subscriptions table tracks plan tiers and billing cycles. When configuring relationships in the model, enforce single-direction filtering from dimension tables to fact tables to prevent circular dependencies and unexpected filter propagati...
Powered by Readybot.io
DEV Community
Cross-validation, and the split that hides a model's failure
Cross-validation is how most models get their score. Six points worked through by hand show how k-fold works, and how the same model scores 0.80 or −0.67 depending only on how the data was split. A model has to be scored on data it was not trained on, or the score only measures memory. Holding back one test set works, but with little data the score then depends heavily on which rows landed in it. Cross-validation fixes that by testing on every row exactly once. It also has a failure that does not show in the number. I ran into it in my research, which I wrote about in a note on a model that scored perfectly. This note works both parts through by hand. How k-fold cross-validation works Split the data into k equal parts, called folds. Train on k − 1 of them and test on the one left out. Repeat k times, so each fold is the test set once, and combine the k test results into one score. Every row is used for testing once and for training k − 1 times. Five and ten are the usual choices for k. With k equal to the number of rows it is called leave-one-out. Six points, three folds The true relationship is y = x², and there are six measurements in two groups. Group A: x = 0, 0.5, 1. Group B: x = 2, 2.5, 3. The model is a straight line fitted by least squares, and the score is R², where 1 is perfect and 0 means no better than always answering with the average. Ordinary 3-fold cross-validation, with the rows dealt into folds without regard to group: fold 1 holds x = 0 and 2.5, fold 2 holds 0.5 and 3, fold 3 holds 1 and 2. Every fold mixes one point from each group. Test fold Line fitted on the other four Predictions (true) x = 0, 2.5 y = 3.517x − 2.153 −2.15 (0), 6.64 (6.25) x = 0.5, 3 y = 2.483x − 0.602 0.64 (0.25), 6.85 (9) x = 1, 2 y = 3.000x − 0.625 2.38 (1), 5.38 (4) Pooling all six test predictions, the mean squared error is 2.23 and R² is 0.80. (How those two scores relate, and when to use RMSE or MAE instead, is in a note on error metrics.) A straight line through a curve, and cross-validation calls it a decent model. The same model, split by group Now split by group instead: train on group A and test on group B, then the reverse. This is group k-fold, and with one group per fold it is called leave-one-group-out. Trained on group B, the line is y = 5x − 6.083. On group A it predicts −6.08, −3.58 and −1.08, against true values of 0, 0.25 and 1. Trained on group A, the line is y = x − 1/12. On group B it predicts 1.92, 2.42 and 2.92, against 4, 6.25 and 9. The mean squared error is now 18.68 and R² is −0.67: worse than ignoring x altogether. Same six points, same model. The only change is which points were allowed to sit together in a fold. Each group-trained line fits its own points and misses the other group. Random folds never ask the model to do this. Why the random folds flattered it In the random folds, every test point had neighbours from its own group in the training set. The model never had to reach anything new. It only had to fill gaps between points it had already seen, and a straight line can fill small gaps in a curve quite well. That is the general rule. Cross-validation measures performance on data like the test folds. If the folds mix groups that will never be mixed in real use, the score answers a question nobody is asking. What this looked like in my research I trained models to predict the stiffness of metal plates with patterns of holes. A network trained on round holes scored essentially perfectly on held-out round-hole cells. Trained on one family and tested on another, 20 of the 30 combinations scored below zero. Splitting by row would have kept the near-perfect score. Splitting by family, the equivalent of the group split above, showed the model had learned the families it saw rather than how stiffness works. The worked version of that collapse is in a note on out-of-distribution failure. Choosing the split Ask what a new case will look like in use, and make the folds match. Several measurements from the ...
Powered by Readybot.io
DEV Community
Linear Light Upscaling Is Correct, and It Cost Me 18 Shadow Levels
Every resampling article opens with the same demo: downscale a black-and-white checkerboard in sRGB, get a muddy grey that should have been mid-grey, then do it in linear light and get the right answer. The demo is correct. I have reproduced it. Then I took that conclusion — "always resample in linear light" — and applied it to a real 512×512 photograph, and to a shadow gradient, and to an unsharp mask. It is not that simple, and the reasons are specific enough to measure. Seven experiments below. Two of them contradict the advice I started with. All of them run on numpy 1.26.4 and Pillow 12.2.0, and every number comes from the snippet at the end. Why the theory says linear light wins sRGB is a non-linear encoding. A stored value of 128 is not 50% of the light — it is about 21%. The encoding exists because human contrast perception is roughly logarithmic, so spending code values where the eye is sensitive wastes fewer bits. Good decision, for storage. Most image operations, though, are physical operations on light. Averaging two pixels means averaging the light they emitted. Average the encoded values instead and you are averaging logarithms, and the average of logarithms is not the logarithm of the average. The error is systematic, not random, so it does not average away at higher resolutions. That argument is airtight, as far as it goes. It is an argument about averaging. An upscaler does more than average, and an 8-bit file has to store the result somewhere. Those two facts are where the tidy story breaks. Method One 512×512 crop from a 1080×1620 photo, converted to 8-bit greyscale so the colour-space question is not confounded by chroma. Two pipelines: sRGB pipeline: resize the 8-bit buffer directly. This is what every naive Image.resize() call does. Linear pipeline: convert to linear float, resize with the same kernel, convert back to sRGB, store 8-bit. Both pipelines use the same filter, because the filter is not the variable being tested. Between the downscale and the upscale each pipeline stores its intermediate as 8-bit, which is what actually happens when a tool writes a temp file or an application holds a texture. High-frequency retention is mean |Laplacian| of the result divided by mean |Laplacian| of the ground truth, both computed in sRGB code values so the two pipelines are compared in the same units the eye sees. Experiment 1: linear wins on detail, loses on PSNR Downscale 4× to 128×128, then back up to 512×512. Kernel PSNR sRGB PSNR linear HF retained sRGB HF retained linear Max error sRGB Max error linear bilinear 25.746 dB 24.763 dB 19.11% 20.23% 153 166 lanczos 27.309 dB 26.123 dB 29.45% 32.97% 151 172 Two things point in opposite directions, and both are real. Linear light keeps more high-frequency detail: +1.12 percentage points at bilinear, +3.52 at lanczos, a 12% relative improvement. That is the theoretical prediction confirmed — resampling in the correct space preserves structure better. Linear light also has worse PSNR, by 0.98 dB at bilinear and 1.19 dB at lanczos. And worse worst-case error: 172 code values against 151. The resolution is that PSNR is a mean squared error over the whole image, and the linear pipeline spends its error where the eye is most sensitive: the shadows. MSE does not know that a 6-code-value error at value 12 is far more visible than a 20-code-value error at value 200. It weights them by the same squared distance. So which pipeline is "better" depends on whether you believe your metric or your optics. That is not a satisfying answer, so I went looking for where the error actually lives. Experiment 2: the metric and the pipeline disagree by brightness Same round trip, lanczos, absolute error bucketed by the brightness of the source pixel. Source brightness Pixels MAE sRGB MAE linear Winner 0–32 23,513 6.216 11.085 sRGB, by 78% 32–64 9,676 13.185 18.867 sRGB, by 43% 64–96 16,419 9.596 12.229 sRGB, by 27% 96–128 19,729 7.736 7.875 sRGB, marginally 128–160 31,386 5.375 5.023...
Powered by Readybot.io
DEV Community
I Had Never Written a Line of Code. Then I Shipped a Paid App With AI.
What a complete non-coder in Japan learned building, launching, and charging for a real product using only prompts — and an AI partner. I am not an engineer. Before this project, I had never built an app, never written production code, and honestly, never expected to ship anything that strangers could pay for. In November 2026, I launched my first product anyway. It's called Ippin Log — a food log that doesn't record restaurants with stars, but records a single dish by its taste. Not "this place was 4.2 stars." But: light vs. rich, thin noodles vs. thick noodles, crisp vs. chewy. Every genre — ramen, curry, and seven others — gets its own two-axis taste chart. Over time, your logs become a map of your own palate. I built it entirely by prompting an AI app builder (Bolt.new), with a second AI (Muse) acting as my strategist, editor, and memory. I was the product manager, the tester, and the only user researcher. This is what that actually looked like — not the highlight reel. 1. The idea was smaller than I thought it needed to be I didn't start with "an app." I started with a frustration: star ratings tell you what other people liked. They don't help you remember what you liked, or why. A bowl of ramen can be perfect for me because it's light and the noodles are thin — and terrible for someone who wants the opposite. A single number erases that. So the core decision came first, and it never changed: Record the dish, not the store. Record the taste, not the score. Everything else — the forms, the charts, the nearby feature — had to serve that one sentence. When you can't code, that sentence is your most important tool. AI will happily build ten features in ten directions. Your job is to say no. 2. Prompting is not "one magic prompt" The fantasy is: type an idea, get an app. The reality is closer to managing a very fast, very literal junior builder who forgets context and sometimes confidently tells you something is fixed when it isn't. What worked for me: Bundle small fixes, split hard ones. Small UI fixes work best when grouped by area and sent as one request. But the hardest item in a bundle will quietly get dropped. I learned to send difficult changes separately, one at a time, and verify each one on the live, published version — never on a preview, never on the AI's summary. "I fixed it" means nothing. The live number means everything. More than once, a summary said a change was done and the public version showed otherwise. My rule became embarrassingly simple: If I didn't see it on the published app, it didn't happen. Publish is a step, not an afterthought. I forgot to press Publish more than once and then wondered why nothing changed. Now it's a mantra: fix, publish, verify — in that order, every time. None of this requires coding skill. It requires stubborn verification. That turned out to be the real job. 3. The parts nobody warns non-coders about Building the screens was maybe 40% of the work. The other 60% was everything around them: Setting up payments for real: switching Stripe to live mode, creating real prices (¥300/month, ¥3,000/year), connecting webhooks, and then making an actual payment myself to prove a real user could become a paying member. Writing the legal pages a paid service in Japan needs — and deciding not to print my home address and phone number publicly, using the "disclosed promptly on request" approach instead. Designing the free/paid line: I raised the free limit from 10 to 40 posts, because free users aren't just free users — in a local-discovery app, their logs are the data that makes the product valuable for everyone nearby. Creating accounts, icons, and a social presence under a developer name, so this first app wouldn't be the ceiling for the next ones. AI helped draft almost all of it. But every decision — price, limits, what to disclose — was mine to make and mine to live with. That's the part that felt most like becoming a founder, not a prompter. 4. Launch day is quiet. Then the real ...
Powered by Readybot.io
DEV Community
AWS's Spring AI Agent Blueprint Gets the Boring Parts Right
An agent demo can fit in one class. A production agent needs an answer to harder questions: who can invoke it, what can it remember, which actions require review, how do you trace a bad decision, and what happens when a model call stalls? AWS's November 11 reference architecture for Spring AI and Amazon Bedrock AgentCore is interesting less because it makes Java agents autonomous, and more because it treats those questions as part of the application. The post by Viquar Khan and Mahammadali Saheb walks through a travel assistant and a document-processing system, with a runtime contract, tool calling, memory, rules, human review, resilience, and observability.[1] This is a reading of AWS's published design and sample, not a hands-on deployment or benchmark. The post is vendor-authored, so its implementation details are useful, while its claims about production readiness should be treated as design guidance rather than independent proof. The useful idea is not “agents, but in Java” The headline is about building autonomous agents with Amazon Bedrock and Spring AI. But the more useful framing is that familiar application engineering still matters when a model starts choosing tools. The sample uses Spring Boot 4.1, Spring AI 2.0, Java 21, and the spring-ai-agentcore SDK. One example is a travel agent that calls tools and keeps conversation context. Another routes submitted documents to specialist agents, applies a rules engine, and sends low-confidence or flagged cases for human review.[1] That second design is the more revealing one. Its five document specialists do not get the final say merely because a model returned structured data. A classifier routes the document, the specialist extracts information, and a rules engine evaluates the output. Alerts and blocks can send cases to a human. The model is one component in a decision path, not the policy engine itself. That is a valuable pattern for any framework: keep probabilistic interpretation separate from deterministic business constraints. A model can extract a cancellation reason. Your application should still decide whether the customer is eligible, whether a manager must approve, and whether the action is reversible. AgentCore and Spring AI occupy different layers It is easy to read the announcement as a contest between an AWS agent product and a Java framework. They are not competing at the same layer. Spring AI gives a Java application model integrations, a ChatClient, tool-calling abstractions, and composable advisors. Its documentation is explicit that the model proposes tool calls, but the application owns the execution logic. The application decides which tools are available and carries out the requested operation.[2] AgentCore is a managed platform layer for deploying and operating agents. AWS describes it as framework- and model-agnostic, with modular capabilities for runtime, memory, identity, browser use, code execution, and monitoring.[3] In the reference architecture, Spring AI remains the programming model while AgentCore supplies managed runtime and supporting services. That division gives teams a practical question to answer: which responsibilities do you want in your application, and which do you want to buy as managed infrastructure? A managed runtime can reduce platform work, but it does not decide whether a tool should be available to a particular user or whether an extracted field is trustworthy enough to trigger an action. The runtime contract is a concrete engineering boundary The sample's AgentCore runtime expects POST /invocations for requests and GET /ping for health. The @AgentCoreInvocation annotation wires these endpoints, handles JSON and server-sent event framing, and reports health status.[1] This is more than deployment trivia. It makes the boundary between the application and its hosting environment explicit. An agent process needs a defined request shape, a streaming behavior, and a health signal. When a task runs for a long time, the he...
Powered by Readybot.io
Announcements
Share your community's updates and events to help potential members discover your server's activity and culture.
You might also be interested in
External Link
Platform
You are about to visit:
https://example.com
This will open in a new tab. Make sure you trust this link.
Want your members to see this?
Pick a channel for upvote and positive review notifications so your members can celebrate together.
It looks like our bot has been removed from your Discord server. To continue using CommunityOne features, you'll need to re-invite the bot to your server.
Don't worry! Re-inviting the bot will restore all your previous settings and data.
External Link
Platform
You are about to visit:
https://example.comThis will open in a new tab. Make sure you trust this link.