|
1 | | -# Resume State — Spec 0030 primitive_obsession |
| 1 | +# Resume State — Spec 0031 test_naming_conventions |
2 | 2 |
|
3 | | -**Last updated:** 2026-06-08 |
4 | | -**Branch:** `primitive_obsession` |
5 | | -**Spec dir:** `specs/0030-primitive_obsession/` · `specs/.current-spec` = `0030-primitive_obsession` |
6 | | -**Issue:** #4164 · ADR: `docs/adr/0061-box-provisioning-value-types.md` |
7 | | -**HEAD:** `7f451cd96` |
| 3 | +**Last updated:** 2026-06-09 |
| 4 | +**Branch:** `test_naming` · **Spec dir:** `specs/0031-test_naming_conventions/` · **Issue:** #4157 |
8 | 5 |
|
9 | | -## Where we are in the workflow |
| 6 | +## ✅ STATUS: IMPLEMENTATION + VERIFICATION COMPLETE — nothing pushed yet |
10 | 7 |
|
11 | | -Issue → **Requirements ✅** → **Design (ADR 0061) ✅** → **Tasks ✅** → **Tests/Code ✅** → **Code Review ✅ (all findings resolved)** |
| 8 | +Spec 0031 was a **pure rename refactor** (no behaviour/assertion/logic/count changes; `/test-first` |
| 9 | +did not apply). All 7 tasks done & committed on `test_naming`: |
12 | 10 |
|
13 | | -## Code Review — COMPLETE ✅ |
14 | | - |
15 | | -Findings from `specs/0030-primitive_obsession/review-code.md` all resolved in `7f451cd96`: |
16 | | -- **Finding 2 (Score 72)** — Spanner provisioners now forward `_configuration.SchemaName` to migration activity |
17 | | -- **Finding 1 fix-forward** — ServiceActivator .Value call-site completions for string?-widened operators |
18 | | -- **Finding 3 (Score 64)** — 4 characterisation tests added for mapper null paths |
19 | | -- **Phase 2 miss** — 3 BoxProvisioning test doubles updated to `BoxTableName` type |
20 | | -- **Finding 4 (Score 38)** / **Finding 5 (Score 22)** — low severity, no action required |
21 | | - |
22 | | -## Phase 1 — COMPLETE ✅ (111/111 tests, net9.0) |
23 | | - |
24 | | -All six value types implemented and committed: |
25 | | - |
26 | | -| Commit | What | |
| 11 | +| Commit | Task | |
27 | 12 | |---|---| |
28 | | -| `6262cc15d` | fix: resolve CS8604/CS8601 call-site nullability in `Paramore.Brighter` (boy-scout) | |
29 | | -| `56f77029a` | feat(spec-0030): `BoxTableName` round-trip + value equality (4 tests) | |
30 | | -| `056204fc7` | feat(spec-0030): `BoxTableName.IsNullOrEmpty` (3 tests) | |
31 | | -| `30e7ea169` | feat(spec-0030): `SchemaName` round-trip + nullable + `IsNullOrEmpty` (8 tests) | |
32 | | -| `2efa24466` | feat(spec-0030): `MigrationDescription` round-trip + `IsNullOrEmpty` (7 tests) | |
33 | | -| `e8f854397` | feat(spec-0030): `SqlScript` round-trip + nullable + no-validation + `IsNullOrEmpty` (9 tests) | |
34 | | -| `a92ffc70c` | feat(spec-0030): `SourceReference` round-trip + nullable + `IsNullOrEmpty` (8 tests) | |
35 | | -| `4cb46c41d` | feat(spec-0030): `MigrationVersion` round-trip + int arithmetic + `IComparable` (7 tests) | |
36 | | - |
37 | | -New type files (all in `src/Paramore.Brighter.BoxProvisioning/`): |
38 | | -- `BoxTableName.cs`, `SchemaName.cs`, `MigrationDescription.cs` |
39 | | -- `SqlScript.cs`, `SourceReference.cs`, `MigrationVersion.cs` |
40 | | - |
41 | | ---- |
42 | | - |
43 | | -## Phase 2 — COMPLETE ✅ (111/111 tests net9.0+net10.0, all TFMs build clean) |
44 | | - |
45 | | -Commit: `2d0aaa80c` — retype BoxProvisioning contracts to value types. |
46 | | - |
47 | | -All Phase 3 and Phase 4 verification tasks also done: |
48 | | -- All 4 relational backends + Spanner compile with 0 warnings/errors |
49 | | -- All 4 TFMs (netstandard2.0/net8/net9/net10) build clean |
50 | | -- Identifier-validation regression: 11/11 tests pass |
51 | | -- Monotonicity regression: pass |
52 | | -- Full suite: 111/111 on net9.0 and net10.0 |
53 | | -- No types leaked outside Paramore.Brighter.BoxProvisioning |
54 | | -- Core Paramore.Brighter assembly unmodified |
55 | | - |
56 | | -## Current phase: CODE REVIEW 🔄 |
57 | | - |
58 | | -All implementation tasks complete. Ready for `/spec:review` or PR creation. |
59 | | - |
60 | | ---- |
61 | | - |
62 | | -### Archived: Phase 2 contract-retyping plan (for reference) |
63 | | - |
64 | | -### Task 2a — Retype `IAmABoxMigration` and `BoxMigration` |
65 | | - |
66 | | -Files to edit: |
67 | | -- `src/Paramore.Brighter.BoxProvisioning/IAmABoxMigration.cs` |
68 | | -- `src/Paramore.Brighter.BoxProvisioning/BoxMigration.cs` |
69 | | - |
70 | | -Changes: |
71 | | -- `int Version` → `MigrationVersion` |
72 | | -- `string Description` → `MigrationDescription` |
73 | | -- `string UpScript` → `SqlScript` |
74 | | -- `string? SourceReference` → `SourceReference?` |
75 | | -- `string? IdempotencyCheckSql` → `SqlScript?` |
76 | | -- `LogicalColumns` stays `IReadOnlyCollection<string>` — do NOT change |
77 | | - |
78 | | -Verify existing `new BoxMigration(1, "Add Source", "ALTER TABLE …", new[] { "Source" })` call sites in the four relational catalog assemblies compile unchanged via implicit conversions (no argument changes needed). |
79 | | - |
80 | | -### Task 2b — Retype `IAmABoxMigrationRunner.MigrateAsync` + fix D4 ternary |
81 | | - |
82 | | -Files to edit: |
83 | | -- `src/Paramore.Brighter.BoxProvisioning/IAmABoxMigrationRunner.cs` |
84 | | -- `src/Paramore.Brighter.BoxProvisioning/SqlBoxMigrationRunner.cs` |
85 | | - |
86 | | -Changes: |
87 | | -- `MigrateAsync(string tableName, string? schemaName, …)` → `MigrateAsync(BoxTableName tableName, SchemaName? schemaName, …)` |
88 | | -- **D4 ternary** at `SqlBoxMigrationRunner.cs:285`: change to `migrations.Count == 0 ? (MigrationVersion)0 : migrations[migrations.Count - 1].Version` (resolves CS0172 bidirectional-implicit ambiguity) |
89 | | -- `Identifiers.AssertSafe(tableName, …)` and `AssertSafe(schemaName, …)` lines ~191/194 pass `string?` via implicit conversion — resolve any CS8604 with `.Value` or `!`, do NOT revert operator return type |
90 | | -- `SqlBoxProvisioner` call `_migrationRunner.MigrateAsync(BoxTableName, _configuration.SchemaName, …)` compiles via implicit `string? → SchemaName?` |
91 | | - |
92 | | -### Task 2c — Retype `IAmABoxProvisioner.BoxTableName` |
93 | | - |
94 | | -Files to edit: |
95 | | -- `src/Paramore.Brighter.BoxProvisioning/IAmABoxProvisioner.cs` |
96 | | -- `src/Paramore.Brighter.BoxProvisioning/SqlBoxProvisioner.cs` (line ~105) |
97 | | - |
98 | | -Changes: |
99 | | -- `string BoxTableName` property → `BoxTableName` |
100 | | -- `SqlBoxProvisioner` derives property from `_configuration.OutBoxTableName`/`InBoxTableName` (core `string`) — compiles via implicit conversion, no core changes |
101 | | -- `Identifiers.AssertSafe(BoxTableName, …)` at line ~105 still compiles via implicit `→ string?`; resolve CS8604 with `.Value` or `!` |
102 | | - |
103 | | -### Task 2d — Update test doubles to new types (mechanical, no behaviour) |
104 | | - |
105 | | -Files to edit (exhaustive list): |
106 | | - |
107 | | -**`IAmABoxMigration` implementers** (update property declarations only): |
108 | | -- `tests/.../When_relational_box_migration_runner_base_migrate_receives_non_monotonic_migrations_it_should_throw_before_opening_connection.cs` (`StubBoxMigration`) |
109 | | -- `tests/.../When_relational_box_migration_runner_base_migrate_receives_unsafe_identifier_it_should_throw_before_opening_connection.cs` (`StubBoxMigration`) |
110 | | - |
111 | | -**`IAmABoxMigrationRunner` direct implementers** (update `MigrateAsync` signature only): |
112 | | -- `tests/.../When_sql_box_provisioner_detect_table_state_inlines_negative_version_clamp.cs` (`VersionCapturingMigrationRunner`) |
113 | | -- `tests/.../When_sql_box_provisioner_effective_schema_name_is_overridden_it_should_propagate_to_detection_and_payload_calls_only.cs` (`SchemaCapturingMigrationRunner`) |
114 | | -- `tests/.../When_sql_box_provisioner_provision_async_receives_unsafe_identifier_it_should_throw_before_opening_connection.cs` (`ThrowingMigrationRunner`) |
115 | | -- `tests/.../When_sql_box_provisioner_provision_async_runs_successfully_it_should_invoke_hooks_in_documented_order.cs` (`RecordingMigrationRunner`) |
116 | | - |
117 | | -**`IAmABoxProvisioner` implementer**: |
118 | | -- `tests/.../TestDoubles/StubBoxProvisioner.cs` (`BoxTableName` property type) |
119 | | - |
120 | | -Do NOT modify: `StubBoxDetectionHelper.cs` (detection-helper, out of scope). |
121 | | - |
122 | | ---- |
123 | | - |
124 | | -## Phase 3 — Backend compilability (after Phase 2) |
125 | | - |
126 | | -Build all four relational backends (MsSql, MySql, PostgreSql, Sqlite) + Spanner against the retyped interfaces. Confirm compilation via implicit conversions — no argument changes expected. Also confirm null-path behaviour: SQLite null `SchemaName` and V2+ null `IdempotencyCheckSql` produce no NRE. |
127 | | - |
128 | | ---- |
129 | | - |
130 | | -## Phase 4 — Cross-cutting verification (after Phase 3) |
131 | | - |
132 | | -1. All TFMs compile (`netstandard2.0;net8.0;net9.0;net10.0`) — confirm no `netstandard2.0`-unavailable APIs |
133 | | -2. Identifier-validation regression: `1Outbox` → `ConfigurationException`; SQLite null schema → succeeds |
134 | | -3. Monotonicity regression: `[1,2,3]` passes; `[1,3]` → `ConfigurationException` with `V1 followed by V3 (expected V2)` |
135 | | -4. Full suite parity + telemetry/log string content unchanged |
136 | | -5. Scope guard: no new types leaked outside `Paramore.Brighter.BoxProvisioning`; core assembly unmodified |
137 | | - |
138 | | ---- |
139 | | - |
140 | | -## Key implementation notes |
141 | | - |
142 | | -- **No behaviour changes in Phase 2** — only type signatures change; call sites compile via implicit conversions |
143 | | -- **D4 ternary** is the one required explicit cast; it is pre-identified at `SqlBoxMigrationRunner.cs:285` |
144 | | -- **`AssertSafe` stays at call sites** — do NOT move validation into constructors (D3) |
145 | | -- **`LogicalColumns` unchanged** — stays `IReadOnlyCollection<string>` throughout (D5) |
146 | | -- **CS8604 pattern**: all string-backed operators return `string?`; when passing into non-nullable `AssertSafe(string, …)`, resolve with `.Value` or `!` at the call site (established codebase pattern) |
147 | | -- Phase 2 tasks 2a–2c should each be committed separately; 2d (test doubles) committed after 2c |
148 | | - |
149 | | -## Test run command |
150 | | - |
| 13 | +| `a3b2bc33d` | T2 — BoxProvisioning.Tests (2) | |
| 14 | +| `53520bb84` | T3 — Sqlite (22) | |
| 15 | +| `d9947c90b` | T4 — MSSQL (33) | |
| 16 | +| `e9358acb3` | T5 — MySQL (27) | |
| 17 | +| `24c4f168d` | T6 — PostgreSQL (34) | |
| 18 | +| `299f18d5c` | spec docs + T1 baseline + T7 sign-off | |
| 19 | + |
| 20 | +**118 non-conforming files renamed** to the convention in `.agent_instructions/testing.md` |
| 21 | +(class `[Behavior]Tests`, method `When_..._should_...`). 0 WRONG + 0 MIXED remain. All AC-1..10 PASS; |
| 22 | +all 5 projects build clean; count + green/red parity vs baseline (MSSQL keeps its 13 pre-existing |
| 23 | +failures — 12 = DateTimeOffset/BST #4161, 1 now under a renamed FQN). 0 file renames needed (names |
| 24 | +already conformed), 0 `src/`/analyzer/CI/agent-instruction changes, 0 `Assert.` lines touched. |
| 25 | +Full evidence: `specs/0031-test_naming_conventions/.scratch/T7-signoff.md`. |
| 26 | + |
| 27 | +## ▶️ FIRST THING NEXT SESSION — ask before reviewing |
| 28 | + |
| 29 | +This change is **style only** (identifier + comment renames, mechanically verified by build + suite |
| 30 | +parity). Before doing more work, **ASK the user whether a `/spec:review code` / code review is even |
| 31 | +warranted here**, or whether we should skip straight to opening the PR / merging. A full adversarial |
| 32 | +code review is likely overkill for a rename-only diff — surface that and let the user decide. |
| 33 | + |
| 34 | +## Remaining options (pending the user's answer) |
| 35 | +- `/spec:review code` (if they want it) → then PR / merge, OR |
| 36 | +- open PR for branch `test_naming` directly, OR |
| 37 | +- merge to `master`. |
| 38 | + |
| 39 | +## Verify (per project) |
151 | 40 | ```bash |
152 | | -dotnet test tests/Paramore.Brighter.BoxProvisioning.Tests/ --framework net9.0 --no-build -q |
| 41 | +dotnet test tests/Paramore.Brighter.<Project>.Tests --framework net9.0 -q |
153 | 42 | ``` |
154 | | - |
155 | | -## Spec 0030 about |
156 | | - |
157 | | -Replace bare `string`/`int` primitives in Box Provisioning public interfaces with six dedicated value-type `record`s modelled on `src/Paramore.Brighter/Id.cs`. Six types: `BoxTableName`, `SchemaName`, `MigrationDescription`, `SqlScript`, `SourceReference`, `MigrationVersion`. Implicit conversions preserve full source compatibility at every existing call site. |
0 commit comments