From 87166ffbee2d2ca96c9fea092f07cc07329f71ef Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Tue, 29 Sep 2026 11:18:32 +0200 Subject: [PATCH] Cut the prose this change made false or redundant --- AGENTS.md | 13 +++---------- CHANGELOG.md | 4 ++-- README.md | 7 +++---- docs/decisions.md | 9 +++------ src/held-messages.ts | 2 -- src/sms.ts | 1 - todo.md | 6 ++++++ 7 files changed, 17 insertions(+), 25 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a238b2f..23b6822 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,8 +1,5 @@ # AGENTS.md -Guidance for LLM agents working in this repository. What each file in it is for is under -[Documentation](#documentation). - ## What this is A ground-up TypeScript rewrite of `larvitsmpp` 0.4.0, published as `@larvit/smpp` 0.5.0. The branch @@ -13,7 +10,7 @@ not for structure or style. ## Goals The goals, in priority order, live in -[README.md](https://gitea.larvit.se/larvit/smpp-js/src/branch/main/README.md#goals). The README states the audience alongside them. +[README.md](https://gitea.larvit.se/larvit/smpp-js/src/branch/main/README.md#goals). ## Hard rules @@ -87,8 +84,8 @@ src/ Imports point one way: `defs` knows nothing above it but `result.ts`, `pdu` uses `defs`, `session` uses `pdu`, and `client`/`server` use `session`. The ways back up are the `Session` handed to -`createSms()`, `HeldMessages` and `IncomingRequests`, which call back into it, and to `OnRequest` and `onConnected` -in `session-options.ts`, all imported as a type only. +`createSms()`, `HeldMessages` and `IncomingRequests`, which call back into it, and to `OnRequest` +and `onConnected` in `session-options.ts`, all imported as a type only. **Parameter order is wire order.** The key order inside `cmds.*.params` is the order the fields are written to and read from the buffer. Never sort those alphabetically — the alphabetical-ordering @@ -225,10 +222,6 @@ this is not a changelog. ## Decisions -The decisions themselves live in [docs/decisions.md](docs/decisions.md). Their titles are indexed -here, so a reader sees that a decision exists without carrying its reasoning; the reasoning is in -the file. - ### [The public surface](docs/decisions.md#the-public-surface) - `Session` is publicly constructible, which is what makes `SessionOptions` and `ReconnectOptions` diff --git a/CHANGELOG.md b/CHANGELOG.md index a667c38..7cb5ff7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,8 +74,8 @@ `alert_on_message_delivery` and `broadcast_area_identifier`, the names they read back under. The two alternate names are gone from `tlvs` too, which is now typed by `TlvName`: narrow a `string` with `isTlvName()` before indexing it. - `cmds.broadcast_sm_resp.tlvMap` is removed; nothing read it. -- The `SmsInput` type is no longer exported; nothing exported took one. Annotate with `Sms`, or - `Pick` where you typed a shape of your own. +- The `SmsInput` type is no longer exported; nothing exported took one. Annotate with `Sms`, or a + `Pick` of the fields you use. - `session.boundAs` and `session.peerInterfaceVersion` are read-only, and `session.loggedIn` is removed: read `session.boundAs !== undefined`. A session you wire yourself records the bind it accepted or had accepted with `session.bound(bindType, declaredVersion)`, which returns `err` for a diff --git a/README.md b/README.md index a599cea..9ff2b7d 100644 --- a/README.md +++ b/README.md @@ -713,10 +713,9 @@ one wins. They do not override the [hard rules](https://gitea.larvit.se/larvit/s alphabet, a receipt format — it gets an option or a hook rather than a fork. A call that passes no options stays exactly as easy and as safe, and a hook is a seam the library calls, never a way into its internals. -8. **A small, stable public surface over reshapeable internals.** Only what `src/index.ts` exports is - published. A new option has to beat "the application can do this itself", and has to keep a - promise this library can verify. The low-level surface is a passthrough: policy binds what the - library composes, never what the caller wrote. +8. **A small, stable public surface over reshapeable internals.** A new option has to beat "the + application can do this itself", and has to keep a promise this library can verify. The low-level + surface is a passthrough: policy binds what the library composes, never what the caller wrote. 9. **State wider than one session goes through one store.** A pool of sessions, a limit shared between processes, and what has to survive a restart — receipts still awaited, a message half reassembled — are held through a store interface and never beside it. Without a store the diff --git a/docs/decisions.md b/docs/decisions.md index 7ecd0a3..6d70882 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -8,8 +8,7 @@ rule and an index of the titles below. - **`Session` is publicly constructible, which is what makes `SessionOptions` and `ReconnectOptions` public too.** Raised twice as a leak; it is not one. The collaborators `session.ts` delegates to - (`IncomingRequests`, `OutgoingRequests`, `ReconnectLoop`, `LinkTimers`, `DlrMerger`, - `PduTransport`, `submitSms`) stay unpublished so they can be reshaped. + stay unpublished so they can be reshaped. - **`acceptsOptionalParams()` and `bindAllows()` are predicates, not chokepoints.** The library's own senders consult them; `session.send({ tlvs })` is passed through as written, because silently @@ -418,8 +417,7 @@ rule and an index of the titles below. caller would get wrong, where asking the codec is, and publishing it would freeze this library's error prose as API for an application whose own refusal should read like itself. Goal 8, from the architecture review of [#99](https://github.com/larvit/larvitsmpp/pull/99), 2026-09-09. It is - reached through - `encodeBody()` in `message.ts`, which is where the `data_coding`-to-text pair already lives: + reached through `encodeBody()` in `message.ts`, which is where the `data_coding`-to-text pair already lives: `encodeBody(text, dataCoding)` is `decodeMessage(buffer, dataCoding)`'s mirror and resolves the alphabet through the same `encodingByDataCoding()`. `send()` and `sendReturn()` inherit it, since both build through `buildPdu()`; `sendSms()` does not, and keeps its own guard, because @@ -641,8 +639,7 @@ rule and an index of the titles below. failure belongs to one session's request, and that channel already carries every failure of one. The hook is consulted before the bind-direction gate, so it sees a `submit_sm` a receiver-bound peer may not send; first refusal means first, and one it declines still gets `ESME_RINVBNDSTS`. - Nothing is held for a request the hook answered: `HeldMessages` is opened by the `sms` event the - hook skipped, so the drain waits on none of it. `OnRequest` stays unexported where + Nothing is held for a request the hook answered, so the drain waits on none of it. `OnRequest` stays unexported where `AuthenticateInput` is exported, because that hook's argument is a shape this library invents and this one's are two types already published. Rejected: consulting the hook first, which puts bind and authentication inside the application's reach for nothing. Rejected: a narrower hook diff --git a/src/held-messages.ts b/src/held-messages.ts index a970f6a..b9e740e 100644 --- a/src/held-messages.ts +++ b/src/held-messages.ts @@ -16,7 +16,6 @@ export type HeldMessagesOptions = { maxOctets: number; /** Injected so expiry can be exercised without a wall clock. */ now?: (() => number) | undefined; - /** Past a drain's refusal, for a receipt the drain is itself waiting for. */ sendPastDrain: SmsHandlers['send']; session: Session; timeout: number; @@ -135,7 +134,6 @@ export class HeldMessages { return hold; } - /** Hands a whole message to the application as an `sms` event, held until it is answered. */ offer(pduObjs: PduObject[], answeredAs?: string): MessageHold | undefined { const key = keyOf(pduObjs); diff --git a/src/sms.ts b/src/sms.ts index 19fb0a6..5149ceb 100644 --- a/src/sms.ts +++ b/src/sms.ts @@ -65,7 +65,6 @@ export type SmsInput = { session: Session; }; -/** What the session's incoming side gives a message so it can be answered and accounted for. */ export type SmsHandlers = { answered: () => void; lostLink: () => boolean; diff --git a/todo.md b/todo.md index f70527e..6a5e9ff 100644 --- a/todo.md +++ b/todo.md @@ -352,6 +352,12 @@ below. ### Self-sufficiency — 6–7 today, and the gate is 7 +- [ ] **Move the fixture-copy reasoning out of AGENTS.md's Conventions, and split the longest + decision entries.** The fixtures bullet holds four justifications for tolerated copies — decisions, + so they belong in `docs/decisions.md` under Internals and tests; the entries under the wire's + alphabet and body rules run 30–40 lines with their `Rejected:` clauses inline, where a reader + who knows the answer still hunts for it. From the 2026-09-29 prose pass. + - [ ] **Move the one-line facts out of the decision log and back to the code.** Five of nine readers independently reported being sent to `docs/decisions.md` for a question they hit while reading, with no link from the code; one counted roughly fifty index redirects. The three left to inline