Solana’s Account Types Are Just Database Rows With Different Flags

The Surprise of Day 25

When I got to Day 25 of 100 Days of Solana and inspected the System Program account for the first time, I expected something special. Some distinct “program” structure, different from the wallet accounts I’d been working with.

Instead I got the same four fields I’d already seen a hundred times: balance, owner, executable, data. The only difference was executable: true.

That was the moment “everything is an account” stopped being a tagline and became something I actually understood. This post explains what I found and what it means if you’re coming from a Web2 background.

The Web2 Mental Model You Need to Drop

In Web2, different things have different types. A user account is a database row. Application code is a file on a server. Configuration data is an environment variable or a config service. They’re stored differently, accessed differently, and reasoned about differently.

Solana collapses all of this into one primitive. Everything your wallet, the code that processes transfers, the network’s current timestamp is a row in the same global table with the same four columns.

The Schema

CREATE TABLE accounts (
  address    VARCHAR PRIMARY KEY,
  lamports   BIGINT,        -- SOL balance
  owner      VARCHAR,       -- which program controls this row
  data       BYTEA,         -- arbitrary payload
  executable BOOLEAN        -- is this row code or data?
);

That’s it. Every account on Solana billions of them fits this schema. What varies is the values.

Row Type 1: Your Wallet

address: YOUR_WALLET_ADDRESS
lamports: 1,247,000,000 (1.247 SOL)
owner: 11111111111111111111111111111111 (System Program)
data: empty
executable: false

Your wallet is the simplest possible row. No data payload, not executable, owned by the system program. The SOL balance is all that matters, and it lives in lamports.

Web2 equivalent: A user record with just a balance field. No special logic is attached. The application server (system program) handles all operations on it.

Row Type 2: The System Program

address: 11111111111111111111111111111111
lamports: 1,000,000,000 (1 SOL)
owner: NativeLoader
data: 14 bytes
executable: true

Same schema, completely different purpose. executable: true means the runtime treats the data field as code to execute, not state to store. When you call the System Program, the runtime looks up this row and runs its bytecode.

Web2 equivalent: A stored procedure in your database. It lives in the same storage system as your data rows, but the database engine knows to execute it rather than return it as data.

Row Type 3: Sysvar Accounts

address: SysvarC1ock11111111111111111111111111111111
lamports: 1,169,280
owner: Sysvar1111111111111111111111111111111111111
data: 40 bytes (current slot, epoch, timestamp)
executable: false

Sysvar accounts are read-only rows that the network itself writes to every slot. Programs read them to access runtime information: what slot is it? What’s the current rent rate? What are the recent block hashes?

Web2 equivalent: A system configuration table that your application server updates automatically like a system_config table with current_time, maintenance_mode, and version columns. Your application code reads it but doesn’t write it.

The Flag That Changes Everything

The entire distinction between “code” and “data” in Solana comes down to one boolean: executable.

In Web2, code and data are fundamentally different things stored in different places one on your filesystem, one in your database. You never confuse them. In Solana, they’re the same thing stored the same way. The flag is the only boundary.

This has a profound implication: programs are inspectable the same way data is. You can look up any program’s account in a block explorer, see its bytecode, check its upgrade authority, read its transaction history. There’s no separation between “application layer” and “data layer” it’s all one public table.

What Sat Underneath Everything I Built

Looking back at 25 days of challenges through this lens:

Every airdrop I received → System Program created or credited my wallet row.
Every SOL transfer I sent → System Program debited my row and credited the recipient’s.
Every account I created for a new keypair → System Program inserted a new row.
Every script that read account data → fetched rows from this global table.

The System Program has been the invisible application server behind every operation. Day 25 was the first time I looked at it directly as an account and saw that it’s just another row, with executable: true and the NativeLoader as its owner.

Same table. Same schema. Different flags.

Cryptographic Forensics for AI Coding Agent Sessions

A Claude Code or Codex CLI session writes a JSONL file to disk. If the agent runs rm -rf on a training-data directory or terraform destroy -auto-approve on production, that file is where an incident review starts.

A JSONL file is not evidence. Anyone with shell access can rewrite it. To a third party who doesn’t trust the machine it came from, it proves nothing.

That gap matters once agents have credentials to real infrastructure. Most agent observability tooling is built for debugging and quality, not for the moment after damage is done. This post is about the three cryptographic properties that turn a transcript into something an auditor or regulator can verify, and how the DEPOSE project wires them together.

Three properties

Assume the machine that produced the bundle can’t be trusted. Three things need to hold at once:

  1. Tamper-evident. Any byte change has to be detectable. Hash chain over events: change a byte, replay fails.
  2. Authenticated. The record has to be bound to a key the producer controls and publishes a fingerprint for. Ed25519 signatures over a manifest.
  3. Anti-backdated. A party other than the producer has to anchor the record in time. RFC 3161 tokens from a public TSA.

The primitives are old and well understood. The hard part is wiring them through a normalized event schema and shipping a verifier that doesn’t depend on the producer’s runtime.

No LLM in the signed path

Every event is captured at execution time or normalized from the session JSONL, then committed to the hash chain. The human-readable narrative is generated separately, from deterministic Handlebars templates over the signed events. It’s excluded from the root hash.

If generated prose became part of the signed record, verification would depend on model behavior staying stable and reproducible. DEPOSE avoids that dependency. The signed record is event data and hashes. The prose is templated commentary with [#evt-<ulid>] citations back to the signed events. You can rewrite the narrative without affecting verification. Change an event and verification fails.

What’s in a bundle

A DEPOSE bundle is a directory, not an opaque archive:

incident-01JABC.../
├── manifest.json            bundleId, rootHash, eventsJsonlSha256, sigs, timestamps
├── events.jsonl             every event in canonical JSON, byte-pinned by manifest
├── rules/destructive.yaml   ruleset used at reconstruction time
├── narrative.md / .html     templated prose with per-event citations
├── verify.txt               human-readable verification summary
├── artifacts/               captured file diffs, payloads
├── attestations/            Ed25519 signatures, RFC 3161 timestamp tokens
└── raw/                     source JSONL, shell history, capture records

Change a byte of events.jsonl, manifest.json, or rules/destructive.yaml and verification fails. Canonical JSON follows RFC 8785 (JCS), which is what lets a Go verifier check a TypeScript-produced bundle without either side trusting the other’s serializer.

Two binaries

The producer is TypeScript. The verifier is a separately-built static Go binary, depose-verify. The separation is deliberate: you hand the binary to whoever needs to check the bundle (auditor, opposing counsel, regulator, a customer’s security team) and they run it on their own machine. No producer stack required.

A passing run prints:

parse        OK
signature    OK
chain-replay OK
artifacts    OK
timestamp    OK
PASS  bundleId=...  rootHash=...

The cryptography here is mostly off-the-shelf. The actual engineering work is in normalization: getting Go and Node to serialize identically, getting timing and ordering right across capture sources, deciding what counts as one event versus two. Canonical JSON is the unsexy part. Float formatting, key ordering, unicode escapes: Go and Node have to agree byte-for-byte or the verifier rejects a bundle the producer thinks is fine. That’s what the cross-language conformance vectors in tests/conformance/ are for.

Verifiers can pin a producer’s expected key fingerprint and consult a revocation list, both at the command line. The RFC 3161 timestamp does double duty here: a bundle stamped before a key is revoked stays time-anchored, so “when was this signed” remains answerable even if the key is later compromised.

Capture modes

Two modes, different coverage.

Reconstruction reads the Claude Code session JSONL after the fact, compares it against shell history (bash, zsh, fish) and git reflog where available, and builds a bundle. Lower-bound mode. It can verify integrity after packaging. It can’t prove the original session file was complete before capture.

Active capture installs a Claude Code PreToolUse hook and POSIX shell shims for the binaries that tend to do destructive things: terraform, aws, gh, kubectl, psql, gcloud, railway, rm. Records land under ~/.depose/captures/ at execution time. A later depose package merges them with the session JSONL so every covered event has a verified pre-execution intent on record.

DEPOSE can prove integrity of captured events. It can’t prove an uninstrumented system captured everything. An agent that shells out to a binary not in the shim list, or hits an API directly, still shows up in the JSONL but won’t have an active-capture record. The coverage matrix is in the repo.

macOS and Linux only. Windows isn’t supported (POSIX 0600 on the key store, POSIX shell scripts for the shims). WSL2 works.

Release pipeline

Releases ship with SBOMs, provenance attestations, and signed checksums. The specifics: CycloneDX for both halves, SLSA L3 provenance, and SHA256SUMS signed via cosign keyless. CI rebuilds the two checked-in example bundles (an rm -rf on training data, a terraform destroy on infrastructure) on every push and runs three semantic tamper rejections to confirm the verifier fails closed.

Right now most coding-agent session logs are treated like disposable debug output. That assumption gets weaker the moment an agent can modify infrastructure.

https://github.com/Aftermath-Technologies-Ltd/depose

Testing NGB Platform Beyond a Small Demo Dataset with k6 and TypeScript

I recently released NGB Platform v1.1.1.

The main addition is the first NGB Performance Tests Framework.

This is not just a set of endpoint benchmarks.

NGB Platform is an open-source, metadata-driven business platform for building accounting-first industry solutions. The goal is not to build isolated CRUD applications, but complete business applications where documents, catalogs, accounting, audit history, workflows, reports, and background processes are part of the same architecture.

So performance testing has to follow the same idea.

It needs to test real platform behavior, not only isolated HTTP latency.

Why performance testing matters for NGB

In many applications, performance testing starts with a few simple endpoint checks.

That can be useful.

But it does not answer the most important questions for a business platform.

For NGB, the important questions are different:

  • Can users browse documents while other users are posting documents?
  • Can reports stay usable as data volume grows?
  • Can audit history remain readable under pressure?
  • Can accounting effects be opened quickly after posting?
  • Can document flow stay responsive?
  • Can the platform preserve business correctness while handling mixed read/write workloads?

NGB is accounting-first.

That means a posted document is not just a saved record.

It can produce:

  • Accounting entries
  • Audit records
  • Document relationships
  • Reportable business effects
  • Operational state changes

So performance testing has to cover business workflows.

Not just endpoints.

What was added in v1.1.1

NGB v1.1.1 adds a dedicated performance testing workspace based on:

  • Grafana k6
  • TypeScript
  • Reusable scenario profiles
  • Keycloak tester authentication
  • Custom metrics
  • Thresholds
  • Vertical-specific workload packages

The repository now includes:

performance-tests/
  ngb-performance-tests-framework/
  ngb-property-management-perf/
  ngb-trade-perf/
  ngb-agency-billing-perf/
  scripts/

The most important part is the boundary.

The shared framework is vertical-neutral.

It knows platform concepts:

  • Auth
  • Health
  • Metadata
  • Catalogs
  • Documents
  • Reports
  • Accounting effects
  • Document flow
  • Audit
  • Scenarios
  • Metrics
  • Thresholds

It does not know Property Management, Trade, or Agency Billing.

Vertical packages define their own document types, catalog types, report IDs, fixtures, and workload mixes.

That separation matters.

I do not want performance testing to become another place where platform and vertical layers start leaking into each other.

The first serious validation run

For the first serious validation run, I used the NGB Property Management vertical.

The environment was intentionally local:

  • Local Docker deployment
  • PostgreSQL database around 19GB
  • Around 1.7M business documents
  • Around 27M audit log records

This is not a third-party audited benchmark.

It is not a claim of unlimited scale.

But it is an important production-readiness signal.

NGB is no longer tested only as a small demo dataset.

It now has repeatable performance workloads running against real platform behavior and non-trivial data volume.

What was tested

The performance framework includes multiple workload profiles.

Some of the important ones are:

  • Smoke
  • Baseline
  • Platform read
  • Platform reporting
  • Platform read capacity
  • Platform mixed capacity
  • Platform breakpoint
  • Document lifecycle
  • Audit
  • Maintenance
  • Concurrency
  • Business day
  • Write-heavy

The goal is not to run all of them every time.

Different profiles answer different questions.

Platform read capacity

This profile focuses on read-heavy platform behavior.

It helps validate whether common read paths stay stable under high concurrency.

Platform mixed capacity

This is one of the most important profiles.

It combines different types of platform activity instead of testing only one endpoint.

The workload includes document reads, platform reads, reporting, audit-related operations, accounting effects, document flow, and other common application behavior.

Write-heavy

This profile is more aggressive.

It exercises document create/update/post operations while the system is also reading accounting effects, audit history, document flow, and reports.

For an accounting-first platform, this is one of the most important scenarios.

Writes are not just writes.

They create durable business consequences.

Selected results

Here are selected results from the run set.

Mixed capacity

The mixed-capacity profile ran for around 80 minutes.

Results:

  • 9.5M+ requests
  • 1,000 peak virtual users
  • 0 dropped iterations
  • 0 business failures

This matters because the workload was not a single endpoint benchmark.

It exercised mixed platform behavior under sustained load.

Read capacity

The read-capacity profile pushed read pressure higher.

Results:

  • 10.8M+ requests
  • 1,400 peak virtual users
  • 0 dropped iterations
  • 0 business failures

The important signal here is the combination of request volume, concurrency, and correctness.

Not just one latency number.

Write-heavy workload

The write-heavy profile ran document lifecycle operations under pressure.

Results:

  • 1.75M+ requests
  • Document create/update/post activity
  • Accounting effects reads
  • Audit reads
  • Document flow reads
  • Report execution under write pressure
  • 0 dropped iterations
  • 0 business failures

This is the kind of workload that matters for NGB.

The platform needs to stay usable while documents are being created, posted, audited, explained, and reported on.

What I look at

For this framework, one metric is not enough.

I care about several signals together:

  • HTTP failure rate
  • Business operation failure rate
  • Dropped iterations
  • p95 latency
  • p99 latency
  • Checks
  • Thresholds
  • Report execution behavior
  • Operation-level breakdowns
  • Document post latency
  • Accounting effects latency
  • Audit latency
  • Document flow latency

A good result is not just:

The test finished.

A good result means:

  • No silent business failures
  • No dropped iterations for the target profile
  • No broken checks
  • No hidden vertical coupling in the shared framework
  • No report path that only works on a tiny dataset

For business software, performance is not only speed.

It is also correctness under pressure.

Why this matters for architecture

NGB is built around several platform-level ideas:

  1. Documents represent business intent

    Business operations are modeled as documents, not random database updates.

  2. Posting creates durable effects

    Posted documents can create accounting entries, audit records, operational state, and reportable business consequences.

  3. Auditability is part of the platform

    The system should explain what happened and why.

  4. Reports are connected to business truth

    Reporting is not just a separate dashboard layer.

  5. Verticals extend the platform

    Property Management, Trade, and Agency Billing should reuse the same platform capabilities without duplicating the core engine.

The performance framework follows the same architecture.

The shared framework tests platform concepts.

Vertical packages provide vertical-specific workloads.

That is the same boundary the runtime architecture is supposed to preserve.

What this does not claim

I want to be precise about the result.

This does not mean:

  • NGB has been certified by an external benchmark
  • NGB has unlimited scale
  • A local Docker run is the same as a production Kubernetes deployment
  • Every possible workload has been tested

That would be an overclaim.

What it does mean is more practical:

NGB is now tested beyond a toy demo dataset.

It has repeatable performance workloads for real platform behavior.

It can validate documents, posting, audit, accounting effects, document flow, reports, and mixed read/write scenarios against meaningful data volume.

That is a much stronger foundation than only saying:

It works on my machine.

Links

GitHub:

https://github.com/ngbplatform/NGB

Release:

https://github.com/ngbplatform/NGB/releases/tag/v1.1.1

Performance tests workspace:

https://github.com/ngbplatform/NGB/tree/main/performance-tests

Documentation:

https://docs.ngbplatform.com

Website:

https://ngbplatform.com

Final thought

Performance testing business software is not only about latency.

It is about confidence.

Confidence that the platform can preserve correctness under pressure.

Confidence that reports still work when data grows.

Confidence that audit history and document flow remain usable.

Confidence that posting does not become a black box.

NGB v1.1.1 is an important step in that direction.

The platform is no longer validated only by functional demos.

It now has a reusable performance testing framework for real business workloads.

That is the kind of foundation I want for building serious accounting-first business applications.

Metabase 61: AI fun police, build questions and dashboards with MCP, and much more!

AI access controls by user group

In v60 we put AI features in all plans, including Open Source. With v61, we give you the controls for AI governance that make it yours to deploy safely.

Some call it the Fun Police. We prefer: AI that’s realistic for orgs of all types to roll out, including those who need tighter oversight over who gets to use it (bit of a mouthful though).

Access controls for who can do what with AI

AI access controls by user group

Granular AI controls to manage access per feature and per user group, for internal and embedded analytics. Let your finance team ask questions in their own language in Metabot. Give your product team access to AI for SQL generation or auto-generated transforms. Give your data team access to all AI tools. Set nothing for the teams who shouldn’t have it.

Find AI usage controls in your Admin settings → AI to give access per feature and user group.

AI usage controls

Set token limits so AI doesn’t drain your bank account

Token limits per user group

Turning AI loose in your org without token restrictions is not for the faint of heart. We added controls to set a token limit at the instance level, and allocate a set amount of tokens or messages per user group, or per customer for embedded analytics. Choose when your limits reset — daily, weekly, or monthly.

Set token limits in your Admin settings → AI.

AI usage auditing

The MCP server now supports question and dashboard creation

Connect Metabase to your AI terminal and build questions and dashboards through conversation. With the MCP server connected in Claude, try:

Build me a dashboard from the Metabase sample database showing product performance, like total orders, revenue, and average rating by category.
Copy

It’s more interesting with real data, but you get the idea – now you have a dashboard, and all you had to do was ask.

Make Metabot your own, with system prompts and customization

Metabot customization and system prompts

White-label Metabot for your org by customizing its name, icon, and adding system prompts to instruct it on how to perform for AI chat, natural language querying, and SQL generation — so it sounds like it’s on your team.

System prompts are like context files that give AI the specifics of your business and your Metabase. Give it guidance on the tone you want it to use in chat, tables to treat as canonical, which colleague to blame if something goes wrong. Literally, anything.

Customize Metabot and set up your system prompts in Admin settings → AI.

AI usage analytics: see questions asked, token usage, and more

AI usage analytics dashboard

AI usage analytics is a pre-made dashboard in your Admin settings → AI. You can see aggregate views of token spend, which features are being used most, and who’s most active over time.

Track AI usage across your Metabase in Admin settings → AI → Usage auditing.

Dashboards-as-code built in your AI terminal

Git-backed content editing from Claude Code or Cursor

Open Claude Code or Cursor. Type: “Create a dashboard for our support tickets.” Your AI tool pulls context from your Metabase metadata, writes the queries, and commits a dashboard YAML file to git, ready for you to review before anything touches production.

Bulk edit and migrate dashboards to a new schema without clicking through the UI. Everything goes through git, with automated validation, before it goes live. Requires Remote Sync.

Metabot can write custom expressions in the query builder

What it says on the tin. Open the sample database, pull up Metabot, and try:

Show me a breakdown of product reviews by rating. Use emoji labels for each score.
Copy

Metabot will write the CASE expression and build the column without you touching the expression editor.

Not just AI — the metrics layer got smarter too

More power in the Metrics Explorer

Metrics math in the Metrics Explorer

The Metrics Explorer launched in v60 for side-by-side metric comparison. v61 adds metric math and more control over each metric:

  • Write arithmetic expressions across metrics in the top bar (Revenue / Number of orders, Orders this month - Orders last month). Results appear as a new series in the view.
  • Same metric, different slices. Add a metric more than once, each instance with its own filters or dimensions to compare slices side-by-side.
  • Totals tab to see the result as a single number rather than a chart.

Handy when you want to combine or compare metrics that live in different tables without having to set up a join. Open a metric and click into Explore to try it.

Security Center for self-hosted Metabases

Targeted, timely security alerts specific to your version and configuration, with guidance on what to do about it. See them in Security Center, or get notified via email or Slack.

This new Admin page polls your instance every few hours against the Metabase security advisory database, or you can check manually any time. Replaces generic blast emails that can be easy to miss or that aren’t relevant to your instance.

Find the Security in your Admin settings.

Embedded Analytics

AI chat embeds with either inline or dedicated charts

The useMetabot React hook gives you direct access to Metabot’s raw state — messages, loading indicator, send function — so you can build any UI on top of it.

Previously, <MetabotQuestion /> offered AI querying with 3 preset layouts. useMetabot is the lower-level primitive underneath. Same Metabot with more control over how it looks and fits into your app.

useMetabot works with Modular Embedding SDK.

More visibility into how your customers use your embedded charts

More usage analytics for embedded analytics to support admins’ understanding of who your most active customers — or tenants — are, which content gets the most views, and how people are accessing your embedded content via auth method for security audits.

Find the preconfigured embedding usage analytics dashboard in the Usage analytics collection, accessible to admins. Filter on date range, time grouping, and drill through charts for more detail.

Find the dashboard in Usage analytics → Embedding Usage in your left-side nav (admins only).

Automatic token renewal for Guest Embedding

Your embedded users don’t know what JWT is. They just know the dashboard went blank, and they think they’ve hit an error.

Guest embed sessions no longer break mid-dashboard when tokens expire. Automatic renewal means sessions stay alive through multi-tab dashboard explorations, and filters and drill-throughs stay applied for longer sessions.

Easier to configure, preview, and reuse themes for embedded analytics

The new Themes editor gives non-devs a wizard-based tool to try out, preview, and configure new themes to be applied consistently — separating theme configuration from implementation.

Try out themes in Admin settings → Embedding → Themes.

Responsive layout improvements for embedded SDK components

Better experience for mobile users interacting with your embedded analytics. SDK components are now built for a 6-inch screen, not just desktop. No overflowing filters or truncated text — acts the way mobile users expect.

Pay as you go for Transforms, no longer a fixed price add-on

Previously available as a fixed-price add-on. Now pay only for what you use. First 1,000 transforms are free.

See the pricing page for more details, or head to Data Studio and give it a try.

Big thanks to everyone who contributed!

Thanks to everyone who submitted bug reports, feature suggestions, and pull requests. Metabase gets better and better thanks to your efforts.

Hope you enjoy the release. If you want to get into the nitty-gritty, check out our changelog.

Cheers,

The Metabase team

Kadın Mühendis Okulu ikinci dönem mezunlarını verdi

OKA öncülüğünde Samsun’da düzenlenen Kadın Mühendis Okulu’nda 15 kadın mühendis mezun oldu. İlk dönem mezunlarının bir kısmı sanayi bölgelerinde görev alırken, program kapsamında yalın üretim ve dijital dönüşüm eğitimleri verildi.

Kazakistan ve Kenya ilişkilerinde yeni dönem

Kazakistan Cumhurbaşkanı Tokayev, Kenya Devlet Başkanı Ruto’nun ilk resmi ziyaretinin iki ülke ilişkilerinde yeni bir dönem başlatacağını belirtti. Görüşmelerde ticaret, tarım, ulaştırma ve turizm alanlarında işbirliği kararları alınırken, altı anlaşma imzalandı.