Summary
Text-mode delivery reports classify GSM/3GPP TP-ST status-code ranges incorrectly. _parse_cmgr_status_report() currently treats only status code 0 as delivered, 1..31 as pending, and >=32 as failed. Per 3GPP TS 23.040 TP-Status grouping, 0x00..0x1f means the short-message transaction is completed, 0x20..0x3f is a temporary error where the SC is still trying, and 0x40+ represents final failure/reserved ranges.
This means successful reports such as TP-ST 1/2 are surfaced as pending, while still-retrying temporary errors such as 32/33 are surfaced as failed.
Evidence
Affected code:
callstack/sms/service.py:431-436 maps only 0 to delivered, 1 <= code <= 31 to pending, and all other codes to failed.
tests/test_delivery_reports.py:73-99 currently locks in the inverted mapping for 31 and 32.
No-hardware probe on main (92e0f02042bb7496d7bca2fdd7f29a0625592672):
PYTHONPATH=. uv run --no-project --with pyserial-asyncio python - <<'PY'
from callstack.sms.service import _parse_cmgr_status_report
for code in (0, 1, 2, 16, 31, 32, 33, 63, 64, 96):
line = f'+CMGR: "REC READ",6,"+120****0123",145,"24/12/25,14:30:00+04","24/12/25,14:30:05+04",{code}'
print(code, '->', _parse_cmgr_status_report(line))
PY
Actual output:
0 -> (6, '+120****0123', 'delivered')
1 -> (6, '+120****0123', 'pending')
2 -> (6, '+120****0123', 'pending')
16 -> (6, '+120****0123', 'pending')
31 -> (6, '+120****0123', 'pending')
32 -> (6, '+120****0123', 'failed')
33 -> (6, '+120****0123', 'failed')
63 -> (6, '+120****0123', 'failed')
64 -> (6, '+120****0123', 'failed')
96 -> (6, '+120****0123', 'failed')
Spec evidence: 3GPP TS 23.040 section 9.2.3.15 defines 0000000..0011111 as "Short message transaction completed" and 0100000..0111111 as "Temporary error, SC still trying to transfer SM".
Expected behavior
- TP-ST
0x00..0x1f should be reported as completed/delivered (or a richer completed status if the public API grows one).
- TP-ST
0x20..0x3f should remain pending/retrying.
- TP-ST
0x40..0x7f should be treated as failed/final unless a richer status taxonomy is added.
- Existing delivery-report events and HTTP listing should not regress reference/recipient parsing.
Suggested fix direction
Update _parse_cmgr_status_report() to classify ranges by the TP-ST high bits instead of code == 0. Adjust the delivery-report tests so 1, 2, 31 are completed and 32, 33, 63 are pending.
Acceptance criteria
- Regression tests cover at least one completed non-zero code (
1 or 2), an SC-specific completed code (31), and a temporary retry code (32 or 33).
SMSDeliveryReportEvent.status no longer reports completed non-zero delivery reports as pending.
- Still-retrying temporary failures no longer appear as final
failed reports.
- Documentation/comments around delivery report status mapping mention the TP-ST ranges.
Verification gates
git diff --check
PYTHONPATH=. uv run --no-project --with pytest --with pytest-asyncio --with pytest-aiohttp --with pyserial-asyncio --with aiosqlite pytest tests/test_delivery_reports.py -q
PYTHONPATH=. uv run --no-project --with pytest --with pytest-asyncio --with pytest-aiohttp --with pyserial-asyncio --with aiosqlite pytest tests/ -q
Duplicate check
Checked open/closed issues and PRs for delivery report TP-ST pending delivered status code, status report pending failed, and CDSI CMGR status. Closed issue #38 / merged PR #43 added reference/recipient parsing, but I did not find an issue for the TP-ST range classification bug.
Summary
Text-mode delivery reports classify GSM/3GPP TP-ST status-code ranges incorrectly.
_parse_cmgr_status_report()currently treats only status code0asdelivered,1..31aspending, and>=32asfailed. Per 3GPP TS 23.040 TP-Status grouping,0x00..0x1fmeans the short-message transaction is completed,0x20..0x3fis a temporary error where the SC is still trying, and0x40+represents final failure/reserved ranges.This means successful reports such as TP-ST
1/2are surfaced aspending, while still-retrying temporary errors such as32/33are surfaced asfailed.Evidence
Affected code:
callstack/sms/service.py:431-436maps only0todelivered,1 <= code <= 31topending, and all other codes tofailed.tests/test_delivery_reports.py:73-99currently locks in the inverted mapping for31and32.No-hardware probe on
main(92e0f02042bb7496d7bca2fdd7f29a0625592672):Actual output:
Spec evidence: 3GPP TS 23.040 section 9.2.3.15 defines
0000000..0011111as "Short message transaction completed" and0100000..0111111as "Temporary error, SC still trying to transfer SM".Expected behavior
0x00..0x1fshould be reported as completed/delivered (or a richer completed status if the public API grows one).0x20..0x3fshould remainpending/retrying.0x40..0x7fshould be treated as failed/final unless a richer status taxonomy is added.Suggested fix direction
Update
_parse_cmgr_status_report()to classify ranges by the TP-ST high bits instead ofcode == 0. Adjust the delivery-report tests so1,2,31are completed and32,33,63are pending.Acceptance criteria
1or2), an SC-specific completed code (31), and a temporary retry code (32or33).SMSDeliveryReportEvent.statusno longer reports completed non-zero delivery reports aspending.failedreports.Verification gates
Duplicate check
Checked open/closed issues and PRs for
delivery report TP-ST pending delivered status code,status report pending failed, andCDSI CMGR status. Closed issue #38 / merged PR #43 added reference/recipient parsing, but I did not find an issue for the TP-ST range classification bug.