You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
For Hermes: Use subagent-driven-development skill to implement this plan task-by-task.
Goal: Deliver v0.3 in a safe sequence: secure network write surfaces first, then complete robust SMS ingest/reassembly, then expose realtime/metrics without expanding the attack surface or hiding modem quirks.
Architecture: Keep Modem + service classes + typed EventBus as the core boundary. Treat server.py and any future WebSocket/dashboard as authenticated adapters over stable service events, not as places to invent modem state. Add SMS reassembly inside the SMS layer with deterministic mock-transport tests before requiring real hardware validation.
README.md and ROADMAP.md now show v0.2 foundation as mostly complete: SIM PIN, API-key middleware/rate limiting, delivery report plumbing, DTMF send, USSD, SMS prompt handling, packaging discovery, BER descriptions, and multipart UDH parser groundwork.
Local mock suite on the current PR branch: git diff --check && PYTHONPATH=. uv run --no-project --with pytest --with pytest-asyncio --with pytest-aiohttp --with pyserial-asyncio --with aiosqlite pytest tests/ -q → 296 passed in 3.95s.
Do SMS multipart reality discovery before service integration: The existing UDH parser is useful, but text-mode modem behavior may hide UDH or auto-join parts. Confirm whether reliable reassembly requires PDU-mode receive support.
Add realtime/metrics only after event semantics are stable: WebSocket and Prometheus should expose cleaned service events/metrics, not raw partial modem lines with PII-heavy labels.
Add modem auto-detection/capability profiles before broader voice/PBX assumptions: Voice/audio commands and port assignments vary by device family.
Slice 1 — HTTP startup is secure by default
Objective: Close #4 and establish the policy future /ws and dashboard endpoints must follow.
Files likely touched:
server.py
tests/test_api_auth.py
README.md or a new small HTTP server usage section
Acceptance criteria:
Starting server.py on 0.0.0.0 without configured API keys fails closed, or explicitly binds to loopback-only in a documented dev mode.
Tests cover: no-key non-loopback startup, loopback/dev behavior if allowed, authenticated SMS send, authenticated USSD send, and unauthenticated rejection.
Documentation explains how to provide API keys without logging or committing them.
No secrets, SIM numbers, or message bodies are printed in startup/auth errors.
Risk notes:
This is the one place where a product/security choice may be needed: fail startup without keys versus permit loopback-only dev mode.
Prefer fail-closed for Raspberry Pi deployments because write endpoints can send SMS/USSD.
Slice 2 — Finish outbound SMS charset boundary
Objective: Land #8 or equivalent so outbound SMS cannot silently mutate bodies.
Files likely touched:
callstack/sms/service.py
tests/test_sms_service.py
README.md troubleshooting/SMS limitations section if not already updated
Acceptance criteria:
GSM 03.38 basic and extension-table characters are sent as exact modem payload bytes.
Unsupported UCS2-required bodies are rejected before AT+CMGS, with a clear error that PDU/UCS2 send is not implemented yet.
Stored sent-message metadata cannot claim success for a body different from what was handed to the modem.
Mock tests assert raw bytes for representative ASCII, accented GSM characters, extension-table characters, and rejected Unicode.
Risk notes:
Rejecting UCS2 is safer than corruption, but it is not a complete international SMS solution. Track UCS2/PDU send as a future capability if real users need it.
Slice 3 — Multipart SMS receive/reassembly
Objective: Turn UDH metadata groundwork into one complete public incoming-message event per logical long SMS.
Files likely touched:
callstack/sms/types.py
callstack/sms/service.py
callstack/sms/store.py
callstack/sms/pdu.py
tests/test_sms_service.py
tests/test_sms_pdu.py
Acceptance criteria:
A discovery/test task records whether the supported receive path exposes concatenation metadata in text mode; if not, the implementation uses PDU-mode receive for multipart messages.
Parts are keyed by sender + concatenation reference + total parts, tolerate out-of-order arrival, and emit exactly one IncomingSMSEvent when complete.
Partial groups have deterministic expiry/cleanup so the process cannot grow unbounded.
Durable storage can distinguish partial parts from completed messages, or explicitly documents that partial persistence is out of scope for v0.3.
Tests cover: 8-bit refs, 16-bit refs, out-of-order parts, duplicate parts, missing part timeout, and normal single-part SMS unaffected.
Risk notes:
Do not rely on one modem family's text-mode behavior unless capability profiles document it.
Avoid emitting partial bodies to webhooks/WebSocket subscribers as final messages.
Slice 4 — Authenticated WebSocket realtime feed
Objective: Add /ws only after Slice 1 auth policy is merged.
Files likely touched:
server.py or a new callstack/http.py if the server module is split
tests/test_websocket.py
README.md
Acceptance criteria:
/ws requires the same auth policy as write endpoints.
Broadcasts sanitized event envelopes for SMS, delivery reports, call state, signal quality, and USSD responses.
Message bodies and phone numbers are included only where intentionally needed by the API contract; logs avoid PII.
Tests use pytest-aiohttp and mock events, no hardware.
Risk notes:
A realtime feed without auth is effectively a message/call metadata exfiltration endpoint.
WebSocket should not become a second event system; it should adapt the typed EventBus.
Slice 5 — PII-safe metrics endpoint
Objective: Add /metrics with operational counters/gauges that help unattended Pi deployments without leaking private data.
Files likely touched:
server.py or a new HTTP metrics helper
tests/test_metrics.py
README.md
Acceptance criteria:
Exposes counters/gauges for sent/received/failed SMS, delivery-report outcomes, active call state, signal quality, reconnect count, and uptime.
No phone numbers, SMS bodies, webhook URLs, SIM identifiers, or API keys appear in metric labels/values.
Tests assert both metric presence and absence of PII-like dynamic labels.
Risk notes:
Metrics endpoints are often scraped without auth on LANs; decide whether this endpoint follows the same auth policy or is loopback-only by default.
Slice 6 — Modem detection + capability profiles
Objective: Make hardware-specific assumptions explicit before broader voice/PBX work.
Files likely touched:
callstack/config.py
callstack/modem.py
new callstack/hardware/ module if useful
tests/test_modem_detection.py
README.md troubleshooting/hardware section
Acceptance criteria:
Detection scans candidate serial ports, probes with safe commands such as ATI, and reports model/vendor/candidate roles without sending SMS/calls.
A capability profile records which features are known/supported/unknown: audio port role, DTMF command shape, CPCMREG availability, SMS mode, delivery reports, USSD, GNSS.
Default behavior remains explicit and overridable; auto-detection must not break current ModemConfig(at_port=..., audio_port=...) users.
Tests use fake ports/transports and do not require real hardware.
Risk notes:
Avoid baking SIMCOM-only assumptions into the public API before Quectel/Huawei/Sierra-class profiles exist.
v0.3 Hardening Sequence Implementation Plan
Goal: Deliver v0.3 in a safe sequence: secure network write surfaces first, then complete robust SMS ingest/reassembly, then expose realtime/metrics without expanding the attack surface or hiding modem quirks.
Architecture: Keep
Modem+ service classes + typedEventBusas the core boundary. Treatserver.pyand any future WebSocket/dashboard as authenticated adapters over stable service events, not as places to invent modem state. Add SMS reassembly inside the SMS layer with deterministic mock-transport tests before requiring real hardware validation.Tech Stack: Python 3.11, asyncio, aiohttp, aiosqlite, pyserial-asyncio, pytest, pytest-asyncio, pytest-aiohttp, mock transports.
Recent context
README.mdandROADMAP.mdnow show v0.2 foundation as mostly complete: SIM PIN, API-key middleware/rate limiting, delivery report plumbing, DTMF send, USSD, SMS prompt handling, packaging discovery, BER descriptions, and multipart UDH parser groundwork.VOICE CALL: BEGINURC race; PR is open and clean but draft.git diff --check && PYTHONPATH=. uv run --no-project --with pytest --with pytest-asyncio --with pytest-aiohttp --with pyserial-asyncio --with aiosqlite pytest tests/ -q→296 passed in 3.95s.Dependency order
Slice 1 — HTTP startup is secure by default
Objective: Close #4 and establish the policy future
/wsand dashboard endpoints must follow.Files likely touched:
server.pytests/test_api_auth.pyREADME.mdor a new small HTTP server usage sectionAcceptance criteria:
server.pyon0.0.0.0without configured API keys fails closed, or explicitly binds to loopback-only in a documented dev mode.Risk notes:
Slice 2 — Finish outbound SMS charset boundary
Objective: Land #8 or equivalent so outbound SMS cannot silently mutate bodies.
Files likely touched:
callstack/sms/service.pytests/test_sms_service.pyREADME.mdtroubleshooting/SMS limitations section if not already updatedAcceptance criteria:
AT+CMGS, with a clear error that PDU/UCS2 send is not implemented yet.Risk notes:
Slice 3 — Multipart SMS receive/reassembly
Objective: Turn UDH metadata groundwork into one complete public incoming-message event per logical long SMS.
Files likely touched:
callstack/sms/types.pycallstack/sms/service.pycallstack/sms/store.pycallstack/sms/pdu.pytests/test_sms_service.pytests/test_sms_pdu.pyAcceptance criteria:
IncomingSMSEventwhen complete.Risk notes:
Slice 4 — Authenticated WebSocket realtime feed
Objective: Add
/wsonly after Slice 1 auth policy is merged.Files likely touched:
server.pyor a newcallstack/http.pyif the server module is splittests/test_websocket.pyREADME.mdAcceptance criteria:
/wsrequires the same auth policy as write endpoints.pytest-aiohttpand mock events, no hardware.Risk notes:
EventBus.Slice 5 — PII-safe metrics endpoint
Objective: Add
/metricswith operational counters/gauges that help unattended Pi deployments without leaking private data.Files likely touched:
server.pyor a new HTTP metrics helpertests/test_metrics.pyREADME.mdAcceptance criteria:
Risk notes:
Slice 6 — Modem detection + capability profiles
Objective: Make hardware-specific assumptions explicit before broader voice/PBX work.
Files likely touched:
callstack/config.pycallstack/modem.pycallstack/hardware/module if usefultests/test_modem_detection.pyREADME.mdtroubleshooting/hardware sectionAcceptance criteria:
ATI, and reports model/vendor/candidate roles without sending SMS/calls.ModemConfig(at_port=..., audio_port=...)users.Risk notes:
Human decisions requested
python server.py:/metricsshould require API-key auth or default to loopback-only.Definition of done for v0.3