{"id":48549944,"url":"https://github.com/vito416/blackcat-darkmesh-write","last_synced_at":"2026-04-08T08:03:27.127Z","repository":{"id":344885954,"uuid":"1183578540","full_name":"Vito416/blackcat-darkmesh-write","owner":"Vito416","description":"AO Write pipeline (commands/outbox) for Darkmesh, feeds public AO state.","archived":false,"fork":false,"pushed_at":"2026-04-03T16:19:41.000Z","size":805,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-03T19:33:38.384Z","etag":null,"topics":["ao","arweave","bfnl","blackcat","blackcat-covered-system","custom-license","darkmesh","source-available","weavedb","web3"],"latest_commit_sha":null,"homepage":"https://github.com/Vito416","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Vito416.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-16T18:45:46.000Z","updated_at":"2026-04-03T16:19:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Vito416/blackcat-darkmesh-write","commit_stats":null,"previous_names":["vito416/blackcat-darkmesh-write"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/Vito416/blackcat-darkmesh-write","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vito416%2Fblackcat-darkmesh-write","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vito416%2Fblackcat-darkmesh-write/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vito416%2Fblackcat-darkmesh-write/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vito416%2Fblackcat-darkmesh-write/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Vito416","download_url":"https://codeload.github.com/Vito416/blackcat-darkmesh-write/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vito416%2Fblackcat-darkmesh-write/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31545909,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"online","status_checked_at":"2026-04-08T02:00:06.127Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ao","arweave","bfnl","blackcat","blackcat-covered-system","custom-license","darkmesh","source-available","weavedb","web3"],"created_at":"2026-04-08T08:03:03.763Z","updated_at":"2026-04-08T08:03:27.113Z","avatar_url":"https://github.com/Vito416.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"# **blackcat-darkmesh-write**\n[![Project: Blackcat Mesh Nexus](https://img.shields.io/badge/Project-Blackcat%20Mesh%20Nexus-000?logo=github)](https://github.com/users/Vito416/projects/2) [![CI](https://github.com/Vito416/blackcat-darkmesh-write/actions/workflows/ci.yml/badge.svg)](https://github.com/Vito416/blackcat-darkmesh-write/actions/workflows/ci.yml) ![Lua](https://img.shields.io/badge/Lua-5.4-blue) ![License](https://img.shields.io/badge/License-BFNL--1.0-lightgrey)\n\n![Write Banner](.github/blackcat-darkmesh-write-banner.jpg)\n\nAO-native command layer for Blackcat Darkmesh. This repository hosts the write-side AO processes that enforce idempotent, authorized, and auditable changes to the canonical state maintained in `blackcat-darkmesh-ao`. No separate server-side authority exists; any bridge or admin client is only a transport adapter.\n\n\u003e This repo is infrastructure/back-end only: no UI assets, no public read path, no long-lived secrets.\n\n## Contents\n- [Scope](#scope)\n- [Architecture Snapshot](#architecture-snapshot)\n- [Interfaces at a glance](#interfaces-at-a-glance)\n- [Links hub](#links-hub)\n- [AO deploy (current runbook)](#ao-deploy-current-runbook)\n- [Release gate / deep test](#release-gate--deep-test)\n- [Development](#development)\n- [Env toggles (write process)](#env-toggles-write-process)\n- [CLI helpers](#cli-helpers)\n- [Prod hardening checklist](#prod-hardening-checklist)\n- [Monitoring](#monitoring)\n- [Bridge (stub)](#bridge-stub)\n- [Security Guard Rails](#security-guard-rails)\n- [License](#license)\n- [CI notes](#ci-notes)\n- [Docker quickstart](#docker-quickstart)\n\n## Scope\n- In scope: AO command processes, handlers, idempotency registry, audit/event emission, publish workflow (draft → review → publish → rollback), validators and schemas, minimal adapters, deploy/verify scripts, fixtures, CI workflows.\n- Out of scope: public read/state model (lives in `blackcat-darkmesh-ao`), gateway rendering, frontend assets, mailbox payload storage, SMTP/OTP/PSP integrations, template/catalog UI, or long-term secret storage (only public keys here).\n\n## Architecture Snapshot\n- Role: command-first AO process set that owns write semantics, conflict detection, and append-only audit; delegates state materialization to `blackcat-darkmesh-ao`.\n- Pipeline: command envelope → validation (schema + policy) → idempotency / anti-replay → handler → audit + event → downstream AO state update.\n- Identity \u0026 auth: signed commands or capability tokens; gateway is never an implicit authority.\n- Idempotence: `requestId` registry and optimistic `expectedVersion` guards to prevent duplicate writes.\n- Audit: append-only log with correlation to requestId and actor; deterministic status codes.\n\n```mermaid\nflowchart LR\n  A[Client / Gateway] --\u003e|Action envelope| V[Validation\n  - schema\n  - policy\n  - signature/JWT\n  - nonce/replay]\n  V --\u003e I[Idempotency check\n  requestId + expectedVersion]\n  I --\u003e H[Handler]\n  H --\u003e O[Outbox event\n  + HMAC]\n  H --\u003e W[WAL/audit]\n  O --\u003e D[Downstream AO / bridge]\n  style O fill:#0b7285,stroke:#0b7285,color:#fff\n  style W fill:#495057,stroke:#495057,color:#fff\n```\n\n```mermaid\nflowchart LR\n  WB[PSP/Webhook] --\u003e|POST| R[Webhook handler]\n  R --\u003e|verify sig| S{Signature OK?}\n  S --\u003e|no| B[Breaker + 4xx]\n  S --\u003e|yes| DQ[dedupe window]\n  DQ --\u003e|seen?| Drop[409 Conflict]\n  DQ --\u003e|new| Q[enqueue retry queue]\n  Q --\u003e|fetch PSP state| P[Process payment/update]\n  P --\u003e EV[emit event + HMAC]\n  style Q fill:#0b7285,stroke:#0b7285,color:#fff\n```\n\nLegend: teal = queues/events, gray = WAL/audit paths.\n\n### Interfaces at a glance\n\n| Area | Inputs | Outputs | Interfaces / Paths | Health | CI gates |\n|---|---|---|---|---|---|\n| Commands | Signed envelopes (`Action`, `Request-Id`, `Actor`, `Tenant`, `Expected-Version`, `Nonce`, `Signature-Ref`, `Timestamp`) | WAL entries, outbox events (HMACed), audit | `ao/write/process.lua`, schemas under `schemas/` | `scripts/verify/health.lua` | `preflight`, `contracts`, `conflicts`, `batch fixtures` |\n| Webhooks (PSP) | Stripe/PayPal/GoPay webhook POSTs + signatures | PSP events → outbox, breaker state, retry queue | `ao/shared/psp_webhooks.lua`, retry queue | metrics `webhook_retry_*`, `breaker_open` | `webhook_psp_spec`, `gopay_webhook_spec` |\n| Metrics | Prom text file (`METRICS_PROM_PATH`) | scrape/alerts | `/metrics` (if exposed) | `scripts/verify/health.lua` | `docs/ALERTS.md` |\n| Arweave gate | Artifact hash vs TX | pass/fail | `scripts/verify/verify_arweave_hash.sh` | n/a | `ENFORCE_ARWEAVE_HASH` stage |\n\n## Links hub\n- Alerts \u0026 thresholds: `docs/ALERTS.md`\n- Deploy runbook: `docs/runbooks/deploy.md`\n- Rollback runbook (incl. hash-gate handling): `docs/runbooks/rollback.md`\n- Env template: `ops/env.prod.example`\n- Schemas: `schemas/`\n- PSP/webhook specs: `scripts/verify/webhook_psp_spec.lua`, `gopay_webhook_spec.lua`\n\n## AO deploy (current runbook)\n- Canonical endpoint: `https://push.forward.computer`\n- Scheduler: `n_XZJhUnmldNFo4dhajoPZWhBXuJk-OcQr5JQ49c4Zo`\n- Runtime variant/tag family: `ao.TN.1` (module + process + message path in this repo)\n- Source of truth for live module/PID history: `AO_DEPLOY_NOTES.md` (do not treat this README as the TX ledger).\n\n### Publish module (WASM)\n```bash\nnode scripts/build-write-bundle.js\nao-dev build\nnode scripts/publish-wasm.js\n```\n\n`scripts/publish-wasm.js` publishes `dist/write/process.wasm` with the expected tags:\n- `Type=Module`\n- `Content-Type=application/wasm`\n- `Variant=ao.TN.1`\n- `signing-format=ans104`\n- `accept-bundle=true`\n- `accept-codec=httpsig@1.0`\n\n### Spawn process\n```bash\nAO_MODULE=\u003cmodule_tx\u003e \\\nHB_URL=https://push.forward.computer \\\nHB_SCHEDULER=n_XZJhUnmldNFo4dhajoPZWhBXuJk-OcQr5JQ49c4Zo \\\nWRITE_SIG_TYPE=ed25519 \\\nWRITE_SIG_PUBLIC=\u003cpubkey_or_hex\u003e \\\nnode scripts/cli/spawn_wasm_tn.js\n```\n\n### Finalization gate (required)\n- Expect temporary `404` on `https://arweave.net/raw/\u003ctx\u003e` shortly after publish/spawn.\n- Do not trust runtime behavior before both module and PID are indexed/finalized.\n- Typical observed delay in this project: initial 404 window + extended finalization (often tens of minutes).\n\n### Deep test entrypoints\n```bash\nHB_URL=https://push.forward.computer \\\nHB_SCHEDULER=n_XZJhUnmldNFo4dhajoPZWhBXuJk-OcQr5JQ49c4Zo \\\nAO_PID=\u003cpid\u003e \\\nnode scripts/cli/diagnose_message.js\n\nHB_URL=https://push.forward.computer \\\nHB_SCHEDULER=n_XZJhUnmldNFo4dhajoPZWhBXuJk-OcQr5JQ49c4Zo \\\nAO_PID=\u003cpid\u003e \\\nnode scripts/cli/send_write_command.js\n```\n\nFor worker-signed end-to-end tests, set `WORKER_SIGN_URL` + `WORKER_AUTH_TOKEN` (test values are kept locally in `tmp/test-secrets.json`).\n\n### Release gate / deep test\nRun the v1.2.0 readiness gate in one command:\n```bash\nAO_PID=\u003cpid\u003e \\\nHB_URLS=https://push.forward.computer,https://push-1.forward.computer \\\nAO_SECRETS_PATH=tmp/test-secrets.json \\\nscripts/verify/release_gate_v120.sh --strict\n```\n\nFlag form:\n```bash\nscripts/verify/release_gate_v120.sh \\\n  --pid \u003cpid\u003e \\\n  --urls https://push.forward.computer,https://push-1.forward.computer \\\n  --secrets tmp/test-secrets.json \\\n  --strict\n```\n\n- The gate runs preflight, luacheck, stylua, the core write smokes, and AO deep checks in a fixed order.\n- Without `--strict`, it still requires the send and primary readback probes to pass.\n- `--strict` extends CU readback assertions to every URL you pass.\n\n## Repository Layout (blueprint)\n```\ndocs/              # command contracts, flows, failure modes, ADRs, runbooks\nao/                # AO command process and shared libs\n  write/           # command handlers, routing\n  shared/          # auth, idempotency, validation, audit\nschemas/           # JSON schemas for command envelopes and actions\nscripts/           # deploy | verify\nfixtures/          # sample command envelopes and expected outcomes\ntests/             # contract, conflict, and security tests\nscripts/bridge/    # stub forwarder from write outbox to -ao\nscripts/cli/       # local helpers (run command)\n.github/workflows/ # CI entrypoint\n```\n\n## Minimal Command Envelope\n- Required tags: `Action`, `Request-Id`, `Actor`, `Tenant`, `Expected-Version`, `Nonce`, `Signature-Ref`, `Timestamp`.\n- Core handlers (initial set): `SaveDraftPage`, `PublishPageVersion`, `UpsertRoute`, `UpsertProduct`, `UpsertProfile`, `AssignRole`, `GrantEntitlement`, `LinkDomain`, `RotateKey`, `CreateReceipt`.\n- Conflict strategy: reject on missing/expired nonce, replayed `Request-Id`, or mismatched `Expected-Version`; return prior result when replayed.\n\n## Development\n- Prereqs: `lua5.4` (or `luac`) and `python3`.\n- Static checks: `scripts/verify/preflight.sh` (JSON schema validation + Lua syntax).\n- Contract smoke tests: `LUA_PATH=\"?.lua;?/init.lua;ao/?.lua;ao/?/init.lua\" lua5.4 scripts/verify/contracts.lua` (or set `RUN_CONTRACTS=1` to run during preflight).\n- Conflict/security smoke tests: `LUA_PATH=\"?.lua;?/init.lua;ao/?.lua;ao/?/init.lua\" lua5.4 scripts/verify/conflicts.lua` (or `RUN_CONFLICTS=1`).\n- Batch fixtures: `LUA_PATH=\"?.lua;?/init.lua;ao/?.lua;ao/?/init.lua\" lua5.4 scripts/cli/batch_run.lua` (or `RUN_BATCH=1` in preflight) – compares fixtures to `*.expected.json`.\n- Branches: `main` (releasable), `develop` (integration), `feature/*`, `adr/*`, `release/*`.\n- Message contracts and schemas are public API; prefer additive changes over breaking ones.\n\n### Quickstart (local dev)\n1) Install deps: `sudo apt-get install lua5.4 lua5.4-dev luarocks libsodium-dev`  \n   then install rocks from the lockfile:\n   ```bash\n   while read -r name ver; do\n     case \"$name\" in \\#*|\"\") continue ;;\n     esac\n     luarocks --lua-version=5.4 install --local \"$name\" \"$ver\"\n   done \u003c ops/rocks.lock\n   ```\n2) Copy env template: `cp ops/env.prod.example ops/.env.local` and fill secrets:  \n   - `OUTBOX_HMAC_SECRET` (required)  \n   - signature verifier (`WRITE_SIG_PUBLIC` or `WRITE_SIG_SECRET` when `WRITE_SIG_TYPE=hmac`)  \n   - optional `WRITE_JWT_HS_SECRET` if you turn on `WRITE_REQUIRE_JWT=1`.\n3) Run checks: `RUN_DEPS_CHECK=1 LUA_PATH=\"?.lua;?/init.lua;ao/?.lua;ao/?/init.lua\" LUA_CPATH=\"$HOME/.luarocks/lib/lua/5.4/?.so\" scripts/verify/preflight.sh` (or `make preflight RUN_DEPS_CHECK=1`).\n4) Fixtures: `RUN_BATCH=1 LUA_PATH=\"?.lua;?/init.lua;ao/?.lua;ao/?/init.lua\" lua scripts/cli/batch_run.lua` (uses the env from step 2; hashes/nonce/signature checks can be relaxed via `WRITE_REQUIRE_*` env).\n5) Outbox/queue paths in the template default to `/var/lib/ao/...`; for dev you can override to `dev/*` paths next to the repo.\n6) Optional specs:  \n   - JWT: `RUN_JWT_SPEC=1 lua5.4 scripts/verify/jwt_actor_spec.lua` + `scripts/verify/jwt_expiry_spec.lua`  \n   - Rate/nonce: `RUN_RATE_SPEC=1 WRITE_RATE_STORE_PATH=dev/write-rate-store.json lua5.4 scripts/verify/rate_store_spec.lua`; `RUN_RATE_SPEC=1 lua5.4 scripts/verify/rate_tenant_scope_spec.lua`  \n   - Outbox HMAC: `RUN_OUTBOX_SPEC=1 lua5.4 scripts/verify/outbox_hmac_spec.lua`\n\n## Env toggles (write process)\n- `WRITE_REQUIRE_SIGNATURE=1` — reject commands without `signatureRef`.\n- `WRITE_REQUIRE_NONCE=1` — reject commands without nonce and block replay.\n- `WRITE_NONCE_TTL_SECONDS` (default 300) and `WRITE_NONCE_MAX` (default 2048) — nonce cache sizing.\n- `WRITE_ALLOW_ANON=1` — allow missing actor/tenant (off by default).\n- `WRITE_SIG_TYPE=ed25519|ecdsa|hmac` (prod default: `ed25519`).\n- Signature verification inputs:\n  - `WRITE_SIG_PUBLIC` (single key; PEM path or `hex:\u003cpubkey\u003e` form),\n  - `WRITE_SIG_PUBLICS` (rotation/keyring map keyed by `signatureRef`, supports `default`),\n  - `WRITE_SIG_SECRET` (for `hmac` mode).\n- Optional JWT gate: set `WRITE_JWT_HS_SECRET` (HS256) and optionally `WRITE_REQUIRE_JWT=1` to fail-closed; claims `sub/tenant/role/nonce` populate `actor/tenant/role/nonce` when missing.\n- `WRITE_WAL_PATH=/var/lib/ao/write-wal.ndjson` — append-only WAL with request/response hashes.\n- `WRITE_IDEM_PATH=/var/lib/ao/write-idem.json` — persist idempotent responses across restarts (optional).\n- `WRITE_OUTBOX_PATH=/var/lib/ao/write-outbox.json` — persist outbox events (used by forwarders/export).\n- Checksum watchdog: `ops/systemd/write-checksum.service` + `scripts/verify/checksum_daemon.sh` (set `WRITE_WAL_PATH`, `WRITE_OUTBOX_PATH`, `CHECKSUM_INTERVAL_SEC`).\n- Resolver flags: `WRITE_FLAGS_PATH=/etc/ao/resolver-flags.ndjson` to block/readonly resolvers (shared with registry/AO); enforced before policy.\n- Shipping/Tax export for AO: persist rates with `WRITE_RATE_STORE_PATH` and run `scripts/export/rates.lua [rate_store] [shipping.ndjson] [tax.ndjson]`; point AO to the outputs via `AO_SHIPPING_RATES_PATH` / `AO_TAX_RATES_PATH`.\n- Dispute evidence payload: `AddDisputeEvidence` accepts `evidence.url|hash|hashAlgo|type|note|fileName` to carry provider links/hashes; stored in `payment_disputes` and can be sent via provider webhooks.\n- `WRITE_RL_WINDOW_SECONDS` / `WRITE_RL_MAX_REQUESTS` — rate-limit per tenant+actor (default 60s / 200 reqs).\n- `WRITE_RL_BUCKET_TTL_SECONDS` / `WRITE_RL_MAX_BUCKETS` — trim idle buckets (default 4× window, 4096 buckets).\n- `WRITE_RATE_STORE_PATH` — persist rate-limit buckets across restarts (optional; JSON file written atomically).\n- `WRITE_NONCE_STORE_PATH` — persist nonce cache (tenant+actor namespaced) to survive restarts.\n- Bridge/env for queue/HTTP: `AO_ENDPOINT=https://...` (optional); `AO_API_KEY`; `DRY_RUN=1` or `AO_BRIDGE_MODE=mock|off|http`; `AO_BRIDGE_RETRIES`/`AO_BRIDGE_BACKOFF_MS`; `AO_QUEUE_PATH` (persisted queue), `AO_QUEUE_LOG_PATH=/var/lib/ao/queue-log.ndjson`, `AO_QUEUE_MAX_RETRIES=5`, `AO_EXPECT_RESPONSE_HASH` to enforce downstream body hash.\n- PSP webhook hardening: set `STRIPE_WEBHOOK_SECRET` (32-byte secret from Stripe), `PAYPAL_WEBHOOK_STRICT=1` to require PayPal signatures, tune replay cache with `WRITE_WEBHOOK_REPLAY_WINDOW` / `WRITE_WEBHOOK_SEEN_TTL` (and optional `WRITE_WEBHOOK_SEEN_MAX`), and cap backlog with `WRITE_WEBHOOK_RETRY_MAX_QUEUE` alongside the existing `WRITE_WEBHOOK_RETRY_*` knobs.\n- Outbox HMAC enforcement: `WRITE_STRICT_OUTBOX_HMAC=1` rejects outbox events without `hmac` when `OUTBOX_HMAC_SECRET` is set (default off; forwarder still checks mismatches when `hmac` is present). HMAC input defaults to full canonical JSON of the event; set `WRITE_OUTBOX_HMAC_MODE=legacy` to use the older limited field hash.\n- Trust manifest signing (resolvers): set `TRUST_MANIFEST_HMAC` and run `lua scripts/cli/trust_manifest_sign.lua manifest.json \u003e manifest.signed.json`; optionally set `TRUST_MANIFEST_SIGNER`.\n- Key management: keep public keys under `/etc/ao/keys`, record their `sha256sum` in ops docs, rotate on a schedule; never store private keys in repos, artifacts, or CI logs.\n- OTP/passwordless flows and payment/PSP callbacks have been removed from this repo; keep secrets and such logic in upstream gateway/web layers.\n\n## Docker quickstart\n```bash\ndocker compose build\ndocker compose run --rm write         # runs full preflight (schemas, contracts, conflicts, batch)\ndocker compose run --rm write bash    # drop into shell with deps preinstalled\n```\nNotes: the image ships with Lua openssl + luasodium so PSP/webhook specs run with crypto enabled. `outbox replay smoke` will print `hmac failures: missing=1` if `OUTBOX_HMAC_SECRET` is unset; set it to silence that warning.\n\n## CLI helpers\n- `lua scripts/cli/run_command.lua ./fixtures/sample-save-draft.json` — route a JSON command locally and print the response (uses in-memory state). A publish sample is at `fixtures/sample-publish.json`.\n- `RUN_BATCH=1 LUA_PATH=\"?.lua;?/init.lua;ao/?.lua;ao/?/init.lua\" lua scripts/cli/batch_run.lua` — run all fixtures and enforce matches to `*.expected.json` (CI uses this).\n- Queue forwarder (persisted outbox → HTTP):  \n  `AO_QUEUE_PATH=dev/outbox-queue.ndjson AO_QUEUE_LOG_PATH=dev/queue-log.ndjson AO_QUEUE_MAX_RETRIES=5 LUA_PATH=\"?.lua;?/init.lua;ao/?.lua;ao/?/init.lua\" lua scripts/bridge/queue_forward.lua`\n- Outbox replay into a fresh queue (with HMAC verify):  \n  `OUTBOX_HMAC_SECRET=dev-secret WRITE_OUTBOX_PATH=dev/outbox.json AO_QUEUE_PATH=dev/outbox-queue.ndjson lua scripts/worker/outbox_replay.lua`\n- Health snapshot (write-side files \u0026 deps):  \n  `WRITE_WAL_PATH=... WRITE_OUTBOX_PATH=... AO_QUEUE_PATH=... LUA_PATH=\"?.lua;?/init.lua;ao/?.lua;ao/?/init.lua\" lua scripts/verify/health.lua`\n- Export verifier (PII scrub check):  \n  `WRITE_OUTBOX_EXPORT_PATH=dev/outbox.ndjson lua scripts/verify/export_verify.lua`\n\n## Prod hardening checklist\n\u003e 🚦 **Production readiness** — keep these on before serving real traffic.\n- Set `WRITE_STRICT_OUTBOX_HMAC=1` and ensure every emitted event includes `hmac`.\n- Keep signature/JWT verification on (WRITE_REQUIRE_SIGNATURE/WRITE_REQUIRE_JWT) and rotate keys regularly.\n- Persist idempotency/rate buckets/outbox where applicable (`WRITE_IDEM_PATH`, `WRITE_RATE_STORE_PATH`, `WRITE_OUTBOX_PATH`) and back them up.\n- Monitor `/metrics` (bearer from METRICS_BEARER_TOKEN) for `rate_limited`, `replay_nonce`, and outbox HMAC counters; alert on sustained errors.\n- If Arweave verification is mandatory on all branches, set `ENFORCE_ARWEAVE_HASH=1` and provide `ARWEAVE_VERIFY_FILE/ARWEAVE_VERIFY_TX`; CI will fail-closed otherwise.\n- Licensing quick links: BFNL-1.0 and Founder Fee Policy are authoritative — keep deployments within their terms.\n\n\u003e **Common pitfalls**\n\u003e - `OUTBOX_HMAC_SECRET` must be 64 hex chars (32B) or HMAC drifts and `secrets_lint` will fail.\n\u003e - `WRITE_SIG_TYPE` must match the key you provide (public key for ed25519/ecdsa vs shared secret for hmac).\n\u003e - `WRITE_NONCE_TTL_SECONDS` / replay window: too low → false rejects; too high → oversized seen-cache.\n\u003e - Arweave hash gate: with `ENFORCE_ARWEAVE_HASH=1` you need the correct `ARWEAVE_VERIFY_TX` + artifact, otherwise CI fails closed.\n\n## Monitoring\n- Expose Prom-style `/metrics` via `ao.shared.metrics` (see `METRICS_PROM_PATH`, `METRICS_LOG`, `METRICS_BEARER_TOKEN`).\n- Key counters:\n  - `outbox_queue_depth`, `write.outbox.queue_size`\n  - `write_auth_signature_failed_total`, `write_auth_signature_missing_total`\n  - `write_auth_jwt_invalid_total`, `write_auth_jwt_expired_total`, `write_auth_jwt_not_before_total`, `write_auth_jwt_skew_total`, `write_auth_jwt_*_mismatch_total`\n  - `write_auth_nonce_replay_total`\n  - `write_auth_rate_limited_total`\n  - `write.idempotency.collisions`, `idempotency_collisions_total`\n  - `write.webhook.retry_queue`, `webhook_retry_queue`, `write.webhook.retry_lag_seconds`, `webhook_retry_lag_seconds`, `webhook_retry_overdue`\n  - `write.psp.breaker_open`, `breaker_open`\n  - `write.wal.apply_duration_seconds`, `wal_apply_duration_seconds`\n  - `write_outbox_hmac_missing_total`, `write_outbox_hmac_mismatch_total`\n- Sample alerts (PromQL):\n  - `increase(write_auth_rate_limited_total[5m]) \u003e 50`\n  - `increase(write_auth_jwt_invalid_total[5m]) \u003e 5 or increase(write_auth_jwt_expired_total[5m]) \u003e 20`\n  - `increase(write_auth_nonce_replay_total[5m]) \u003e 0`\n  - `increase(write_outbox_hmac_mismatch_total[5m]) \u003e 0 or increase(write_outbox_hmac_missing_total[5m]) \u003e 5`\n  - `max_over_time(outbox_queue_depth[5m]) \u003e 100 or increase(webhook_retry_queue[5m]) \u003e 20`\n  - `increase(breaker_open[5m]) \u003e 0`\n- Add alerts on rising trends; log/Prom output controlled by `METRICS_*` envs in `ao/shared/metrics.lua`.\n- More alert examples: `docs/ALERTS.md`.\n\n## Bridge (stub)\n- `scripts/bridge/forward_outbox.lua` reads the in-memory outbox (`write._storage_outbox()`) and logs events you would forward to `blackcat-darkmesh-ao`. Replace `forward_event` with signed POST to AO endpoint (registry/site process) in production.\n- `scripts/bridge/export_outbox.lua [outfile]` dumps outbox to NDJSON (default `dev/outbox.ndjson`) for offline inspection or manual upload.\n- `scripts/bridge/forward_outbox_http.lua` posts outbox events to `AO_ENDPOINT` (set `DRY_RUN=1` to log only; optional `AO_API_KEY`, `AO_SITE_ID` tag).\n\n## Security Guard Rails\n- No secrets or raw keys in AO state, manifests, or adapters.\n- Gateways act only as clients; write process re-validates auth and policy.\n- All comments and docs remain in English.\n\n## License\nBlackcat Darkmesh Write is licensed under `BFNL-1.0` (see `LICENSE`). Contribution and relicensing rules are governed by the companion documents in `blackcat-darkmesh-ao/docs/`. This repository is an official component of the Blackcat Covered System; the repo split inside `BLACKCAT_MESH_NEXUS` is only for maintenance/safety/auditability and does **not** trigger a separate fee event for the same deployment.\n\nCanonical licensing bundle:\n- BFNL 1.0: https://github.com/Vito416/blackcat-darkmesh-ao/blob/main/docs/BFNL-1.0.md\n- Founder Fee Policy: https://github.com/Vito416/blackcat-darkmesh-ao/blob/main/docs/FEE_POLICY.md\n- Covered-System Notice: https://github.com/Vito416/blackcat-darkmesh-ao/blob/main/docs/LICENSING_SYSTEM_NOTICE.md\n\n## CI notes\n- CI currently runs schema/lua/stylua checks, ingest/envelope/action validation, publish/idempotency/conflict/hmac smokes, and Arweave/hash gates (based on env flags).\n- If `scripts/sign-write.js` is used in verify scripts, Node dependencies must be installed (`npm ci` step is required in CI).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvito416%2Fblackcat-darkmesh-write","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvito416%2Fblackcat-darkmesh-write","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvito416%2Fblackcat-darkmesh-write/lists"}