Commit 573ac80
authored
feat(tendlc)!: command-tree cutover and number reads (PR 5 of 5) (#41)
* feat(tendlc): add phone number service methods
* feat(tendlc): add band tendlc number list, get, and history
* fix(tendlc): add number list --campaign-id-contains, correct filter/projection docs
Re-measurement showed campaignId[contains] filters correctly (the earlier
zero-match probe used a campaign with no assigned numbers) and the list
projection has two shapes, not a fixed five keys (assigned numbers carry
three extra fields). status remains confirmed dead under every operator
and value, so --status stays absent.
* docs(tendlc): correct the phone number projection and filter comments
Two claims in ListPhoneNumbers' doc comment were wrong, both from probe
design rather than API behaviour.
The projection is conditional, not fixed: 16 of 23 records carry five keys,
the 7 assigned to a campaign carry three more. The original claim came from
a single record fetched with limit=1.
campaignId[contains] works correctly. The original probe filtered on a
campaign with no assigned numbers, got zero results, and read the empty set
as a broken filter. Re-tested against a campaign with three numbers, it
returns three.
status genuinely does not filter under any operator, including a value that
matches nothing on the account.
* feat(tendlc)!: remove the legacy campaigns, numbers, and number commands
Deletes band tendlc campaigns, campaigns numbers, numbers, and the flat
number <tn> command, ending the deprecation window from the two previous
PRs where the legacy and new command trees coexisted deliberately. No
aliases or shims: v0.3.0-beta status and no substantial customer traffic
justify a clean break here.
number.go's three subcommands (list/get/history) now attach to a plain
numberCmd parent registered directly on Cmd, matching brandCmd/campaignCmd,
instead of the numberGetCmd node that lived in the now-deleted numbers.go.
extractData and filterNumbers in helpers.go existed only to serve the
deleted commands and are removed along with their tests. Also folds in a
carried-over test assertion: number list must not gain an exact-match
--campaign-id flag, since campaignId[eq] is silently ignored by the API
and returns every record — the same anti-pattern already avoided by
brand list and campaign list.
* fix(tendlc)!: reject stray args on tendlc's dispatcher commands
band tendlc campaigns, band tendlc numbers, and band tendlc number <tn> --
all removed in the previous commit -- exited 0 with a help dump instead of
failing, because cobra checks Runnable() before it ever consults Args, and
none of Cmd/brandCmd/campaignCmd/numberCmd/vettingCmd had a RunE. A stray
token that used to be a real, now-deleted command was indistinguishable
from a successful help request.
Gives each of those five dispatcher commands Args: cobra.NoArgs plus a
trivial RunE (return cmd.Help()) so NoArgs actually runs: a bare invocation
still prints help and exits 0, but a trailing token matching no subcommand
now exits non-zero. customer-profile has the same latent shape but is out
of scope for this branch.
* test: make the doc-contract parser distinguish subcommands from positionals
* test: close the fully-resolves-but-rejects-args blind spot in the doc-contract parser
Adds a third gate that calls the resolved command's real cobra Args
validator against the documented arguments, catching stale references
that resolve completely (so the Use-string heuristic sees no remainder
to judge) but whose command no longer accepts what follows it.
* docs: retire the deleted commands and drop every doc-contract suppression
The parser fix landed with five knownDriftCommands entries: four for real
drift the deletion left behind, one for a shell comment that parsed as a
command. All five are now unnecessary.
The six stale lines are rewritten to the new tree, the numbers block no
longer advertises a --status filter the API silently ignores, and the
parser skips shell comments inside fenced blocks — prose that mentions a
command mid-sentence is not an invocation.
knownDriftCommands is empty. Verified by planting three shapes of stale
reference and confirming each is caught: a deleted subcommand, a deleted
positional form, and a bare argument on a parent that takes none.
* feat(tendlc): retry once when a PUT rejects fields we can safely drop
brand update and campaign update build a full-replacement PUT body by
stripping a known list of read-only keys from the resource the API just
returned. That only works because production currently accepts read-only
fields it does not use. If that is ever tightened to a 400, both commands
break the same day, since the strip lists cannot enumerate every field the
API might start rejecting.
Add putReplaceWithReadOnlyRetry, shared by UpdateBrand and UpdateCampaign:
on a 400 whose error source.POINTER values name top-level fields present in
the outgoing body, strip exactly those fields and retry once, noting the
drop on stderr. Any other 400, or a retry that also fails, surfaces
untouched/original. No loop, no backoff, no mutation of the shared strip
lists.
* docs: document band tendlc number and finish the command-tree cutover
* docs: replace two real phone numbers with reserved-range placeholders
Pre-existing on main, in the band number list example. This repo is public
and the 919 numbers are real Bandwidth TNs; the rest of the docs already
use the reserved 555-0100 block.
* fix(tendlc): never let the PUT retry drop a field the caller set
* fix(tendlc): the PUT retry may only drop fields the CLI does not model
An independent adversarial pass found the previous guard insufficient. It
protected fields the caller changed in this invocation, but an unchanged
field still holds real data: a brand with a stored website that no longer
passes validation would have that website dropped from the retry body by
an unrelated --display-name update, and a full-replacement PUT nulls it.
neverDrop is now built from the entire update flag surface, so the retry
can only ever drop a field the CLI does not model at all — which is the
only case it was designed for. The invariant is stated in putretry.go.
Also: trailing punctuation no longer bypasses the doc-contract parser, so
a documented 'band tendlc campaigns,' is caught rather than abstained on;
a port-in example shows two distinct numbers again; and a caller-id moves
into the reserved range.
* test(cmd): normalize CRLF before parsing docs in the doc-contract gate
The doc-contract parser is line-oriented and splits on "\n". On a Windows
checkout the files land with CRLF, so the trailing "\r" survives the split
and glues itself to the last token on every line.
That broke the gate two ways. A command token became "get\r", which fails
commandTokenRe, so the path resolved one token short and the test reported
`band tendlc campaign` rejecting "get". And the lone "\" shell
line-continuation marker became "\\\r", which no longer matched the
documented abstain rule for it, so multi-line examples were parsed as if
the continuation backslash were a real positional argument.
Four AGENTS.md examples failed this way on windows-latest only. Normalize
once at the read site rather than defending against "\r" at each token
check downstream.
Verified: passes under LF, passes under simulated CRLF, and still catches
a planted `band tendlc brandz list` under CRLF -- the normalization does
not neuter the gate.1 parent 43b9b5c commit 573ac80
25 files changed
Lines changed: 2236 additions & 465 deletions
File tree
- cmd
- message
- tendlc
- internal/tendlc
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
| 6 | + | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| |||
83 | 83 | | |
84 | 84 | | |
85 | 85 | | |
86 | | - | |
| 86 | + | |
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
| |||
138 | 138 | | |
139 | 139 | | |
140 | 140 | | |
141 | | - | |
| 141 | + | |
142 | 142 | | |
143 | 143 | | |
144 | 144 | | |
| |||
149 | 149 | | |
150 | 150 | | |
151 | 151 | | |
152 | | - | |
| 152 | + | |
153 | 153 | | |
154 | 154 | | |
155 | 155 | | |
| |||
164 | 164 | | |
165 | 165 | | |
166 | 166 | | |
167 | | - | |
| 167 | + | |
168 | 168 | | |
169 | 169 | | |
170 | 170 | | |
| |||
196 | 196 | | |
197 | 197 | | |
198 | 198 | | |
199 | | - | |
| 199 | + | |
200 | 200 | | |
201 | 201 | | |
202 | 202 | | |
| |||
276 | 276 | | |
277 | 277 | | |
278 | 278 | | |
279 | | - | |
280 | | - | |
| 279 | + | |
| 280 | + | |
281 | 281 | | |
282 | 282 | | |
283 | 283 | | |
| |||
306 | 306 | | |
307 | 307 | | |
308 | 308 | | |
309 | | - | |
310 | | - | |
311 | | - | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
312 | 312 | | |
313 | 313 | | |
314 | 314 | | |
| |||
334 | 334 | | |
335 | 335 | | |
336 | 336 | | |
337 | | - | |
| 337 | + | |
338 | 338 | | |
339 | 339 | | |
340 | 340 | | |
| |||
359 | 359 | | |
360 | 360 | | |
361 | 361 | | |
362 | | - | |
| 362 | + | |
363 | 363 | | |
364 | 364 | | |
365 | 365 | | |
| |||
477 | 477 | | |
478 | 478 | | |
479 | 479 | | |
480 | | - | |
| 480 | + | |
481 | 481 | | |
482 | | - | |
| 482 | + | |
483 | 483 | | |
484 | 484 | | |
485 | 485 | | |
| |||
504 | 504 | | |
505 | 505 | | |
506 | 506 | | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
507 | 510 | | |
508 | 511 | | |
509 | 512 | | |
| |||
0 commit comments