myc

Self-custodial remote signer for Radroots apps
git clone https://radroots.dev/git/myc.git
Log | Files | Refs | README | LICENSE

AGENTS.md (26804B)


      1 # myc — repository agent contract
      2 
      3 ## 1. Scope and operating model
      4 
      5 - This file applies to the complete repository unless a nearer `AGENTS.md` is
      6   stricter.
      7 - This repository owns `myc`, the standalone Radroots NIP-46 signer service.
      8   Treat identity custody, signing, approval, session, persistence, and
      9   signer-facing transport as security-critical behavior.
     10 - Keep the repository independently buildable, testable, packageable, and
     11   operable. Do not depend on private repositories, unreachable or unlocked
     12   artifacts, internal monorepo paths, absolute workstation paths, or private
     13   harnesses. An unpublished public dependency is allowed only when its exact
     14   commit is reachable from the governed public Git source and pinned by the
     15   checked-in source lock.
     16 - `.github/**` and capsule-local CI workflows are forbidden; keep validation
     17   forge-agnostic, and place any required monorepo orchestration exclusively
     18   under the parent monorepo's root `.act/**` authority.
     19 - Do not add or retain tracked `docs/**`, `.github/**`, or `.act/**` content in
     20   this capsule. Human-facing Myc specifications, decisions, runbooks, and
     21   qualification evidence belong under the parent monorepo's
     22   `docs/oss/myc/**` authority; standalone machine-enforced declarations belong
     23   under this repository's governed contract surfaces.
     24 - Myc does not own relay storage or tenancy, general relay fanout, SDK contract
     25   generation, wallet UX, hosted accounts, telemetry, artifact promotion, or
     26   deployment transport.
     27 
     28 ## 2. Authority and preflight
     29 
     30 - Before editing, read this file, `README`, `Cargo.toml`,
     31   `radroots.service.source-lock.v2.toml`, the relevant implementation and tests,
     32   and `flake.nix` or migrations when they are in scope.
     33 - `.radroots-consumer-root` is the standalone source-lock identity and must
     34   remain exactly `myc`. The implemented control-plane contract is
     35   `contracts/services_hardening/operator_contract.v1.json`.
     36   Service implementation must use its exact routes, operation IDs, model
     37   fields, doctor checks, and shared host/exit references; prototype CLI or
     38   HTTP behavior is not authority to reinterpret that contract.
     39 - The exact signer-provider inventory and resource boundary is
     40   `contracts/services_hardening/provider_contract.v1.json`. Keep its role,
     41   provider, capability, call-identity, deadline, limit, credential-reference,
     42   cancellation, and no-publication facts synchronized with the sealed Rust
     43   models. Provider wire encoding and result verification may refine only the
     44   later checkpoints that own those boundaries; they may not widen this
     45   contract.
     46 - The encrypted-file implementation is frozen by
     47   `contracts/services_hardening/encrypted_identity_envelope.v1.json`. It must
     48   use the source-locked `radroots_secrets` v2 context-bound envelope, explicit
     49   caller-supplied entropy, create-new owner-only persistence, expected-public-
     50   key verification, and state-backup exclusion. Credential artifact resolution
     51   remains a separate boundary and may not introduce a sibling-key fallback.
     52 - Wrapping-credential resolution is frozen by
     53   `contracts/services_hardening/wrapping_credential_resolution.v1.json`. It
     54   derives one validated shared artifact name beneath the canonical instance
     55   secrets root, reads only an existing exact owner-only artifact, and exposes
     56   neither a caller path nor caller bytes. Production injection/mounting and
     57   repo-local provisioning are external/offline; ordinary run, TOML,
     58   environment, arguments, envelope siblings, and state backup never create or
     59   carry the credential.
     60 - Local-signer transport is frozen by
     61   `contracts/services_hardening/local_signer_transport.v1.json`. It uses the
     62   hardened Lib `AdminClient` for one fixed HTTP/1.1 JSON endpoint over a Unix
     63   socket, carries the complete provider-operation binding in closed tagged
     64   request/response models, enforces configured body/deadline/concurrency
     65   limits, and returns only semantically untrusted output for Step 135.
     66 - Provider verification is frozen by
     67   `contracts/services_hardening/provider_verification.v1.json`. It requires
     68   injected observation time, rebinds the complete response to the configured
     69   provider and original operation, verifies peer/direction/version and exact
     70   protocol shapes, cryptographically verifies signed events, retains their
     71   exact canonical bytes, and returns only a sealed redacted result.
     72   Verification is not publication and performs no provider execution or
     73   database mutation.
     74 - Step 136 removes the orphaned prototype provider tree and its keyring,
     75   managed-account, plaintext/adjacent-key, child-process, implicit-identity,
     76   generic remote-session, legacy logging/client, and unused dependency
     77   surfaces. Do not restore those files, dependencies, or Tokio process
     78   capability; `radroots_nostr_connect` remains only as the active NIP-46
     79   protocol dependency.
     80 - Step 137 owns only the existing-state runtime foundation and exact startup
     81   prerequisite inventory. Encrypted-file opening runs in joined one-shot
     82   supervisor tasks; local-signer construction performs no probe, and no
     83   provider is ready before its governed verification. Do not add detached
     84   handles, a library runtime, signals, process exit, relay/admin execution, or
     85   a false readiness transition here.
     86 - Step 138 freezes a root-only public API. Keep every implementation module
     87   private, expose only curated crate-root names, keep public errors crate-owned
     88   and source-free, and update the reviewed API baseline and package guards for
     89   every intentional public-surface change. Shared runtime-path, SQLite, and
     90   storage identity types are deliberate governed contract dependencies;
     91   provider, SQLx, Serde, transport, and task implementation types are not.
     92 - Step 139 established the predecessor service source lock and pre-promotion
     93   native package metadata. Keep the exact Lib revision consistent across every
     94   direct Radroots dependency, Cargo.lock, the verified source archive, and the
     95   generated v2 service lock. Deferred `flake.nix` and `flake.lock` material is
     96   independently digest-bound and may select an older reachable Lib revision;
     97   it is not active native revision authority. Native target metadata does not
     98   qualify an artifact; Nix, OCI, signing, tags, publication, and deployment
     99   remain deferred.
    100 - RCLD-RSHR-195 Step 245 advances the active native Lib source lock and freezes
    101   Myc state creation behind the runtime-path directory plan plus the sealed
    102   service-SQLite initializer. Explicit initialization may provision only the
    103   exact governed service-instance suffix after identity and catalog validation;
    104   every existing-only open remains non-creating. Do not restore raw paths, raw
    105   SQLx connections, filesystem probes, or directory-creation fallbacks at the
    106   state-host boundary.
    107 - Step 148 closes the production NIP-46 response authority in
    108   `contracts/services_hardening/nip46_response_commit.v1.json`. Production
    109   code may commit a completion only through the atomic exact-response method;
    110   a retained completion without its immutable response and initial delivery
    111   state is inconsistent evidence and must never be repaired implicitly.
    112 - Step 150 introduced the historical 21-route and 35-model Myc Unix-admin
    113   adapter. Step 159 unit 13 owns its final 19-route and 32-model form by
    114   removing live identity rekey and replacement. Keep the shared Lib router
    115   private; reject model drift, unknown/duplicate/null
    116   fields, noncanonical response bytes, invalid path/query values, and unsafe
    117   errors at the adapter boundary. Domain handlers must bind authenticated
    118   cursors to route/filter/snapshot identity and must retain exact operation-ID
    119   replay/conflict evidence before returning success. Do not infer relay
    120   delivery from a successful local mutation and do not add TCP admin routes.
    121 - Step 152 freezes the one-parse CLI execution split. Every admitted command
    122   must select exactly daemon, offline, or permissioned Unix-admin authority;
    123   only the explicitly contracted read-only status, backup, and public-identity
    124   operations may fall back after proving the daemon writer lock is free.
    125   Identity rekey and replacement are offline create-new/config-apply
    126   operations and have no live command or route. Every retained live mutation
    127   has no direct-state fallback.
    128   Do not reparse process arguments or let a live CLI plan obtain SQLite,
    129   provider, relay, task, signal, or runtime authority.
    130 - Step 153 freezes one ordered 13-check doctor engine. Check adapters retain
    131   their operation-specific authority and may return only closed observations;
    132   the engine owns exact deadlines, required/optional aggregation, fixed safe
    133   summaries/remediation codes, bounded canonical JSON, and exit 6 for required
    134   failure or timeout. Do not admit raw errors, paths, URLs, keys, credentials,
    135   arbitrary details, unbounded output, detached probe work, or
    136   liveness/readiness probe authority. A pass must prove every contracted scope
    137   facet, and deadline cancellation must stop or synchronously own cleanup.
    138 - Step 154 freezes one passive latest-value status cache around the shared Lib
    139   lifecycle primitive. The non-clone publisher encodes the complete bounded v1
    140   local-status envelope before atomic replacement; cloneable readers may only
    141   return the retained immutable snapshot. Status reads never query SQLite,
    142   providers, relays, credentials, DNS, time, or fresh probes and never spawn a
    143   task. Keep connection-count keys and identity roles closed, preserve the last
    144   valid snapshot on any failed publication, admit only the fixed twelve status
    145   reasons, and keep detailed status on the permissioned Unix-admin boundary.
    146 - Step 159 unit 10 owns schema-v10 offline configuration lifecycle. Keep the
    147   configuration-binding ledger append-only and capped at 1,024 generations;
    148   seed one post-migration generation without rewriting the immutable birth
    149   record. Startup must match the latest config/public-identity binding. Identity
    150   changes revoke live connection/challenge authority, permission narrowing
    151   revokes affected sessions only, and an existing relay referenced by
    152   nonterminal delivery work cannot be removed or changed. Do not persist relay
    153   URLs, paths, credentials, provider envelopes, or protected values in the
    154   binding history.
    155 - Step 159 unit 11 owns schema-v11 bounded admin idempotency. Keep operation
    156   identifiers on the fixed ASCII grammar, bind route plus canonical request
    157   digest, cap replay models at 8,192 bytes, prune only expired Completed rows,
    158   reserve completion capacity at admission, and retain unresolved Prepared
    159   evidence as outcome-unknown. The configured admin response cap must admit the
    160   maximum model in its bounded success envelope. Never persist a
    161   request body, path, correlation ID, credential, bundle path, or secret in the
    162   journal. Database-only mutations must later compose their effect, audit, and
    163   completion in one transaction; online backup records Prepared before capture
    164   and completes only after the bundle is durable.
    165 - Step 159 unit 12 owns the crate-private provider executor, the exact
    166   source-locked `radroots_transport_nostr` adapter, and the durable delivery
    167   worker. Provider results remain untrusted until independently verified.
    168   Delivery preparation performs no relay I/O; the worker persists Submitted
    169   immediately before execution, maps post-submit cancellation or lost
    170   acknowledgement to UnknownAcknowledgement, and retries only the exact
    171   committed signed bytes. Never hold a SQLite transaction across provider or
    172   relay work, detach protected blocking work, expose the executor/client, or
    173   create one task per relay. Unit 15 alone wires these components into the
    174   fixed runtime graph and startup handshake.
    175 - Step 159 unit 13 owns the final 19-route/32-model production Unix-admin
    176   server around the exact handler boundary, the configured transport-limit
    177   projection, the canonical permissioned `admin.sock` binding, and the
    178   machine-bound composition facts for the existing sole status publisher,
    179   passive three-route operations server, and injected 13-check doctor. Keep
    180   shared routers, listeners, entropy, and cancellation private. Unit 14 owns
    181   secure CLI/config bootstrap and concrete doctor probes; Unit 15 alone owns
    182   server task spawning, provider/relay wiring, readiness, reconnect, and
    183   shutdown.
    184 - Step 159 unit 14 owns the one-pass process executor, descriptor-bound config
    185   loading and create-new persistence, fixed zeroizing identity-provisioning
    186   input, actual existing-state metadata discovery, explicit backup/restore
    187   inputs, one binary-owned configured Tokio runtime, and concrete bounded
    188   doctor probes. Keep result bytes on stdout and fixed diagnostics on stderr.
    189   The executable must not provision deployment directory trees, derive runtime
    190   limits from host CPUs, read secret arguments or environment variables, open
    191   an existing live database before validating a restore manifest, publish from
    192   doctor, or return success without the Unit 15 daemon `run` graph. Unit 15
    193   owns that graph, process signals, readiness/reconnect, and phase-aware drain.
    194 - Step 160 owns the standalone native release-artifact boundary in
    195   `contracts/services_hardening/native_release.v2.json` and `cargo xtask
    196   native-release`. Keep its exact two Linux targets, clean committed source,
    197   caller-supplied binary, positive deterministic epoch, bounded generated
    198   inventory, vendored offline source archive, source lock, CycloneDX SBOM,
    199   notices, checksums, unsigned provenance, and fixed systemd template closed.
    200   Outputs remain external to the source tree. Do not accept a caller service
    201   root, arbitrary member name, Nix/NixOS/OCI input or output, signing key,
    202   parent-owned human document, private harness, protected material, or
    203   publication/deployment authority.
    204 - RCLD-RSHR-150 Step 227 owns the fixed standalone systemd unit and
    205   `systemd_qualification.v1.json`. Keep the canonical service-host directory
    206   directives, stable exit-code restart split, bounded stop, empty capability
    207   sets, no environment-carried credentials, systemd 252 minimum, and maximum
    208   offline exposure 3.0 exact. The Linux verifier must fail closed when
    209   `systemd-analyze` is absent. Do not enable compatibility-sensitive
    210   `MemoryDenyWriteExecute` or syscall filters until the Step 229 integration
    211   wave proves them against the real binary; do not install, enable, start, or
    212   deploy a production service here.
    213 - Step 221 integration requires a signer-transport-authored `pending_connection` response for an
    214   explicitly approval-gated NIP-46 connect request. Keep that exact response
    215   and its initial delivery job atomic and immutable without recording a false
    216   terminal operation completion; relay delivery and exact replay use only the
    217   retained signed bytes, and terminal response authority must not conflict
    218   with the pending response.
    219 - Step 161 owns the closed executable qualification matrix in
    220   `contracts/services_hardening/process_qualification.v1.json`. Keep its
    221   process deadlines, parallelism, soak count, crash fixture, output bound,
    222   actual-process corpus, and component evidence exact. Crash injection is an
    223   external test-process termination only; do not add a production failpoint,
    224   hidden command, environment selector, detached test worker, or public test
    225   API. Failed backup and restore work must retain collision/recovery evidence,
    226   preserve the live database, and recover only through the governed next
    227   process open.
    228 - Treat checked-in source, tests, and prototype behavior as implementation
    229   evidence, not permission to preserve behavior that the active requirement
    230   removes.
    231 - Do not invent protocol behavior, APIs, dependencies, release processes,
    232   identity authority, migration behavior, or external integration semantics.
    233 - Inspect `git status --short`, the exact repository root, and nearby tests
    234   before changing behavior. Preserve unrelated work and stop on an unresolved
    235   security or custody conflict.
    236 - Keep changes narrowly scoped and independently reviewable. Do not mix
    237   unrelated cleanup, speculative abstractions, roadmap work, or compatibility
    238   scaffolding into a checkpoint.
    239 
    240 ## 3. Clean-slate service rule
    241 
    242 - Do not add or preserve prototype configuration readers, `.env` or
    243   `--env-file` runtime configuration, `MYC_*` runtime selectors, JSON/JSONL
    244   mutable state, prototype config/state importers or migrations, worker paths,
    245   old-path probes, aliases, fallbacks, dual readers/writers, deprecated
    246   modules/APIs/re-exports, or old/new feature switches. Offline production
    247   schema migration must never accept an unreleased prototype format.
    248 - Remove superseded behavior and update every affected Radroots-owned consumer
    249   directly. Do not hide a breaking change behind a compatibility adapter unless
    250   an accepted public requirement explicitly requires one.
    251 - Preserve canonical NIP-04, NIP-44, and NIP-46 interoperability. Clean-slate
    252   product behavior never authorizes protocol drift or relaxed wire validation.
    253 - A breaking config, CLI, state, provider, admin, error, or wire change must
    254   update its public machine contracts, examples, tests, generated surfaces, and
    255   release qualification in the same coherent sequence.
    256 
    257 ## 4. Identity, provider, and secret boundaries
    258 
    259 - Keep transport, user, and optional discovery identities explicit. Never
    260   generate, replace, infer, or collapse an identity during ordinary `run`.
    261 - Support only the governed `encrypted_file` and permissioned Unix-socket
    262   `local_signer` providers. Do not add plaintext keys, arbitrary child
    263   commands, shells, desktop/server keyrings, managed accounts, TCP signers, or
    264   sibling wrapping-key fallback.
    265 - Treat every provider result as untrusted. Verify contract version, operation
    266   and correlation IDs, expected identity and role, bounds, exact unsigned event
    267   fields, author, event ID, signature, and applicable NIP semantics before use.
    268 - Keep plaintext keys, decrypted key material, wrapping credentials, provider
    269   secrets, and equivalent protected material out of config, logs, status,
    270   metrics, audit output, fixtures, backups, process arguments, environment
    271   contracts, error strings, and ordinary `Debug` output. A governed backup may
    272   contain the encrypted ciphertext envelope, but never the material needed to
    273   unwrap it. Minimize and zeroize protected values where practical.
    274 - Use typed request, response, approval, permission, session, provider, and
    275   error models. Raw provider, relay, SQL, or source-chain errors never cross a
    276   public or operator boundary.
    277 
    278 ## 5. Configuration, state, and process boundaries
    279 
    280 - Load exactly one immutable, strictly versioned TOML document. Reject unknown
    281   fields, implicit relays, unsafe defaults, environment overlays, includes,
    282   interpolation, fragments, hot reload, and arbitrary leaf flags.
    283 - Each service instance owns one explicitly initialized SQLite catalog and one
    284   live writer lock. Normal `run` opens existing state only and never creates,
    285   imports, guesses, or silently migrates prototype state.
    286 - Keep raw SQLite pools and write authority private to the store. The daemon is
    287   the only live writer; live mutations and online backup use the typed,
    288   permissioned Unix-socket admin boundary and never fall back to direct writes.
    289   Offline state operations must prove that no daemon writer lock is held.
    290 - Never hold a database transaction while waiting for a provider, relay, DNS,
    291   clock, entropy, or other external effect.
    292 - Parse the process CLI and initialize the tracing subscriber only in the
    293   binary composition boundary. Library modules may emit tracing events but
    294   must not install signal handlers, create nested Tokio runtimes, call
    295   `process::exit`, or detach authoritative tasks.
    296 - Inject wall time, monotonic time, entropy, providers, transport, and
    297   failpoints. Supervise and join every authoritative task; panic, error, or
    298   unexpected successful return from a critical task must coordinate shutdown
    299   and produce a nonzero process result.
    300 - Keep the Myc critical-task graph bounded and sealed. A task receives only its
    301   cooperative cancellation observer; callers cannot name tasks, extract task
    302   handles, detach work, install signals, or select process exits through this
    303   library boundary. Step 159 owns signal and forced-shutdown composition.
    304 
    305 ## 6. Admission, commit, and publication invariants
    306 
    307 - Bound and validate signed event bytes, tags, authored time, recipient,
    308   signature, event ID, decrypted plaintext, request identity, method, replay,
    309   conflicting reuse, connection admission, authorization challenges, and rate
    310   retention before accepting work.
    311 - Keep authorization-challenge URLs and display-only client metadata under
    312   operator policy; untrusted clients never choose redirect or display
    313   authority. Use separate bounded rate budgets for connection admission and
    314   authorization challenges so exhaustion of one cannot bypass or disable the
    315   other.
    316 - Commit the request decision, session effects, audit, exact serialized signed
    317   response bytes, immutable target set, and initial outbox state atomically
    318   before any relay submission.
    319 - Treat stored signed bytes as the sole publication authority. Retry, crash
    320   recovery, and reopen must submit the identical bytes and digest without
    321   deserializing, rebuilding, re-signing, or changing targets.
    322 - Create delivery jobs only inside the atomic signed-response or discovery
    323   transaction. Recovery is a bounded, cursor-driven repository operation with
    324   injected time/jitter evidence; final supervised startup looping remains a
    325   later runtime owner.
    326 - Render NIP-05 only from verified committed discovery state through an
    327   explicit desired/current offline operation. The service library must not
    328   silently host the document or acquire network authority while rendering it.
    329 - Distinguish submitted, delivered, failed, and unknown outcomes. Lost
    330   acknowledgement never becomes proof of failure or delivery.
    331 - Bound every queue, pool, request, response, event, tag set, retry schedule,
    332   deadline, rate window, retention set, audit query, and in-memory collection.
    333   Saturation must reject or defer safely without dropping committed work.
    334 
    335 ## 7. Admin and observability boundaries
    336 
    337 - Detailed status and every live mutation use bounded, versioned HTTP/JSON over
    338   the permissioned Unix socket. Do not add TCP admin, browser auth, CORS, or a
    339   direct writable CLI fallback.
    340 - Optional TCP operations expose only cached `/livez`, `/readyz`, and
    341   `/metrics`. They must not perform SQLite, provider, relay, credential, DNS,
    342   or other active probes.
    343 - Keep the Myc TCP adapter sealed around the source-locked service-host server.
    344   Do not add route registration, raw listener/server access, dependency-owned
    345   public types, or a second independently observed lifecycle cache. Publish
    346   only the fixed cached phase/readiness metric families and closed phase label.
    347 - Keep logs as safe structured stderr output. Keep result data on stdout and
    348   diagnostics on stderr. Use stable bounded public codes and messages, bounded
    349   metric labels, and explicit redaction.
    350 - Emit only the sealed `MycLogRecord` vocabulary. Do not log caller text, raw
    351   errors or sources, paths, SQL, relay URLs, identifiers, credentials,
    352   protected content, or decrypted payloads. Keep the exact 0-6 process result
    353   mapping synchronized with the operator contract; do not call process exit
    354   from library code or add file logging.
    355 - Backup and restore must preserve lock, manifest, integrity, schema, service,
    356   instance, identity, permission, fsync, atomic-rename, and protected-material
    357   exclusion invariants.
    358 
    359 ## 8. Rust and test discipline
    360 
    361 - Prefer pure transformations, explicit state machines, validated newtypes,
    362   tagged enums, narrow side-effect boundaries, and private visibility.
    363 - Avoid hidden production panics. Use typed errors for expected failures and
    364   reserve `unwrap` or `expect` for tests or locally proven invariants.
    365 - Keep `#![forbid(unsafe_code)]` at the crate roots; unsafe code is forbidden.
    366 - Add deterministic positive, negative, boundary, crash/retry, cancellation,
    367   saturation, redaction, and interoperability tests for every behavior change.
    368   Tests and examples must not contain real secrets, realistic private keys,
    369   reusable credentials, or sensitive event content.
    370 - Treat generated files as generated. Update them through the owning command
    371   and run the corresponding freshness check.
    372 
    373 ## 9. Canonical verification
    374 
    375 Through RCLD-RSHR-170, run the standalone native command authority through
    376 extbuild. Do not install, repair, invoke, or require Nix, and do not claim Nix,
    377 NixOS-module, or Nix-produced OCI qualification:
    378 
    379 ```text
    380 cargo extbuild doctor
    381 cargo extbuild run -- cargo fmt --all --check
    382 cargo extbuild run -- cargo check --workspace --locked
    383 cargo extbuild run -- cargo test --workspace --all-targets --locked
    384 cargo extbuild run -- cargo clippy --workspace --all-targets --locked -- -D warnings
    385 cargo extbuild run -- ./scripts/verify-boundaries.sh
    386 cargo extbuild run -- ./scripts/verify-supply-chain.sh
    387 cargo extbuild run -- ./scripts/verify-systemd.sh
    388 cargo extbuild run -- ./scripts/release-acceptance.sh
    389 ```
    390 
    391 The supply-chain gate requires exact cargo-deny 0.19.8 and cargo-vet 0.10.2,
    392 the checked-in exemption inventory, the locked graph, approved licenses and
    393 sources, and only the explicitly justified Nostr 0.44 advisories. Exemptions
    394 are visible accepted review debt, not claims of independent source audits.
    395 The release-acceptance contract requires formatting, locked metadata, locked
    396 all-target checking and testing, warnings-denied all-target Clippy, rustdoc with
    397 warnings denied, and diff hygiene. Run any gate not yet covered by the current
    398 release script explicitly; do not describe the script as sufficient until it
    399 enforces the complete contract. Run additional SQLx freshness, source-lock,
    400 systemd, package, SBOM, checksum, notice, and fresh-install gates when their
    401 surfaces change. Checked-in Nix material remains deferred source data through
    402 RCLD-RSHR-170 and is not a verification gate. Every OCI production or
    403 qualification path is likewise deferred and unclaimed through RCLD-RSHR-170.
    404 Use narrower checked-in commands only for iteration, and never claim a command
    405 passed unless it ran successfully.
    406 
    407 ## 10. Commits and irreversible actions
    408 
    409 - Format commits as `<scope>: <imperative summary>`, with a blank line and
    410   `- ` bullets when a body is useful. Split unrelated changes.
    411 - Report the exact files changed, behavior changed, commands run, results,
    412   unresolved risks, and whether the next checkpoint is safe.
    413 - Do not publish, push, tag, sign, deploy, rotate credentials, change ownership,
    414   or mutate trusted-publisher or external runtime state without explicit
    415   authorization for that exact action.