claude_profile 1.0.0

Claude Code account credential management and token status
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
# Test: `.account.status`

Integration test planning for the `.account.status` command. See [commands.md](../../commands.md#command--4-accountstatus) for specification.

## Test Case Index

| ID | Test Name | Category |
|----|-----------|----------|
| IT-1 | No `_active` file → exit 2, stderr reports no active account | Error Handling |
| IT-2 | Empty `_active` file → exit 2, stderr reports no active account | Error Handling |
| IT-3 | Active account with valid token → name and "valid" in output | Basic Invocation |
| IT-4 | Active account with expired token → name and "expired" in output | Token State |
| IT-5 | Active account with near-expiry token → "expiring in Xm" in output | Token State |
| IT-6 | Missing credentials file → token shows "unknown", exit 0 | Error Recovery |
| IT-7 | `v::0` shows bare name then token state (no labels) | Verbosity |
| IT-8 | `v::1` (default) shows Account: and Token: labels; no Expires: line | Verbosity |
| IT-9 | `v::2` shows additional "Expires:" line | Verbosity |
| IT-10 | `format::json` returns `{"account":"...","token":"..."}` | Output Format |
| IT-11 | `name::` = active account → same name and "valid" as no-name path | FR-16 / Named Account |
| IT-12 | `name::` = non-active account → shows that account's own expired token | FR-16 / P2 Guard |
| IT-13 | `name::` = nonexistent account → exit 2 + "not found" in stderr | FR-16 / Error Handling |
| IT-14 | `name::` with invalid chars → exit 1 | FR-16 / Input Validation |
| IT-15 | `name::` + `v::0` → two bare lines (name, token state) | FR-16 / Verbosity |
| IT-16 | `name::` = active + `.claude.json` present → shows Email/Org at `v::1` | FR-16 / Email/Org |
| IT-17 | `name::` = non-active + `v::1` → Email and Org are N/A | FR-16 / Email/Org |
| IT-18 | `name::` = non-active + `v::2` → "Expires:" line present | FR-16 / Verbosity |
| IT-19 | `name::` + `format::json` → JSON with `account` and `token` fields | FR-16 / Output Format |
| IT-20 | `name::` = non-active + `v::0` → two bare lines with named account's state | FR-16 / P2 Guard |
| IT-21 | Active path `v::1` — default `.account.status` shows Sub:, Tier:, Email:, Org: | FR-16 / Sub/Tier |
| IT-22 | Named active `v::1``name::work v::1` shows Sub:, Tier:, Email:, Org: | FR-16 / Sub/Tier |
| IT-23 | Named non-active `v::1``name::personal v::1` shows own Sub:, Tier: (not active's) | FR-16 / Sub/Tier |
| IT-24 | Active path — empty-string `subscriptionType` in credentials → `Sub: N/A` | FR-16 / N/A Normalization |
| IT-25 | Named non-active — `subscriptionType` absent in account file → `Sub: N/A` | FR-16 / N/A Normalization |
| IT-26 | Named non-active — `rateLimitTier` absent in account file → `Tier: N/A` | FR-16 / N/A Normalization |

## Test Coverage Summary

- Basic Invocation: 1 test
- Token State: 2 tests
- Error Handling: 3 tests
- Error Recovery: 1 test
- Verbosity: 5 tests
- Output Format: 2 tests
- FR-16 Named Account: 6 tests (IT-11, IT-12, IT-16, IT-17, IT-18, IT-20)
- FR-16 Sub/Tier: 3 tests (IT-21, IT-22, IT-23)
- FR-16 N/A Normalization: 3 tests (IT-24, IT-25, IT-26)

**Total:** 26 integration tests

---

### IT-1: No `_active` file → exit 2, stderr reports no active account

**Goal:** Confirm that a missing `_active` marker produces a clear error and non-zero exit.
**Setup:** Create `~/.claude/.credentials.json` (valid token). Do NOT create `~/.claude/accounts/_active`.
**Command:** `clp .account.status`
**Expected Output:** Empty stdout; stderr contains "no active account set".
**Verification:**
- Capture stdout and stderr
- Assert exit code is 2
- Assert stderr contains `no active account`
- Assert stdout is empty
**Pass Criteria:** Exit 2; actionable error message on stderr.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus

---

### IT-2: Empty `_active` file → exit 2, stderr reports no active account

**Goal:** Confirm that an existing but empty `_active` marker is treated the same as absent.
**Setup:** Create `~/.claude/accounts/_active` with empty contents (zero bytes or whitespace only).
**Command:** `clp .account.status`
**Expected Output:** Empty stdout; stderr contains "no active account set".
**Verification:**
- Capture stdout and stderr
- Assert exit code is 2
- Assert stderr contains `no active account`
**Pass Criteria:** Exit 2; empty `_active` is not treated as a valid account name.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus

---

### IT-3: Active account with valid token → name and "valid" in output

**Goal:** Confirm the happy-path output shows the account name and "valid" token state.
**Setup:** Write `~/.claude/accounts/_active` = `"work"`. Write `~/.claude/.credentials.json` with `expiresAt` far in the future (year ~2286).
**Command:** `clp .account.status`
**Expected Output:** Output contains `work` and `valid`.
**Verification:**
- Capture stdout
- Assert exit code is 0
- Assert stdout contains `work`
- Assert stdout contains `valid`
**Pass Criteria:** Exit 0; account name and valid token state present.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus

---

### IT-4: Active account with expired token → name and "expired" in output

**Goal:** Confirm that an expired token is reported as "expired" in the output.
**Setup:** Write `~/.claude/accounts/_active` = `"work"`. Write `~/.claude/.credentials.json` with `expiresAt` in the past (Unix ms 1_000_000_000).
**Command:** `clp .account.status`
**Expected Output:** Output contains `work` and `expired`.
**Verification:**
- Capture stdout
- Assert exit code is 0
- Assert stdout contains `work`
- Assert stdout contains `expired`
**Pass Criteria:** Exit 0; expired state reported without crashing.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus

---

### IT-5: Active account with near-expiry token → "expiring in Xm" in output

**Goal:** Confirm that a token within the warning threshold is reported as expiring.
**Setup:** Write `~/.claude/accounts/_active` = `"work"`. Write `~/.claude/.credentials.json` with `expiresAt` 30 minutes from now (within 3600s default threshold).
**Command:** `clp .account.status`
**Expected Output:** Output contains `work` and `expiring in`.
**Verification:**
- Capture stdout
- Assert exit code is 0
- Assert stdout contains `work`
- Assert stdout contains `expiring in`
**Pass Criteria:** Exit 0; near-expiry state distinguishable from valid and expired.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus

---

### IT-6: Missing credentials file → token shows "unknown", exit 0

**Goal:** Confirm that a missing credentials file does not crash the command — account name is still shown with token state "unknown".
**Setup:** Write `~/.claude/accounts/_active` = `"work"`. Do NOT create `~/.claude/.credentials.json`.
**Command:** `clp .account.status`
**Expected Output:** Output contains `work` and `unknown`. Exit 0.
**Verification:**
- Capture stdout and stderr
- Assert exit code is 0
- Assert stdout contains `work`
- Assert stdout contains `unknown`
**Pass Criteria:** Exit 0; graceful degradation when credentials are unreadable.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus

---

### IT-7: `v::0` shows bare name then token state (no labels)

**Goal:** Confirm verbosity 0 produces exactly two lines: account name then token state, no "Account:" or "Token:" labels.
**Setup:** Write `~/.claude/accounts/_active` = `"work"`. Write valid credentials.
**Command:** `clp .account.status v::0`
**Expected Output:** Two lines: line 1 = `work`, line 2 = `valid`. No label prefixes.
**Verification:**
- Capture stdout
- Assert exit code is 0
- Split stdout into lines
- Assert line 0 is `work`
- Assert line 1 is `valid`
- Assert stdout does not contain `Account:`
- Assert stdout does not contain `Token:`
**Pass Criteria:** Exit 0; two unlabelled lines only.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus

---

### IT-8: `v::1` (default) shows "Account:" and "Token:" labels

**Goal:** Confirm the default verbosity level 1 shows labelled output with "Account:" and "Token:" prefixes.
**Setup:** Write `~/.claude/accounts/_active` = `"work"`. Write valid credentials.
**Command:** `clp .account.status` (implicit v::1)
**Expected Output:** Lines like `Account: work` and `Token:   valid`.
**Verification:**
- Capture stdout
- Assert exit code is 0
- Assert stdout contains `Account: work`
- Assert stdout contains `Token:`
- Assert stdout does not contain `Expires:`
**Pass Criteria:** Exit 0; Account: and Token: labels present, no Expires: line (Sub/Tier/Email/Org presence verified by IT-21).
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus

---

### IT-9: `v::2` shows additional "Expires:" line

**Goal:** Confirm verbosity level 2 adds the "Expires:" line beyond what v::1 shows.
**Setup:** Write `~/.claude/accounts/_active` = `"work"`. Write valid credentials with far-future expiry.
**Command:** `clp .account.status v::2`
**Expected Output:** Seven lines: `Account: work`, `Token:   valid`, `Sub:     pro`, `Tier:    standard`, `Expires: in Xh Ym`, `Email:   N/A`, `Org:     N/A` (no `.claude.json` in setup, so email/org fall back to N/A).
**Verification:**
- Capture stdout
- Assert exit code is 0
- Assert stdout contains `Account: work`
- Assert stdout contains `Token:`
- Assert stdout contains `Expires:`
**Pass Criteria:** Exit 0; seven-line output (Account, Token, Sub, Tier, Expires, Email, Org) with expiry detail.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus

---

### IT-10: `format::json` returns `{"account":"...","token":"..."}`

**Goal:** Confirm JSON format output is a valid JSON object with `account` and `token` fields.
**Setup:** Write `~/.claude/accounts/_active` = `"work"`. Write valid credentials.
**Command:** `clp .account.status format::json`
**Expected Output:** A single JSON object `{"account":"work","token":"valid"}`.
**Verification:**
- Capture stdout
- Assert exit code is 0
- Parse stdout as JSON (must not fail)
- Assert parsed value is a JSON object
- Assert object has `account` field equal to `"work"`
- Assert object has `token` field equal to `"valid"`
**Pass Criteria:** Exit 0; valid JSON object with both required fields.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus

---

### IT-11: `name::` = active account → same name and "valid" as no-name path

**Goal:** Confirm `name::work` when `work` is the active account produces equivalent output to omitting `name::`.
**Setup:** Write `work` as active account with valid far-future credentials.
**Command:** `clp .account.status name::work`
**Expected Output:** Contains `work` and `valid`.
**Verification:**
- Assert exit code is 0
- Assert stdout contains `work`
- Assert stdout contains `valid`
**Pass Criteria:** Exit 0; named active account shown correctly.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus (FR-16)

---

### IT-12: `name::` = non-active account → shows that account's own expired token

**Goal:** Confirm the P2 guard: `name::personal` where personal has an expired token (but active account `work` has valid token) reports `expired`, not `valid`.
**Setup:** Write `work` as active with valid far-future token. Write `personal` as non-active with past-expired token.
**Command:** `clp .account.status name::personal`
**Expected Output:** Contains `personal` and `expired`. Does NOT contain `valid`.
**Verification:**
- Assert exit code is 0
- Assert stdout contains `personal`
- Assert stdout contains `expired`
- Assert stdout does NOT contain `valid`
**Pass Criteria:** Exit 0; non-active account reports its own token state, not the active account's.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus (FR-16, P2)

---

### IT-13: `name::` = nonexistent account → exit 2 + "not found" in stderr

**Goal:** Confirm that querying an unknown account name produces exit 2 with a descriptive error.
**Setup:** Write `work` as active with valid credentials. Do NOT create a `ghost` account.
**Command:** `clp .account.status name::ghost`
**Expected Output:** Empty stdout; stderr contains `not found` or `ghost`.
**Verification:**
- Assert exit code is 2
- Assert stderr contains `not found` or `ghost`
- Assert stdout is empty
**Pass Criteria:** Exit 2; unknown account name reported clearly.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus (FR-16)

---

### IT-14: `name::` with invalid chars → exit 1

**Goal:** Confirm that a `name::` value containing `/` is rejected as a usage error.
**Setup:** Any valid active account exists.
**Command:** `clp .account.status name::a/b`
**Expected Output:** Exit 1; stderr contains validation error.
**Verification:**
- Assert exit code is 1
**Pass Criteria:** Exit 1; forbidden character rejected before lookup.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus (FR-16)

---

### IT-15: `name::` + `v::0` → two bare lines (name, token state)

**Goal:** Confirm `v::0` with a named account produces exactly two unlabelled lines.
**Setup:** Write `work` as active with valid far-future credentials.
**Command:** `clp .account.status name::work v::0`
**Expected Output:** Exactly two lines: `work` and `valid`.
**Verification:**
- Assert exit code is 0
- Assert stdout splits into exactly 2 lines
- Assert line 0 is `work`
- Assert line 1 is `valid`
- Assert stdout does NOT contain `Account:`
**Pass Criteria:** Exit 0; bare two-line output matching account name and token state.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus (FR-16)

---

### IT-16: `name::` = active + `.claude.json` present → shows Email/Org at `v::1`

**Goal:** Confirm that at `v::1`, querying the active account shows email and org from `.claude.json`.
**Setup:** Write `work` as active with valid credentials. Write `~/.claude/.claude.json` with `emailAddress` = `alice@example.com` and `organizationName` = `Acme Corp`.
**Command:** `clp .account.status name::work v::1`
**Expected Output:** Contains `alice@example.com` and `Acme Corp`.
**Verification:**
- Assert exit code is 0
- Assert stdout contains `alice@example.com`
- Assert stdout contains `Acme Corp`
**Pass Criteria:** Exit 0; active account's email/org shown from `.claude.json`.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus (FR-16)

---

### IT-17: `name::` = non-active + `v::1` → Email and Org are N/A

**Goal:** Confirm that at `v::1`, querying a non-active account shows N/A for email/org even if `.claude.json` exists.
**Setup:** Write `work` as active. Write `personal` as non-active. Write `.claude.json` with `alice@example.com`.
**Command:** `clp .account.status name::personal v::1`
**Expected Output:** Contains `personal` and `N/A`. Does NOT contain `alice@example.com`.
**Verification:**
- Assert exit code is 0
- Assert stdout contains `personal`
- Assert stdout contains `N/A`
- Assert stdout does NOT contain `alice@example.com`
**Pass Criteria:** Exit 0; active session's email not leaked to non-active account query.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus (FR-16, P3)

---

### IT-18: `name::` = non-active + `v::2` → "Expires:" line present

**Goal:** Confirm that `v::2` includes the `Expires:` line for a named account query.
**Setup:** Write `work` as active. Write `personal` as non-active with far-future token.
**Command:** `clp .account.status name::personal v::2`
**Expected Output:** Contains `personal` and `Expires:`.
**Verification:**
- Assert exit code is 0
- Assert stdout contains `personal`
- Assert stdout contains `Expires:`
**Pass Criteria:** Exit 0; expiry detail line present at v::2.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus (FR-16)

---

### IT-19: `name::` + `format::json` → JSON with `account` and `token` fields

**Goal:** Confirm JSON output for a named account query has the correct `account` and `token` fields.
**Setup:** Write `work` as active with valid credentials.
**Command:** `clp .account.status name::work format::json`
**Expected Output:** `{"account":"work","token":"valid"}`.
**Verification:**
- Assert exit code is 0
- Assert stdout starts with `{`
- Assert stdout contains `"account":"work"`
- Assert stdout contains `"token":"valid"`
**Pass Criteria:** Exit 0; valid JSON with correct field values.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus (FR-16)

---

### IT-20: `name::` = non-active + `v::0` → two bare lines with named account's state

**Goal:** Confirm the P2 guard at `v::0`: `name::personal` where personal has an expired token produces bare `personal` then `expired`.
**Setup:** Write `work` as active with valid token. Write `personal` as non-active with past-expired token.
**Command:** `clp .account.status name::personal v::0`
**Expected Output:** Exactly two lines: `personal` and `expired`.
**Verification:**
- Assert exit code is 0
- Assert stdout splits into exactly 2 lines
- Assert line 0 is `personal`
- Assert line 1 is `expired`
**Pass Criteria:** Exit 0; non-active account's own expired state shown in bare format.
**Source:** [commands.md — .account.status]../../commands.md#command--4-accountstatus (FR-16, P2)

---

### IT-21: Active path `v::1` — default `.account.status` shows Sub:, Tier:, Email:, Org:

**Goal:** Confirm the active-path `v::1` output includes `Sub:`, `Tier:`, `Email:`, and `Org:` fields after the FR-16 spec compliance fix.
**Setup:** Write `work` as active with valid far-future credentials (subscriptionType=`pro`, rateLimitTier=`standard`). Write `~/.claude/.claude.json` with emailAddress=`alice@example.com` and organizationName=`Acme Corp`.
**Command:** `clp .account.status` (implicit v::1)
**Expected Output:** Contains `Sub:`, `Tier:`, `pro`, `standard`, `alice@example.com`, `Acme Corp`.
**Verification:**
- Assert exit code is 0
- Assert stdout contains `Sub:`
- Assert stdout contains `Tier:`
- Assert stdout contains `pro`
- Assert stdout contains `standard`
- Assert stdout contains `alice@example.com`
- Assert stdout contains `Acme Corp`
**Pass Criteria:** Exit 0; all four fields present in v::1 output.
**Source:** `account_list_status_test.rs::astat11_v1_shows_sub_tier_email_org` (spec FR-16 line 283)

---

### IT-22: Named active `v::1``name::work v::1` shows Sub:, Tier:, Email:, Org:

**Goal:** Confirm `name::work v::1` when `work` is the active account shows `Sub:`, `Tier:`, `Email:`, and `Org:`.
**Setup:** Write `work` as active with valid far-future credentials (subscriptionType=`pro`, rateLimitTier=`standard`). Write `.claude.json` with email and org.
**Command:** `clp .account.status name::work v::1`
**Expected Output:** Contains `Sub:`, `Tier:`, `pro`, `standard`.
**Verification:**
- Assert exit code is 0
- Assert stdout contains `Sub:`
- Assert stdout contains `Tier:`
- Assert stdout contains `pro`
- Assert stdout contains `standard`
**Pass Criteria:** Exit 0; Sub/Tier fields present in named-active v::1 output.
**Source:** `account_status_name_test.rs::astname11_active_named_v1_shows_sub_tier` (spec FR-16 line 283)

---

### IT-23: Named non-active `v::1``name::personal v::1` shows own Sub:, Tier: (not active's)

**Goal:** Confirm that querying a non-active account at `v::1` shows that account's own `Sub:` and `Tier:` — not the active account's values.
**Setup:** Write `work` as active with subscriptionType=`max` and rateLimitTier=`tier4`. Write `personal` as non-active with subscriptionType=`pro` and rateLimitTier=`standard`.
**Command:** `clp .account.status name::personal v::1`
**Expected Output:** Contains `pro` and `standard`. Does NOT contain `max` or `tier4`.
**Verification:**
- Assert exit code is 0
- Assert stdout contains `Sub:`
- Assert stdout contains `Tier:`
- Assert stdout contains `pro`
- Assert stdout contains `standard`
- Assert stdout does NOT contain `max`
- Assert stdout does NOT contain `tier4`
**Pass Criteria:** Exit 0; non-active account's own Sub/Tier shown without leaking active account's values.
**Source:** `account_status_name_test.rs::astname12_nonactive_named_v1_shows_own_sub_tier` (spec FR-16 line 283)

---

### IT-24: Active path — empty-string `subscriptionType` in credentials → `Sub: N/A`

**Goal:** Confirm that an empty-string `subscriptionType` in `~/.claude/.credentials.json` produces `Sub:     N/A` rather than a blank `Sub:     ` line.
**Setup:** Write `work` as active with valid far-future expiry. Write `~/.claude/.credentials.json` manually with `"subscriptionType":""` (explicit empty string) and `"rateLimitTier":"standard"`.
**Command:** `clp .account.status` (implicit v::1)
**Expected Output:** Contains `Sub:     N/A`.
**Verification:**
- Assert exit code is 0
- Assert stdout contains `Sub:     N/A`
**Pass Criteria:** Exit 0; empty-string subscriptionType normalizes to N/A, not a blank value.
**Source:** `account_list_status_test.rs::astat12_v1_empty_sub_in_creds_shows_n_a` (spec FR-16)

---

### IT-25: Named non-active — `subscriptionType` absent in account file → `Sub: N/A`

**Goal:** Confirm that a missing `subscriptionType` field in a named account's credential file produces `Sub:     N/A` rather than a blank line.
**Setup:** Write `work` as active with `subscriptionType=max`. Write `personal` as non-active with a credentials file that has no `subscriptionType` field at all (only `rateLimitTier` and `expiresAt`).
**Command:** `clp .account.status name::personal`
**Expected Output:** Contains `Sub:     N/A`.
**Verification:**
- Assert exit code is 0
- Assert stdout contains `Sub:     N/A`
**Pass Criteria:** Exit 0; absent subscriptionType field normalizes to N/A via empty-string path from `unwrap_or_default()`.
**Source:** `account_status_name_test.rs::astname13_missing_sub_in_file_shows_n_a` (spec FR-16)

---

### IT-26: Named non-active — `rateLimitTier` absent in account file → `Tier: N/A`

**Goal:** Confirm that a missing `rateLimitTier` field in a named account's credential file produces `Tier:    N/A` rather than a blank line.
**Setup:** Write `work` as active with `rateLimitTier=tier4`. Write `personal` as non-active with a credentials file that has no `rateLimitTier` field (only `subscriptionType` and `expiresAt`).
**Command:** `clp .account.status name::personal`
**Expected Output:** Contains `Tier:    N/A`.
**Verification:**
- Assert exit code is 0
- Assert stdout contains `Tier:    N/A`
**Pass Criteria:** Exit 0; absent rateLimitTier field normalizes to N/A via empty-string path from `unwrap_or_default()`.
**Source:** `account_status_name_test.rs::astname14_missing_tier_in_file_shows_n_a` (spec FR-16)