今日已更新 344 条资讯 | 累计 37249 条内容
关于我们

标签:#architecture

找到 724 篇相关文章

AI 资讯

Nowhere to Put the Disagreement: What a Memory Store Cannot Tell Your Agent

Ask a memory system what database production uses, and it can hand back two records that flatly contradict each other, each with a confident similarity score, and nothing else. Ken Alger opened his piece on this with exactly that shape: PostgreSQL at 0.94, MongoDB at 0.91, and a migration four months ago that neither number knows anything about. He wrote it from the interface side. This is the same problem from the store side, and the uncomfortable part is that a store can hold everything it needs to see the conflict, both records and both timestamps, and still return it flattened. Disclosure up front: I work on Mnemoverse, a memory engine for AI agents, so read the parts about our own failures as the ones I am most sure of. Why does a memory store hand back a contradiction without saying so? Because the response has nowhere to put it. A memory API returns a list of items with scores. That shape can express "here are five things, sorted by how well they match." It cannot express "these two are in conflict," "this one was superseded by that one," or "this is still true but no longer governs." Those are relations between records, and a flat list has no field for a relation. So even a store that tracked the conflict perfectly will flatten it on the way out. The agent sees two ordinary hits, takes the top one, and 0.94 beating 0.91 quietly becomes conflict resolution, performed by a number that was never asked to adjudicate anything. This is not a bug in anyone's ranker. It is a type problem. Fixing it means the response carries edges, not just items, and that is a much bigger change than adding a column. What are the three operations hiding inside "update"? This decomposition is Ken's, from the conversation that produced both pieces, and it is the sharpest thing either of us wrote: Supersession : this was true, now this other thing is. The world changed. Correction : this was never true. Our record was wrong, and it was load-bearing for whatever happened while we belie

2026-08-24 原文 →
AI 资讯

From Developer to Architect — What Really Changes?

One of the biggest transitions in a software engineer’s career is moving from “How do I implement this?” to “How should we design this?” As developers, we naturally focus on writing clean code, implementing features, fixing bugs, and improving performance. But as you move toward an architect role, the questions become different: 🔹 Scalability — Will this solution work when the number of users or transactions increases 10x? 🔹 Maintainability — Can another team understand and extend this solution two years from now? 🔹 Security — Are authentication, authorization, data protection, and secrets management considered from the beginning? 🔹 Performance — Where could bottlenecks occur, and how can we identify them before they become production issues? 🔹 Resilience — What happens when a dependent service goes down? 🔹 Integration — How will this solution interact with existing enterprise systems? 🔹 Technology choices — Does the technology solve the actual business problem, or are we choosing it simply because it is popular? 🔹 Trade-offs — What are we gaining, and what are we giving up with each architectural decision? A senior developer asks: “How can I build this feature?” An architect asks: “What is the right solution for the business, technical, operational, and long-term requirements?” The most important lesson I’ve learned is that architecture is not about creating complicated diagrams or using more technologies. Good architecture is about making the right decisions at the right level , understanding trade-offs, and creating solutions that can evolve with the business. And you don't suddenly become an architect because of a designation. You gradually become one by thinking beyond your code. Java #SoftwareArchitecture #SpringBoot #Microservices #SoftwareEngineering #JavaDeveloper #TechnologyLeadership #Architect

2026-08-24 原文 →
AI 资讯

Presentation: Prompt to Prod: Engineering an Autonomous SDLC at Scale

Andrew Swerdlow shares how Roblox scales autonomous software development from prompt to production. He discusses building robust security sandboxes, extracting institutional knowledge via code review exemplars, updating engineering infrastructure, and redefining productivity metrics around feature velocity and long-running AI turns to achieve trusted, automated deployment at scale. By Andrew Swerdlow

2026-08-24 原文 →
AI 资讯

Article: Rightsizing Platform Engineering: Building the Platform Your Organization Actually Needs

Shift-left and DevOps have impacted how we flow changes from inception to production, but at the cost of increased cognitive load and duplication of effort across testing, security, and maintenance. This article explores the real-world challenges of rightsizing developer platforms and finding a cultural match for engineering teams who use them to reduce cognitive load and deliver change faster. By John Keates

2026-08-24 原文 →
AI 资讯

Auto Subtitles Are Drafts: Why 99% Accuracy Isn’t the Finish Line

In one test clip, the auto subtitles looked almost perfect. Then one auto subtitle showed gp where the speaker had actually said HP . It was one token in a long transcript, and that was exactly the problem: nothing in the editor made it look more dangerous than the clean words around it. Disclosure: AI helped me edit and structure this article. The gp / HP mistake came from my own build, and I checked the technical details against the code and the working editor. I ran into this while building a subtitle editor. The ASR system already returned word-level timing and confidence values, but a polished block of text made every word look equally trustworthy. The model exposed uncertainty; the interface hid it. That led me to a narrower engineering conclusion: Auto subtitles are drafts. An accuracy score describes a model result; it does not define a finished review workflow. Why auto subtitles need more than one accuracy percentage Speech-to-text systems are often evaluated with word error rate , or WER. In its simplest form: WER = (substitutions + deletions + insertions) / reference words That is useful for comparing transcripts against a known reference. For auto subtitles, trouble starts when a model-level metric is turned into a product-level promise. Suppose a 100-word transcript contains one wrong word. Its word accuracy may look excellent. But a single auto subtitle can carry very different consequences: Changing “and” to “an” may be harmless. Changing a person’s name damages trust. Changing 15 to 50 changes the meaning. Changing HP to gp made my test caption look careless. Dropping “not” reverses the sentence. WER counts errors. It does not price their consequences. Good auto subtitles also depend on things that a transcript-only score does not fully describe: whether words appear at the right time; whether cue boundaries follow the sentence; whether a line is readable before it disappears; whether punctuation helps or hurts comprehension; whether the user knows

2026-08-24 原文 →
AI 资讯

Effective Engagement Management in Enterprise Architecture Projects

Communication and Stakeholder Management Successfully executing enterprise architecture projects requires more than just technical expertise. The key to success lies in effective engagement management, where communication and stakeholder management play a central role. In this post, we’ll explore strategies and tactics for successfully engaging stakeholders in complex IT projects and enterprise architecture initiatives. The Challenge: Complexity and Different Perspectives Enterprise architecture projects are often characterized by high complexity. They span various business units and teams, from IT to management and external service providers. These projects are not only technologically demanding but also require close collaboration between all involved parties. Each stakeholder brings their own perspectives, priorities, and objectives, which increases the risk of misunderstandings, delays, and misaligned outcomes. The Key to Success: Engagement Management Effective engagement management ensures that all stakeholders are involved from the start and that their needs and expectations are understood. This involves not only regular communication but also a structured and strategic approach. Below are some proven strategies to achieve successful engagement: 1. Early and Comprehensive Stakeholder Mapping Successful engagement begins with a clear understanding of the involved stakeholders. Stakeholder mapping helps identify all relevant actors, their interests, and their potential influence on the project. The following questions should be considered: Who are the internal and external stakeholders? What are their expectations for the project? How much influence do they have on decision-making? What are their communication needs? A comprehensive stakeholder mapping allows for the establishment of clear communication paths and consideration of specific needs from the start. 2. Transparent Communication One of the most common causes of project failure is insufficient or ineff

2026-08-24 原文 →
AI 资讯

Building a Scalable, HIPAA‑Compliant Healthcare Document Processing Pipeline in .NET & Azure

Building a Scalable, HIPAA‑Compliant Healthcare Document Processing Pipeline in .NET & Azure Quick Answer A deep dive into architecting a production‑grade Healthcare Document Processing Pipeline—covering AI extraction, FHIR integration, vector search, and compliance at scale. In my experience, the biggest cost is not the AI model, but the orchestration that turns raw scans into audit‑ready FHIR resources. The right mix of services can reduce latency by 30‑50% while keeping the bill below 10% of the raw compute budget. Choose services that expose a BAA and native hybrid search (Azure Cognitive Search) to avoid a second compliance layer. Prioritize deterministic scaling (Container Apps + Aspire) over elastic serverless when real‑time SLAs are tight. Version your embeddings; treat the vector index as a first‑class contract. HIPAA‑Ready High‑Volume Document Ingestion When a health system starts ingesting thousands of paper‑to‑digital documents per day, the naïve “scan‑and‑store” approach quickly becomes a compliance and performance nightmare. The real challenge is to produce HIPAA‑ready, FHIR‑compliant, low‑latency data that can be consumed by downstream clinical decision support or billing systems. Compliance is not a checkbox; it’s a series of audit trails that must survive a 30‑day retention policy and survive a forensic review. In production, the cost of a single PHI exposure can exceed the annual budget of the entire platform. Real‑World Example Consider a mid‑size hospital that receives 25,000 inpatient discharge summaries, 8,000 lab reports, and 12,000 imaging PDFs every month. Each document is a mixture of scanned images, PDFs, and legacy forms. The billing team needs structured diagnoses and procedure codes within 30 seconds to avoid claim denials, while the analytics team wants similarity search for rare disease cases in the last 12 months. The pipeline must: Extract structured entities with ≥95% accuracy. Redact PHI in transit and at rest. Provide audit logs

2026-08-24 原文 →
AI 资讯

One Knowledge Base, Four Surfaces: Pages, Graph, Search Index, and MCP

Originally published on michael-kaminski.io . The Genome of Games publishes the same 1,180 records four different ways, and one command writes all four: node build.js , 0.39 seconds, zero npm dependencies. Out come 1,245 static HTML pages for crawlers, an interactive canvas graph for humans, a 129,037-byte search index for the site's own search box, and a Model Context Protocol server exposing 8 tools to agents. The decision worth copying is the one that sounds like a downgrade. The MCP server does not query the site and does not read the source data. It statically imports a 1.9 MB index that the build wrote. There is exactly one place where slugs, lineage, and adoption edges get joined, so an agent and a crawler cannot come back with different answers. The dataset is an ontology of video game mechanics — 168 mechanics, 618 games, 394 companies, 4,366 recorded links, 1962 to 2025. What the records are about does not matter here. The shape of the problem shows up anywhere a structured knowledge base has to serve both a search engine and a model. Four surfaces, one build, a twelve-fold expansion Six hand-edited JSON files under data/ are the source of truth: the feature ontology, the graph, the prose, the company registry, the site copy, and the verified outbound links. Together they are 1,312,577 bytes. The build turns that into 16,644,215 bytes of generated read surface. A 12.7× expansion, and every byte of it is disposable. Surface Consumer Bytes Per entity 1,245 static HTML pages Crawlers, humans 14,613,203 11,728 / page mcp-index.json → MCP server Agents 1,901,975 1,612 search-index.json The site's own search box 129,037 109 /graph/ canvas Humans exploring lineage data injected at build — The build also emits sitemap.xml with 1,245 entries, llms.txt , robots.txt , and a 404 page. The same run reports 96,843 internal links across those pages. Nothing in that list is authored. Delete the whole output directory and the next build restores it in under half a second.

2026-08-24 原文 →
AI 资讯

Your Retry Loop Is a Token Incinerator: A Cascade Router for Mixed-Tier Endpoints

When a free endpoint returns 429, most agents do the most expensive thing possible: retry. Retrying looks harmless. A 200-millisecond request becomes a 2-second wait, then another attempt. But under peak load, that loop becomes a 30-second stall while your agent clicks refresh on an empty response. If the quota window resets during the stall, every retry burns tokens you could have spent on actual work. The retry loop assumes the failure is temporary. For rate limits, that assumption is usually wrong. Quota counters reset on a fixed schedule, not on your convenience. You are not just waiting; you are burning wall-clock time that could have gone elsewhere. The Cascade Pattern A cascade router is the alternative. It sends requests to the free endpoint, backs off on rate-limit signals, then degrades gracefully to a backup endpoint. The free tier carries the load; the backup exists only when needed. You get the cost advantage of the free tier and the reliability of the paid tier. The design has three parts: an endpoint abstraction layer, a rate-limit detector, and a circuit breaker that trips when the free endpoint fails repeatedly. Here is the core code: # cascade_router.py — free tier first, paid/self-hosted as fallback. import json import os import time import urllib.error import urllib.request from dataclasses import dataclass @dataclass class Endpoint : name : str url : str api_key : str model : str cooldown_until : float = 0.0 consecutive_failures : int = 0 def available ( self ) -> bool : return time . time () >= self . cooldown_until class CascadeRouter : def __init__ ( self , endpoints : list [ Endpoint ]): self . endpoints = endpoints def _call_one ( self , ep : Endpoint , messages : list [ dict ]) -> tuple [ int , dict ]: body = json . dumps ({ " model " : ep . model , " messages " : messages , " max_tokens " : 256 }). encode () req = urllib . request . Request ( ep . url , data = body , headers = { " Content-Type " : " application/json " , " Authorization "

2026-08-24 原文 →
AI 资讯

Shipping Stock CLIs as Subprocess Instead of Static-Linking SDKs

I'm building yyzTools, which bundles 9 third-party engines (OpenSSL, FFmpeg, ImageMagick, pdfcpu, Aria2, 7-Zip, RapidOCR, Everything...). I chose to spawn them as subprocesses rather than static-link their SDKs. Here's why—and the cost. The conventional approach When your app needs OpenSSL crypto, FFmpeg video processing, ImageMagick image ops—you reach for the SDK. Link libssl, link libav*, link libMagick. One binary, no external deps, fast function calls. It's the textbook answer. I did the opposite. yyzTools ships the stock CLI binaries (openssl.exe, ffmpeg.exe, magick.exe, pdfcpu, aria2c, 7z) and spawns them as subprocesses. The C++ layer is a thin loop: build args → CreateProcess → read stdout → wrap as JSON → return. It doesn't know what -gravity southeast or sm4-cbc means. It just passes the algorithm name through. Why I went this way Upgrades without recompiling This is the big one for a desktop app. OpenSSL ships a CVE, or adds sm2/sm3/sm4 support in 3.x. If you've static-linked, you recompile the whole app, run full regression, re-release, and every user reinstalls. With the subprocess model, I drop in a new openssl.exe. Zero C++ changes. The update is a few-MB delta, not a full reinstall. For a product where users won't tolerate reinstalling for a library bump, this is the deciding factor. No symbol conflicts OpenSSL, zlib, libpng—multiple libraries want to own these symbols. Static linking them all into one binary is a recipe for "which inflate did I just call?" With subprocess CLIs, each tool brings its own dependencies in its own process. No conflict. Transparent supply chain openssl version, ffmpeg -version—auditing which version of each tool is live is trivial. It's an independent binary. Far easier than digging symbols out of a statically-linked blob. Free crash isolation If ffmpeg.exe misbehaves, it exits non-zero and my host wraps that as an error. My main process keeps running. A static-linked bug can take down the whole app. The process boundary

2026-08-23 原文 →
AI 资讯

A Developer's Checklist for Every RAG Lifecycle (Beyond Chunk-Embed-Search)

If your mental model of RAG is "chunk → embed → search → LLM," you're missing about 80% of what actually makes a RAG system production-ready. Here's a practical checklist across all 10 lifecycles I ran into while building one. Full technical breakdown with diagrams is on Hashnode (linked above) — this is the condensed, "what to actually check" version. ✅ Document lifecycle [ ] Can you update a single document without a full re-index? [ ] Do you have a deletion path (not just an addition path)? [ ] Are you deduplicating before you embed? ✅ Embedding lifecycle [ ] Do you know what happens if you switch embedding models? [ ] Are you tracking dimensions and normalization consistently? [ ] Can you re-embed the whole store without downtime? ✅ Retrieval lifecycle [ ] Are you tuning Top-K, or using a default and hoping? [ ] Do you have metadata filtering before similarity search? [ ] Have you tried hybrid (keyword + semantic) search yet? ✅ Inference lifecycle [ ] Do you know your cold-start latency vs. warm inference? [ ] Are you tracking tokens/sec as a real metric, not a vibe? [ ] CPU or GPU — did you choose, or did it choose you? ✅ Prompt lifecycle [ ] Are you compressing context, or dumping everything retrieved? [ ] Do you track input vs. output tokens separately? [ ] Is your system prompt fighting your retrieved context? ✅ Request lifecycle [ ] Can you see latency broken down by stage (embed / retrieve / generate)? [ ] Do you know which stage is your actual bottleneck? ✅ Cache lifecycle [ ] Are you caching query embeddings? [ ] Are you caching full responses for repeated questions? ✅ Evaluation lifecycle [ ] Can you measure retrieval precision/recall? [ ] Do you have a faithfulness or answer-relevance check? [ ] If you "improved" something, can you prove it? ✅ Production lifecycle [ ] Health checks, retries, rate limiting — in place or assumed? [ ] Are secrets actually out of your codebase? [ ] Do you have CI/CD, or are you deploying by hand? ✅ Cloud lifecycle [ ] Do y

2026-08-23 原文 →
AI 资讯

Building Fluentic Style: Rethinking How Outside Styles Reach Inside Components

This is part of my Building Fluentic Style series, where I’m writing down the design decisions, tradeoffs, and small surprises from building Fluentic Style . The feeling I keep having is that styling in component frameworks often asks components to fit back into the old HTML + CSS model, instead of asking what CSS composition should look like when components are the main unit. That is not meant as a takedown of CSS. I like CSS. And the HTML + CSS model makes a lot of sense in its own world. In that model, you write HTML, give elements class names, and use selectors when a nested part needs styling. <div class= "card" > <h2 class= "card-title" > Revenue </h2> <p class= "card-body" > $42,300 </p> </div> .card { padding : 16px ; border-radius : 12px ; } .card-title { font-size : 18px ; font-weight : 700 ; } .card .card-body { color : #475569 ; } That model has problems. Global CSS can leak. Naming is hard. Specificity can become painful. Large stylesheets can become difficult to maintain. But the basic mental model is easy to understand: Give the part a name, then style that named part. Even when the ecosystem adds SCSS, BEM, naming conventions, CSS Modules, and other tools, a lot of the core idea stays familiar. There is markup. There are names. There are selectors. Styles reach elements through those names. That world feels coherent because HTML and CSS are built around that relationship. Then components change the shape of UI. Components Change The Unit In React and other component frameworks, we usually stop thinking of UI as one big HTML document. We think in components: < Card title = "Revenue" > $42,300 </ Card > That is a huge improvement. A component owns its internal markup. It receives props. It composes with children. It hides implementation details. It can be typed. It can be transformed by tooling. It can become part of a design system. But styling still has to answer a familiar question: How do I style the thing inside? In HTML + CSS, if I want to style

2026-08-23 原文 →
AI 资讯

How to Build a Local-Service Site That Can Answer ‘Can You Fix My RV Today?’

An RV repair business does not lose a service call because a visitor failed to read a clever headline. It loses the call when a person with a broken slide-out, roof leak, or electrical issue cannot answer four basic questions quickly: Do you handle this exact problem? Do you serve where I am? Are you available and credible? What do I do next? That sounds like marketing. It is mostly a systems-design problem. The implementation goal is not “make more city pages.” It is to make the business's real-world facts available, consistent, crawlable, and usable across the website, Google Business Profile, analytics, and the conversion flow. This post turns SEOG’s RV repair checklist into an implementation pattern a developer can apply to any local-service site. The model: one source of truth, many decision surfaces Local customers do not encounter a business in one place. They may see a Google result, a Maps profile, a service page, a review, or a call button before they ever submit a form. Treat the site as one consumer of a small, canonical business data model rather than a collection of independently written pages. business facts ─┬─> server-rendered service pages ├─> JSON-LD ├─> XML sitemap + canonical URLs ├─> GBP sync/review queue (with human approval) ├─> call/form events └─> audit and change history The important part is the left side. If a mobile RV technician's phone number, service coverage, repair categories, and hours live in five unrelated CMS fields, a mismatch is inevitable. Start with an explicit domain object. type BusinessLocation = { id : string ; legalName : string ; publicName : string ; phoneE164 : string ; website : string ; address ?: { streetAddress : string ; addressLocality : string ; addressRegion : string ; postalCode : string ; addressCountry : " US " ; }; geo ?: { latitude : number ; longitude : number }; serviceAreas : Array < { name : string ; state : string ; proof : string [] } > ; hours : Array < { dayOfWeek : string []; opens : string ; c

2026-08-22 原文 →
AI 资讯

Planning Feature Integrations Before Development: A Practical Approach

When working on a web project, one of the easiest ways to create unnecessary development work is to start coding before the feature requirements and integration approach are clear. I’ve found that creating an issue, proposal, or short technical plan before development can make a big difference. It gives everyone an opportunity to discuss the idea, identify potential problems, and agree on an implementation approach before code changes begin. This is particularly useful for projects that evolve over time. New features can affect existing components, user flows, APIs, databases, and the overall interface. Thinking about these dependencies early can reduce redesigns and duplicated work. For example, while working on projects such as Simulator Drag Race , planning new simulation features before implementation helps keep the existing functionality organized while making room for future improvements. A simple pre-development process can be: Describe the feature and the problem it solves. Create an issue or proposal for discussion. Identify which existing components will be affected. Discuss possible implementation approaches. Agree on the approach before development starts. Break the approved approach into smaller development tasks. This process doesn't need to be complicated. Even a short issue with clear requirements and a few implementation notes can prevent misunderstandings later. Another benefit is that early communication gives maintainers and contributors visibility into upcoming changes. Someone may already be working on a related feature, or a maintainer may know about an architectural limitation that isn't immediately obvious. For open-source and collaborative projects, I think this approach is especially valuable. Good communication before development can be just as important as the code itself. How does your team handle feature proposals before development? Do you prefer detailed technical proposals, simple GitHub issues, or discussing the implementation dire

2026-08-22 原文 →
AI 资讯

Presentation: SafeChat: Building AI-Powered Safety Systems at Scale in a Real-Time Marketplace

Bruna Pereira explains how DoorDash built a content-agnostic AI moderation platform. She covers replacing costly LLM-only pipelines with a hybrid pattern: using fast internal models to filter obvious cases, LLM multi-axis scoring for nuanced decisions, and no-code workflows with backtesting. Discover how this architectural pattern cut safety incidents while scaling to millions of daily messages. By Bruna Pereira

2026-08-22 原文 →
AI 资讯

Your TTS shortlist is three shortlists, and they barely intersect

Every "best text-to-speech API" list I have read is ranked. Number one, number two, number three, with a verdict at the bottom. That shape cannot express the actual decision, and I want to show you why with something you can run. The problem is that the three things that decide a TTS vendor are measured in units that do not convert into each other. Price is dollars per million characters. Transport is a shape — held-open socket, chunked body, finished file. Compliance is a document that either exists or does not. There is no exchange rate between them, so there is no ordering. A ranked list has to pick one axis and pretend the others are tiebreakers. They are not tiebreakers. They are filters, and filters compose by intersection. The three sets Price spans about 40x. Google Cloud's legacy voices and Amazon Polly's standard engine sit at $4 per million characters. The mid-market — OpenAI's tts-1 , Deepgram Aura-1, Inworld TTS-2 Flash — clusters at $15. Cartesia runs $37.38 to $50. ElevenLabs is $166.11 at its Scale tier. A million characters is roughly 22 hours of speech, so at prototype volume this axis is noise; at a hundred million characters a year it is the difference between a $400 bill and a $16,600 one. Transport comes in three shapes and the difference is architectural, not incremental. WebSocket streaming holds a connection open and pushes audio as it is synthesised. The first syllable can reach the caller while the model is still working on the sentence. This is what a live agent needs. Chunked REST streams the response body back progressively. OpenAI works this way, and its docs recommend wav or pcm output specifically because those start playing sooner than a compressed container. Meaningfully better than waiting for a whole file; meaningfully worse than a held-open socket. Batch returns a finished file. Correct for narration, e-learning, anything rendered ahead of time. Wrong for conversation. Two entries in that column are routinely stated wrong, so th

2026-08-22 原文 →
AI 资讯

Designing a Reasoning Ledger Record

A companion to Part 4 of the Building the AI Memory Stack series. Part 4.5 of the series. Part 4 argued that agentic systems need a Reasoning Ledger : a layer that preserves why a decision happened, not just what was decided. The comment thread that followed turned into something more specific and more useful, a working design conversation about what a single ledger record should actually contain. This piece consolidates that. Several of the strongest ideas below arrived from other people, and I have tried to credit them where they land. The easy version of this article is a schema. Here are the fields, copy them, done. I want to resist that, because the field list is the least durable thing I could hand you. Implementations differ, field names drift, and a record shape copied without its reasoning becomes cargo-cult structure that nobody maintains. The useful thing is the set of design tensions that decide what belongs in the record and what does not. Get those right and you can derive the fields yourself. Get them wrong and no schema will save you. So this is principles first, record second. At the end there is a worked record and a field reference, tagged for what is core and what is genuinely optional. A Starting Point Here is the baseline record from Part 4. It is a reasonable start and, as the thread quickly established, incomplete in instructive ways. reasoning_ledger : decision : " Approve deployment" timestamp : 2026-03-14T09:22:00Z evidence : - artifact : ADR-014 authority : architecture-review version : 3 - artifact : security-policy authority : security-team version : 7 tools : - GitHub - CI pipeline approvals : - release manager outcome : approved Every principle below is, in effect, a thing this record does not yet say. Principle 1: The Ledger Witnesses, It Does Not Enforce The first tension is architectural, and it is the one I would defend hardest. A reasoning ledger must not be able to block, veto, or gate the action it records. Its job is to preser

2026-08-22 原文 →
AI 资讯

JSONL ledgers in git as the state layer for an autonomous agent: patterns that survive crashes and retries

Our autonomous agent has been running a small publishing business for three months: it posts, replies, follows, publishes articles, and tracks every decision it makes. The state layer behind all of that is not Postgres, not SQLite, not Redis. It is a directory of JSONL files committed to git. This choice gets us laughed at occasionally, so this post is the honest case for it — the patterns that make append-only text files survive crashes, retries, concurrent writers, and an LLM's enthusiasm for re-running things it already ran. Why files-in-git at all Three properties turned out to matter more than query power: Every state change is a diff. When the agent follows someone, replies to a thread, or publishes an article, the evidence lands in git log with a timestamp and an author. Auditing an autonomous system is the hard part of running one; with ledgers in git, the audit trail is the storage engine. Scheduled jobs and interactive sessions share state with no server. Our GitHub Actions jobs check out the repo, read the ledgers, act, commit. The interactive session pulls before deciding anything. The merge boundary is git's problem, which is a well-understood problem. The LLM can read its own state natively. An agent that can grep its full decision history is meaningfully smarter than one that needs a query layer written for it. Pattern 1: append-only, with one exception Almost every ledger is append-only: one JSON object per line, new facts go at the end. Append-only means a crashed write corrupts at most the final line, and recovery is "drop the broken tail," not "restore from backup." The exception: consumption ledgers (a stock of pre-written posts, a queue of follow candidates) need a consumedAt stamp on existing rows. For those we load-modify-rewrite the whole file — acceptable because the files are small — with one hard rule: a consumed mark is never overwritten. The update function refuses to touch a row whose consumedAt is already set. Retry-safety comes from t

2026-08-22 原文 →