Correct three claims a reader would have built on
Test / lint (pull_request) Successful in 29s
Test / test (18) (pull_request) Successful in 30s
Test / test (20) (pull_request) Successful in 29s
Test / test (22) (pull_request) Successful in 29s
Test / test (24) (pull_request) Successful in 29s
Test / test (26) (pull_request) Successful in 30s
Mirror / push (push) Successful in 5s
Test / lint (pull_request) Successful in 29s
Test / test (18) (pull_request) Successful in 30s
Test / test (20) (pull_request) Successful in 29s
Test / test (22) (pull_request) Successful in 29s
Test / test (24) (pull_request) Successful in 29s
Test / test (26) (pull_request) Successful in 30s
Mirror / push (push) Successful in 5s
This commit was merged in pull request #18.
This commit is contained in:
@@ -348,8 +348,9 @@ Name a later instant as a `Date`, which goes out absolute.
|
|||||||
|
|
||||||
**What gets checked.** The library checks what it composes: an address you gave as `from` or `to`,
|
**What gets checked.** The library checks what it composes: an address you gave as `from` or `to`,
|
||||||
an alphabet or a time you named, a string body under a `data_coding` you named. What you formed
|
an alphabet or a time you named, a string body under a `data_coding` you named. What you formed
|
||||||
yourself, a `Buffer` body or a stamp you formatted, passes through as written. The same rule holds
|
yourself, a `Buffer` body or a stamp you formatted, passes through as written, except that a text
|
||||||
for `session.send()`.
|
field is still checked: [PDUs and the low-level API](#pdus-and-the-low-level-api). The same rule
|
||||||
|
holds for `session.send()`.
|
||||||
|
|
||||||
## Session
|
## Session
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -65,8 +65,8 @@ rule and an index of the titles below.
|
|||||||
which serve their own tables that way. Rejected: a `Result` signature on all three, which costs
|
which serve their own tables that way. Rejected: a `Result` signature on all three, which costs
|
||||||
every typed consumer a narrow forever — goal 8, and the tag is the last cheap chance to spend it —
|
every typed consumer a narrow forever — goal 8, and the tag is the last cheap chance to spend it —
|
||||||
to guard a state the compiler refuses. Where the domain really is open the check is already there:
|
to guard a state the compiler refuses. Where the domain really is open the check is already there:
|
||||||
`sendSms()` takes its options as `unknown` and refuses `encoding` by name, which is what a caller
|
`sendSms()` widens `encoding`, `messagingMode` and the two time options to `unknown` and refuses
|
||||||
without types gets. `smppTime.encode()` is where that reasoning lands the other way and is recorded
|
each by name, which is what a caller without types gets. `smppTime.encode()` is where that reasoning lands the other way and is recorded
|
||||||
under [The wire](#the-wire): `Date | number | string` is not a closed set, so it is a `Result`.
|
under [The wire](#the-wire): `Date | number | string` is not a closed set, so it is a `Result`.
|
||||||
|
|
||||||
- **A segment the SMSC took and named no id for is `undefined` in `smsIds`, not an empty string.**
|
- **A segment the SMSC took and named no id for is `undefined` in `smsIds`, not an empty string.**
|
||||||
@@ -485,12 +485,12 @@ rule and an index of the titles below.
|
|||||||
Goal 1 settles the write, being 3.4 as SMSCs actually run it: an operator routing an alphanumeric
|
Goal 1 settles the write, being 3.4 as SMSCs actually run it: an operator routing an alphanumeric
|
||||||
sender through the upper half is traffic to keep, and Node's `ascii` write already put those octets
|
sender through the upper half is traffic to keep, and Node's `ascii` write already put those octets
|
||||||
on the wire, so naming the write latin1 makes the round trip idempotent and no peer sees a change.
|
on the wire, so naming the write latin1 makes the round trip idempotent and no peer sees a change.
|
||||||
Goal 2 settles the refusals, both of them a `size()` that would have agreed with a `write()` that
|
Goal 2 settles the two latin1 refusals, each a `size()` that would have agreed with a `write()`
|
||||||
put something else on the wire: a character past `U+00FF` written as its low octet, and a caller's
|
that put something else on the wire: a character past `U+00FF` written as its low octet, and a caller's
|
||||||
own `U+0000`, which a mandatory field's reader takes as the end of the field. Goal 4 settles them
|
own `U+0000`, which a mandatory field's reader takes as the end of the field. Goal 4 settles them
|
||||||
twice over: for one character in every 256 that low octet is `0x00`, and the PDU went out malformed
|
twice over: for one character in every 256 that low octet is `0x00`, and the PDU went out malformed
|
||||||
on the operator's parser. `wantText()` and `wantCstringText()` are the only two places that decide
|
on the operator's parser. `wantText()` and `wantCstringText()` are the two places that decide the
|
||||||
it. Rejected: reading latin1 and leaving the write spelled ASCII, which leaves two halves agreeing
|
refusals; every read and write spells `latin1` itself. Rejected: reading latin1 and leaving the write spelled ASCII, which leaves two halves agreeing
|
||||||
only by accident. Rejected: refusing the upper half on send
|
only by accident. Rejected: refusing the upper half on send
|
||||||
to stay strict to 3.4's ASCII, which would be a new restriction taking away traffic this library
|
to stay strict to 3.4's ASCII, which would be a new restriction taking away traffic this library
|
||||||
already sends and operators already accept, on no defect. Rejected: refusing `U+0000` in every
|
already sends and operators already accept, on no defect. Rejected: refusing `U+0000` in every
|
||||||
|
|||||||
@@ -189,6 +189,17 @@ and is also what the panel ranked hardest — two methods, one answer.
|
|||||||
|
|
||||||
### Correctness, ahead of everything below
|
### Correctness, ahead of everything below
|
||||||
|
|
||||||
|
- [ ] **Take the maintainer's call on whether goal 2 covers a value we could not send as given.**
|
||||||
|
Goal 2's four clauses are one family — an undeterminable outcome, a non-final report, a
|
||||||
|
re-send, dropped work — and none of them covers *the wire carried a value the caller did not
|
||||||
|
write, and the call reported success*, which is the `NaN` sender, the `sm_length: 0` body and
|
||||||
|
`1e+21`. Items below cite goal 2 for exactly that, and the DLR-merge item concedes it "is
|
||||||
|
stated in no file today either way". Proposed clause, after "…is not dropped": "; a call that
|
||||||
|
reports a message as sent asserts that the wire carried what the caller wrote, so a value we
|
||||||
|
cannot send as given is refused before anything goes out rather than coerced into one the
|
||||||
|
caller never wrote." A goal is the maintainer's, so nothing edits README until that is
|
||||||
|
answered. From the prose pass of #18.
|
||||||
|
|
||||||
- [ ] **Answer `alert_notification` and `outbind` by not answering them.** Both are response-less in
|
- [ ] **Answer `alert_notification` and `outbind` by not answering them.** Both are response-less in
|
||||||
SMPP 3.4, both fall through `route()`'s default into `unhandled()`, which calls
|
SMPP 3.4, both fall through `route()`'s default into `unhandled()`, which calls
|
||||||
`sendReturn(pduObj, 'ESME_RINVCMDID')`; `pduReturn()` then finds no response command, and the
|
`sendReturn(pduObj, 'ESME_RINVCMDID')`; `pduReturn()` then finds no response command, and the
|
||||||
@@ -411,6 +422,18 @@ and is also what the panel ranked hardest — two methods, one answer.
|
|||||||
creation rule and the FIFO one, which nothing else states, and drop "CI's ten-minute cap" —
|
creation rule and the FIFO one, which nothing else states, and drop "CI's ten-minute cap" —
|
||||||
that number lives in `.gitea/workflows/test.yaml`. Raised by the prose pass, 2026-09-20.
|
that number lives in `.gitea/workflows/test.yaml`. Raised by the prose pass, 2026-09-20.
|
||||||
|
|
||||||
|
- [ ] **Leave AGENTS.md hard rule 1 the rule, and the decision log its reasoning.** Rule 1's fourth
|
||||||
|
sentence — "a function whose argument types are a closed set is guarded by the compiler and
|
||||||
|
stays total, which is why the encoding helpers return plainly, and the check belongs at
|
||||||
|
whichever boundary the argument arrives untyped at" — is the reasoning of the
|
||||||
|
`bitCount()`/`encodeMessage()`/`splitMessage()` entry in `docs/decisions.md`, which AGENTS.md's
|
||||||
|
own Documentation section makes a defect: it scopes AGENTS.md to an index of the decisions. It
|
||||||
|
also reads two ways — "wherever the types admit one" as an exemption for a typed field,
|
||||||
|
"the check belongs at whichever boundary the argument arrives untyped at" as a requirement at
|
||||||
|
`sendSms()` — and the `message` `TypeError` item sits exactly between them, so one rewrite
|
||||||
|
settles both. Maintainer's call, since it changes what a hard rule asks. From the prose pass
|
||||||
|
of #18.
|
||||||
|
|
||||||
- [ ] **Refuse a delay Node's timers cannot hold, in `checkLimits`.** `idleTimeout`,
|
- [ ] **Refuse a delay Node's timers cannot hold, in `checkLimits`.** `idleTimeout`,
|
||||||
`reassemblyTimeout`, `responseTimeout` and `shutdownTimeout` take any integer, and `setTimeout`
|
`reassemblyTimeout`, `responseTimeout` and `shutdownTimeout` take any integer, and `setTimeout`
|
||||||
fires after 1 ms for anything above 2147483647 — so a value in the wrong unit gets the inverse
|
fires after 1 ms for anything above 2147483647 — so a value in the wrong unit gets the inverse
|
||||||
|
|||||||
Reference in New Issue
Block a user