diff --git a/.scheduler-memory/latest/daily/memories.md b/.scheduler-memory/latest/daily/memories.md
index ee545171..8dcfff20 100644
--- a/.scheduler-memory/latest/daily/memories.md
+++ b/.scheduler-memory/latest/daily/memories.md
@@ -1,19 +1,22 @@
-### 1. [2026-02-25] (scheduler, daily, store, insight)
+### 1. [2026-02-26] (scheduler, daily, store, insight)
-### 1. [2026-02-25] (torch, init, reinstall)
-If `npx --no-install torch-lock init --help` prints initialization prompts, it may be interactive; use `printf '\n' | npx --no-install torch-lock init --force` to accept defaults non-interactively in CI/agent runs.
+# Memory Update (2026-02-25)
-### 2. [2026-02-25…
+## Docs Cleanup
+- Replaced `docs/README.md` content that referenced Archivox with a SeedPass-focused docs index.
+- Updated docs-site default title in `docs/src/config/loadConfig.js` from `Archivox` to `SeedPass Docs`.
+
+## Outcome
+- Removed stale Arc…
---
### 2. [2026-02-25] (scheduler, daily, store, insight)
-### 1. [2026-02-25] (torch, scheduler, host-mode)
-When running `npm run --prefix torch scheduler:daily`, the scheduler resolves config from `torch/torch-config.json` (cwd-scoped), not the repo-root `torch-config.json`.
+### 1. [2026-02-25] (torch, init, reinstall)
+If `npx --no-install torch-lock init --help` prints initialization prompts, it may be interactive; use `printf '\n' | npx --no-install torch-lock init --force` to accept defaults non-interactively in CI/agent runs.
-### 2. [2026-02-25] (torch, scheduler, handoff)
-A non-inter…
+### 2. [2026-02-25…
---
@@ -27,12 +30,16 @@ A non-inter…
---
-### 4. [2026-02-26] (scheduler, daily, retrieve)
+### 4. [2026-02-25] (scheduler, daily, store, insight)
-Memory retrieval seed for daily :: scheduler memory retrieval
+### 1. [2026-02-25] (torch, scheduler, host-mode)
+When running `npm run --prefix torch scheduler:daily`, the scheduler resolves config from `torch/torch-config.json` (cwd-scoped), not the repo-root `torch-config.json`.
+
+### 2. [2026-02-25] (torch, scheduler, handoff)
+A non-inter…
---
-### 5. [2026-02-25] (scheduler, daily, retrieve)
+### 5. [2026-02-26] (scheduler, daily, retrieve)
Memory retrieval seed for daily :: scheduler memory retrieval
\ No newline at end of file
diff --git a/.scheduler-memory/memory-store.json b/.scheduler-memory/memory-store.json
index 48a66d19..d3f51354 100644
--- a/.scheduler-memory/memory-store.json
+++ b/.scheduler-memory/memory-store.json
@@ -68,7 +68,7 @@
"importance": 0.8,
"embedding_id": null,
"created_at": 1772047328158,
- "last_seen": 1772073624638,
+ "last_seen": 1772075164390,
"source": "agent-output",
"ttl_days": null,
"merged_into": null,
@@ -119,7 +119,7 @@
"importance": 0.8,
"embedding_id": null,
"created_at": 1772049603683,
- "last_seen": 1772073624638,
+ "last_seen": 1772075164390,
"source": "agent-output",
"ttl_days": null,
"merged_into": null,
@@ -170,7 +170,7 @@
"importance": 0.8,
"embedding_id": null,
"created_at": 1772050579374,
- "last_seen": 1772073624638,
+ "last_seen": 1772075164390,
"source": "agent-output",
"ttl_days": null,
"merged_into": null,
@@ -272,7 +272,58 @@
"importance": 0.8,
"embedding_id": null,
"created_at": 1772073865813,
- "last_seen": 1772073865813,
+ "last_seen": 1772075164390,
+ "source": "agent-output",
+ "ttl_days": null,
+ "merged_into": null,
+ "pinned": false
+ }
+ ],
+ [
+ "4c74e02d-3631-4b74-b405-a7f65fa31266",
+ {
+ "schema_version": 1,
+ "id": "4c74e02d-3631-4b74-b405-a7f65fa31266",
+ "agent_id": "scheduler-memory-daily",
+ "session_id": "session-mm2vsrtm",
+ "type": "batch_window",
+ "content": "Memory retrieval seed for daily :: scheduler memory retrieval",
+ "summary": "Memory retrieval seed for daily :: scheduler memory retrieval",
+ "tags": [
+ "scheduler",
+ "daily",
+ "retrieve"
+ ],
+ "importance": 0.4,
+ "embedding_id": null,
+ "created_at": 1772075164378,
+ "last_seen": 1772075164390,
+ "source": "scheduler-retrieve",
+ "ttl_days": null,
+ "merged_into": null,
+ "pinned": false
+ }
+ ],
+ [
+ "9d3a0422-ba3f-40b3-ba12-a7d72bd1288b",
+ {
+ "schema_version": 1,
+ "id": "9d3a0422-ba3f-40b3-ba12-a7d72bd1288b",
+ "agent_id": "scheduler-memory-daily",
+ "session_id": "session-mm2vx4hn",
+ "type": "batch_window",
+ "content": "**Protocol Research Findings**: The codebase uses `bip_utils` and `nostr_sdk` correctly. However, `BIP85` implementation uses `app_no=2` for symmetric key derivation, which is non-standard (usually `128` or `0`). A regression test `src/tests/test_bip85_compliance.py` was added to document and monitor this behavior.",
+ "summary": "**Protocol Research Findings**: The codebase uses `bip_utils` and `nostr_sdk` correctly. However, `BIP85` implementation uses `app_no=2` for symmetric key derivation, which is non-standard (usually `128` or `0`). A regression test `src/tests/test_bip85_compliance.py` was added t…",
+ "tags": [
+ "scheduler",
+ "daily",
+ "store",
+ "insight"
+ ],
+ "importance": 0.8,
+ "embedding_id": null,
+ "created_at": 1772075367419,
+ "last_seen": 1772075367419,
"source": "agent-output",
"ttl_days": null,
"merged_into": null,
diff --git a/.scheduler-memory/session-mm2vsrtm/retrieve.json b/.scheduler-memory/session-mm2vsrtm/retrieve.json
new file mode 100644
index 00000000..ed75a3f4
--- /dev/null
+++ b/.scheduler-memory/session-mm2vsrtm/retrieve.json
@@ -0,0 +1,18 @@
+{
+ "cadence": "daily",
+ "operation": "retrieve",
+ "runId": "session-mm2vsrtm",
+ "servicePath": "src/services/memory/index.js#getRelevantMemories",
+ "inputs": {
+ "agentId": "scheduler-memory-daily",
+ "promptPath": "",
+ "promptIntent": "scheduler memory retrieval",
+ "query": "scheduler | daily | agent | scheduler-memory-daily | intent | scheduler memory retrieval",
+ "events": 1
+ },
+ "outputs": {
+ "ingestedCount": 1,
+ "retrievedCount": 5
+ },
+ "status": "ok"
+}
\ No newline at end of file
diff --git a/.scheduler-memory/session-mm2vsrtm/retrieve.ok b/.scheduler-memory/session-mm2vsrtm/retrieve.ok
new file mode 100644
index 00000000..84b17199
--- /dev/null
+++ b/.scheduler-memory/session-mm2vsrtm/retrieve.ok
@@ -0,0 +1 @@
+MEMORY_RETRIEVED
diff --git a/.scheduler-memory/session-mm2vx4hn/store.json b/.scheduler-memory/session-mm2vx4hn/store.json
new file mode 100644
index 00000000..b1171ae9
--- /dev/null
+++ b/.scheduler-memory/session-mm2vx4hn/store.json
@@ -0,0 +1,20 @@
+{
+ "cadence": "daily",
+ "operation": "store",
+ "runId": "session-mm2vx4hn",
+ "servicePath": "src/services/memory/index.js#ingestEvents",
+ "inputs": {
+ "agentId": "scheduler-memory-daily",
+ "promptPath": "",
+ "promptIntent": "scheduler memory store",
+ "events": 1,
+ "sourceFile": "memory-update.md"
+ },
+ "outputs": {
+ "storedCount": 1,
+ "summaries": [
+ "**Protocol Research Findings**: The codebase uses `bip_utils` and `nostr_sdk` correctly. However, `BIP85` implementation uses `app_no=2` for symmetric key derivation, which is non-standard (usually `128` or `0`). A regression test `src/tests/test_bip85_compliance.py` was added t…"
+ ]
+ },
+ "status": "ok"
+}
\ No newline at end of file
diff --git a/.scheduler-memory/session-mm2vx4hn/store.ok b/.scheduler-memory/session-mm2vx4hn/store.ok
new file mode 100644
index 00000000..1e40bb67
--- /dev/null
+++ b/.scheduler-memory/session-mm2vx4hn/store.ok
@@ -0,0 +1 @@
+MEMORY_STORED
diff --git a/KNOWN_ISSUES.md b/KNOWN_ISSUES.md
index a3175b5a..de28dd68 100644
--- a/KNOWN_ISSUES.md
+++ b/KNOWN_ISSUES.md
@@ -32,3 +32,11 @@ It is updated daily by the `known-issues-agent`.
- **Root Cause**: Unsafe DOM manipulation.
- **Status**: Resolved (verified file content on 2026-02-25).
- **Last Checked**: 2026-02-25
+
+### [Active] BIP85 Non-Standard Derivation Path
+- **Symptoms**: `BIP85` uses `app_no=2` for symmetric key derivation instead of `128` (Hex) or `0` (BIP32).
+- **Repro**: `src/local_bip85/bip85.py:derive_symmetric_key` uses default `app_no=2`.
+- **Workaround**: None required; internal consistency is maintained.
+- **Root Cause**: Implementation choice or legacy behavior.
+- **Status**: Active (Documented in `PROTOCOL_INVENTORY.md` and `reports/protocol/protocol-report-2026-02-26.md`).
+- **Last Checked**: 2026-02-26
diff --git a/PROTOCOL_INVENTORY.md b/PROTOCOL_INVENTORY.md
new file mode 100644
index 00000000..a64af0df
--- /dev/null
+++ b/PROTOCOL_INVENTORY.md
@@ -0,0 +1,18 @@
+# Protocol Inventory
+
+| Protocol | Source | Implementation | Status | Notes |
+|----------|--------|----------------|--------|-------|
+| **BIP39** | [bips/bip-0039](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) | `src/local_bip85/bip85.py`
`src/seedpass/core/seedqr.py` | **Compliant** | Uses `bip-utils` for standard mnemonic generation. |
+| **BIP32** | [bips/bip-0032](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) | `src/local_bip85/bip85.py` | **Compliant** | Uses `bip-utils` (`Bip32Slip10Secp256k1`) for HD key derivation. |
+| **BIP85** | [bips/bip-0085](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki) | `src/local_bip85/bip85.py` | **Partial** | Implements BIP39 derivation correctly (`app_no=39`).
Generic entropy (`app_no=2`) usage needs verification against spec (Hex app is usually 128'). |
+| **SLIP-0010** | [satoshilabs/slips/slip-0010](https://github.com/satoshilabs/slips/blob/master/slip-0010.md) | `src/local_bip85/bip85.py` | **Compliant** | Used via `bip-utils` for Secp256k1 derivation. |
+| **Nostr** | [nostr-protocol/nips](https://github.com/nostr-protocol/nips) | `src/nostr/client.py`
`src/nostr/key_manager.py` | **Compliant** | Uses `nostr-sdk` (Rust bindings) for protocol operations. |
+| **HKDF** | [RFC 5869](https://tools.ietf.org/html/rfc5869) | `src/utils/key_derivation.py`
`src/local_bip85/bip85.py` | **Compliant** | Uses `cryptography` library implementation. |
+| **AES-GCM** | [NIST SP 800-38D](https://csrc.nist.gov/publications/detail/sp/800-38d/final) | `src/utils/memory_protection.py`
`src/seedpass/core/encryption.py` | **Compliant** | Uses `cryptography` library. Ensure nonces are unique (random). |
+| **TOTP** | [RFC 6238](https://tools.ietf.org/html/rfc6238) | `src/seedpass/core/totp.py`
`src/utils/key_validation.py` | **Compliant** | Uses `pyotp`. |
+| **OpenPGP** | [RFC 4880](https://tools.ietf.org/html/rfc4880) | `src/utils/key_validation.py`
`src/seedpass/core/password_generation.py` | **Compliant** | Uses `pgpy`. |
+| **Bech32** | [bips/bip-0173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) | `src/nostr/client.py` (implied) | **Compliant** | Uses `bech32` library. |
+
+## Gap Analysis
+- **BIP85 `app_no=2`**: The implementation uses `app_no=2` for symmetric key derivation. BIP85 spec assigns `2` to nothing? `0` is BIP32, `2` is usually WIF (in some implementations) or unassigned. Hex/Raw entropy is usually `128'`. This custom derivation path should be documented or aligned if interoperability is desired.
+- **Nostr Relay Health**: No explicit relay health check protocol (NIP-11) found in `src/nostr/`, but `nostr-sdk` handles much of this.
diff --git a/memory-update.md b/memory-update.md
index d69ed096..6cb9edff 100644
--- a/memory-update.md
+++ b/memory-update.md
@@ -1,121 +1 @@
-# Memory Update (2026-02-25)
-
-## Docs Cleanup
-- Replaced `docs/README.md` content that referenced Archivox with a SeedPass-focused docs index.
-- Updated docs-site default title in `docs/src/config/loadConfig.js` from `Archivox` to `SeedPass Docs`.
-
-## Outcome
-- Removed stale Archivox branding from the docs README and default docs title so the correct SeedPass README/content is displayed.
-
-## Supply Chain and Release Integrity (Checklist #8)
-- Added a dedicated release integrity workflow at `.github/workflows/release-integrity.yml`.
-- Workflow now enforces lockfile drift checks, runs `pip-audit`, builds release artifacts, generates `SHA256SUMS`, signs checksum manifest with keyless `cosign`, and publishes signatures/certs with release assets.
-- Added `scripts/release_integrity.py` CLI with `check-lockfile`, `generate`, and `verify` subcommands.
-- Added reusable checksum logic in `src/seedpass/release_integrity.py` and regression tests in `src/tests/test_release_integrity_utils.py`.
-- Updated `docs/security_readiness_checklist.md` item #8 from `Not Started` to `In Progress` with evidence links.
-- Added process documentation in `docs/supply_chain_release_integrity.md` and linked it from `docs/README.md` and `README.md`.
-
-## Determinism Regression Guardrail
-- Added `src/tests/test_deterministic_artifact_regression.py` to lock deterministic vectors at index `352` for password, SSH, seed phrase, TOTP, PGP (fingerprint + armored hash), and Nostr keys.
-- Added repeatability assertions for same-seed/same-index derivation in the same run.
-- Logged explicit remaining tasks to finish checklist item #8 in both `docs/supply_chain_release_integrity.md` and `TODO.md`.
-
-## CI Determinism Enforcement
-- Expanded deterministic regression vectors to cover indices `0`, `1`, `352`, and `1024` across password, SSH, seed phrase, TOTP, and Nostr outputs.
-- Added pinned PGP vectors for both `ed25519` and `rsa` at index `352` (fingerprints + armored key hashes).
-- Added explicit deterministic regression steps to push CI workflows:
- - `.github/workflows/python-ci.yml`
- - `.github/workflows/tests.yml`
-
-## Profile Unlock Failure Recovery
-- Hardened startup profile selection to avoid fatal crash loops when unlock/decryption fails or is cancelled.
-- `select_fingerprint(...)` now returns `False` on unlock/setup failure instead of always raising; selection menu now keeps the user in-flow.
-- Added profile recovery flow `recover_profile_with_blank_index()` reachable from seed-profile selection menu.
-- Recovery flow verifies that user-provided seed matches selected fingerprint, then re-encrypts seed and resets local entry index/checksum files to a blank state.
-- Fixed "switch to existing profile" path during add-new-seed so it does not call `initialize_managers()` without an initialized `EncryptionManager`.
-- Added regression tests in `src/tests/test_profile_recovery_flow.py` for these paths.
-
-## TUI Crash Hardening
-- Hardened `display_menu()` to catch per-action `PasswordPromptError`, `SeedPassError`, and generic exceptions so failures no longer terminate the whole TUI session.
-- Added graceful timeout-lock recovery messaging when unlock is cancelled/failed after inactivity timeout.
-- Fixed incorrect call signature in Add Entry submenu header rendering (`clear_header_with_notification(...)` now receives `password_manager`).
-- Added crash-regression coverage in `src/tests/test_cli_invalid_input.py` for action failures and timeout-unlock cancellation handling.
-
-## Settings/Relay Submenu Hardening
-- Added local exception guards in `handle_settings`, `handle_profiles_menu`, and `handle_nostr_menu` so submenu actions report failures and return control instead of crashing the TUI.
-- Added explicit graceful handling for Settings -> Lock Vault unlock cancellations/failures.
-- Corrected `clear_header_with_notification(...)` call signatures in settings-related submenus to pass `password_manager` as first argument.
-- Added regression tests in `src/tests/test_settings_menu.py` for:
- - missing settings handler method
- - lock/unlock cancellation
- - profiles submenu action failure
-
-## Import/Export + Nostr Workflow Guardrails
-- Hardened settings menu options for export/import/TOTP export with explicit error messaging (`Export failed`, `Import failed`, `2FA export failed`) instead of generic crashes.
-- Added graceful no-path handling for Settings -> Import (`No path entered.`).
-- Hardened CLI subcommand entrypoints in `main.py`:
- - require `--file` for `export`/`import`
- - catch and report failures for `export`, `import`, `search`, `get`, and `totp` commands.
-- Added regression tests for these cases in:
- - `src/tests/test_settings_menu.py`
- - `src/tests/test_cli_export_import.py`
-
-## Installer Dependency Resolution Fix (2026-02-26)
-- Root cause of installer failures was a stale `requirements.lock` pin (`cffi==1.17.1`) conflicting with `pynacl==1.6.2` (requires `cffi>=2.0.0` on Python >=3.9).
-- A second hidden source issue blocked clean lock regeneration: `starlette>=0.49.1` was incompatible with `fastapi>=0.110` resolution path (current fastapi metadata requires `starlette<0.48`).
-- Updated dependency sources to consistent constraints:
- - `src/requirements.txt`: `starlette>=0.40,<0.48`
- - `src/runtime_requirements.txt`: `starlette>=0.40,<0.48`
- - `pyproject.toml`: `starlette = ">=0.40,<0.48"`
-- Regenerated `requirements.lock` with hashes; key resolved pins now include:
- - `cffi==2.0.0`
- - `pynacl==1.6.2`
- - `fastapi==0.116.1`
- - `starlette==0.47.3`
-- Verified the installer-critical step succeeds in a fresh virtualenv:
- - `python -m pip install --require-hashes -r requirements.lock`
-
-## TORCH Windows Checkout Fix (2026-02-26)
-- Root cause: tracked TORCH artifact filenames used `:` in timestamps (e.g. `CONTEXT_2026-02-15T01:03:31Z.md`), which Windows cannot checkout.
-- Confirmed scheduler/runtime already emits Windows-safe scheduler/memory filenames (`HH-mm-ss`), and backup folder names were already sanitized.
-- Removed all tracked colon-variant duplicates under `torch/src/*` and `torch/_backups/*` where matching dash-variant files already existed.
-- Validation: `git ls-files | rg ':'` now returns no results.
-
-## TORCH Update + Windows Filename Validation (2026-02-26)
-- Updated TORCH package to `1e3f88e` via tarball install, then ran `torch-lock update --force` and `npm install --prefix torch`.
-- Quick validation passed: `npm run --prefix torch lock:check:daily -- --json --quiet` returned `lockCount: 0` with a full available roster.
-- Windows compatibility check passed: `git ls-files | rg ':'` returned no tracked paths.
-
-## GitHub Actions Poetry Cache Bootstrap Fix (2026-02-26)
-- `actions/setup-python` with `cache: poetry` requires `poetry` to already exist on PATH in that same step.
-- In `.github/workflows/tests.yml`, Poetry was installed after setup-python via `pipx`, causing CI bootstrap failure.
-- Switched cache mode to `cache: pip` to avoid requiring Poetry during Python setup.
-
-## pip-audit Advisory Alias Handling (2026-02-26)
-- CI failures appeared in `python-ci` on macOS because `pip-audit` surfaced Starlette issue as `CVE-2025-62727` while workflows ignored only `GHSA-wj6h-64fc-37mp`.
-- Updated strict audit workflows to ignore both IDs so the existing temporary exception is robust to advisory ID alias/reporting differences.
-- Updated files: `.github/workflows/python-ci.yml`, `.github/workflows/dependency-audit.yml`, `.github/workflows/release-integrity.yml`.
-
-## Poetry Lock Sync for Tests Workflow (2026-02-26)
-- `tests.yml` uses Poetry (`poetry install`), and the job failed because `pyproject.toml` had drifted from `poetry.lock`.
-- Regenerated `poetry.lock` with Poetry 2.3.2 so lock metadata/dependency graph matches the current project file.
-- Result: CI should no longer fail with "pyproject.toml changed significantly since poetry.lock was last generated".
-
-## CI Black Check Failure Fix (2026-02-26)
-- `tests.yml` failed at `poetry run black --check .` on 9 files (SeedPass tests/core file plus TORCH script/backups).
-- Applied Black formatting to all reported files and verified `poetry run black --check .` passes locally.
-
-## Python 3.10 datetime.UTC Compatibility Fix (2026-02-26)
-- CI `test (ubuntu-latest, 3.10)` failed during test collection because `datetime.UTC` is unavailable on Python 3.10.
-- Replaced `datetime.UTC` usage with `timezone.utc` in `src/seedpass/cli/agent.py` and `scripts/ai_tui_agent_test.py`.
-- Verified with targeted tests: `src/tests/test_cli_agent_mode.py` and `src/tests/test_ai_tui_agent_harness.py`.
-
-## Settings Unlock Cancellation Robustness (2026-02-26)
-- CI showed `test_settings_lock_unlock_cancelled_is_graceful` intermittently receiving a generic exception path instead of `PasswordPromptError` during Settings -> Lock Vault unlock.
-- Hardened `handle_settings()` lock flow to treat any exception containing "cancelled by user" as cancellation, printing `Unlock cancelled: ...` instead of a hard failure message.
-- Verified with targeted pytest for the failing test.
-
-## Docs Alignment Agent Memory (2026-02-26)
-- Root README drift to code can hide in security/prereq sections; verify against `pyproject.toml` and `ConfigManager` constants before editing.
-- Dead-link checks across `README.md` + `docs/**/*.md` quickly expose stale internal docs references and are safe to run in CI/local.
-- If scheduler prompts require `docs/agent-handoffs/*`, ensure the path exists in-repo (not only under `node_modules/torch-lock`).
+**Protocol Research Findings**: The codebase uses `bip_utils` and `nostr_sdk` correctly. However, `BIP85` implementation uses `app_no=2` for symmetric key derivation, which is non-standard (usually `128` or `0`). A regression test `src/tests/test_bip85_compliance.py` was added to document and monitor this behavior.
diff --git a/reports/protocol/protocol-report-2026-02-26.md b/reports/protocol/protocol-report-2026-02-26.md
new file mode 100644
index 00000000..94e98874
--- /dev/null
+++ b/reports/protocol/protocol-report-2026-02-26.md
@@ -0,0 +1,47 @@
+# Protocol Compliance Report - 2026-02-26
+
+**Agent:** `protocol-research-agent`
+**Focus:** Protocol Inventory & Compliance Assessment
+
+## Executive Summary
+The codebase relies heavily on standard libraries (`cryptography`, `bip-utils`, `nostr-sdk`, `pyotp`) for cryptographic and protocol implementations, ensuring a high baseline of compliance. Most protocol implementations delegate to these libraries directly.
+
+One potential deviation from standard specifications was identified in the local BIP85 implementation regarding the application number used for symmetric key derivation.
+
+## Findings
+
+### 1. Strong Library Usage
+- **BIP39/32**: `bip-utils` is used consistently.
+- **Crypto**: `cryptography` (hazmat) is used for AES-GCM, HKDF, and Ed25519.
+- **Nostr**: `nostr-sdk` (Rust bindings) handles protocol complexity.
+
+### 2. BIP85 Custom Derivation Path
+The implementation in `src/local_bip85/bip85.py` uses `app_no=2` for symmetric key derivation:
+```python
+def derive_symmetric_key(self, index: int = 0, app_no: int = 2) -> bytes:
+```
+According to [BIP-85](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki), `app_no` mappings are:
+- `0`: BIP32
+- `2`: WIF (Wallet Import Format) - *Wait, spec usually assigns 2 to WIF.*
+- `128`: Hex
+
+However, the implementation derives raw entropy bytes for a symmetric key using `app_no=2`. If this is intended to match WIF generation logic, it might be acceptable, but typically symmetric keys (Hex) use `app_no=128`.
+**Risk:** Low (internal consistency is maintained), but interoperability with other BIP85 wallets for this specific derivation might be limited.
+
+### 3. BIP39 Word Count Default
+The `derive_entropy` method defaults `word_count` to `entropy_bytes` if `word_count` is None for `app_no=39`.
+```python
+if app_no == 39:
+ if word_count is None:
+ word_count = entropy_bytes
+```
+This is safe as long as `derive_mnemonic` (the primary caller) passes explicit `words_num`. Direct calls to `derive_entropy` with `app_no=39` and `word_count=None` could result in non-standard derivation paths (e.g., `.../16'/...` for 16 bytes entropy).
+
+## Recommendations
+1. **Document `app_no=2` usage**: Clarify in comments why `2` is used for symmetric keys (legacy or specific compatibility).
+2. **Add Compliance Tests**: Verify `derive_entropy` produces expected output vectors (if available) or at least remains stable.
+3. **Monitor `nostr-sdk` updates**: Ensure the Rust bindings stay updated to support newer NIPs.
+
+## Next Steps
+- Add regression test for `app_no=2` derivation path to prevent accidental changes.
+- Investigate if `app_no=128` (Hex) was the intended target for symmetric keys.
diff --git a/src/tests/test_bip85_compliance.py b/src/tests/test_bip85_compliance.py
new file mode 100644
index 00000000..c8f96204
--- /dev/null
+++ b/src/tests/test_bip85_compliance.py
@@ -0,0 +1,56 @@
+import sys
+from pathlib import Path
+
+# Add src to path
+sys.path.append(str(Path(__file__).resolve().parents[2] / "src"))
+
+from bip_utils import Bip39SeedGenerator # noqa: E402
+from local_bip85.bip85 import BIP85 # noqa: E402
+
+# Known test vector for:
+# "abandon abandon abandon abandon abandon abandon abandon abandon abandon
+# abandon abandon about"
+# Derived with app_no=2, index=0, entropy_bytes=32
+KNOWN_SYMMETRIC_KEY_HEX = (
+ "f8c4bd4d57899c08b083e5d999c5041e1cd05bf6a6cded6e382bd231839cd2d8"
+)
+TEST_SEED_PHRASE = (
+ "abandon abandon abandon abandon abandon abandon abandon abandon "
+ "abandon abandon abandon about"
+)
+
+
+def test_bip85_symmetric_key_stability():
+ """
+ Verifies that the BIP85 symmetric key derivation remains stable.
+ This test ensures that the custom use of app_no=2 for symmetric keys
+ does not change unexpectedly.
+ """
+ seed_bytes = Bip39SeedGenerator(TEST_SEED_PHRASE).Generate()
+ bip85 = BIP85(seed_bytes)
+ key = bip85.derive_symmetric_key(index=0, app_no=2)
+ assert key.hex() == KNOWN_SYMMETRIC_KEY_HEX
+
+
+def test_bip85_app_no_39_default_behavior():
+ """
+ Verifies the behavior when app_no=39 is used directly with derive_entropy.
+ The implementation currently defaults word_count to entropy_bytes if
+ not provided. This test documents this behavior to detect
+ regression/changes.
+ """
+ seed_bytes = Bip39SeedGenerator(TEST_SEED_PHRASE).Generate()
+ bip85 = BIP85(seed_bytes)
+
+ # Requesting 16 bytes (128 bits) with app_no=39
+ # If word_count is None, it defaults to 16.
+ # Path becomes m/83696968'/39'/0'/16'/0'
+ entropy = bip85.derive_entropy(index=0, entropy_bytes=16, app_no=39)
+ assert len(entropy) == 16
+
+ # Verify it is DIFFERENT from explicit 12 words
+ # (which uses path .../12'/...)
+ entropy_12_words = bip85.derive_entropy(
+ index=0, entropy_bytes=16, app_no=39, word_count=12
+ )
+ assert entropy != entropy_12_words
diff --git a/torch/task-logs/daily/2026-02-26T03-14-42Z__protocol-research-agent__completed.md b/torch/task-logs/daily/2026-02-26T03-14-42Z__protocol-research-agent__completed.md
new file mode 100644
index 00000000..7dce42f7
--- /dev/null
+++ b/torch/task-logs/daily/2026-02-26T03-14-42Z__protocol-research-agent__completed.md
@@ -0,0 +1,26 @@
+# Task Log: protocol-research-agent
+
+**Timestamp:** 2026-02-26T03:14:42Z
+**Status:** Completed
+**Cadence:** Daily
+**Agent:** protocol-research-agent
+
+## Summary
+The protocol research task was executed successfully.
+
+### Key Actions
+1. **Inventory Creation**: Created `PROTOCOL_INVENTORY.md` tracking BIP39, BIP32, BIP85, Nostr, etc.
+2. **Compliance Assessment**: Identified a non-standard BIP85 derivation path (`app_no=2` for symmetric keys) in `src/local_bip85/bip85.py`.
+3. **Reporting**: Published `reports/protocol/protocol-report-2026-02-26.md` detailing findings.
+4. **Testing**: Added `src/tests/test_bip85_compliance.py` to document and monitor the BIP85 behavior.
+5. **Issue Tracking**: Updated `KNOWN_ISSUES.md` with the BIP85 finding.
+6. **Memory**: Updated scheduler memory with findings.
+
+## Artifacts
+- `PROTOCOL_INVENTORY.md`
+- `reports/protocol/protocol-report-2026-02-26.md`
+- `src/tests/test_bip85_compliance.py`
+- `memory-update.md`
+
+## Learnings
+The codebase is largely compliant but uses a custom BIP85 path for symmetric keys. This is now documented and tested.