DAY 008 / SPIRAL SAFE

Spiral Safe: rebuilding a passkey-gated signing platform across eight repositories

How I reconciled eight repositories into a WebAuthn-authorized signing platform with a Vault boundary, scoped API keys, usage accounting, four demos, Raft deployment intent, and explicit Nitro gates.

01 / THE PRODUCT

Authorize a remote wallet with a passkey—without putting its private key in the browser.

Spiral Safe is a development-stage, WebAuthn-authorized signing and account platform. A dApp can discover a Solana wallet, ask a browser authenticator to approve a bound signing ceremony, and receive signed bytes while the chain key remains behind a Vault plugin.

The finished development pass spans eight repositories: the extension and Wallet Standard adapter, a direct SDK, the HTTP and Vault services, account and usage storage, developer and administrator consoles, deployment scaffolds, demos, and a canonical evidence map. It is a coherent prototype now. It is not an audited custody or billing product.

“Keeps keys out of the browser” is narrower than “non-custodial.” The Vault plugin still loads private-key bytes in process memory to sign, and Vault operators remain part of the trusted computing base. This note uses the narrower claim throughout.

02 / THE ARCHAEOLOGY RUN

The first deliverable was a trustworthy map of what already existed.

I began by cloning every public repository in the Spiral Safe organization and retaining its independent Git history. The first pass built the extension, SDK, adapter, legacy Hugo site, and token-list tooling; started the Vault plugin, Express adapter, and browser demo; exercised a bounded /check probe; and documented the existing Nitro-oriented branch.

That work mattered because the organization profile, website, issue roadmap, extension, and backend described overlapping versions of the product. The runtime was not one monorepo with one authoritative boundary. It was a set of experiments that had to be reconciled before new features could be trusted.

Two coordinated cross-repository delivery wavestext · source
2026-08-30 · core integration
├── extension       05e9b31  backend-mediated Wallet Standard provider
├── sdk             197ab53  authenticated chain-aware HTTP client
├── wallet-adapter  2922ba6  callable Wallet Standard feature routing
├── services        5c80fc5  hardened service, WebAuthn, Raft, Veil baseline
└── specs           bf7bb8b  architecture, runbook, security, verification

2026-08-31 · product and accounting layer
├── extension       ef79738  secure annotated extension demo
├── sdk             def536c  operation-bound completion contract
├── services        34ff343  accounts, billing consoles, recordings, Nitro admission
└── specs           38e3431  reconciled product and quorum documentation

The exact final main-branch heads were checked again for this article. The core repositories do not currently publish hosted CI workflows, so a public commit proves the source is present—not that every recorded command ran on GitHub infrastructure.

03 / THE FAULT LINE

The browser and backend disagreed about who owned the key.

The extension prototype generated a Solana key inside the browser, stored its secret in local storage, transported it through extension messages, and exposed methods that were not fully implemented. Separately, the service prototype already placed a key behind a Vault secrets-engine plugin and used WebAuthn, but its HTTP boundary had no application authorization and relied on a development root token.

The two inherited custody storiestext · source
browser extension prototype
├── generated its own Solana keypair
├── placed secretKey in localStorage
├── moved that key through extension messages
└── advertised wallet methods that were still stubs

Vault service prototype
├── created a server-side key behind a Vault plugin
├── used WebAuthn ceremonies to authorize signing
├── exposed the adapter with broad CORS and no client authorization
└── used one development root token between HTTP and Vault

finding
└── the browser and backend disagreed about who owned the key

This was not a one-function bug. Making the extension “work with the backend” meant replacing its custody model, completing Wallet Standard behavior, defining the browser bridge, authenticating the HTTP service, binding concurrent ceremonies, and preserving a chain-neutral seam inside the Vault plugin.

04 / EIGHT REPOSITORIES

Four repositories contain current client or runtime code.

Eight repositories become one legible systemFour repositories contain current client or runtime code. The browser path bundles the wallet adapter into the extension and reaches services; the SDK is an alternative direct client. Specs explains the system, while three other repositories sit outside the signing path.
RepositoryLayerRolePin
extensionBrowserVault-backed Solana Wallet Standard provideref79738
wallet-adapterPackageFeature registration and routing; no credentials2922ba6
sdkClientTyped bearer-authenticated service contractdef536c
servicesCoreVault plugin, HTTP API, billing, deployment, demos34ff343
specsEvidenceCanonical architecture, security, runbook, verification38e3431
token-listNon-runtimeInherited Jupiter data/tooling fork7bf90dc
websiteNon-runtimeLegacy Hugo marketing sitee6ce502
.githubNon-runtimeOrganization profile and license88cf033

A request does not traverse all four. The browser path bundles the wallet adapter into the extension and calls the service; a direct SDK client calls the same service contract without the extension.

The token list is an inherited Jupiter data fork and is not imported by the signer. The Hugo website is separate from both current demos. The organization profile contains aspirational production language. The specs repository is the canonical map, but two of its inventory sentences still describe the state immediately before the final pushes; this note therefore pins the final remote heads instead of repeating those stale counts.

05 / THE CUSTODY BOUNDARY

The page handles intent; the trusted worker handles credentials; Vault handles keys.

The injected provider runs in the page’s JavaScript world and speaks a versioned bridge to an isolated content script. The extension service worker then checks the browser-reported top-level tab, frame, and exact origin before it calls the service. Public configuration may return to the page, but the bearer token and ceremony bindings do not.

Browser-to-Vault trust contracttext · source
page context
├── may send: account name, chain, public payload bytes
├── may receive: WebAuthn options, address, signed result
└── must never receive: API token, Vault token, wallet private key

extension trusted worker
├── exact allowlisted origin + top-level frame
├── 2 MB request cap + correlated request ID
├── API token in chrome.storage.session
└── ceremony bound to tab, frame, origin, user, chain, operation

service + Vault plugin
├── derive tenant and scopes from authentication
├── bind payload to a random two-minute ceremony
├── require WebAuthn user verification
└── load the chain key inside the plugin only when signing

The API token and non-secret pending ceremony state live in trusted-context-only browser session storage. That allows a Manifest V3 worker to suspend during a passkey prompt without writing those values to durable page-visible storage. Session storage reduces persistence; it is not a hardware secret store.

Backend and RPC URLs are also reduced to their origins before page-facing inspection, because provider credentials are sometimes embedded in URL paths. The full endpoints remain available only to the worker that performs network requests.

06 / THE WEBAUTHN BRIDGE

Every signature is a two-part ceremony with server-owned continuity.

A passkey authorizes a server-bound payload, not a browser keyThe browser asks the backend to begin a ceremony, invokes WebAuthn locally, and returns the assertion under the original ceremony ID. The Vault plugin checks the stored operation before touching the chain key.
Registration and signing contracttext · source
registration
POST /init
→ navigator.credentials.create(options)
→ POST /create { ceremonyId, credential }

signing
POST /signin { chain, operation, payload }
→ navigator.credentials.get(options)
→ POST /complete { chain, operation, ceremonyId, credential }

server invariants
├── registration and signing states are distinct
├── ceremony IDs are random, expiring, and single-use
├── the requested operation must equal the stored operation
├── a nonzero signature-counter regression disables the credential
└── malformed completion consumes the ceremony before validation

The plugin generates a random, two-minute ceremony ID and stores the operation and payload behind it. Completion consumes that ID before it validates attacker-controlled credential data, preventing replay at the cost of making a malformed or cancelled completion non-retryable. Concurrent tabs receive independent ceremony state instead of racing one mutable user slot.

User verification is required. A cryptographic software authenticator covers the complete server-side lifecycle, including replay, user-verification, ceremony-binding, and signature-counter regression cases. Physical Touch ID, Windows Hello, synchronized passkeys, roaming security keys, and a full browser matrix remain separate release gates.

07 / SERVICE HARDENING

Four credentials now have four different jobs.

Do not collapse these credentialstext · source
API key
└── account + tenant + scopes + username allowlist

WebAuthn assertion
└── one registration or signing ceremony

console session
└── developer or administrator web role + CSRF state

Vault token
└── service workload → Vault; never a browser/client input

Production account mode authenticates a high-entropy API key, then derives the account, tenant, scopes, and non-empty username allowlist on the server. The caller cannot select another tenant in the request body. Unauthorized scope or username is rejected before Vault. Console sessions never act as wallet API bearer credentials, and Vault tokens are workload credentials rather than client input.

The HTTP adapter now has exact CORS origins, identifier and base64 validation, a decoded payload limit, request IDs, stable error mappings, timeouts, security headers, and bounded process-local rate limiting. Kubernetes mode exchanges a service-account JWT for a short-lived, engine-scoped Vault token and refreshes it before lease expiry.

08 / CHAIN-SPECIFIC SIGNING

A reusable ceremony does not make every chain operation safe by default.

The Go plugin now selects a ChainSigner for key generation, address derivation, and operation-specific signing. WebAuthn and storage code stay shared, while each chain owns its parser, signature encoding, and supported-operation boundary.

Chain signer boundary, condensedGo + text · source
type ChainSigner interface {
  Generate() (privateKey []byte, address string, err error)
  Address(privateKey []byte) (string, error)
  Sign(privateKey, payload []byte, operation string) (SignResult, error)
}

solana
├── Ed25519 address
├── legacy transaction signing
└── raw message signing

ethereum
├── secp256k1 + EIP-55 address
└── EIP-191 personal-message signing only
ChainKey / addressImplementedBoundary
SolanaEd25519; base58 addressLegacy transactions and raw messagesVersioned transactions are rejected; trusted intent display is absent.
Ethereumsecp256k1; EIP-55 addressEIP-191 personal messagesNo transaction signing, EIP-712, EIP-155, nonce, fees, simulation, or broadcast.

A panic boundary turns malformed Solana parser input into a normal signing error rather than losing the Vault plugin process. Ethereum proves the abstraction with one EIP-191 message path. It does not establish “anychain” custody, Ethereum transaction support, or a generic safety policy for future chains.

09 / THE ACCOUNT AND BILLING LAYER

Reserve usage before custody work; export it after a trusted result.

PostgreSQL now owns accounts, plans, password-derived console users, keyed session-token hashes, scoped API-key hashes, quotas, usage reservations, committed usage, an outbox, and Stripe webhook claims. A newly created API key’s plaintext is revealed once; only its non-secret prefix, scope, user allowlist, and peppered digest persist.

Usage accounting fails closed before custody workBilling is deliberately wrapped around signing rather than inserted into the cryptographic path. A quota reservation happens first; successful work commits usage and an outbox row; provider delivery happens asynchronously.
Reserve, sign, commit, exporttext · source
request
├── authenticate one-time-reveal API key from stored HMAC digest
├── resolve account, tenant, scopes, users, plan, period
└── reserve active_wallet or transaction_signed usage

Vault fails
└── cancel a newly created reservation

Vault succeeds and stored operation matches
├── commit usage + durable outbox row in PostgreSQL
├── return signature or signed transaction
└── export stable event asynchronously to Metronome

provider boundary
└── Metronome ingest creates no charge until an externally verified
    customer/contract/rate-card → Stripe mapping exists

The first successful action for a wallet in a billing period commits one active-wallet unit. Only successful transaction completion commits a transaction unit; message signatures do not. Idempotency keys prevent duplicate accounting, and the service compares the requested completion operation with the value returned from Vault before exposing output or charging usage.

Stripe Checkout and Customer Portal helpers, signature-verified webhooks, and asynchronous Metronome export are implemented. They have not produced a live invoice or collected a charge. Production also fails closed until an administrator attests the current Metronome-customer, contract/rate-card, and Stripe-customer mapping for each account.

10 / THREE DEPLOYMENT STORIES

Runnable Compose, rendered Kubernetes, and Nitro admission are different evidence levels.

Do not collapse three deployment modes into one claimThe repository contains three distinct deployment stories. Compose is disposable onboarding, Kubernetes is a rendered production baseline, and the Veil path is a fail-closed admission scaffold whose three missing infrastructure boundaries prevent a live Nitro quorum.

The production Kustomize overlay describes two service replicas and three Vault StatefulSet members using Integrated Storage/Raft, retained data and audit volumes, TLS, anti-affinity, a disruption budget, Kubernetes authentication, restricted pod security, and NetworkPolicies. The production profile deletes the local browser client.

PostgreSQL, KMS workload identity, ingress, public TLS, provider egress, StorageClass, recovery-key custody, snapshots, monitoring, and backup/restore remain operator inputs. The manifests were rendered during the development session; they were not applied to a real production cluster.

11 / VEIL AND NITRO ENCLAVES

One image can describe bootstrap and join—but it still cannot form a real quorum.

The historical Nitriding build path was replaced with a pinned Veil revision. One Linux/amd64 image can render either a bootstrap or join configuration from a strict, short-lived manifest. The enrollment script verifies nonce-bound PCR, TLS-certificate, source, and image expectations before it may call an external enrollment hook, then checks that the candidate appears as the expected Raft voter with healthy Autopilot state.

Same-image admission and its missing boundariestext · source
one pinned source image
├── mode: bootstrap | join
├── pinned source revision + Veil revision
├── unique Raft node ID and advertised addresses
├── shared KMS auto-unseal identity
├── fresh admission window ≤ 30 minutes
└── verification must pass before enrollment hook

three still-missing production boundaries
├── private cross-host L4 routing
├── rollback-protected durable enclave storage
└── attestation-bound manifest, TLS, and KMS delivery

therefore
└── same-image simulation ≠ EIF ≠ live Nitro quorum

The local simulation proves that one source image can render distinct node identities and controlled retry_join configuration. The enrollment test uses mock verifier, hook, peer-list, and Autopilot responses. No EIF was created, no enclave ran on EC2, and no live PCR, NSM, KMS, storage, cross-host route, or quorum behavior was demonstrated.

“Anyone can run a node” is incompatible with ordinary Vault Raft replication: membership grants a node custody-state access. A genuinely open operator network needs an explicit admission and governance protocol—and potentially threshold or MPC custody rather than a shared Vault database.

12 / FOUR ANNOTATED WALKTHROUGHS

The videos show product wiring—not hardware, cloud, billing, or capacity proof.

One final Playwright run produced four separate 1440×900 recordings. Each one contains five highlighted steps, a title and explanation overlay, a machine-readable timeline, and a permanent FIXTURE MODE · SYNTHETIC LOCAL DATA badge. They exercise real product code around named substitutes.

Actual unpacked extension demoThe actual unpacked Manifest V3 extension, Wallet Standard demo, trusted worker, browser WebAuthn calls, and deterministic fixture signing. Download the WebM.
Visual transcript for this silent fixture recording

There is no narration or audio track. The five visible chapters are:

  1. 01Configure the trusted worker with loopback-only fixture settings.
  2. 02Discover the extension through Wallet Standard.
  3. 03Register through navigator.credentials.create and a virtual authenticator.
  4. 04Authorize a deterministic message signature.
  5. 05Authorize a deterministic legacy Solana transaction signature.
Standalone wallet pageThe real standalone page selects Ethereum, registers a fixture wallet, prepares an EIP-191 message, and returns a deterministic signature. Download the WebM.
Visual transcript for this silent fixture recording

There is no narration or audio track. The five visible chapters are:

  1. 01Review the backend custody boundary.
  2. 02Select the Ethereum message-signing demonstration.
  3. 03Register the deterministic fixture wallet.
  4. 04Prepare a clearly synthetic message.
  5. 05Complete navigator.credentials.get and show the fixture signature.
Developer dashboardThe actual developer login and console routes show onboarding, masked key lifecycle, scoped-key creation fields, and seeded usage. Download the WebM.
Visual transcript for this silent fixture recording

There is no narration or audio track. The five visible chapters are:

  1. 01Sign in with a clearly fake fixture account.
  2. 02Review the seeded developer overview.
  3. 03Open scoped API-key management.
  4. 04Fill—but deliberately do not submit—the synthetic key form.
  5. 05Inspect active-wallet and transaction usage against fixture limits.
Admin dashboardThe actual administrator routes show tenant selection, policy state, account usage, and outbox delivery state with synthetic records. Download the WebM.
Visual transcript for this silent fixture recording

There is no narration or audio track. The five visible chapters are:

  1. 01Sign in through the actual administrator route with fixture credentials.
  2. 02Review the synthetic system posture.
  3. 03Open the tenant directory.
  4. 04Inspect a clearly labeled seeded account.
  5. 05Review pending and delivered usage-outbox state.

13 / LOAD AND ENDPOINT COVERAGE

The harness covers every route while refusing to masquerade as a capacity benchmark.

The guarded runner distinguishes safe probes from mutation scenarios, requires an explicit token, refuses remote targets and remote plaintext tokens without separate opt-ins, observes redirects instead of following them, and creates a unique ceremony ID for every request. Its parser and safety contract pass nine fresh tests at the pinned service commit.

26method/path scenarios
260fixture requests
0unexpected outcomes
9 / 9harness contract tests

The final session result was 260 requests across 26 method/path scenarios with zero unexpected statuses or client errors. Wallet mutation cases use successful /init plus expected negative or missing-user completion paths. The run does not measure successful WebAuthn-signing throughput, sustained capacity, multi-replica contention, soak behavior, or production latency.

14 / WHAT BROKE

The difficult bugs lived at boundaries, not inside the happy-path signature.

01

The key lived on both sides of the architecture

The original extension generated a local key while the backend already owned a Vault key. Integration began by deleting that disagreement, not by polishing either UI.

02

Redirect following hid the load result

Automatic redirects erased the status the endpoint matrix intended to inspect. The harness now preserves redirects and classifies exact expected outcomes.

03

Concurrent probes reused one-use ceremony state

The load runner needed a fresh ceremony identifier per request because replay protection is part of the contract, not noise to disable for testing.

04

Correct CORS rejection looked like a failure

A console login probe without the exact Origin correctly returned 403. The load expectation changed; the security boundary did not.

05

Completion lost the requested operation

The SDK and service now carry transaction versus message through completion and compare it with Vault’s stored ceremony before returning output or committing usage.

06

A deterministic demo hid persuasive security moments

Virtual WebAuthn removes operating-system UI, and the key form intentionally stops before secret reveal. Those are safer recordings, but they require explicit explanation.

15 / VERIFIED RESULT

The exact public pins reproduce the self-contained suites and keep external evidence labeled.

15 / 15extension tests
6 / 6SDK tests
2 / 2wallet-adapter tests
45 + 1service pass + DB skip
Fresh site-audit commands and final remote pinsshell + text · source
$ npm test                 # extension: 15 / 15
$ npm test                 # sdk: 6 / 6
$ npm test                 # wallet-adapter: 2 / 2
$ npm test                 # services: 45 pass + 1 PostgreSQL skip locally
$ npm run load:test        # harness: 9 / 9
$ npm run recording:test   # recorder: 8 / 8
$ go test ./...            # Vault/chain core: 10 / 10 in pinned Go image
$ go test ./...            # Nitro config renderer: 8 / 8 in pinned Go image
$ npm run build            # extension production bundle passed with warnings
$ npm run build:demo       # extension demo bundle passed with warnings

remote main pins
├── extension       ef797388f9f38a9b5f2879ee62c74bf2714a886e
├── sdk             def536cdbef94b3456b89c1e824d131ef17d2bda
├── services        34ff343bcb5a5f81ecceff7f8ed3102ead53645b
├── specs           38e34313a3c8046ac567177a49fa79e95f5f8425
└── four other repositories pinned in the evidence ledger below
Evidence classObserved resultSafe conclusion
Final public Git pinsEight remote main refs match the commits linked by this note.Code, tests, manifests, and documented boundaries exist at those exact revisions.
Fresh no-network rerun103 tests passed: extension 15, SDK 6, adapter 2, service 45, load 9, recorder 8, Vault/chain Go 10, and Nitro renderer 8; one database test skipped.Named client, service, harness, recorder, and Go behavior reproduced on one machine; no hosted CI claim.
Pinned verification recordFull 46/46 service run with ephemeral PostgreSQL, Go plugin checks, rendered manifests, and provider-mocked billing tests are recorded.Committed session evidence; this site audit did not independently rerun PostgreSQL, Kubernetes, Stripe, or Metronome.
Fixture walkthrough runFour 1440×900 recordings, twenty annotated steps, and no recorder warnings.Product wiring and presentation with a virtual authenticator, fake wallet, fake credentials, and loopback services.
Live all-route fixture load260 requests across 26 method/path scenarios with zero unexpected statuses or client errors.Endpoint/control-plane smoke with negative signing paths—not successful-ceremony throughput or capacity.

Across the current pinned suites, 103 tests passed and one PostgreSQL integration test skipped. The fresh service run intentionally had no TEST_DATABASE_URL, so 45 service tests passed; the pinned verification record preserves the earlier full 46-test run against an ephemeral PostgreSQL database. Its SDK count of five predates the final operation-binding test; the final SDK pin now passes six.

The extension production and demo bundles also build. Webpack reports non-blocking size warnings—462 KiB for the injected production bundle and 279 KiB for the demo bundle. That is a real performance debt, not a reason to hide a passing build behind a green checkmark.

16 / CURRENT TRUTH

The system is integrated and demonstrable. Production custody remains gated.

GateCurrent evidenceRequired next proof
Human authorizationSoftware and virtual authenticators exercise the ceremony.Run physical Touch ID, Windows Hello, passkey, and security-key matrices across supported browsers.
Signing intentWebAuthn binds an opaque payload and operation.Decode, simulate, apply policy, and show a trusted human-readable recipient, amount, program, fee, and nonce.
Identity and recoveryPassword consoles, scoped keys, and account-local roles exist.Add OIDC/SSO, MFA, forced reset, credential recovery, delegated approvals, and centralized abuse controls.
BillingStripe/Metronome adapters, webhooks, mapping gates, quotas, and outbox exist.Prove sandbox Checkout through invoice and collection, reconcile mappings, decide tax, and test provider failure.
Kubernetes and VaultSkaffold/Kustomize describe a three-node Raft baseline.Apply to a real cluster; test TLS, KMS, failover, backups, restore, upgrades, monitoring, and database HA.
Nitro quorumPinned Veil image and strict bootstrap/join admission scaffold exist.Implement routing, durable anti-rollback storage, attestation-bound delivery, then run EIF/EC2/NSM and quorum tests.
Release assuranceLocal tests and dated dependency scans are recorded.Add core CI, SBOMs, provenance, signed releases, license review, penetration testing, and an external custody audit.

WebAuthn currently approves an opaque challenge. There is no trusted transaction display, policy engine, wallet recovery, multi-credential management, or complete result-recovery protocol if a valid signature response is lost. A compromised allowlisted dApp can still choose confusing bytes for the user to approve.

There has been no independent custody, billing, or security audit; no penetration test; no production PostgreSQL recovery drill; no live Stripe charge; no real Kubernetes apply; and no Nitro enclave quorum. Until those gates close, use disposable devnet keys and test messages only.

17 / FILE GUIDE

The final system keeps custody, product, deployment, and evidence surfaces inspectable.

Organization maptext · source
Spiral-Safe/
├── extension/              # Manifest V3 provider and trusted worker
├── wallet-adapter/         # Wallet Standard registration and feature routing
├── sdk/                    # direct TypeScript HTTP client
├── services/
│   ├── backend.go          # Vault secrets-engine plugin
│   ├── signer.go           # Solana and Ethereum signer boundary
│   ├── src/                # HTTP adapter, consoles, billing runtime
│   ├── migrations/         # PostgreSQL account and usage schema
│   ├── load-test/          # guarded endpoint matrix
│   ├── recording/          # four annotated Playwright flows
│   ├── deploy/             # Kustomize local/production overlays
│   └── nitro/              # pinned Veil same-image admission scaffold
├── specs/docs/             # architecture, API, runbook, security, evidence
├── token-list/             # inherited data fork; outside runtime
├── website/                # legacy Hugo site; outside runtime
└── .github/                # organization profile; outside runtime

SECURITY

Release blockers

Current controls, threat assumptions, residual risks, and production gates.

18 / WHAT IS NEXT

The next milestone should prove one real boundary at a time.

  1. 01

    Record a desktop-level physical-authenticator run against the real Vault backend, covering registration, message, legacy transaction, batch, send, and SIWS.

  2. 02

    Decode and simulate supported transactions, bind a canonical human-readable intent to approval, and add a reviewed policy surface before any real asset.

  3. 03

    Run a Stripe/Metronome sandbox account from Checkout through usage events, invoice, collection, reconciliation, refund, provider failure, and a deliberate tax decision.

  4. 04

    Apply the Kubernetes baseline in a disposable cloud-real cluster and exercise KMS, Raft joins, failover, snapshots, restore, upgrades, database HA, and restrictive egress.

  5. 05

    Keep the Nitro experiment blocked until private cross-host routing, rollback-protected durable storage, and attestation-bound runtime delivery exist—then test a real quorum.

19 / EVIDENCE LEDGER

The article is pinned to final public source and labels session artifacts separately.

The shared development conversation supplied chronology and the final local recording manifest. Repository claims were checked against the public pins above. The four embedded WebMs are ignored development-session artifacts published here with explicit fixture labeling; their recorder source, flow definitions, and boundaries are committed in services. No private conversation URL, credential, trace, or private model deliberation is published.