Amend plan 3 with its architecture review
Test / lint (pull_request) Successful in 21s
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 4s
Test / lint (pull_request) Successful in 21s
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 4s
This commit was merged in pull request #51.
This commit is contained in:
@@ -205,21 +205,7 @@ exception AGENTS allows), and named in AGENTS.md's architecture list as "hard".
|
|||||||
|
|
||||||
## 6. Build order
|
## 6. Build order
|
||||||
|
|
||||||
Each chunk leaves the suite green and ships through /larv-review.
|
The order that runs is todo.md's, amended by §8.
|
||||||
|
|
||||||
1. **Moves only**: `defs/` → `codec/`, `options.ts` with one defaults table, `result.ts` absorbs
|
|
||||||
error-from. No behaviour change.
|
|
||||||
2. **protocol/**: vocabulary, data-coding table (256-octet equivalence test), esm-class, segments,
|
|
||||||
receipt, message-ids, time, bind, arrival; internal gsm7 rename; citation test.
|
|
||||||
3. **messages/**: bounded-store, reassembly and receipt-merge on it (refuse-not-evict, decision
|
|
||||||
recorded, README bound text updated), split, submit.
|
|
||||||
4. **session/** under the new contract: one-socket Session, requests-out, requests-in replies,
|
|
||||||
handlers, onSms/Reply/`dlr` in Reply, onRequest returning Reply (A2–A5). server/ ported. Tests
|
|
||||||
ported by the F translation table; the held-message tests become handler tests.
|
|
||||||
5. **client/**: SmppClient, connect, backoff; reconnect and `fromStart` tests re-pointed (A1).
|
|
||||||
6. **A6**, README/MIGRATION/CHANGELOG/decisions/AGENTS architecture; README examples executed;
|
|
||||||
interop suite; benchmarks against goal 6's floors.
|
|
||||||
7. **Four-seat panel run**; its findings become the next chunk.
|
|
||||||
|
|
||||||
## 7. Predicted panel risks
|
## 7. Predicted panel risks
|
||||||
|
|
||||||
@@ -239,3 +225,55 @@ Each chunk leaves the suite green and ships through /larv-review.
|
|||||||
- **The coarse scale**: even if every named unit is fixed, a mean of 7.0 needs all four seats to move,
|
- **The coarse scale**: even if every named unit is fixed, a mean of 7.0 needs all four seats to move,
|
||||||
and the hardest-unit list has moved every round; expect a new one (likely requests-in.ts or
|
and the hardest-unit list has moved every round; expect a new one (likely requests-in.ts or
|
||||||
SmppClient's request loop) at 6.
|
SmppClient's request loop) at 6.
|
||||||
|
|
||||||
|
## 8. Architecture review, 2026-09-30
|
||||||
|
|
||||||
|
Verdict ALIGN: the direction serves the goals, but §6 could not leave the suite green and the plan
|
||||||
|
overturned recorded decisions without naming them. todo.md carries the reordered build; the rest:
|
||||||
|
|
||||||
|
1. **Each public API row names the decision it replaces**, and the replacement lands in
|
||||||
|
docs/decisions.md in the chunk that makes it. Overturned without saying so: `src/` stays flat;
|
||||||
|
`Session` publicly constructible (`ReconnectOptions` moves); both emitters re-declare listeners
|
||||||
|
(`SmppClient` is a third); every segment answered on arrival (a refused `smsId` becomes a
|
||||||
|
`sessionError`); `server()` composes `onRequest` (A4 is its rejected alternative); the drain waits
|
||||||
|
on held messages, capped on constants; `linkEnd` beside `boundAs` (A5 makes it an option); bind state
|
||||||
|
holds through the gap, and one owner decides whether a link carries a request; `close` means over;
|
||||||
|
a receipt does not belong to the link; a base merged once, capped like the groups; the total
|
||||||
|
encoding signatures and GSM declaring 0x00 (A6 renames `EncodingName`, so the codec exports do
|
||||||
|
change); the abort dance copied, not extracted (`waiting.ts`: recount the sites, then keep the
|
||||||
|
copies or revise the decision).
|
||||||
|
2. **The segment reference counter is `SmppClient` state**, passed to `messages/submit.ts`; `protocol/`
|
||||||
|
holds none.
|
||||||
|
3. **`client/next-link.ts`** bounds the wait by `responseTimeout` from when the send was issued,
|
||||||
|
builds the PDU against the session it lands on (retiring "bind state holds through the gap"), fails
|
||||||
|
waiting requests as unwritten on `close()`/`unbind()`, and registers a multipart send's merge before
|
||||||
|
its segments go out.
|
||||||
|
4. **`SmppClient` re-emits every `Session` event but `sms` and `close`**; a session's `close` is
|
||||||
|
`disconnected` unless the client is over. `client.session` is the current link, and a listener on it
|
||||||
|
lasts one link.
|
||||||
|
5. **`sms.sendDlr()` goes through a receipt sender `handlers.ts` is given**: `SmppClient`'s next-link
|
||||||
|
path in client mode. The answer stays on the arrival session, which `Sms.session` names.
|
||||||
|
6. **One function in `session.ts` owns the async answer**: `replyFor()`, then `handlers.run(sms)` where
|
||||||
|
the application decides, then `write()`. `handlers.ts` returns a `Promise<Reply>` and never calls
|
||||||
|
into `Session`.
|
||||||
|
7. **`BoundedStore` is internal**, not goal 9's store interface; `ReceiptMerge` records stay plain data.
|
||||||
|
Reassembly refuses at its bound: an evicted group is answered segments lost, goal 2 outranks goal 4,
|
||||||
|
and the store is per session. The spent set expires by age.
|
||||||
|
8. **`retained.ts` goes to `codec/`**; `options.ts` joins AGENTS.md's type-only ways back up.
|
||||||
|
|
||||||
|
Public API questions, each with the review's recommendation:
|
||||||
|
|
||||||
|
- **Q1 (A1).** `client()` returns `{ err, client }`? Yes: the returned type changes anyway.
|
||||||
|
- **Q2 (A3).** `onSms` may return a receipt state? Yes, against the board: without it "answer, then
|
||||||
|
report at once" has no correct spelling, and the two differ in result, so they are not two spellings.
|
||||||
|
- **Q3 (A4).** `onRequest`'s `Reply`: any status, `params` and `tlvs`, or an explicit no-answer, async
|
||||||
|
allowed. Narrower cannot answer a bind, a vendor command or a `data_sm`.
|
||||||
|
- **Q4 (A6).** `'ASCII'` becomes `'GSM7'` in every export? Yes: dropping it keeps two names for one
|
||||||
|
alphabet at the boundary.
|
||||||
|
- **Q5.** `sendSms()` and `messageDlr` on `SmppClient` only, `Session` keeping `send()`? Yes: one send
|
||||||
|
surface and one counter; a hand-wired `Session` loses `sendSms()`.
|
||||||
|
- **Q6.** No `onSms` answers the retry status, with a warning once per session? Yes, goal 2 over goal 4.
|
||||||
|
- **Q7.** `handlerTimeout` a constant, answering the retry status on expiry, a late `Reply` on
|
||||||
|
`sessionError`, the drain waiting at most that long? Yes.
|
||||||
|
- **Q8.** A full merge store: register before sending and say in `SendSmsResult` that no merged report
|
||||||
|
follows? Yes, over oldest-eviction for merges or a silent refusal.
|
||||||
|
|||||||
@@ -218,35 +218,41 @@ Each chunk also closes the items further down that it absorbs, and its PR names
|
|||||||
`refusing`, the three `defaults`, `ASCII`, `session-options.ts`, the flat `src/`, and the link that
|
`refusing`, the three `defaults`, `ASCII`, `session-options.ts`, the flat `src/`, and the link that
|
||||||
dropped mid-rebind.
|
dropped mid-rebind.
|
||||||
|
|
||||||
- [ ] **Run the architecture review on plan 3 as amended here, before chunk 1.** Put its findings
|
Every chunk that changes the public API updates README's examples, MIGRATION.md, CHANGELOG.md,
|
||||||
into the plan, and ask where they change a public API choice.
|
docs/decisions.md and the AGENTS.md map in its own PR, and deletes what it replaces; no old and new
|
||||||
|
file stand side by side. The architecture review of 2026-09-30 (ALIGN) set this order; its amendments
|
||||||
|
to the plan are [plan 3 §8](docs/comprehension-rewrite/plan-3.md#8-architecture-review-2026-09-30).
|
||||||
|
|
||||||
|
- [ ] **Answer the review's public API questions Q1–Q8 before the chunk each gates.** Q4 (A6) before
|
||||||
|
`protocol/`, Q1 (A1) and Q5 before the lifecycle split, Q2 (A3), Q3 (A4) and Q6–Q8 before
|
||||||
|
answering on return. Each answer lands
|
||||||
|
as a goal or a decision, never here alone.
|
||||||
- [ ] **Move without changing behaviour.** `defs/` becomes `codec/`, `options.ts` becomes one defaults
|
- [ ] **Move without changing behaviour.** `defs/` becomes `codec/`, `options.ts` becomes one defaults
|
||||||
table, and `result.ts` absorbs `error-from.ts`.
|
table, and `result.ts` absorbs `error-from.ts`. Every file with one target moves to its folder
|
||||||
|
now, and the "`src/` stays flat" decision is retired in the same PR.
|
||||||
- [ ] **Build `protocol/`: every multi-fact octet read once into a named plain type.**
|
- [ ] **Build `protocol/`: every multi-fact octet read once into a named plain type.**
|
||||||
- `vocabulary.ts`: the glossary as types with one-line TSDoc.
|
- `vocabulary.ts`: the glossary as types with one-line TSDoc.
|
||||||
- `data-coding.ts`: the `data_coding` table as rows, with a test that it equals today's function
|
- `data-coding.ts`: the `data_coding` table as rows, with a test that it equals today's function
|
||||||
on all 256 octets.
|
on all 256 octets.
|
||||||
- `esm_class`, segments, receipts, message ids, time and bind.
|
- `esm_class`, segments, receipts, message ids, time and bind; no state, so the segment
|
||||||
- The internal `gsm7` rename.
|
reference counter goes to `SmppClient` in the lifecycle split.
|
||||||
|
- The internal `gsm7` rename, with A6 if Q4 says so.
|
||||||
- A test that fails on a spec citation without its sentence.
|
- A test that fails on a spec citation without its sentence.
|
||||||
- [ ] **Build `messages/` on a `BoundedStore` that enforces its own bounds and refuses instead of
|
- [ ] **Build `messages/` on a `BoundedStore` that enforces its own bounds.** Reassembly refuses at its
|
||||||
evicting.** Reassembly and receipt merging move onto it. Record the refuse-not-evict decision
|
bound instead of evicting, recorded against goals 2 and 4; the receipt merge follows Q8 and its
|
||||||
against goals 2 and 4, and update README's bound text.
|
spent set expires by age. README's bound text is updated.
|
||||||
- [ ] **Make a `Session` one socket under the `onSms` contract (plan 3's A2, A4 and A5).**
|
- [ ] **List every test by name, mapped to its survivor or a reason for deleting it, before the lifecycle split.**
|
||||||
- Its life moves only forward.
|
Every defect-table regression test survives by name.
|
||||||
- Every inbound request resolves to one `Reply`, written by one function.
|
- [ ] **Split the lifecycle (A1, A5): a one-socket `Session`, reconnect above it in `client/`.**
|
||||||
- `onRequest` returns a `Reply`, and `server/` is ported.
|
- `SmppClient`, `connect.ts`, `backoff.ts`, and `client/next-link.ts` holding the wait for a bound
|
||||||
- The board advises dropping A3 (a receipt state returned from `onSms`) as a second way to send a
|
session and the retry of only what never reached the socket, invariant at the top, so
|
||||||
receipt; ask before building it.
|
`client.ts` only composes.
|
||||||
- [ ] **Put reconnect above the session in `client/` (A1).**
|
- `sendResp()` and `HeldMessages` are ported as they are.
|
||||||
- `SmppClient`, `connect` and backoff.
|
- Absorbs registering a multipart send's receipt merge before its segments go out.
|
||||||
- The unanimous board amendment: the wait for a bound session and the retry of only what never
|
- The interop suite and goal 6's benchmarks run before it merges.
|
||||||
reached the socket get their own `client/next-link.ts`, invariant at the top, so `client.ts`
|
- [ ] **Answer on return (A2, A4, and A3 if kept).** `handlers.ts`, `requests-in.ts` returning a `Reply`,
|
||||||
only composes.
|
`onRequest` returning one, `server/` ported, `HeldMessages` deleted. The interop suite and the
|
||||||
- The board rated A1's `{ err, client }` rename worth questioning; ask before shipping it.
|
benchmarks run before it merges.
|
||||||
- [ ] **Finish the contract (A6) and the prose.** A6 renames `'ASCII'` to `'GSM7'`; the plan names it
|
|
||||||
the cheapest break to drop, so ask. Then README, MIGRATION.md, CHANGELOG.md, decisions and the
|
|
||||||
AGENTS.md map; the interop suite; and the benchmarks against goal 6's floors.
|
|
||||||
- [ ] **Confirm Locality at 7 with a final scoring run.** A run reading 7.0 or above retires the
|
- [ ] **Confirm Locality at 7 with a final scoring run.** A run reading 7.0 or above retires the
|
||||||
Locality-first decision.
|
Locality-first decision.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user